1439 lines
58 KiB
C#
1439 lines
58 KiB
C#
namespace System.Workflow.ComponentModel.Design
|
|
{
|
|
using System;
|
|
using System.IO;
|
|
using System.Drawing;
|
|
using System.Diagnostics;
|
|
using System.Collections;
|
|
using System.Windows.Forms;
|
|
using System.ComponentModel;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel.Design;
|
|
using System.Collections.ObjectModel;
|
|
using System.Workflow.ComponentModel.Design;
|
|
using System.ComponentModel.Design.Serialization;
|
|
using System.Workflow.ComponentModel.Serialization;
|
|
|
|
#region Interface IConnectableDesigner
|
|
internal interface IConnectableDesigner
|
|
{
|
|
bool CanConnect(ConnectionPoint source, ConnectionPoint target);
|
|
void OnConnected(ConnectionPoint source, ConnectionPoint target);
|
|
}
|
|
#endregion
|
|
|
|
#region Enum ZOrder
|
|
internal enum ZOrder
|
|
{
|
|
Foreground = 1,
|
|
Background = 2
|
|
}
|
|
#endregion
|
|
|
|
#region Class FreeformActivityDesigner
|
|
//
|
|
|
|
|
|
|
|
|
|
//By default this designer will use the CompositeActivityDesigner theme
|
|
[DesignerSerializer(typeof(FreeformActivityDesignerLayoutSerializer), typeof(WorkflowMarkupSerializer))]
|
|
[Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")]
|
|
public class FreeformActivityDesigner : CompositeActivityDesigner
|
|
{
|
|
#region Class FreeformDesignerAccessibleObject
|
|
|
|
internal class FreeformDesignerAccessibleObject : CompositeDesignerAccessibleObject
|
|
{
|
|
public FreeformDesignerAccessibleObject(FreeformActivityDesigner activityDesigner)
|
|
: base(activityDesigner)
|
|
{
|
|
}
|
|
|
|
public override AccessibleObject GetChild(int index)
|
|
{
|
|
FreeformActivityDesigner designer = (FreeformActivityDesigner)this.ActivityDesigner;
|
|
if (designer.ShowConnectorsInForeground)
|
|
{
|
|
int connectorsCount = designer.Connectors.Count;
|
|
if (index < connectorsCount)
|
|
return designer.Connectors[index].AccessibilityObject;
|
|
else
|
|
return designer.ContainedDesigners[index - connectorsCount].AccessibilityObject;
|
|
}
|
|
else
|
|
{
|
|
int containedDesignersCount = designer.ContainedDesigners.Count;
|
|
if (index < containedDesignersCount)
|
|
return designer.ContainedDesigners[index].AccessibilityObject;
|
|
else
|
|
return designer.Connectors[index - containedDesignersCount].AccessibilityObject;
|
|
}
|
|
}
|
|
|
|
public override int GetChildCount()
|
|
{
|
|
FreeformActivityDesigner designer = (FreeformActivityDesigner)this.ActivityDesigner;
|
|
int count = base.GetChildCount() + designer.Connectors.Count;
|
|
return count;
|
|
}
|
|
}
|
|
|
|
#endregion Class FreeformDesignerAccessibleObject
|
|
|
|
#region Members
|
|
internal static Size DefaultAutoSizeMargin = new Size(40, 40);
|
|
|
|
private FreeformDesignerAccessibleObject accessibilityObject;
|
|
private bool autoSize = true;
|
|
private AutoSizeMode autoSizeMode = AutoSizeMode.GrowOnly;
|
|
private Size autoSizeMargin = FreeformActivityDesigner.DefaultAutoSizeMargin;
|
|
|
|
private bool enableUserDrawnConnectors = true;
|
|
private List<Connector> connectors = new List<Connector>();
|
|
|
|
private bool retainContainedDesignerLocations = false;
|
|
|
|
public event ConnectorEventHandler ConnectorAdded;
|
|
public event ConnectorEventHandler ConnectorChanged;
|
|
public event ConnectorEventHandler ConnectorRemoved;
|
|
#endregion
|
|
|
|
#region Construction / Destruction
|
|
public FreeformActivityDesigner()
|
|
{
|
|
}
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
#region Public Properties
|
|
|
|
public override AccessibleObject AccessibilityObject
|
|
{
|
|
get
|
|
{
|
|
if (this.accessibilityObject == null)
|
|
this.accessibilityObject = new FreeformDesignerAccessibleObject(this);
|
|
return this.accessibilityObject;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or Sets value indicating if the designer will be resized automatically based on the child designers
|
|
/// </summary>
|
|
[DefaultValue(true)]
|
|
public bool AutoSize
|
|
{
|
|
get
|
|
{
|
|
return this.autoSize;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (this.autoSize == value)
|
|
return;
|
|
|
|
this.autoSize = value;
|
|
PerformLayout();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or Sets the auto sizing mode
|
|
/// </summary>
|
|
[DefaultValue(AutoSizeMode.GrowOnly)]
|
|
public AutoSizeMode AutoSizeMode
|
|
{
|
|
get
|
|
{
|
|
return this.autoSizeMode;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (this.autoSizeMode == value)
|
|
return;
|
|
|
|
this.autoSizeMode = value;
|
|
PerformLayout();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the margins left around the contained designers when autosizing
|
|
/// </summary>
|
|
public Size AutoSizeMargin
|
|
{
|
|
get
|
|
{
|
|
Size margin = this.autoSizeMargin;
|
|
if (WorkflowTheme.CurrentTheme.AmbientTheme.ShowGrid)
|
|
{
|
|
Size gridSize = WorkflowTheme.CurrentTheme.AmbientTheme.GridSize;
|
|
margin.Width += gridSize.Width / 2;
|
|
margin.Height += gridSize.Height / 2;
|
|
}
|
|
|
|
return margin;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (this.autoSizeMargin == value)
|
|
return;
|
|
|
|
this.autoSizeMargin = value;
|
|
PerformLayout();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Allows user to drag and draw connectors on the design surface
|
|
/// </summary>
|
|
[DefaultValue(true)]
|
|
public bool EnableUserDrawnConnectors
|
|
{
|
|
get
|
|
{
|
|
return (this.enableUserDrawnConnectors && IsEditable);
|
|
}
|
|
|
|
set
|
|
{
|
|
this.enableUserDrawnConnectors = value;
|
|
}
|
|
}
|
|
|
|
public override bool CanExpandCollapse
|
|
{
|
|
get
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public override object FirstSelectableObject
|
|
{
|
|
get
|
|
{
|
|
IList<ActivityDesigner> childdesigners = ContainedDesigners;
|
|
return (childdesigners.Count > 0) ? childdesigners[0].Activity : null;
|
|
}
|
|
}
|
|
|
|
public override object LastSelectableObject
|
|
{
|
|
get
|
|
{
|
|
IList<ActivityDesigner> childdesigners = ContainedDesigners;
|
|
return (childdesigners.Count > 0) ? childdesigners[childdesigners.Count - 1].Activity : null;
|
|
}
|
|
}
|
|
|
|
public override Size MinimumSize
|
|
{
|
|
get
|
|
{
|
|
//Now go thru all the activity designers and consider the bottom coordinate + selection size + page separator as the min size
|
|
Size minimumSize = base.MinimumSize;
|
|
|
|
if (Activity != null && ((IComponent)Activity).Site != null && !(ParentDesigner is FreeformActivityDesigner))
|
|
{
|
|
minimumSize.Width *= 4;
|
|
minimumSize.Height *= 4;
|
|
}
|
|
|
|
//If the designer is root designer and not inlined then we should occupy the area of workflow view
|
|
if (IsRootDesigner && InvokingDesigner == null)
|
|
{
|
|
WorkflowView workflowView = ParentView;
|
|
minimumSize.Width = Math.Max(minimumSize.Width, workflowView.ViewPortSize.Width - 2 * WorkflowRootLayout.Separator.Width);
|
|
minimumSize.Height = Math.Max(minimumSize.Height, workflowView.ViewPortSize.Height - 2 * WorkflowRootLayout.Separator.Height);
|
|
}
|
|
|
|
if (AutoSize)
|
|
{
|
|
Rectangle childRectangle = GetEnclosingRectangle();
|
|
if (!childRectangle.IsEmpty)
|
|
{
|
|
minimumSize.Width = Math.Max(minimumSize.Width, childRectangle.Width);
|
|
minimumSize.Height = Math.Max(minimumSize.Height, childRectangle.Height);
|
|
}
|
|
}
|
|
|
|
return minimumSize;
|
|
}
|
|
}
|
|
|
|
public override Point Location
|
|
{
|
|
get
|
|
{
|
|
return base.Location;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (Location == value)
|
|
return;
|
|
|
|
//Please note that we require this logic to maintain the contained designer location when
|
|
//resizing the designer
|
|
ReadOnlyCollection<ActivityDesigner> containedDesigners = ContainedDesigners;
|
|
List<Point> containedDesignerLocations = new List<Point>();
|
|
if (this.retainContainedDesignerLocations)
|
|
{
|
|
foreach (ActivityDesigner activityDesigner in containedDesigners)
|
|
containedDesignerLocations.Add(activityDesigner.Location);
|
|
}
|
|
else
|
|
{
|
|
Size moveDelta = new Size(value.X - base.Location.X, value.Y - base.Location.Y);
|
|
FreeformActivityDesigner freeFormActivityDesigner = this;
|
|
Collection<Connector> connectors = new Collection<Connector>();
|
|
while (freeFormActivityDesigner != null)
|
|
{
|
|
foreach (Connector connector in freeFormActivityDesigner.Connectors)
|
|
if (connector.RenderingOwner == this)
|
|
connectors.Add(connector);
|
|
|
|
freeFormActivityDesigner = freeFormActivityDesigner.ParentDesigner as FreeformActivityDesigner;
|
|
}
|
|
foreach (Connector connector in connectors)
|
|
{
|
|
connector.Offset(moveDelta);
|
|
}
|
|
}
|
|
|
|
base.Location = value;
|
|
|
|
if (this.retainContainedDesignerLocations && containedDesigners.Count == containedDesignerLocations.Count)
|
|
{
|
|
for (int i = 0; i < containedDesigners.Count; i++)
|
|
containedDesigners[i].Location = containedDesignerLocations[i];
|
|
}
|
|
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns collection of connectors
|
|
/// </summary>
|
|
public ReadOnlyCollection<Connector> Connectors
|
|
{
|
|
get
|
|
{
|
|
return this.connectors.AsReadOnly();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Protected Properties
|
|
/// <summary>
|
|
/// Get the value indicating if the connectors are drawn in the forground
|
|
/// </summary>
|
|
protected virtual bool ShowConnectorsInForeground
|
|
{
|
|
get
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
protected internal override bool EnableVisualResizing
|
|
{
|
|
get
|
|
{
|
|
if (AutoSize && AutoSizeMode == AutoSizeMode.GrowAndShrink)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
}
|
|
|
|
protected internal override ActivityDesignerGlyphCollection Glyphs
|
|
{
|
|
get
|
|
{
|
|
ActivityDesignerGlyphCollection glyphs = new ActivityDesignerGlyphCollection();
|
|
glyphs.AddRange(base.Glyphs);
|
|
|
|
//Now go thru all the designers and for the designers which are connectable, return connection glyphs
|
|
//Also return the move glyphs for movable designer
|
|
ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
|
|
if (selectionService != null)
|
|
{
|
|
foreach (object selectedObject in selectionService.GetSelectedComponents())
|
|
{
|
|
ConnectorHitTestInfo connectorHitInfo = selectedObject as ConnectorHitTestInfo;
|
|
if (connectorHitInfo != null && connectorHitInfo.AssociatedDesigner == this)
|
|
glyphs.Add(new FreeFormConnectorSelectionGlyph(connectorHitInfo.MapToIndex(), (connectorHitInfo == selectionService.PrimarySelection)));
|
|
}
|
|
}
|
|
|
|
return glyphs;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Private Properties
|
|
internal override WorkflowLayout SupportedLayout
|
|
{
|
|
get
|
|
{
|
|
return new WorkflowRootLayout(Activity.Site);
|
|
}
|
|
}
|
|
|
|
#region Properties used during serialization only
|
|
//NOTE THAT THIS WILL ONLY BE USED FOR SERIALIZATION PURPOSES
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
internal List<Connector> DesignerConnectors
|
|
{
|
|
get
|
|
{
|
|
List<Connector> connectors = new List<Connector>(this.connectors);
|
|
return connectors;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
#region Public Methods
|
|
/// <summary>
|
|
/// Adds connector to the designer
|
|
/// </summary>
|
|
/// <param name="connector">Connector to add</param>
|
|
public Connector AddConnector(ConnectionPoint source, ConnectionPoint target)
|
|
{
|
|
if (source == null)
|
|
throw new ArgumentNullException("source");
|
|
|
|
if (source.AssociatedDesigner == null)
|
|
throw new ArgumentException("source", SR.GetString(SR.Error_AssociatedDesignerMissing));
|
|
|
|
if (target == null)
|
|
throw new ArgumentNullException("target");
|
|
|
|
if (target.AssociatedDesigner == null)
|
|
throw new ArgumentException("target", SR.GetString(SR.Error_AssociatedDesignerMissing));
|
|
|
|
//This check can be eliminated if it slows down connections, this is just to ensure we are adding connectors
|
|
//to correct activity designer
|
|
FreeformActivityDesigner connectorContainer = ConnectionManager.GetConnectorContainer(source.AssociatedDesigner);
|
|
if (this != connectorContainer)
|
|
throw new InvalidOperationException(DR.GetString(DR.Error_AddConnector1));
|
|
|
|
if ((Activity != source.AssociatedDesigner.Activity && !Helpers.IsChildActivity(Activity as CompositeActivity, source.AssociatedDesigner.Activity)) ||
|
|
(Activity != target.AssociatedDesigner.Activity && !Helpers.IsChildActivity(Activity as CompositeActivity, target.AssociatedDesigner.Activity)))
|
|
throw new ArgumentException(DR.GetString(DR.Error_AddConnector2));
|
|
|
|
Connector connector = CreateConnector(source, target);
|
|
if (connector != null)
|
|
{
|
|
if (this.connectors.Contains(connector))
|
|
throw new InvalidOperationException(DR.GetString(DR.Error_AddConnector3));
|
|
|
|
this.connectors.Add(connector);
|
|
connector.SetParent(this);
|
|
OnConnectorAdded(new ConnectorEventArgs(connector));
|
|
}
|
|
|
|
PerformLayout();
|
|
|
|
return connector;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes connector from the designer
|
|
/// </summary>
|
|
/// <param name="connector">Connector to remove</param>
|
|
public void RemoveConnector(Connector connector)
|
|
{
|
|
if (connector == null)
|
|
throw new ArgumentNullException("connector");
|
|
|
|
if (this.connectors.Contains(connector))
|
|
{
|
|
OnConnectorRemoved(new ConnectorEventArgs(connector));
|
|
connector.SetParent(null);
|
|
this.connectors.Remove(connector);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends the contained designer to back of z-order
|
|
/// </summary>
|
|
/// <param name="containedDesigner">Designer to send to back</param>
|
|
public void SendToBack(ActivityDesigner containedDesigner)
|
|
{
|
|
if (containedDesigner == null)
|
|
throw new ArgumentNullException("containedDesigner");
|
|
|
|
if (!ContainedDesigners.Contains(containedDesigner))
|
|
throw new ArgumentException(DR.GetString(DR.InvalidDesignerSpecified, "containedDesigner"));
|
|
|
|
UpdateZOrder(containedDesigner, ZOrder.Background);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Brings the contained designer to top of z-order
|
|
/// </summary>
|
|
/// <param name="containedDesigner">Designer to bring to front</param>
|
|
public void BringToFront(ActivityDesigner containedDesigner)
|
|
{
|
|
if (containedDesigner == null)
|
|
throw new ArgumentNullException("containedDesigner");
|
|
|
|
if (!ContainedDesigners.Contains(containedDesigner))
|
|
throw new ArgumentException(DR.GetString(DR.InvalidDesignerSpecified, "containedDesigner"));
|
|
|
|
UpdateZOrder(containedDesigner, ZOrder.Foreground);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Moves specified contained designer to specified location inside designer
|
|
/// </summary>
|
|
/// <param name="containedDesigner">Designer to move</param>
|
|
/// <param name="newLocation">Location to move to.</param>
|
|
public void MoveContainedDesigner(ActivityDesigner containedDesigner, Point newLocation)
|
|
{
|
|
if (containedDesigner == null)
|
|
throw new ArgumentNullException("containedDesigner");
|
|
|
|
if (!ContainedDesigners.Contains(containedDesigner))
|
|
throw new ArgumentException(DR.GetString(DR.InvalidDesignerSpecified, "containedDesigner"));
|
|
|
|
FreeformActivityDesigner.SetDesignerBounds(containedDesigner, new Rectangle(newLocation, containedDesigner.Size));
|
|
|
|
PerformLayout();
|
|
Invalidate();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resizes specified contained designer to specified size
|
|
/// </summary>
|
|
/// <param name="containedDesigner">Designer to resize</param>
|
|
/// <param name="newSize">Size to resize it to</param>
|
|
public void ResizeContainedDesigner(ActivityDesigner containedDesigner, Size newSize)
|
|
{
|
|
if (containedDesigner == null)
|
|
throw new ArgumentNullException("containedDesigner");
|
|
|
|
if (!ContainedDesigners.Contains(containedDesigner))
|
|
throw new ArgumentException(DR.GetString(DR.InvalidDesignerSpecified, "containedDesigner"));
|
|
|
|
FreeformActivityDesigner.SetDesignerBounds(containedDesigner, new Rectangle(containedDesigner.Location, newSize));
|
|
|
|
PerformLayout();
|
|
}
|
|
|
|
public override HitTestInfo HitTest(Point point)
|
|
{
|
|
HitTestInfo hitInfo = base.HitTest(point);
|
|
|
|
//First check that if the drag drop is in progress and the drop operation has been initiated based on
|
|
//A child designer then if the queried point is also on the drop initiated designer then we return freeform
|
|
//designer as the designer where hittest occured
|
|
ReadOnlyCollection<ActivityDesigner> containedDesigners = ContainedDesigners;
|
|
|
|
WorkflowView workflowView = ParentView;
|
|
DragDropManager dragDropManager = GetService(typeof(DragDropManager)) as DragDropManager;
|
|
if (workflowView != null && dragDropManager != null &&
|
|
workflowView.DragDropInProgress && hitInfo.AssociatedDesigner != null &&
|
|
dragDropManager.DraggedActivities.Contains(hitInfo.AssociatedDesigner.Activity) &&
|
|
hitInfo.AssociatedDesigner.Bounds.Contains(point))
|
|
{
|
|
if (Activity == hitInfo.AssociatedDesigner.Activity)
|
|
return HitTestInfo.Nowhere;
|
|
else if (containedDesigners.Contains(hitInfo.AssociatedDesigner))
|
|
return new HitTestInfo(this, HitTestLocations.Designer);
|
|
}
|
|
|
|
//Now try going through the connectors
|
|
if (!(hitInfo is ConnectionPointHitTestInfo) &&
|
|
(hitInfo.HitLocation == HitTestLocations.None || hitInfo.AssociatedDesigner == this || ShowConnectorsInForeground))
|
|
{
|
|
//Now go thru all the connectors and try to select them
|
|
for (int i = 0; i < this.connectors.Count; i++)
|
|
{
|
|
if (this.connectors[i].HitTest(point))
|
|
return new ConnectorHitTestInfo(this, HitTestLocations.Designer | HitTestLocations.Connector, i);
|
|
}
|
|
}
|
|
|
|
return hitInfo;
|
|
}
|
|
|
|
//activities being moved within the same container
|
|
private List<ActivityDesigner> movedActivities = null;
|
|
private List<ActivityDesigner> MovingActivities
|
|
{
|
|
get
|
|
{
|
|
if (this.movedActivities == null)
|
|
this.movedActivities = new List<ActivityDesigner>();
|
|
|
|
return this.movedActivities;
|
|
}
|
|
}
|
|
|
|
public override void MoveActivities(HitTestInfo moveLocation, ReadOnlyCollection<Activity> activitiesToMove)
|
|
{
|
|
if (moveLocation == null)
|
|
throw new ArgumentNullException("moveLocation");
|
|
|
|
if (activitiesToMove == null)
|
|
throw new ArgumentNullException("activitiesToMove");
|
|
|
|
FreeformActivityDesigner connectorContainer = ConnectionManager.GetConnectorContainer(this);
|
|
try
|
|
{
|
|
connectorContainer.MovingActivities.Clear();
|
|
if (connectorContainer != null && connectorContainer.Connectors.Count > 0)
|
|
{
|
|
foreach (Activity movingActivity in activitiesToMove)
|
|
{
|
|
ActivityDesigner designerToMove = ActivityDesigner.GetDesigner(movingActivity);
|
|
FreeformActivityDesigner topMostParentDesigner = ConnectionManager.GetConnectorContainer(designerToMove);
|
|
|
|
if (topMostParentDesigner == connectorContainer)
|
|
connectorContainer.MovingActivities.Add(designerToMove);
|
|
}
|
|
}
|
|
|
|
base.MoveActivities(moveLocation, activitiesToMove);
|
|
}
|
|
finally
|
|
{
|
|
connectorContainer.MovingActivities.Clear();
|
|
}
|
|
}
|
|
|
|
public override object GetNextSelectableObject(object current, DesignerNavigationDirection navigate)
|
|
{
|
|
object nextObject = null;
|
|
|
|
ArrayList activityDesigners = new ArrayList(ContainedDesigners);
|
|
ActivityDesigner activityDesigner = (current is Activity) ? ActivityDesigner.GetDesigner(current as Activity) : ActivityDesigner.GetParentDesigner(current);
|
|
int index = (activityDesigner != null) ? activityDesigners.IndexOf(activityDesigner) : -1;
|
|
if ((navigate == DesignerNavigationDirection.Left || navigate == DesignerNavigationDirection.Up) && index >= 0 && index < activityDesigners.Count)
|
|
nextObject = ((ActivityDesigner)activityDesigners[(index > 0) ? index - 1 : activityDesigners.Count - 1]).Activity;
|
|
else if ((navigate == DesignerNavigationDirection.Right || navigate == DesignerNavigationDirection.Down) && index <= activityDesigners.Count - 1)
|
|
nextObject = ((ActivityDesigner)activityDesigners[(index < activityDesigners.Count - 1) ? index + 1 : 0]).Activity;
|
|
|
|
return nextObject;
|
|
}
|
|
#endregion
|
|
|
|
#region Protected Methods
|
|
protected override void Initialize(Activity activity)
|
|
{
|
|
base.Initialize(activity);
|
|
|
|
//We only add the designer property extender here, it will be removed when the design surface is
|
|
//destroyed
|
|
EnsureDesignerExtender();
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
//Dispose the connectors
|
|
for (int i = 0; i < this.connectors.Count; i++)
|
|
((IDisposable)this.connectors[i]).Dispose();
|
|
this.connectors.Clear();
|
|
|
|
base.Dispose(disposing);
|
|
}
|
|
|
|
//
|
|
|
|
|
|
protected override void OnContainedActivitiesChanging(ActivityCollectionChangeEventArgs listChangeArgs)
|
|
{
|
|
base.OnContainedActivitiesChanging(listChangeArgs);
|
|
|
|
if (listChangeArgs.Action == ActivityCollectionChangeAction.Remove)
|
|
{
|
|
FreeformActivityDesigner connectorContainer = ConnectionManager.GetConnectorContainer(this);
|
|
List<Connector> connectorsToDelete = new List<Connector>();
|
|
|
|
//check if the removed designer is being moved within the same container
|
|
//in this case dont remove the connector...
|
|
ActivityDesigner activityDesigner = this;
|
|
while (activityDesigner != null)
|
|
{
|
|
FreeformActivityDesigner freeFormDesigner = activityDesigner as FreeformActivityDesigner;
|
|
if (freeFormDesigner != null && freeFormDesigner.Connectors.Count > 0)
|
|
{
|
|
foreach (Activity activityToRemove in listChangeArgs.RemovedItems)
|
|
{
|
|
ActivityDesigner designerToRemove = ActivityDesigner.GetDesigner(activityToRemove);
|
|
|
|
//if the designer is being moved within the same container, ignore it
|
|
//otherwise remove all related connectors
|
|
if (!connectorContainer.MovingActivities.Contains(designerToRemove))
|
|
{
|
|
foreach (Connector connector in freeFormDesigner.Connectors)
|
|
{
|
|
if (designerToRemove == connector.Source.AssociatedDesigner || designerToRemove == connector.Target.AssociatedDesigner)
|
|
connectorsToDelete.Add(connector);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
activityDesigner = activityDesigner.ParentDesigner;
|
|
}
|
|
|
|
foreach (Connector connectorToDelete in connectorsToDelete)
|
|
{
|
|
connectorToDelete.ParentDesigner.RemoveConnector(connectorToDelete);
|
|
((IDisposable)connectorToDelete).Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates the connector between specified connection points.
|
|
/// </summary>
|
|
/// <param name="source">Source connection point</param>
|
|
/// <param name="target">Target connection point</param>
|
|
/// <returns></returns>
|
|
protected internal virtual Connector CreateConnector(ConnectionPoint source, ConnectionPoint target)
|
|
{
|
|
return new Connector(source, target);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called to check if contained designers can be connected
|
|
/// </summary>
|
|
/// <param name="source">Source connection point</param>
|
|
/// <param name="target">Target connection point</param>
|
|
/// <returns></returns>
|
|
protected internal virtual bool CanConnectContainedDesigners(ConnectionPoint source, ConnectionPoint target)
|
|
{
|
|
return (((IConnectableDesigner)source.AssociatedDesigner).CanConnect(source, target) &&
|
|
((IConnectableDesigner)target.AssociatedDesigner).CanConnect(source, target));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when the connection between contained designers is established
|
|
/// </summary>
|
|
/// <param name="source">Source connection point</param>
|
|
/// <param name="target">Target connection point</param>
|
|
protected internal virtual void OnContainedDesignersConnected(ConnectionPoint source, ConnectionPoint target)
|
|
{
|
|
((IConnectableDesigner)source.AssociatedDesigner).OnConnected(source, target);
|
|
((IConnectableDesigner)target.AssociatedDesigner).OnConnected(source, target);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called to find if the contained designer can be visually resized by the user
|
|
/// </summary>
|
|
/// <param name="containedDesigner">Designer to visually resize</param>
|
|
/// <returns>True if the designer can be visually resize, false otherwise</returns>
|
|
protected internal virtual bool CanResizeContainedDesigner(ActivityDesigner containedDesigner)
|
|
{
|
|
return (containedDesigner is FreeformActivityDesigner);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when a new connector has been added in the freeform designer
|
|
/// </summary>
|
|
/// <param name="e">Event args containing connector</param>
|
|
protected virtual void OnConnectorAdded(ConnectorEventArgs e)
|
|
{
|
|
if (ConnectorAdded != null)
|
|
ConnectorAdded(this, e);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when the user changed the end points of the connector
|
|
/// </summary>
|
|
/// <param name="e"></param>
|
|
protected internal virtual void OnConnectorChanged(ConnectorEventArgs e)
|
|
{
|
|
if (ConnectorChanged != null)
|
|
ConnectorChanged(this, e);
|
|
}
|
|
|
|
protected virtual void OnConnectorRemoved(ConnectorEventArgs e)
|
|
{
|
|
if (ConnectorRemoved != null)
|
|
ConnectorRemoved(this, e);
|
|
}
|
|
|
|
protected override void OnLayoutPosition(ActivityDesignerLayoutEventArgs e)
|
|
{
|
|
base.OnLayoutPosition(e);
|
|
|
|
if (AutoSize)
|
|
{
|
|
Point newLocation = Location;
|
|
|
|
Rectangle childRectangle = GetEnclosingRectangle();
|
|
if (!childRectangle.IsEmpty)
|
|
{
|
|
if (AutoSizeMode == AutoSizeMode.GrowOnly)
|
|
{
|
|
newLocation.X = Math.Min(newLocation.X, childRectangle.Left);
|
|
newLocation.Y = Math.Min(newLocation.Y, childRectangle.Top);
|
|
}
|
|
else
|
|
{
|
|
newLocation = childRectangle.Location;
|
|
}
|
|
}
|
|
|
|
this.retainContainedDesignerLocations = true;
|
|
Location = newLocation;
|
|
this.retainContainedDesignerLocations = false;
|
|
}
|
|
|
|
foreach (Connector connector in this.connectors)
|
|
connector.OnLayout(e);
|
|
}
|
|
|
|
protected override Size OnLayoutSize(ActivityDesignerLayoutEventArgs e)
|
|
{
|
|
Rectangle bounds = Bounds;
|
|
Size size = bounds.Size;
|
|
|
|
base.OnLayoutSize(e);
|
|
|
|
if (AutoSize)
|
|
{
|
|
if (AutoSizeMode == AutoSizeMode.GrowOnly)
|
|
{
|
|
Rectangle childRectangle = GetEnclosingRectangle();
|
|
if (!childRectangle.IsEmpty)
|
|
{
|
|
size.Width += Math.Max(bounds.Left - childRectangle.Left, 0);
|
|
size.Width += Math.Max(childRectangle.Right - bounds.Right, 0);
|
|
size.Height += Math.Max(bounds.Top - childRectangle.Top, 0);
|
|
size.Height += Math.Max(childRectangle.Bottom - bounds.Bottom, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
size = MinimumSize;
|
|
}
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
protected override void OnThemeChange(ActivityDesignerTheme newTheme)
|
|
{
|
|
base.OnThemeChange(newTheme);
|
|
|
|
if (WorkflowTheme.CurrentTheme.AmbientTheme.ShowGrid)
|
|
{
|
|
foreach (ActivityDesigner containedDesigner in ContainedDesigners)
|
|
containedDesigner.Location = DesignerHelpers.SnapToGrid(containedDesigner.Location);
|
|
PerformLayout();
|
|
}
|
|
}
|
|
|
|
protected override void OnDragOver(ActivityDragEventArgs e)
|
|
{
|
|
bool ctrlKeyPressed = ((e.KeyState & 8) == 8);
|
|
if (ctrlKeyPressed && (e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy)
|
|
e.Effect = DragDropEffects.Copy;
|
|
else if ((e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move)
|
|
e.Effect = DragDropEffects.Move;
|
|
}
|
|
|
|
protected override void OnDragDrop(ActivityDragEventArgs e)
|
|
{
|
|
//Set the correct drag drop effect
|
|
bool ctrlKeyPressed = ((e.KeyState & 8) == 8);
|
|
if (ctrlKeyPressed && (e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy)
|
|
e.Effect = DragDropEffects.Copy;
|
|
else if ((e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move)
|
|
e.Effect = DragDropEffects.Move;
|
|
|
|
//Now there can be set of activities which are inserted and set of activities which are moved
|
|
//So first lets get the list of activities which need to be inserted
|
|
List<Activity> activitiesToInsert = new List<Activity>();
|
|
List<Activity> newActivities = new List<Activity>();
|
|
foreach (Activity activity in e.Activities)
|
|
{
|
|
if (activity.Site == null || activity.Parent != Activity)
|
|
activitiesToInsert.Add(activity);
|
|
|
|
if (activity.Site == null)
|
|
newActivities.Add(activity);
|
|
}
|
|
|
|
//If the component are sited then that means that we are inserting it
|
|
if (activitiesToInsert.Count > 0)
|
|
CompositeActivityDesigner.InsertActivities(this, new ConnectorHitTestInfo(this, HitTestLocations.Designer, ((CompositeActivity)Activity).Activities.Count), activitiesToInsert.AsReadOnly(), SR.GetString(SR.DragDropActivities));
|
|
|
|
Point dropPoint = new Point(e.X, e.Y);
|
|
Point[] movedLocations = FreeFormDragDropManager.GetDesignerLocations(e.DragInitiationPoint, dropPoint, e.Activities);
|
|
if (movedLocations.Length == e.Activities.Count)
|
|
{
|
|
for (int i = 0; i < e.Activities.Count; i++)
|
|
{
|
|
ActivityDesigner designerToMove = ActivityDesigner.GetDesigner(e.Activities[i]);
|
|
if (designerToMove != null)
|
|
{
|
|
Point location = (newActivities.Contains(designerToMove.Activity)) ? dropPoint : movedLocations[i];
|
|
MoveContainedDesigner(designerToMove, location);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.Assert(false);
|
|
}
|
|
}
|
|
|
|
public override void InsertActivities(HitTestInfo insertLocation, ReadOnlyCollection<Activity> activitiesToInsert)
|
|
{
|
|
base.InsertActivities(insertLocation, activitiesToInsert);
|
|
|
|
//Now go through all the designers for activities and make sure that if their locations are 0,0 then we set the
|
|
//locations at Location.X + AutoSizeMargin
|
|
if (AutoSize)
|
|
{
|
|
Size autoSizeMargin = AutoSizeMargin;
|
|
Point location = Location;
|
|
foreach (Activity activity in activitiesToInsert)
|
|
{
|
|
ActivityDesigner designer = ActivityDesigner.GetDesigner(activity);
|
|
if (designer.Location.IsEmpty)
|
|
designer.Location = new Point(location.X + autoSizeMargin.Width, location.Y + autoSizeMargin.Height);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override void OnResizing(ActivityDesignerResizeEventArgs e)
|
|
{
|
|
//If we are in AutoSize mode with grow and shrink option then dont allow resizing
|
|
if (AutoSize)
|
|
{
|
|
if (AutoSizeMode == AutoSizeMode.GrowOnly)
|
|
{
|
|
Rectangle minRectangle = GetEnclosingRectangle();
|
|
if (!minRectangle.IsEmpty)
|
|
{
|
|
Rectangle bounds = Rectangle.Empty;
|
|
bounds.X = Math.Min(minRectangle.Left, e.Bounds.Left);
|
|
bounds.Y = Math.Min(minRectangle.Top, e.Bounds.Top);
|
|
bounds.Width = Math.Max(minRectangle.Right - bounds.Left, e.Bounds.Right - bounds.Left);
|
|
bounds.Height = Math.Max(minRectangle.Bottom - bounds.Top, e.Bounds.Bottom - bounds.Top);
|
|
|
|
if (bounds != e.Bounds)
|
|
e = new ActivityDesignerResizeEventArgs(e.SizingEdge, bounds);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PerformLayout();
|
|
}
|
|
}
|
|
|
|
this.retainContainedDesignerLocations = true;
|
|
base.OnResizing(e);
|
|
this.retainContainedDesignerLocations = false;
|
|
}
|
|
|
|
protected override void OnKeyDown(KeyEventArgs e)
|
|
{
|
|
if (e == null)
|
|
throw new ArgumentNullException("e");
|
|
|
|
ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
|
|
object selectedObject = (selectionService != null) ? selectionService.PrimarySelection : null;
|
|
if (selectedObject == null)
|
|
return;
|
|
|
|
List<Activity> topLevelActivities = new List<Activity>(Helpers.GetTopLevelActivities(selectionService.GetSelectedComponents()));
|
|
|
|
if (e.KeyCode == Keys.Left || e.KeyCode == Keys.Right || e.KeyCode == Keys.Up || e.KeyCode == Keys.Down)
|
|
{
|
|
Size direction = Size.Empty;
|
|
const int step = 5;
|
|
|
|
if (e.KeyCode == Keys.Left)
|
|
direction = new Size(-step, 0);
|
|
else if (e.KeyCode == Keys.Right)
|
|
direction = new Size(step, 0);
|
|
else if (e.KeyCode == Keys.Up)
|
|
direction = new Size(0, -step);
|
|
else if (e.KeyCode == Keys.Down)
|
|
direction = new Size(0, step);
|
|
|
|
foreach (Activity selectedActivity in topLevelActivities)
|
|
{
|
|
//move designer by 'direction'
|
|
ActivityDesigner designer = ActivityDesigner.GetDesigner(selectedActivity);
|
|
if (designer != null)
|
|
{
|
|
//refresh designer area both before and after move
|
|
ParentView.InvalidateClientRectangle(new Rectangle(designer.Location, designer.Size));
|
|
designer.Location += direction;
|
|
ParentView.InvalidateClientRectangle(new Rectangle(designer.Location, designer.Size));
|
|
}
|
|
}
|
|
|
|
//update layout to grow the parent if needed after all designers have been moved
|
|
//
|
|
PerformLayout();
|
|
e.Handled = true;
|
|
}
|
|
else if (e.KeyCode == Keys.Delete)
|
|
{
|
|
//if there is a connector selected, delete it
|
|
ICollection components = selectionService.GetSelectedComponents();
|
|
foreach (object component in components)
|
|
{
|
|
ConnectorHitTestInfo connector = component as ConnectorHitTestInfo;
|
|
if (connector != null)
|
|
{
|
|
FreeformActivityDesigner freeformDesigner = connector.AssociatedDesigner as FreeformActivityDesigner;
|
|
if (freeformDesigner != null)
|
|
{
|
|
ReadOnlyCollection<Connector> connectors = freeformDesigner.Connectors;
|
|
int connectorIndex = connector.MapToIndex();
|
|
if (connectorIndex < connectors.Count)
|
|
{
|
|
selectionService.SetSelectedComponents(new object[] { connector }, SelectionTypes.Remove);
|
|
freeformDesigner.RemoveConnector(connectors[connectorIndex]);
|
|
|
|
object nextSelectableObject = freeformDesigner;
|
|
if (connectors.Count > 0)
|
|
nextSelectableObject = new ConnectorHitTestInfo(freeformDesigner, HitTestLocations.Connector | HitTestLocations.Designer, (connectorIndex > 0) ? connectorIndex - 1 : connectorIndex);
|
|
|
|
selectionService.SetSelectedComponents(new object[] { nextSelectableObject }, SelectionTypes.Replace);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
e.Handled = true;
|
|
}
|
|
|
|
if (!e.Handled)
|
|
{
|
|
//let the base handle all other keys including tabs
|
|
base.OnKeyDown(e);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Private Methods
|
|
internal static void SetDesignerBounds(ActivityDesigner designer, Rectangle bounds)
|
|
{
|
|
if (designer == null || designer.Activity == null || designer.Activity.Site == null)
|
|
return;
|
|
|
|
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(designer);
|
|
|
|
PropertyDescriptor sizeProperty = (properties != null) ? properties["Size"] : null;
|
|
if (sizeProperty != null)
|
|
sizeProperty.SetValue(designer.Activity, bounds.Size);
|
|
else
|
|
designer.Size = bounds.Size;
|
|
|
|
PropertyDescriptor locationProperty = (properties != null) ? properties["Location"] : null;
|
|
if (locationProperty != null)
|
|
locationProperty.SetValue(designer.Activity, bounds.Location);
|
|
else
|
|
designer.Location = bounds.Location;
|
|
|
|
WorkflowView workflowView = designer.Activity.Site.GetService(typeof(WorkflowView)) as WorkflowView;
|
|
if (workflowView != null)
|
|
{
|
|
if (designer.ParentDesigner != null)
|
|
workflowView.InvalidateLogicalRectangle(designer.ParentDesigner.Bounds);
|
|
else
|
|
workflowView.Invalidate();
|
|
}
|
|
}
|
|
|
|
internal override void OnPaintContainedDesigners(ActivityDesignerPaintEventArgs e)
|
|
{
|
|
if (ShowConnectorsInForeground)
|
|
base.OnPaintContainedDesigners(e);
|
|
|
|
FreeformActivityDesigner connectorContainer = ConnectionManager.GetConnectorContainer(this);
|
|
if (connectorContainer != null && Activity != null && Activity.Site != null)
|
|
{
|
|
Region clipRegion = null;
|
|
Region oldClipRegion = e.Graphics.Clip;
|
|
|
|
try
|
|
{
|
|
if (oldClipRegion != null)
|
|
{
|
|
clipRegion = new Region(connectorContainer.Bounds);
|
|
clipRegion.Intersect(e.ViewPort);
|
|
e.Graphics.Clip = clipRegion;
|
|
}
|
|
|
|
//Lets draw all the connectors before the designers so that designers always overlap connectors
|
|
foreach (Connector connector in connectorContainer.Connectors)
|
|
{
|
|
if (this == connector.RenderingOwner)
|
|
connector.OnPaint(e);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
if (oldClipRegion != null)
|
|
{
|
|
e.Graphics.Clip = oldClipRegion;
|
|
clipRegion.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ShowConnectorsInForeground)
|
|
base.OnPaintContainedDesigners(e);
|
|
}
|
|
|
|
private Rectangle GetEnclosingRectangle()
|
|
{
|
|
Point leftTop = new Point(int.MaxValue, int.MaxValue), rightBottom = new Point(int.MinValue, int.MinValue);
|
|
foreach (ActivityDesigner activityDesigner in ContainedDesigners)
|
|
{
|
|
if (activityDesigner.IsVisible)
|
|
{
|
|
leftTop.X = (activityDesigner.Bounds.Left < leftTop.X) ? activityDesigner.Bounds.Left : leftTop.X;
|
|
leftTop.Y = (activityDesigner.Bounds.Top < leftTop.Y) ? activityDesigner.Bounds.Top : leftTop.Y;
|
|
rightBottom.X = (rightBottom.X < activityDesigner.Bounds.Right) ? activityDesigner.Bounds.Right : rightBottom.X;
|
|
rightBottom.Y = (rightBottom.Y < activityDesigner.Bounds.Bottom) ? activityDesigner.Bounds.Bottom : rightBottom.Y;
|
|
}
|
|
}
|
|
|
|
//for the invoked workflow dont take connectors into account
|
|
//this causes un-necessary growth of the workflow...
|
|
if (this.InvokingDesigner == null)
|
|
{
|
|
foreach (Connector connector in Connectors)
|
|
{
|
|
leftTop.X = (connector.Bounds.Left < leftTop.X) ? connector.Bounds.Left : leftTop.X;
|
|
leftTop.Y = (connector.Bounds.Top < leftTop.Y) ? connector.Bounds.Top : leftTop.Y;
|
|
rightBottom.X = (rightBottom.X < connector.Bounds.Right) ? connector.Bounds.Right : rightBottom.X;
|
|
rightBottom.Y = (rightBottom.Y < connector.Bounds.Bottom) ? connector.Bounds.Bottom : rightBottom.Y;
|
|
}
|
|
}
|
|
|
|
Rectangle enclosingRectangle = Rectangle.Empty;
|
|
if (leftTop.X != int.MaxValue && rightBottom.X != int.MinValue)
|
|
{
|
|
enclosingRectangle.X = leftTop.X;
|
|
enclosingRectangle.Width = rightBottom.X - leftTop.X;
|
|
}
|
|
if (leftTop.Y != int.MaxValue && rightBottom.Y != int.MinValue)
|
|
{
|
|
enclosingRectangle.Y = leftTop.Y;
|
|
enclosingRectangle.Height = rightBottom.Y - leftTop.Y;
|
|
}
|
|
|
|
if (!enclosingRectangle.IsEmpty)
|
|
enclosingRectangle.Inflate(AutoSizeMargin);
|
|
|
|
return enclosingRectangle;
|
|
}
|
|
|
|
internal bool CanUpdateZOrder(ActivityDesigner activityDesigner, ZOrder zorder)
|
|
{
|
|
bool canUpdateZOrder = false;
|
|
CompositeActivityDesigner parentDesigner = this;
|
|
ActivityDesigner childDesigner = activityDesigner;
|
|
while (parentDesigner != null && childDesigner != null)
|
|
{
|
|
if (parentDesigner is FreeformActivityDesigner)
|
|
{
|
|
ReadOnlyCollection<ActivityDesigner> containedDesigners = parentDesigner.ContainedDesigners;
|
|
if (containedDesigners.Count > 1 && containedDesigners[(zorder == ZOrder.Background) ? 0 : containedDesigners.Count - 1] != childDesigner)
|
|
{
|
|
canUpdateZOrder = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
childDesigner = parentDesigner;
|
|
parentDesigner = parentDesigner.ParentDesigner;
|
|
}
|
|
|
|
return canUpdateZOrder;
|
|
}
|
|
|
|
private void UpdateZOrder(ActivityDesigner activityDesigner, ZOrder zorder)
|
|
{
|
|
IDesignerHost designerHost = GetService(typeof(IDesignerHost)) as IDesignerHost;
|
|
DesignerTransaction transaction = null;
|
|
if (designerHost != null)
|
|
transaction = designerHost.CreateTransaction(DR.GetString(DR.ZOrderUndoDescription, activityDesigner.Text));
|
|
|
|
try
|
|
{
|
|
bool zOrderChanged = false;
|
|
CompositeActivityDesigner parentDesigner = this;
|
|
ActivityDesigner childDesigner = activityDesigner;
|
|
while (parentDesigner != null && childDesigner != null)
|
|
{
|
|
if (parentDesigner is FreeformActivityDesigner)
|
|
{
|
|
ReadOnlyCollection<ActivityDesigner> containedDesigners = parentDesigner.ContainedDesigners;
|
|
if (containedDesigners.Count > 1 && containedDesigners[(zorder == ZOrder.Background) ? 0 : containedDesigners.Count - 1] != childDesigner)
|
|
{
|
|
int moveIndex = (zorder == ZOrder.Background) ? 0 : containedDesigners.Count;
|
|
parentDesigner.MoveActivities(new ConnectorHitTestInfo(this, HitTestLocations.Designer, moveIndex), new List<Activity>(new Activity[] { childDesigner.Activity }).AsReadOnly());
|
|
zOrderChanged = true;
|
|
}
|
|
}
|
|
|
|
childDesigner = parentDesigner;
|
|
parentDesigner = parentDesigner.ParentDesigner;
|
|
}
|
|
|
|
if (zOrderChanged)
|
|
Invalidate();
|
|
|
|
if (transaction != null)
|
|
transaction.Commit();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
if (transaction != null)
|
|
transaction.Cancel();
|
|
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
private void EnsureDesignerExtender()
|
|
{
|
|
bool addExtender = true;
|
|
IExtenderListService extenderListService = GetService(typeof(IExtenderListService)) as IExtenderListService;
|
|
if (extenderListService != null)
|
|
{
|
|
foreach (IExtenderProvider extenderProvider in extenderListService.GetExtenderProviders())
|
|
{
|
|
if (extenderProvider.GetType() == typeof(FreeFormDesignerPropertyExtender))
|
|
{
|
|
addExtender = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (addExtender)
|
|
{
|
|
IExtenderProviderService extenderProviderService = GetService(typeof(IExtenderProviderService)) as IExtenderProviderService;
|
|
if (extenderProviderService != null)
|
|
{
|
|
extenderProviderService.AddExtenderProvider(new FreeFormDesignerPropertyExtender());
|
|
TypeDescriptor.Refresh(Activity);
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Private Classes
|
|
|
|
#region Class FreeFormConnectorSelectionGlyph
|
|
//
|
|
private sealed class FreeFormConnectorSelectionGlyph : ConnectorSelectionGlyph
|
|
{
|
|
internal FreeFormConnectorSelectionGlyph(int connectorIndex, bool isPrimarySelectionGlyph)
|
|
: base(connectorIndex, isPrimarySelectionGlyph)
|
|
{
|
|
}
|
|
|
|
public override Rectangle GetBounds(ActivityDesigner designer, bool activated)
|
|
{
|
|
//FreeformActivityDesigner connectorContainer = designer as FreeformActivityDesigner;
|
|
//return (connectorContainer != null) ? DesignerGeometryHelper.RectangleFromLineSegments(connectorContainer.Connectors[this.connectorIndex].ConnectorSegments) : Rectangle.Empty;
|
|
return Rectangle.Empty;
|
|
}
|
|
|
|
protected override void OnPaint(Graphics graphics, bool activated, AmbientTheme ambientTheme, ActivityDesigner designer)
|
|
{
|
|
/*IConnectorContainer connectorContainer = designer as IConnectorContainer;
|
|
if (connectorContainer == null)
|
|
return;
|
|
|
|
Connector connector = connectorContainer[this.connectorIndex];
|
|
Rectangle[] grabHandles = new Rectangle[connector.Segments.Length];
|
|
for (int i = 0; i < connector.Segments.Length; i++)
|
|
{
|
|
grabHandles[i].X = connector.Segments[i].X - ambientTheme.SelectionSize.Width / 2;
|
|
grabHandles[i].Y = connector.Segments[i].Y - ambientTheme.SelectionSize.Height / 2;
|
|
grabHandles[i].Size = ambientTheme.SelectionSize;
|
|
}
|
|
|
|
ActivityDesignerPaint.DrawGrabHandles(graphics, grabHandles, this.isPrimarySelectionGlyph);*/
|
|
}
|
|
|
|
public override bool IsPrimarySelection
|
|
{
|
|
get
|
|
{
|
|
return this.isPrimarySelectionGlyph;
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Class FreeFormDesignerPropertyExtender
|
|
[ProvideProperty("Location", typeof(Activity))]
|
|
[ProvideProperty("Size", typeof(Activity))]
|
|
private sealed class FreeFormDesignerPropertyExtender : IExtenderProvider
|
|
{
|
|
#region Properties
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
[DesignOnly(true)]
|
|
[MergableProperty(false)]
|
|
[Browsable(false)]
|
|
public Point GetLocation(Activity activity)
|
|
{
|
|
Point location = Point.Empty;
|
|
ActivityDesigner designer = ActivityDesigner.GetDesigner(activity);
|
|
if (designer != null)
|
|
location = designer.Location;
|
|
return location;
|
|
}
|
|
|
|
public void SetLocation(Activity activity, Point location)
|
|
{
|
|
ActivityDesigner designer = ActivityDesigner.GetDesigner(activity);
|
|
if (designer != null)
|
|
{
|
|
FreeformActivityDesigner freeformDesigner = (designer.ParentDesigner != null) ? designer.ParentDesigner as FreeformActivityDesigner : designer as FreeformActivityDesigner;
|
|
if (freeformDesigner != null)
|
|
{
|
|
designer.Location = location;
|
|
|
|
if (freeformDesigner.AutoSize)
|
|
freeformDesigner.PerformLayout();
|
|
}
|
|
}
|
|
}
|
|
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
[DesignOnly(true)]
|
|
[MergableProperty(false)]
|
|
[Browsable(false)]
|
|
public Size GetSize(Activity activity)
|
|
{
|
|
Size size = Size.Empty;
|
|
ActivityDesigner designer = ActivityDesigner.GetDesigner(activity);
|
|
if (designer != null)
|
|
size = designer.Size;
|
|
return size;
|
|
}
|
|
|
|
public void SetSize(Activity activity, Size size)
|
|
{
|
|
ActivityDesigner designer = ActivityDesigner.GetDesigner(activity);
|
|
if (designer != null)
|
|
{
|
|
FreeformActivityDesigner freeformDesigner = (designer.ParentDesigner != null) ? designer.ParentDesigner as FreeformActivityDesigner : designer as FreeformActivityDesigner;
|
|
if (freeformDesigner != null)
|
|
{
|
|
designer.Size = size;
|
|
|
|
if (freeformDesigner.AutoSize)
|
|
freeformDesigner.PerformLayout();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
bool IExtenderProvider.CanExtend(object extendee)
|
|
{
|
|
bool canExtend = false;
|
|
|
|
Activity activity = extendee as Activity;
|
|
if (activity != null)
|
|
{
|
|
ActivityDesigner designer = ActivityDesigner.GetDesigner(activity);
|
|
if (designer != null)
|
|
{
|
|
FreeformActivityDesigner freeformDesigner = (designer.ParentDesigner != null) ? designer.ParentDesigner as FreeformActivityDesigner : designer as FreeformActivityDesigner;
|
|
if (freeformDesigner != null)
|
|
canExtend = true;
|
|
}
|
|
}
|
|
|
|
return canExtend;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#endregion
|
|
}
|
|
#endregion
|
|
|
|
#region Class FreeFormDesignerVerbProvider
|
|
internal sealed class FreeFormDesignerVerbProvider : IDesignerVerbProvider
|
|
{
|
|
#region IDesignerVerbProvider Members
|
|
ActivityDesignerVerbCollection IDesignerVerbProvider.GetVerbs(ActivityDesigner activityDesigner)
|
|
{
|
|
ActivityDesignerVerbCollection verbs = new ActivityDesignerVerbCollection();
|
|
if (activityDesigner.ParentDesigner is FreeformActivityDesigner)
|
|
{
|
|
ActivityDesignerVerb verb = new ActivityDesignerVerb(activityDesigner, DesignerVerbGroup.Actions, DR.GetString(DR.BringToFront), new EventHandler(OnZOrderChanged), new EventHandler(OnZOrderStatusUpdate));
|
|
verb.Properties[DesignerUserDataKeys.ZOrderKey] = ZOrder.Foreground;
|
|
verbs.Add(verb);
|
|
verb = new ActivityDesignerVerb(activityDesigner, DesignerVerbGroup.Actions, DR.GetString(DR.SendToBack), new EventHandler(OnZOrderChanged), new EventHandler(OnZOrderStatusUpdate));
|
|
verb.Properties[DesignerUserDataKeys.ZOrderKey] = ZOrder.Background;
|
|
verbs.Add(verb);
|
|
}
|
|
return verbs;
|
|
}
|
|
#endregion
|
|
|
|
#region Helpers
|
|
private void OnZOrderChanged(object sender, EventArgs e)
|
|
{
|
|
ActivityDesignerVerb designerVerb = sender as ActivityDesignerVerb;
|
|
if (designerVerb != null && designerVerb.Properties.Contains(DesignerUserDataKeys.ZOrderKey))
|
|
{
|
|
FreeformActivityDesigner freeformDesigner = designerVerb.ActivityDesigner.ParentDesigner as FreeformActivityDesigner;
|
|
if (freeformDesigner != null)
|
|
{
|
|
if ((ZOrder)designerVerb.Properties[DesignerUserDataKeys.ZOrderKey] == ZOrder.Foreground)
|
|
freeformDesigner.BringToFront(designerVerb.ActivityDesigner);
|
|
else if ((ZOrder)designerVerb.Properties[DesignerUserDataKeys.ZOrderKey] == ZOrder.Background)
|
|
freeformDesigner.SendToBack(designerVerb.ActivityDesigner);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnZOrderStatusUpdate(object sender, EventArgs e)
|
|
{
|
|
ActivityDesignerVerb designerVerb = sender as ActivityDesignerVerb;
|
|
if (designerVerb != null && designerVerb.Properties.Contains(DesignerUserDataKeys.ZOrderKey))
|
|
{
|
|
FreeformActivityDesigner freeformDesigner = designerVerb.ActivityDesigner.ParentDesigner as FreeformActivityDesigner;
|
|
if (freeformDesigner != null)
|
|
designerVerb.Enabled = freeformDesigner.CanUpdateZOrder(designerVerb.ActivityDesigner, (ZOrder)designerVerb.Properties[DesignerUserDataKeys.ZOrderKey]);
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
#endregion
|
|
}
|