|
#pragma warning disable 1634, 1691
namespace System.Workflow.ComponentModel.Design
{
using System;
using System.IO;
using System.Drawing;
using System.CodeDom;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.ComponentModel;
using System.Globalization;
using System.Drawing.Design;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Windows.Forms.Design;
using System.ComponentModel.Design;
using System.Collections.Specialized;
using System.ComponentModel.Design.Serialization;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Workflow.ComponentModel.Design;
using System.Runtime.Serialization.Formatters.Binary;
//
#region StructuredCompositeActivityDesigner Class
/// <summary>
/// Base class for CompositActivityDesigner which have a structured layouts where contained ContainedDesigners
/// are connected to each other using connectors. Class is used when the user needs to provide different types
/// of layouts for CompositeActivityDesigner
/// </summary>
[Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")]
public abstract class StructuredCompositeActivityDesigner : CompositeActivityDesigner
{
#region Fields
private int currentDropTarget = -1;
private List<DesignerView> views = null;
private DesignerView activeView;
private ItemPalette itemPalette = null;
#endregion
#region Properties
#region Public Properties
public override ReadOnlyCollection<ActivityDesigner> ContainedDesigners
{
get
{
List<ActivityDesigner> containedDesigners = new List<ActivityDesigner>();
ActivityDesigner activeDesigner = ActiveDesigner;
if (activeDesigner != null)
{
if (activeDesigner == this)
{
//We need to remove the secondary activities
containedDesigners.AddRange(base.ContainedDesigners);
List<ActivityDesigner> designersToRemove = new List<ActivityDesigner>();
IList<ActivityDesigner> mappedDesigners = DesignersFromSupportedViews;
foreach (ActivityDesigner containedDesigner in containedDesigners)
{
bool isAlternateFlowActivityAttribute = Helpers.IsAlternateFlowActivity(containedDesigner.Activity);
if (mappedDesigners.Contains(containedDesigner) || isAlternateFlowActivityAttribute)
designersToRemove.Add(containedDesigner);
}
foreach (ActivityDesigner activityDesigner in designersToRemove)
containedDesigners.Remove(activityDesigner);
}
else
{
containedDesigners.Add(activeDesigner);
}
}
return containedDesigners.AsReadOnly();
}
}
public override object FirstSelectableObject
{
get
{
ActivityDesigner activeDesigner = ActiveDesigner;
if (activeDesigner != null && activeDesigner != this)
return activeDesigner.Activity;
else
return base.FirstSelectableObject;
}
}
public override object LastSelectableObject
{
get
{
ActivityDesigner activeDesigner = ActiveDesigner;
if (activeDesigner != null && activeDesigner != this && activeDesigner is CompositeActivityDesigner)
return ((CompositeActivityDesigner)activeDesigner).LastSelectableObject;
else
return base.LastSelectableObject;
}
}
/// <summary>
/// Gets the ActiveView supported by the designer
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public DesignerView ActiveView
{
get
{
if (this.activeView == null)
this.activeView = ValidatedViews[0];
return this.activeView;
}
set
{
if (this.activeView == value || value == null)
return;
DesignerView previousView = this.activeView;
this.activeView = value;
value.OnActivate();
ActivityDesigner designer = value.AssociatedDesigner;
if (designer == null)
{
value.OnDeactivate();
this.activeView = previousView;
return;
}
if (previousView != null)
previousView.OnDeactivate();
OnViewChanged(this.activeView);
//When we change the view we want to make sure that if we hide any of the child
//activities with errors we want to reveal these activities
DesignerHelpers.RefreshDesignerActions(Activity.Site);
//Keep the dynamic action and designer verbs in sync
RefreshDesignerVerbs();
}
}
public override Size MinimumSize
{
get
{
Size minimumSize = base.MinimumSize;
ActivityDesigner activeDesigner = ActiveDesigner;
if (activeDesigner != null && activeDesigner != this && Expanded)
{
minimumSize.Width = Math.Max(minimumSize.Width, 160);
minimumSize.Height = Math.Max(minimumSize.Height, 160);
}
return minimumSize;
}
}
/// <summary>
/// Gets the array of views supported by the current designer
/// </summary>
public virtual ReadOnlyCollection<DesignerView> Views
{
get
{
if (this.views == null)
{
this.views = new List<DesignerView>();
this.views.AddRange(SecondaryViewProvider.GetViews(this));
}
return this.views.AsReadOnly();
}
}
#endregion
#region Protected Properties
/// <summary>
/// Gets the index of the cuurent drop target in the array of drop targets returned by method GetDropTargets
/// This property is only used when the drag drop operation is in progress
/// </summary>
protected virtual int CurrentDropTarget
{
get
{
return this.currentDropTarget;
}
set
{
this.currentDropTarget = value;
Invalidate();
}
}
protected override bool ShowSmartTag
{
get
{
return (!String.IsNullOrEmpty(Text) && !TextRectangle.Size.IsEmpty && Views.Count > 1);
}
}
protected override ReadOnlyCollection<ActivityDesignerVerb> SmartTagVerbs
{
get
{
List<ActivityDesignerVerb> smartTagVerbs = new List<ActivityDesignerVerb>(base.SmartTagVerbs);
//Return smarttag actions only if there is more than one view
if (Views.Count > 1)
{
for (int i = 0; i < Views.Count; i++)
{
DesignerView view = Views[i];
ActivityDesignerVerb smartVerb = new ActivityDesignerVerb(this, DesignerVerbGroup.Actions, view.Text, new EventHandler(OnSmartTagVerb), new EventHandler(OnSmartTagVerbStatus));
smartVerb.Properties[DesignerUserDataKeys.DesignerView] = view;
smartVerb.Properties[DesignerUserDataKeys.Image] = view.Image;
smartTagVerbs.Add(smartVerb);
}
}
return smartTagVerbs.AsReadOnly();
}
}
#endregion
#region Private Properties
internal ActivityDesigner ActiveDesigner
{
get
{
if (ActiveView != null)
return ActiveView.AssociatedDesigner;
else
return null;
}
}
internal override bool SmartTagVisible
{
get
{
if (this.itemPalette != null && this.itemPalette.IsVisible)
return true;
return base.SmartTagVisible;
}
set
{
base.SmartTagVisible = value;
}
}
private ReadOnlyCollection<DesignerView> ValidatedViews
{
get
{
ReadOnlyCollection<DesignerView> views = Views;
if (views.Count == 0)
#pragma warning suppress 56503
throw new InvalidOperationException(DR.GetString(DR.Error_MultiviewSequentialActivityDesigner));
return views;
}
}
private IList<ActivityDesigner> DesignersFromSupportedViews
{
get
{
List<ActivityDesigner> mappedDesigners = new List<ActivityDesigner>();
foreach (DesignerView view in ValidatedViews)
{
ActivityDesigner mappedDesigner = view.AssociatedDesigner;
if (mappedDesigner != null)
mappedDesigners.Add(mappedDesigner);
}
return mappedDesigners.AsReadOnly();
}
}
#endregion
#endregion
#region Methods
#region Public Methods
public override bool CanInsertActivities(HitTestInfo insertLocation, ReadOnlyCollection<Activity> activitiesToInsert)
{
if (insertLocation == null)
throw new ArgumentNullException("insertLocation");
if (activitiesToInsert == null)
throw new ArgumentNullException("activitiesToInsert");
ActivityDesigner hostedDesigner = (ActiveView != null) ? ActiveView.AssociatedDesigner : null;
if (hostedDesigner != this)
return false;
IList<Type> secondaryViewTypes = SecondaryViewProvider.GetActivityTypes(this);
foreach (Activity activity in activitiesToInsert)
{
if (activity == null)
throw new ArgumentException("activitiesToInsert", SR.GetString(SR.Error_CollectionHasNullEntry));
if (secondaryViewTypes.Contains(activity.GetType()))
return false;
}
return base.CanInsertActivities(GetUpdatedLocation(insertLocation), activitiesToInsert);
}
public override void InsertActivities(HitTestInfo insertLocation, ReadOnlyCollection<Activity> activitiesToInsert)
{
if (insertLocation == null)
throw new ArgumentNullException("insertLocation");
if (activitiesToInsert == null)
throw new ArgumentNullException("activitiesToInsert");
base.InsertActivities(GetUpdatedLocation(insertLocation), activitiesToInsert);
}
public override void MoveActivities(HitTestInfo moveLocation, ReadOnlyCollection<Activity> activitiesToMove)
{
if (moveLocation == null)
throw new ArgumentNullException("moveLocation");
if (activitiesToMove == null)
throw new ArgumentNullException("activitiesToMove");
base.MoveActivities(GetUpdatedLocation(moveLocation), activitiesToMove);
}
public override bool CanRemoveActivities(ReadOnlyCollection<Activity> activitiesToRemove)
{
if (activitiesToRemove == null)
throw new ArgumentNullException("activitiesToRemove");
return base.CanRemoveActivities(activitiesToRemove);
}
public override void EnsureVisibleContainedDesigner(ActivityDesigner containedDesigner)
{
if (containedDesigner == null)
throw new ArgumentNullException("containedDesigner");
//we could be collapsed, make sure the view itself is visible
this.Expanded = true;
ActivityDesigner activeDesigner = ActiveDesigner;
if (containedDesigner != activeDesigner && containedDesigner != this)
{
DesignerView viewToActivate = null;
ReadOnlyCollection<DesignerView> views = ValidatedViews;
//Go thru the views and check if the child designer is one of the views
foreach (DesignerView view in views)
{
if (containedDesigner == view.AssociatedDesigner)
{
viewToActivate = view;
break;
}
}
//This means that the child designer is in our main flow
if (viewToActivate == null)
viewToActivate = views[0];
ActiveView = viewToActivate;
//Invoking a verb might change the shown view so we map again
CompositeActivityDesigner activeCompositeDesigner = ActiveDesigner as CompositeActivityDesigner;
if (activeCompositeDesigner != null)
{
if (activeCompositeDesigner != this)
activeCompositeDesigner.EnsureVisibleContainedDesigner(containedDesigner);
else
base.EnsureVisibleContainedDesigner(containedDesigner);
}
}
}
public override object GetNextSelectableObject(object current, DesignerNavigationDirection direction)
{
object nextObject = null;
ActivityDesigner activeDesigner = ActiveDesigner;
if (activeDesigner != null)
{
if (activeDesigner != this)
{
if (current != activeDesigner.Activity && activeDesigner is CompositeActivityDesigner)
nextObject = ((CompositeActivityDesigner)activeDesigner).GetNextSelectableObject(current, direction);
}
else
{
nextObject = base.GetNextSelectableObject(current, direction);
}
}
return nextObject;
}
#endregion
#region Protected Methods
protected override void Initialize(Activity activity)
{
base.Initialize(activity);
ActiveView = ValidatedViews[0];
}
/// <summary>
/// Returns the collection of points which represents the inner connections of the designer. The designer can have connectors
/// within it, the points returned are the connection points used for connectable designer.
/// </summary>
/// <param name="edges">Designer Edge along which the connection point lies</param>
/// <returns>List of connection Points</returns>
protected virtual ReadOnlyCollection<Point> GetInnerConnections(DesignerEdges edges)
{
List<Point> connectionPoints = new List<Point>(GetConnections(edges));
if (connectionPoints.Count > 0 && (edges & DesignerEdges.Top) > 0)
connectionPoints[0] = new Point(connectionPoints[0].X, connectionPoints[0].Y + TitleHeight);
return connectionPoints.AsReadOnly();
}
/// <summary>
/// Returns array of rectangles representing the valid drop locations with the designer
/// </summary>
/// <param name="dropPoint"></param>
/// <returns></returns>
protected virtual Rectangle[] GetDropTargets(Point dropPoint)
{
return new Rectangle[] { Bounds };
}
protected override void OnContainedActivitiesChanging(ActivityCollectionChangeEventArgs listChangeArgs)
{
base.OnContainedActivitiesChanging(listChangeArgs);
if (listChangeArgs.Action == ActivityCollectionChangeAction.Remove && listChangeArgs.RemovedItems[0] != null)
{
ActivityDesigner activeDesigner = ActiveDesigner;
if (activeDesigner != null && listChangeArgs.RemovedItems[0] == activeDesigner.Activity)
ActiveView = ValidatedViews[0];
SecondaryViewProvider.OnViewRemoved(this, listChangeArgs.RemovedItems[0].GetType());
}
}
protected void DrawConnectors(Graphics graphics, Pen pen, Point[] points, LineAnchor startCap, LineAnchor endCap)
{
Size arrowCapSize = Size.Empty;
Size maxCapSize = Size.Empty;
CompositeDesignerTheme compositeDesignerTheme = DesignerTheme as CompositeDesignerTheme;
if (compositeDesignerTheme != null)
{
arrowCapSize = new Size(compositeDesignerTheme.ConnectorSize.Width / 3, compositeDesignerTheme.ConnectorSize.Height / 3);
maxCapSize = compositeDesignerTheme.ConnectorSize;
}
ActivityDesignerPaint.DrawConnectors(graphics, pen, points, arrowCapSize, maxCapSize, startCap, endCap);
}
protected override void OnDragEnter(ActivityDragEventArgs e)
{
base.OnDragEnter(e);
CurrentDropTarget = CanDrop(e);
e.Effect = CheckDragEffect(e);
e.DragImageSnapPoint = SnapInToDropTarget(e);
}
protected override void OnDragOver(ActivityDragEventArgs e)
{
base.OnDragOver(e);
CurrentDropTarget = CanDrop(e);
e.Effect = CheckDragEffect(e);
e.DragImageSnapPoint = SnapInToDropTarget(e);
}
protected override void OnDragLeave()
{
base.OnDragLeave();
//Clear earlier drop target information
CurrentDropTarget = -1;
}
protected override void OnDragDrop(ActivityDragEventArgs e)
{
base.OnDragDrop(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;
//If the component is sited then that means that we are moving it
try
{
CompositeActivityDesigner.InsertActivities(this, new ConnectorHitTestInfo(this, HitTestLocations.Designer, CurrentDropTarget), e.Activities, SR.GetString(SR.DragDropActivities));
}
finally
{
CurrentDropTarget = -1;
}
}
protected override void OnLayoutPosition(ActivityDesignerLayoutEventArgs e)
{
if (e == null)
throw new ArgumentNullException("e");
base.OnLayoutPosition(e);
if (Expanded)
{
ActivityDesigner activeDesigner = ActiveDesigner;
if (activeDesigner != null && activeDesigner != this)
{
Point location = Location;
location.X += (Size.Width - activeDesigner.Size.Width) / 2;
location.Y += e.AmbientTheme.SelectionSize.Height;
activeDesigner.Location = location;
}
int titleHeight = TitleHeight;
foreach (ActivityDesigner activityDesigner in ContainedDesigners)
activityDesigner.Location = new Point(activityDesigner.Location.X, activityDesigner.Location.Y + titleHeight);
}
}
protected override Size OnLayoutSize(ActivityDesignerLayoutEventArgs e)
{
Size containerSize = base.OnLayoutSize(e);
if (Expanded)
{
ActivityDesigner activeDesigner = ActiveDesigner;
if (activeDesigner != null && activeDesigner != this)
{
containerSize.Width = Math.Max(containerSize.Width, activeDesigner.Size.Width);
containerSize.Height += activeDesigner.Size.Height;
containerSize.Width += 2 * e.AmbientTheme.SelectionSize.Width;
containerSize.Width += 3 * e.AmbientTheme.Margin.Width;
containerSize.Height += e.AmbientTheme.Margin.Height;
containerSize.Height += 2 * e.AmbientTheme.SelectionSize.Height;
}
}
return containerSize;
}
protected override void SaveViewState(BinaryWriter writer)
{
if (writer == null)
throw new ArgumentNullException("writer");
List<DesignerView> views = new List<DesignerView>(ValidatedViews);
writer.Write("ActiveView");
writer.Write(views.IndexOf(this.activeView));
base.SaveViewState(writer);
}
protected override void LoadViewState(BinaryReader reader)
{
if (reader == null)
throw new ArgumentNullException("reader");
string str = reader.ReadString();
if (str != null && str.Equals("ActiveView", StringComparison.Ordinal))
{
int activeDesignerIndex = reader.ReadInt32();
ReadOnlyCollection<DesignerView> views = ValidatedViews;
if (activeDesignerIndex != -1 && activeDesignerIndex < views.Count)
ActiveView = views[activeDesignerIndex];
}
base.LoadViewState(reader);
}
/// <summary>
/// Called when the current view of the designer changes
/// </summary>
/// <param name="view">View which is being set.</param>
protected virtual void OnViewChanged(DesignerView view)
{
PerformLayout();
}
protected override void OnShowSmartTagVerbs(Point smartTagPoint)
{
if (this.itemPalette == null)
{
this.itemPalette = new ItemPalette();
this.itemPalette.Closed += new EventHandler(OnPaletteClosed);
this.itemPalette.SelectionChanged += new SelectionChangeEventHandler<SelectionChangeEventArgs>(OnSmartAction);
}
//we need to update the font every time the menu is shown
this.itemPalette.SetFont(WorkflowTheme.CurrentTheme.AmbientTheme.Font);
this.itemPalette.Items.Clear();
foreach (ActivityDesignerVerb smartVerb in SmartTagVerbs)
{
Image image = smartVerb.Properties[DesignerUserDataKeys.Image] as Image;
ItemInfo smartVerbItem = new ItemInfo(smartVerb.Id, image, smartVerb.Text);
smartVerbItem.UserData[DesignerUserDataKeys.DesignerVerb] = smartVerb;
this.itemPalette.Items.Add(smartVerbItem);
}
Point location = PointToScreen(smartTagPoint);
this.itemPalette.Show(location);
}
protected override void OnActivityChanged(ActivityChangedEventArgs e)
{
ReadOnlyCollection<DesignerView> newViews = SecondaryViewProvider.GetViews(this);
ReadOnlyCollection<DesignerView> oldViews = Views;
if (newViews.Count != oldViews.Count)
{
this.views = null;
//
PerformLayout();
}
base.OnActivityChanged(e);
}
#endregion
#region Private Methods
internal override void OnPaintContainedDesigners(ActivityDesignerPaintEventArgs e)
{
//Draw all the activity designers contained by the activity designer
//We know that all the children which are in drawing range will be always
//consecutive both for parallel and for sequential containers hence
//once we go in the invisible range we bail out of drawing logic for rest of
//the children
bool bDrawingVisibleChildren = false;
foreach (ActivityDesigner activityDesigner in ContainedDesigners)
{
Rectangle designerBounds = activityDesigner.Bounds;
if (e.ViewPort.IntersectsWith(designerBounds))
{
bDrawingVisibleChildren = true;
using (PaintEventArgs paintEventArgs = new PaintEventArgs(e.Graphics, e.ViewPort))
{
((IWorkflowDesignerMessageSink)activityDesigner).OnPaint(paintEventArgs, e.ViewPort);
}
}
else
{
if (bDrawingVisibleChildren)
break;
}
}
}
private Point SnapInToDropTarget(ActivityDragEventArgs e)
{
if (CurrentDropTarget >= 0)
{
Rectangle[] dropTargets = GetDropTargets(new Point(e.X, e.Y));
if (CurrentDropTarget < dropTargets.Length)
{
Rectangle dropConnector = dropTargets[CurrentDropTarget];
return new Point(dropConnector.Left + dropConnector.Width / 2, dropConnector.Top + dropConnector.Height / 2);
}
}
return Point.Empty;
}
private int CanDrop(ActivityDragEventArgs e)
{
if (e.Activities.Count == 0)
return -1;
Point dropPoint = new Point(e.X, e.Y);
int dropIndex = -1;
Rectangle[] dropTargets = GetDropTargets(dropPoint);
for (int i = 0; i < dropTargets.Length; i++)
{
if (dropTargets[i].Contains(dropPoint))
{
dropIndex = i;
break;
}
}
if (dropIndex >= 0 && !CanInsertActivities(new ConnectorHitTestInfo(this, HitTestLocations.Designer, dropIndex), e.Activities))
dropIndex = -1;
bool ctrlKeyPressed = ((e.KeyState & 8) == 8);
if (dropIndex >= 0 && !ctrlKeyPressed && (e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move)
{
ConnectorHitTestInfo moveLocation = new ConnectorHitTestInfo(this, HitTestLocations.Designer, dropIndex);
foreach (Activity activity in e.Activities)
{
if (activity.Site != null)
{
ActivityDesigner activityDesigner = ActivityDesigner.GetDesigner(activity);
if (activityDesigner == null || activityDesigner.ParentDesigner == null || !activityDesigner.ParentDesigner.CanMoveActivities(moveLocation, new List<Activity>(new Activity[] { activity }).AsReadOnly()))
{
dropIndex = -1;
break;
}
}
}
}
return dropIndex;
}
private DragDropEffects CheckDragEffect(ActivityDragEventArgs e)
{
if (e.Activities.Count == 0)
{
return DragDropEffects.None;
}
else if (CurrentDropTarget >= 0)
{
bool ctrlKeyPressed = ((e.KeyState & 8) == 8);
if (ctrlKeyPressed && (e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy)
return DragDropEffects.Copy;
else if ((e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move)
return DragDropEffects.Move;
}
return e.Effect;
}
private void OnSmartTagVerbStatus(object sender, EventArgs e)
{
ActivityDesignerVerb verb = sender as ActivityDesignerVerb;
DesignerView view = verb.Properties[DesignerUserDataKeys.DesignerView] as DesignerView;
if (view != null)
verb.Checked = (view == ActiveView);
}
private void OnSmartTagVerb(object sender, EventArgs e)
{
ActivityDesignerVerb verb = sender as ActivityDesignerVerb;
DesignerView view = verb.Properties[DesignerUserDataKeys.DesignerView] as DesignerView;
if (view != null)
{
ActiveView = view;
if (Expanded && view.AssociatedDesigner != null)
{
ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
if (selectionService != null)
selectionService.SetSelectedComponents(new object[] { view.AssociatedDesigner.Activity }, SelectionTypes.Replace);
}
}
}
private void OnSmartAction(object sender, SelectionChangeEventArgs e)
{
ItemInfo itemInfo = e.CurrentItem as ItemInfo;
if (itemInfo != null)
{
ActivityDesignerVerb smartVerb = itemInfo.UserData[DesignerUserDataKeys.DesignerVerb] as ActivityDesignerVerb;
if (smartVerb != null)
smartVerb.Invoke();
}
}
private void OnPaletteClosed(object sender, EventArgs e)
{
Invalidate(DesignerSmartTag.GetBounds(this, true));
}
private HitTestInfo GetUpdatedLocation(HitTestInfo location)
{
int lockedActivityOffset = 0;
foreach (DesignerView secondaryView in Views)
{
if (secondaryView.AssociatedDesigner != null &&
this != secondaryView.AssociatedDesigner &&
Helpers.IsActivityLocked(secondaryView.AssociatedDesigner.Activity))
{
lockedActivityOffset++;
}
}
return new ConnectorHitTestInfo(this, location.HitLocation, lockedActivityOffset + location.MapToIndex());
}
#endregion
#endregion
}
#endregion
}
|