|
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
}
|