1 #pragma warning disable 1634, 1691
2 namespace System.Workflow.ComponentModel.Design
8 using System.Diagnostics;
9 using System.Collections;
10 using System.Collections.Generic;
11 using System.Windows.Forms;
12 using System.ComponentModel;
13 using System.Globalization;
14 using System.Drawing.Design;
15 using System.Drawing.Imaging;
16 using System.Drawing.Drawing2D;
17 using System.Windows.Forms.Design;
18 using System.ComponentModel.Design;
19 using System.Collections.Specialized;
20 using System.ComponentModel.Design.Serialization;
21 using System.Workflow.ComponentModel.Compiler;
22 using System.Workflow.ComponentModel.Serialization;
23 using System.Collections.ObjectModel;
24 using System.Reflection;
25 using System.Workflow.ComponentModel.Design;
26 using System.Runtime.Serialization.Formatters.Binary;
32 #region StructuredCompositeActivityDesigner Class
34 /// Base class for CompositActivityDesigner which have a structured layouts where contained ContainedDesigners
35 /// are connected to each other using connectors. Class is used when the user needs to provide different types
36 /// of layouts for CompositeActivityDesigner
38 [Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")]
39 public abstract class StructuredCompositeActivityDesigner : CompositeActivityDesigner
42 private int currentDropTarget = -1;
44 private List<DesignerView> views = null;
45 private DesignerView activeView;
46 private ItemPalette itemPalette = null;
51 #region Public Properties
52 public override ReadOnlyCollection<ActivityDesigner> ContainedDesigners
56 List<ActivityDesigner> containedDesigners = new List<ActivityDesigner>();
57 ActivityDesigner activeDesigner = ActiveDesigner;
58 if (activeDesigner != null)
60 if (activeDesigner == this)
62 //We need to remove the secondary activities
63 containedDesigners.AddRange(base.ContainedDesigners);
65 List<ActivityDesigner> designersToRemove = new List<ActivityDesigner>();
66 IList<ActivityDesigner> mappedDesigners = DesignersFromSupportedViews;
68 foreach (ActivityDesigner containedDesigner in containedDesigners)
70 bool isAlternateFlowActivityAttribute = Helpers.IsAlternateFlowActivity(containedDesigner.Activity);
71 if (mappedDesigners.Contains(containedDesigner) || isAlternateFlowActivityAttribute)
72 designersToRemove.Add(containedDesigner);
75 foreach (ActivityDesigner activityDesigner in designersToRemove)
76 containedDesigners.Remove(activityDesigner);
80 containedDesigners.Add(activeDesigner);
84 return containedDesigners.AsReadOnly();
88 public override object FirstSelectableObject
92 ActivityDesigner activeDesigner = ActiveDesigner;
93 if (activeDesigner != null && activeDesigner != this)
94 return activeDesigner.Activity;
96 return base.FirstSelectableObject;
100 public override object LastSelectableObject
104 ActivityDesigner activeDesigner = ActiveDesigner;
105 if (activeDesigner != null && activeDesigner != this && activeDesigner is CompositeActivityDesigner)
106 return ((CompositeActivityDesigner)activeDesigner).LastSelectableObject;
108 return base.LastSelectableObject;
113 /// Gets the ActiveView supported by the designer
115 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
116 public DesignerView ActiveView
120 if (this.activeView == null)
121 this.activeView = ValidatedViews[0];
122 return this.activeView;
127 if (this.activeView == value || value == null)
130 DesignerView previousView = this.activeView;
132 this.activeView = value;
136 ActivityDesigner designer = value.AssociatedDesigner;
137 if (designer == null)
139 value.OnDeactivate();
140 this.activeView = previousView;
144 if (previousView != null)
145 previousView.OnDeactivate();
147 OnViewChanged(this.activeView);
149 //When we change the view we want to make sure that if we hide any of the child
150 //activities with errors we want to reveal these activities
151 DesignerHelpers.RefreshDesignerActions(Activity.Site);
153 //Keep the dynamic action and designer verbs in sync
154 RefreshDesignerVerbs();
158 public override Size MinimumSize
162 Size minimumSize = base.MinimumSize;
164 ActivityDesigner activeDesigner = ActiveDesigner;
165 if (activeDesigner != null && activeDesigner != this && Expanded)
167 minimumSize.Width = Math.Max(minimumSize.Width, 160);
168 minimumSize.Height = Math.Max(minimumSize.Height, 160);
176 /// Gets the array of views supported by the current designer
178 public virtual ReadOnlyCollection<DesignerView> Views
182 if (this.views == null)
184 this.views = new List<DesignerView>();
185 this.views.AddRange(SecondaryViewProvider.GetViews(this));
188 return this.views.AsReadOnly();
193 #region Protected Properties
195 /// Gets the index of the cuurent drop target in the array of drop targets returned by method GetDropTargets
196 /// This property is only used when the drag drop operation is in progress
198 protected virtual int CurrentDropTarget
202 return this.currentDropTarget;
207 this.currentDropTarget = value;
212 protected override bool ShowSmartTag
216 return (!String.IsNullOrEmpty(Text) && !TextRectangle.Size.IsEmpty && Views.Count > 1);
220 protected override ReadOnlyCollection<ActivityDesignerVerb> SmartTagVerbs
224 List<ActivityDesignerVerb> smartTagVerbs = new List<ActivityDesignerVerb>(base.SmartTagVerbs);
226 //Return smarttag actions only if there is more than one view
229 for (int i = 0; i < Views.Count; i++)
231 DesignerView view = Views[i];
232 ActivityDesignerVerb smartVerb = new ActivityDesignerVerb(this, DesignerVerbGroup.Actions, view.Text, new EventHandler(OnSmartTagVerb), new EventHandler(OnSmartTagVerbStatus));
233 smartVerb.Properties[DesignerUserDataKeys.DesignerView] = view;
234 smartVerb.Properties[DesignerUserDataKeys.Image] = view.Image;
235 smartTagVerbs.Add(smartVerb);
239 return smartTagVerbs.AsReadOnly();
244 #region Private Properties
245 internal ActivityDesigner ActiveDesigner
249 if (ActiveView != null)
250 return ActiveView.AssociatedDesigner;
256 internal override bool SmartTagVisible
260 if (this.itemPalette != null && this.itemPalette.IsVisible)
263 return base.SmartTagVisible;
268 base.SmartTagVisible = value;
272 private ReadOnlyCollection<DesignerView> ValidatedViews
276 ReadOnlyCollection<DesignerView> views = Views;
277 if (views.Count == 0)
278 #pragma warning suppress 56503
279 throw new InvalidOperationException(DR.GetString(DR.Error_MultiviewSequentialActivityDesigner));
284 private IList<ActivityDesigner> DesignersFromSupportedViews
288 List<ActivityDesigner> mappedDesigners = new List<ActivityDesigner>();
289 foreach (DesignerView view in ValidatedViews)
291 ActivityDesigner mappedDesigner = view.AssociatedDesigner;
292 if (mappedDesigner != null)
293 mappedDesigners.Add(mappedDesigner);
296 return mappedDesigners.AsReadOnly();
305 #region Public Methods
306 public override bool CanInsertActivities(HitTestInfo insertLocation, ReadOnlyCollection<Activity> activitiesToInsert)
308 if (insertLocation == null)
309 throw new ArgumentNullException("insertLocation");
311 if (activitiesToInsert == null)
312 throw new ArgumentNullException("activitiesToInsert");
314 ActivityDesigner hostedDesigner = (ActiveView != null) ? ActiveView.AssociatedDesigner : null;
315 if (hostedDesigner != this)
318 IList<Type> secondaryViewTypes = SecondaryViewProvider.GetActivityTypes(this);
319 foreach (Activity activity in activitiesToInsert)
321 if (activity == null)
322 throw new ArgumentException("activitiesToInsert", SR.GetString(SR.Error_CollectionHasNullEntry));
324 if (secondaryViewTypes.Contains(activity.GetType()))
328 return base.CanInsertActivities(GetUpdatedLocation(insertLocation), activitiesToInsert);
331 public override void InsertActivities(HitTestInfo insertLocation, ReadOnlyCollection<Activity> activitiesToInsert)
333 if (insertLocation == null)
334 throw new ArgumentNullException("insertLocation");
336 if (activitiesToInsert == null)
337 throw new ArgumentNullException("activitiesToInsert");
339 base.InsertActivities(GetUpdatedLocation(insertLocation), activitiesToInsert);
342 public override void MoveActivities(HitTestInfo moveLocation, ReadOnlyCollection<Activity> activitiesToMove)
344 if (moveLocation == null)
345 throw new ArgumentNullException("moveLocation");
347 if (activitiesToMove == null)
348 throw new ArgumentNullException("activitiesToMove");
350 base.MoveActivities(GetUpdatedLocation(moveLocation), activitiesToMove);
353 public override bool CanRemoveActivities(ReadOnlyCollection<Activity> activitiesToRemove)
355 if (activitiesToRemove == null)
356 throw new ArgumentNullException("activitiesToRemove");
358 return base.CanRemoveActivities(activitiesToRemove);
361 public override void EnsureVisibleContainedDesigner(ActivityDesigner containedDesigner)
363 if (containedDesigner == null)
364 throw new ArgumentNullException("containedDesigner");
366 //we could be collapsed, make sure the view itself is visible
367 this.Expanded = true;
369 ActivityDesigner activeDesigner = ActiveDesigner;
370 if (containedDesigner != activeDesigner && containedDesigner != this)
372 DesignerView viewToActivate = null;
373 ReadOnlyCollection<DesignerView> views = ValidatedViews;
375 //Go thru the views and check if the child designer is one of the views
376 foreach (DesignerView view in views)
378 if (containedDesigner == view.AssociatedDesigner)
380 viewToActivate = view;
385 //This means that the child designer is in our main flow
386 if (viewToActivate == null)
387 viewToActivate = views[0];
389 ActiveView = viewToActivate;
391 //Invoking a verb might change the shown view so we map again
392 CompositeActivityDesigner activeCompositeDesigner = ActiveDesigner as CompositeActivityDesigner;
393 if (activeCompositeDesigner != null)
395 if (activeCompositeDesigner != this)
396 activeCompositeDesigner.EnsureVisibleContainedDesigner(containedDesigner);
398 base.EnsureVisibleContainedDesigner(containedDesigner);
403 public override object GetNextSelectableObject(object current, DesignerNavigationDirection direction)
405 object nextObject = null;
407 ActivityDesigner activeDesigner = ActiveDesigner;
408 if (activeDesigner != null)
410 if (activeDesigner != this)
412 if (current != activeDesigner.Activity && activeDesigner is CompositeActivityDesigner)
413 nextObject = ((CompositeActivityDesigner)activeDesigner).GetNextSelectableObject(current, direction);
417 nextObject = base.GetNextSelectableObject(current, direction);
425 #region Protected Methods
426 protected override void Initialize(Activity activity)
428 base.Initialize(activity);
430 ActiveView = ValidatedViews[0];
434 /// Returns the collection of points which represents the inner connections of the designer. The designer can have connectors
435 /// within it, the points returned are the connection points used for connectable designer.
437 /// <param name="edges">Designer Edge along which the connection point lies</param>
438 /// <returns>List of connection Points</returns>
439 protected virtual ReadOnlyCollection<Point> GetInnerConnections(DesignerEdges edges)
441 List<Point> connectionPoints = new List<Point>(GetConnections(edges));
442 if (connectionPoints.Count > 0 && (edges & DesignerEdges.Top) > 0)
443 connectionPoints[0] = new Point(connectionPoints[0].X, connectionPoints[0].Y + TitleHeight);
444 return connectionPoints.AsReadOnly();
448 /// Returns array of rectangles representing the valid drop locations with the designer
450 /// <param name="dropPoint"></param>
451 /// <returns></returns>
452 protected virtual Rectangle[] GetDropTargets(Point dropPoint)
454 return new Rectangle[] { Bounds };
457 protected override void OnContainedActivitiesChanging(ActivityCollectionChangeEventArgs listChangeArgs)
459 base.OnContainedActivitiesChanging(listChangeArgs);
461 if (listChangeArgs.Action == ActivityCollectionChangeAction.Remove && listChangeArgs.RemovedItems[0] != null)
463 ActivityDesigner activeDesigner = ActiveDesigner;
464 if (activeDesigner != null && listChangeArgs.RemovedItems[0] == activeDesigner.Activity)
465 ActiveView = ValidatedViews[0];
466 SecondaryViewProvider.OnViewRemoved(this, listChangeArgs.RemovedItems[0].GetType());
470 protected void DrawConnectors(Graphics graphics, Pen pen, Point[] points, LineAnchor startCap, LineAnchor endCap)
472 Size arrowCapSize = Size.Empty;
473 Size maxCapSize = Size.Empty;
475 CompositeDesignerTheme compositeDesignerTheme = DesignerTheme as CompositeDesignerTheme;
476 if (compositeDesignerTheme != null)
478 arrowCapSize = new Size(compositeDesignerTheme.ConnectorSize.Width / 3, compositeDesignerTheme.ConnectorSize.Height / 3);
479 maxCapSize = compositeDesignerTheme.ConnectorSize;
481 ActivityDesignerPaint.DrawConnectors(graphics, pen, points, arrowCapSize, maxCapSize, startCap, endCap);
484 protected override void OnDragEnter(ActivityDragEventArgs e)
488 CurrentDropTarget = CanDrop(e);
489 e.Effect = CheckDragEffect(e);
490 e.DragImageSnapPoint = SnapInToDropTarget(e);
493 protected override void OnDragOver(ActivityDragEventArgs e)
497 CurrentDropTarget = CanDrop(e);
498 e.Effect = CheckDragEffect(e);
499 e.DragImageSnapPoint = SnapInToDropTarget(e);
502 protected override void OnDragLeave()
506 //Clear earlier drop target information
507 CurrentDropTarget = -1;
510 protected override void OnDragDrop(ActivityDragEventArgs e)
514 bool ctrlKeyPressed = ((e.KeyState & 8) == 8);
515 if (ctrlKeyPressed && (e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy)
516 e.Effect = DragDropEffects.Copy;
517 else if ((e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move)
518 e.Effect = DragDropEffects.Move;
520 //If the component is sited then that means that we are moving it
523 CompositeActivityDesigner.InsertActivities(this, new ConnectorHitTestInfo(this, HitTestLocations.Designer, CurrentDropTarget), e.Activities, SR.GetString(SR.DragDropActivities));
527 CurrentDropTarget = -1;
531 protected override void OnLayoutPosition(ActivityDesignerLayoutEventArgs e)
534 throw new ArgumentNullException("e");
536 base.OnLayoutPosition(e);
540 ActivityDesigner activeDesigner = ActiveDesigner;
541 if (activeDesigner != null && activeDesigner != this)
543 Point location = Location;
544 location.X += (Size.Width - activeDesigner.Size.Width) / 2;
545 location.Y += e.AmbientTheme.SelectionSize.Height;
546 activeDesigner.Location = location;
549 int titleHeight = TitleHeight;
550 foreach (ActivityDesigner activityDesigner in ContainedDesigners)
551 activityDesigner.Location = new Point(activityDesigner.Location.X, activityDesigner.Location.Y + titleHeight);
555 protected override Size OnLayoutSize(ActivityDesignerLayoutEventArgs e)
557 Size containerSize = base.OnLayoutSize(e);
561 ActivityDesigner activeDesigner = ActiveDesigner;
562 if (activeDesigner != null && activeDesigner != this)
564 containerSize.Width = Math.Max(containerSize.Width, activeDesigner.Size.Width);
565 containerSize.Height += activeDesigner.Size.Height;
567 containerSize.Width += 2 * e.AmbientTheme.SelectionSize.Width;
568 containerSize.Width += 3 * e.AmbientTheme.Margin.Width;
569 containerSize.Height += e.AmbientTheme.Margin.Height;
570 containerSize.Height += 2 * e.AmbientTheme.SelectionSize.Height;
574 return containerSize;
577 protected override void SaveViewState(BinaryWriter writer)
580 throw new ArgumentNullException("writer");
582 List<DesignerView> views = new List<DesignerView>(ValidatedViews);
583 writer.Write("ActiveView");
584 writer.Write(views.IndexOf(this.activeView));
586 base.SaveViewState(writer);
589 protected override void LoadViewState(BinaryReader reader)
592 throw new ArgumentNullException("reader");
594 string str = reader.ReadString();
595 if (str != null && str.Equals("ActiveView", StringComparison.Ordinal))
597 int activeDesignerIndex = reader.ReadInt32();
598 ReadOnlyCollection<DesignerView> views = ValidatedViews;
599 if (activeDesignerIndex != -1 && activeDesignerIndex < views.Count)
600 ActiveView = views[activeDesignerIndex];
603 base.LoadViewState(reader);
607 /// Called when the current view of the designer changes
609 /// <param name="view">View which is being set.</param>
610 protected virtual void OnViewChanged(DesignerView view)
615 protected override void OnShowSmartTagVerbs(Point smartTagPoint)
617 if (this.itemPalette == null)
619 this.itemPalette = new ItemPalette();
620 this.itemPalette.Closed += new EventHandler(OnPaletteClosed);
621 this.itemPalette.SelectionChanged += new SelectionChangeEventHandler<SelectionChangeEventArgs>(OnSmartAction);
624 //we need to update the font every time the menu is shown
625 this.itemPalette.SetFont(WorkflowTheme.CurrentTheme.AmbientTheme.Font);
627 this.itemPalette.Items.Clear();
629 foreach (ActivityDesignerVerb smartVerb in SmartTagVerbs)
631 Image image = smartVerb.Properties[DesignerUserDataKeys.Image] as Image;
632 ItemInfo smartVerbItem = new ItemInfo(smartVerb.Id, image, smartVerb.Text);
633 smartVerbItem.UserData[DesignerUserDataKeys.DesignerVerb] = smartVerb;
634 this.itemPalette.Items.Add(smartVerbItem);
637 Point location = PointToScreen(smartTagPoint);
638 this.itemPalette.Show(location);
641 protected override void OnActivityChanged(ActivityChangedEventArgs e)
643 ReadOnlyCollection<DesignerView> newViews = SecondaryViewProvider.GetViews(this);
644 ReadOnlyCollection<DesignerView> oldViews = Views;
645 if (newViews.Count != oldViews.Count)
655 base.OnActivityChanged(e);
659 #region Private Methods
660 internal override void OnPaintContainedDesigners(ActivityDesignerPaintEventArgs e)
662 //Draw all the activity designers contained by the activity designer
663 //We know that all the children which are in drawing range will be always
664 //consecutive both for parallel and for sequential containers hence
665 //once we go in the invisible range we bail out of drawing logic for rest of
667 bool bDrawingVisibleChildren = false;
669 foreach (ActivityDesigner activityDesigner in ContainedDesigners)
671 Rectangle designerBounds = activityDesigner.Bounds;
672 if (e.ViewPort.IntersectsWith(designerBounds))
674 bDrawingVisibleChildren = true;
675 using (PaintEventArgs paintEventArgs = new PaintEventArgs(e.Graphics, e.ViewPort))
677 ((IWorkflowDesignerMessageSink)activityDesigner).OnPaint(paintEventArgs, e.ViewPort);
682 if (bDrawingVisibleChildren)
688 private Point SnapInToDropTarget(ActivityDragEventArgs e)
690 if (CurrentDropTarget >= 0)
692 Rectangle[] dropTargets = GetDropTargets(new Point(e.X, e.Y));
693 if (CurrentDropTarget < dropTargets.Length)
695 Rectangle dropConnector = dropTargets[CurrentDropTarget];
696 return new Point(dropConnector.Left + dropConnector.Width / 2, dropConnector.Top + dropConnector.Height / 2);
703 private int CanDrop(ActivityDragEventArgs e)
705 if (e.Activities.Count == 0)
708 Point dropPoint = new Point(e.X, e.Y);
710 Rectangle[] dropTargets = GetDropTargets(dropPoint);
711 for (int i = 0; i < dropTargets.Length; i++)
713 if (dropTargets[i].Contains(dropPoint))
720 if (dropIndex >= 0 && !CanInsertActivities(new ConnectorHitTestInfo(this, HitTestLocations.Designer, dropIndex), e.Activities))
723 bool ctrlKeyPressed = ((e.KeyState & 8) == 8);
724 if (dropIndex >= 0 && !ctrlKeyPressed && (e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move)
726 ConnectorHitTestInfo moveLocation = new ConnectorHitTestInfo(this, HitTestLocations.Designer, dropIndex);
727 foreach (Activity activity in e.Activities)
729 if (activity.Site != null)
731 ActivityDesigner activityDesigner = ActivityDesigner.GetDesigner(activity);
732 if (activityDesigner == null || activityDesigner.ParentDesigner == null || !activityDesigner.ParentDesigner.CanMoveActivities(moveLocation, new List<Activity>(new Activity[] { activity }).AsReadOnly()))
744 private DragDropEffects CheckDragEffect(ActivityDragEventArgs e)
746 if (e.Activities.Count == 0)
748 return DragDropEffects.None;
750 else if (CurrentDropTarget >= 0)
752 bool ctrlKeyPressed = ((e.KeyState & 8) == 8);
753 if (ctrlKeyPressed && (e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy)
754 return DragDropEffects.Copy;
755 else if ((e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move)
756 return DragDropEffects.Move;
762 private void OnSmartTagVerbStatus(object sender, EventArgs e)
764 ActivityDesignerVerb verb = sender as ActivityDesignerVerb;
766 DesignerView view = verb.Properties[DesignerUserDataKeys.DesignerView] as DesignerView;
768 verb.Checked = (view == ActiveView);
771 private void OnSmartTagVerb(object sender, EventArgs e)
773 ActivityDesignerVerb verb = sender as ActivityDesignerVerb;
775 DesignerView view = verb.Properties[DesignerUserDataKeys.DesignerView] as DesignerView;
780 if (Expanded && view.AssociatedDesigner != null)
782 ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
783 if (selectionService != null)
784 selectionService.SetSelectedComponents(new object[] { view.AssociatedDesigner.Activity }, SelectionTypes.Replace);
789 private void OnSmartAction(object sender, SelectionChangeEventArgs e)
791 ItemInfo itemInfo = e.CurrentItem as ItemInfo;
792 if (itemInfo != null)
794 ActivityDesignerVerb smartVerb = itemInfo.UserData[DesignerUserDataKeys.DesignerVerb] as ActivityDesignerVerb;
795 if (smartVerb != null)
800 private void OnPaletteClosed(object sender, EventArgs e)
802 Invalidate(DesignerSmartTag.GetBounds(this, true));
805 private HitTestInfo GetUpdatedLocation(HitTestInfo location)
807 int lockedActivityOffset = 0;
808 foreach (DesignerView secondaryView in Views)
810 if (secondaryView.AssociatedDesigner != null &&
811 this != secondaryView.AssociatedDesigner &&
812 Helpers.IsActivityLocked(secondaryView.AssociatedDesigner.Activity))
814 lockedActivityOffset++;
818 return new ConnectorHitTestInfo(this, location.HitLocation, lockedActivityOffset + location.MapToIndex());