#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 SequentialActivityDesigner Class /// /// Base class used for all the designers which have sequential vertical layout. /// [Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")] public class SequentialActivityDesigner : StructuredCompositeActivityDesigner { #region Constants private static readonly Size DefaultHelpTextSize = new Size(100, 85); #endregion #region Fields private SequenceDesignerAccessibleObject accessibilityObject; private string helpText = String.Empty; private Size helpTextSize = Size.Empty; #endregion #region Constructor /// /// Default Constructor /// public SequentialActivityDesigner() { } #endregion #region Properties #region Public Properties public override bool Expanded { get { if (ParentDesigner is ParallelActivityDesigner) return true; else return base.Expanded; } set { if (ParentDesigner is ParallelActivityDesigner) value = true; base.Expanded = value; } } public override bool CanExpandCollapse { get { if (ParentDesigner is ParallelActivityDesigner) return false; else return base.CanExpandCollapse; } } public override object FirstSelectableObject { get { if (ActiveDesigner != this) return base.FirstSelectableObject; if (GetConnectors().Length == 0 || !Expanded || !IsVisible) return null; // This assumes there is always atleast one connector in SequenceContainer return new ConnectorHitTestInfo(this, HitTestLocations.Designer, 0); } } public override object LastSelectableObject { get { if (ActiveDesigner != this) return base.LastSelectableObject; Rectangle[] connectors = GetConnectors(); if (connectors.Length == 0 || !Expanded || !IsVisible) return null; // This assumes there is always atleast one connector in SequenceContainer return new ConnectorHitTestInfo(this, HitTestLocations.Designer, connectors.Length - 1); } } public override AccessibleObject AccessibilityObject { get { if (this.accessibilityObject == null) this.accessibilityObject = new SequenceDesignerAccessibleObject(this); return this.accessibilityObject; } } #endregion #region Protected Properties /// /// Gets the help text to be displayed when the are no contained designers to display /// protected virtual string HelpText { get { return this.helpText; } set { this.helpText = value; PerformLayout(); } } /// /// Gets the Rectangle bounding the help text. /// protected virtual Rectangle HelpTextRectangle { get { Rectangle[] connectors = GetConnectors(); if (this.HelpText.Length == 0 || ContainedDesigners.Count > 0 || !Expanded || connectors.Length == 0) return Rectangle.Empty; //Get the first connector and align the help text right in the center Rectangle helpTextRectangle = Rectangle.Empty; helpTextRectangle.X = connectors[0].Left + connectors[0].Width / 2 - this.helpTextSize.Width / 2; helpTextRectangle.Y = connectors[0].Top + connectors[0].Height / 2 - this.helpTextSize.Height / 2; helpTextRectangle.Size = this.helpTextSize; return helpTextRectangle; } } /// /// Gets the array of rectangles bounding the connectors /// protected internal virtual Rectangle[] GetConnectors() { if (ActiveDesigner != this) return new Rectangle[] { }; if (!Expanded) return new Rectangle[] { }; CompositeDesignerTheme designerTheme = DesignerTheme as CompositeDesignerTheme; if (designerTheme == null) return new Rectangle[] { }; //Calculate no of connectors for the container; if there is no activityDesigner then we display single connector ReadOnlyCollection containedDesigners = ContainedDesigners; int connectorCount = (containedDesigners.Count > 0) ? (2 + (containedDesigners.Count - 1)) : 1; Rectangle[] connectorBounds = new Rectangle[connectorCount]; ReadOnlyCollection containerConnections = GetInnerConnections(DesignerEdges.Top | DesignerEdges.Bottom); Point containerStartConnection = new Point(); Point containerEndConnection = new Point(); if (containerConnections != null && containerConnections.Count > 0) { containerStartConnection = containerConnections[0]; containerEndConnection = containerConnections[containerConnections.Count - 1]; } if (containedDesigners.Count > 0) { //Add the first connector. This will be from bitmap bottom to activityDesigner start ActivityDesigner startDesigner = containedDesigners[0] as ActivityDesigner; ReadOnlyCollection startDesignerConnections = startDesigner.GetConnections(DesignerEdges.Top | DesignerEdges.Bottom); if (startDesignerConnections.Count == 0) { Rectangle startDesignerBounds = startDesigner.Bounds; List connections = new List(); connections.Add(new Point(startDesignerBounds.Left + startDesignerBounds.Width / 2, startDesignerBounds.Top)); connections.Add(new Point(startDesignerBounds.Left + startDesignerBounds.Width / 2, startDesignerBounds.Bottom)); startDesignerConnections = connections.AsReadOnly(); } connectorBounds[0].Location = new Point(containerStartConnection.X - ((designerTheme != null) ? designerTheme.ConnectorSize.Width : 0) / 2, containerStartConnection.Y); connectorBounds[0].Size = new Size(((designerTheme != null) ? designerTheme.ConnectorSize.Width : 0), startDesignerConnections[0].Y - containerStartConnection.Y); //Add rest of the points for (int i = 0; i < containedDesigners.Count - 1; i++) { ActivityDesigner designerFrom = containedDesigners[i]; ActivityDesigner designerTo = containedDesigners[i + 1]; if (designerFrom != null && designerTo != null) { ReadOnlyCollection designerFromConnections = designerFrom.GetConnections(DesignerEdges.Top | DesignerEdges.Bottom); int designerFromPointCount = designerFromConnections.Count; ReadOnlyCollection designerToConnections = designerTo.GetConnections(DesignerEdges.Top | DesignerEdges.Bottom); connectorBounds[i + 1].Location = new Point(designerFromConnections[designerFromPointCount - 1].X - ((designerTheme != null) ? designerTheme.ConnectorSize.Width : 0) / 2, designerFromConnections[designerFromPointCount - 1].Y); connectorBounds[i + 1].Size = new Size(((designerTheme != null) ? designerTheme.ConnectorSize.Width : 0), designerToConnections[0].Y - designerFromConnections[designerFromPointCount - 1].Y); } } //Add the last connector ActivityDesigner endDesigner = containedDesigners[containedDesigners.Count - 1]; ReadOnlyCollection endDesignerConnections = endDesigner.GetConnections(DesignerEdges.Top | DesignerEdges.Bottom); if (endDesignerConnections.Count == 0) { Rectangle endDesignerBounds = endDesigner.Bounds; List connections = new List(); connections.Add(new Point(endDesignerBounds.Left + endDesignerBounds.Width / 2, endDesignerBounds.Top)); connections.Add(new Point(endDesignerBounds.Left + endDesignerBounds.Width / 2, endDesignerBounds.Bottom)); endDesignerConnections = connections.AsReadOnly(); } connectorBounds[connectorCount - 1].Location = new Point(endDesignerConnections[endDesignerConnections.Count - 1].X - ((designerTheme != null) ? designerTheme.ConnectorSize.Width : 0) / 2, endDesignerConnections[endDesignerConnections.Count - 1].Y); connectorBounds[connectorCount - 1].Size = new Size(((designerTheme != null) ? designerTheme.ConnectorSize.Width : 0), containerEndConnection.Y - endDesignerConnections[endDesignerConnections.Count - 1].Y); } else { //If there are no activity designers in the container then we show only one connector connectorBounds[0].Location = new Point(containerStartConnection.X - ((designerTheme != null) ? designerTheme.ConnectorSize.Width : 0) / 2, containerStartConnection.Y); connectorBounds[0].Size = new Size(((designerTheme != null) ? designerTheme.ConnectorSize.Width : 0), containerEndConnection.Y - containerStartConnection.Y); } //extend the targets a little bit for (int i = 0; i < connectorBounds.Length; i++) connectorBounds[i].Inflate(3 * connectorBounds[i].Width, 0); return connectorBounds; } protected internal override ActivityDesignerGlyphCollection Glyphs { get { ActivityDesignerGlyphCollection designerGlyphs = new ActivityDesignerGlyphCollection(); ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService; if (selectionService != null) { ICollection selectedObjects = selectionService.GetSelectedComponents(); foreach (object obj in selectedObjects) { ConnectorHitTestInfo connectorHitTestInfo = obj as ConnectorHitTestInfo; if (connectorHitTestInfo != null && connectorHitTestInfo.AssociatedDesigner == this) designerGlyphs.Add(new SequentialConnectorSelectionGlyph(connectorHitTestInfo.MapToIndex(), (selectionService.PrimarySelection == obj))); } } designerGlyphs.AddRange(CreateConnectorDragDropGlyphs()); designerGlyphs.AddRange(base.Glyphs); return designerGlyphs; } } protected Size HelpTextSize { get { return this.helpTextSize; } } #endregion #region Private Properties #endregion #endregion #region Methods #region Public Methods public override HitTestInfo HitTest(Point point) { if (ActiveDesigner != this) return base.HitTest(point); HitTestInfo hitInfo = HitTestInfo.Nowhere; if (!Expanded) { hitInfo = base.HitTest(point); } else if (ContainedDesigners.Count == 0 && HelpTextRectangle.Contains(point)) { hitInfo = new ConnectorHitTestInfo(this, HitTestLocations.Designer, 0); } else { //Check if the hit is on any of the connectors Rectangle[] connectors = GetConnectors(); for (int i = 0; i < connectors.Length; i++) { if (connectors[i].Contains(point)) { hitInfo = new ConnectorHitTestInfo(this, HitTestLocations.Designer, i); break; } } if (hitInfo.HitLocation == HitTestLocations.None) hitInfo = base.HitTest(point); } return hitInfo; } public override object GetNextSelectableObject(object obj, DesignerNavigationDirection direction) { if (ActiveDesigner != this) return base.GetNextSelectableObject(obj, direction); if (direction != DesignerNavigationDirection.Down && direction != DesignerNavigationDirection.Up) return null; object nextObject = null; ReadOnlyCollection containedDesigners = ContainedDesigners; if (direction == DesignerNavigationDirection.Down) { if (obj is ConnectorHitTestInfo) { int currentIndex = ((ConnectorHitTestInfo)obj).MapToIndex(); if (currentIndex >= 0 && currentIndex < containedDesigners.Count) nextObject = ((ActivityDesigner)containedDesigners[currentIndex]).Activity; } else if (obj is Activity) { ActivityDesigner activityDesigner = ActivityDesigner.GetDesigner(obj as Activity); int currentIndex = (activityDesigner != null) ? containedDesigners.IndexOf(activityDesigner) : -1; if (currentIndex >= 0 && (currentIndex + 1) < GetConnectors().Length) nextObject = new ConnectorHitTestInfo(this, HitTestLocations.Designer, currentIndex + 1); } } else if (direction == DesignerNavigationDirection.Up) { if (obj is ConnectorHitTestInfo) { int currentIndex = ((ConnectorHitTestInfo)obj).MapToIndex(); if (currentIndex > 0 && currentIndex < GetConnectors().Length) nextObject = ((ActivityDesigner)containedDesigners[currentIndex - 1]).Activity; } else if (obj is Activity) { ActivityDesigner activityDesigner = ActivityDesigner.GetDesigner(obj as Activity); int currentIndex = (activityDesigner != null) ? containedDesigners.IndexOf(activityDesigner) : -1; if (currentIndex >= 0 && currentIndex < GetConnectors().Length) nextObject = new ConnectorHitTestInfo(this, HitTestLocations.Designer, currentIndex); } } return nextObject; } #endregion #region Protected Methods protected override void Initialize(Activity activity) { base.Initialize(activity); HelpText = DR.GetString(DR.DropActivitiesHere); } protected override Rectangle[] GetDropTargets(Point dropPoint) { if (HelpTextRectangle.Contains(dropPoint)) return new Rectangle[] { HelpTextRectangle }; else return GetConnectors(); } protected override void OnPaint(ActivityDesignerPaintEventArgs e) { base.OnPaint(e); CompositeDesignerTheme compositeDesignerTheme = e.DesignerTheme as CompositeDesignerTheme; if (Expanded && compositeDesignerTheme != null) { //Draw the connectors Rectangle helpTextRectangle = HelpTextRectangle; if (CurrentDropTarget == -1 && !helpTextRectangle.Size.IsEmpty) { Rectangle[] connectors = GetConnectors(); if (connectors.Length > 0) { DrawConnectors(e.Graphics, compositeDesignerTheme.ForegroundPen, new Point[] { new Point(connectors[0].X + connectors[0].Width / 2, connectors[0].Y + 2), new Point(connectors[0].X + connectors[0].Width / 2, helpTextRectangle.Top - 2) }, compositeDesignerTheme.ConnectorStartCap, LineAnchor.None); DrawConnectors(e.Graphics, compositeDesignerTheme.ForegroundPen, new Point[] { new Point(connectors[0].X + connectors[0].Width / 2, helpTextRectangle.Bottom + 2), new Point(connectors[0].X + connectors[0].Width / 2, connectors[0].Bottom - 2) }, LineAnchor.None, compositeDesignerTheme.ConnectorEndCap); } ActivityDesignerPaint.DrawText(e.Graphics, compositeDesignerTheme.Font, this.HelpText, helpTextRectangle, StringAlignment.Center, e.AmbientTheme.TextQuality, compositeDesignerTheme.ForegroundBrush); } else { Rectangle[] connectors = GetConnectors(); for (int i = 0; i < connectors.Length; i++) { Pen pen = (i == CurrentDropTarget) ? e.AmbientTheme.DropIndicatorPen : compositeDesignerTheme.ForegroundPen; LineAnchor startCap = ((i == 0 && connectors.Length > 2) || i == connectors.Length - 1) ? LineAnchor.None : compositeDesignerTheme.ConnectorStartCap; LineAnchor endCap = (i == 0 || (i == connectors.Length - 1 && connectors.Length > 2)) ? LineAnchor.None : compositeDesignerTheme.ConnectorEndCap; DrawConnectors(e.Graphics, pen, new Point[] { new Point(connectors[i].Left + connectors[i].Width / 2, connectors[i].Top + 2), new Point(connectors[i].Left + connectors[i].Width / 2, connectors[i].Bottom - 2) }, startCap, endCap); } } } } protected override void OnLayoutPosition(ActivityDesignerLayoutEventArgs e) { if (e == null) throw new ArgumentNullException("e"); base.OnLayoutPosition(e); if (Expanded && ActiveDesigner == this) { CompositeDesignerTheme compositeDesignerTheme = e.DesignerTheme as CompositeDesignerTheme; //This condition is to center align the children int height = 0; ReadOnlyCollection connectionPoints = GetInnerConnections(DesignerEdges.Top | DesignerEdges.Bottom); Point location = (connectionPoints.Count > 0) ? connectionPoints[0] : Location; if (ContainedDesigners.Count == 1) { int heightDelta = 0; if (connectionPoints.Count > 0) heightDelta = Size.Height - (connectionPoints[connectionPoints.Count - 1].Y - connectionPoints[0].Y); height += (Size.Height - heightDelta) / 2 - ContainedDesigners[0].Size.Height / 2; } else { height += ((compositeDesignerTheme != null) ? compositeDesignerTheme.ConnectorSize.Height : 0); } foreach (ActivityDesigner activityDesigner in ContainedDesigners) { Size designerSize = activityDesigner.Size; activityDesigner.Location = new Point(location.X - (designerSize.Width / 2), location.Y + height); height += designerSize.Height + ((compositeDesignerTheme != null) ? compositeDesignerTheme.ConnectorSize.Height : 0); } } } protected override Size OnLayoutSize(ActivityDesignerLayoutEventArgs e) { Size containerSize = base.OnLayoutSize(e); CompositeDesignerTheme compositeDesignerTheme = e.DesignerTheme as CompositeDesignerTheme; if (Expanded && ActiveDesigner == this && compositeDesignerTheme != null) { if (this.HelpText.Length > 0) this.helpTextSize = ActivityDesignerPaint.MeasureString(e.Graphics, compositeDesignerTheme.Font, this.HelpText, StringAlignment.Center, SequentialActivityDesigner.DefaultHelpTextSize); //Calculate the size based on child size containerSize.Height += compositeDesignerTheme.ConnectorSize.Height; //Add the height of first connector foreach (ActivityDesigner activityDesigner in ContainedDesigners) { Size childSize = activityDesigner.Size; containerSize.Width = Math.Max(containerSize.Width, childSize.Width); containerSize.Height += childSize.Height; containerSize.Height += compositeDesignerTheme.ConnectorSize.Height; } if (ContainedDesigners.Count == 0) { Rectangle helpTextRectangle = HelpTextRectangle; containerSize.Width = Math.Max(helpTextRectangle.Width, containerSize.Width); containerSize.Height += helpTextRectangle.Height; containerSize.Height += compositeDesignerTheme.ConnectorSize.Height; //Add the height of last connector } containerSize.Width = Math.Max(containerSize.Width, compositeDesignerTheme.Size.Width); containerSize.Width += 3 * e.AmbientTheme.Margin.Width; containerSize.Width += 2 * e.AmbientTheme.SelectionSize.Width; containerSize.Height = Math.Max(containerSize.Height, compositeDesignerTheme.Size.Height); } return containerSize; } #endregion #region Private Methods private DesignerGlyph[] CreateConnectorDragDropGlyphs() { //see if there's a drag'n'drop operation going on WorkflowView parentView = ParentView; DragDropManager dragDropManager = GetService(typeof(DragDropManager)) as DragDropManager; if (parentView == null || dragDropManager == null || !parentView.DragDropInProgress || DrawingState != DrawingStates.Valid) return new DesignerGlyph[] { }; List glyphs = new List(); Rectangle logicalViewPort = parentView.ClientRectangleToLogical(new Rectangle(Point.Empty, parentView.ViewPortSize)); AmbientTheme ambientTheme = WorkflowTheme.CurrentTheme.AmbientTheme; Rectangle[] connectors = GetConnectors(); Rectangle helpTextRectangle = HelpTextRectangle; for (int i = 0; i < connectors.Length; i++) { if (logicalViewPort.IntersectsWith(connectors[i]) && i != CurrentDropTarget && dragDropManager.IsValidDropContext(new ConnectorHitTestInfo(this, HitTestLocations.Designer, i))) { Point glyphLocation = Point.Empty; if (helpTextRectangle.IsEmpty) glyphLocation = new Point(connectors[i].Location.X + connectors[i].Size.Width / 2 + 1, connectors[i].Location.Y + connectors[i].Size.Height / 2); else glyphLocation = new Point(helpTextRectangle.Left + helpTextRectangle.Width / 2 + 1, helpTextRectangle.Top - ambientTheme.DropIndicatorSize.Height / 2); glyphs.Add(new ConnectorDragDropGlyph(i, glyphLocation)); } } return glyphs.ToArray(); } #endregion #endregion #region Class SequentialConnectorSelectionGlyph private sealed class SequentialConnectorSelectionGlyph : ConnectorSelectionGlyph { public SequentialConnectorSelectionGlyph(int connectorIndex, bool isPrimarySelectionGlyph) : base(connectorIndex, isPrimarySelectionGlyph) { } public override Rectangle GetBounds(ActivityDesigner designer, bool activated) { Rectangle bounds = Rectangle.Empty; if (designer is SequentialActivityDesigner) { Rectangle[] connectors = ((SequentialActivityDesigner)designer).GetConnectors(); if (this.connectorIndex < connectors.Length) bounds = connectors[this.connectorIndex]; } return bounds; } protected override void OnPaint(Graphics graphics, bool activated, AmbientTheme ambientTheme, ActivityDesigner designer) { Rectangle bounds = GetBounds(designer, activated); Rectangle[] grabHandles = new Rectangle[2]; grabHandles[0] = new Rectangle(bounds.X + bounds.Width / 2 - ambientTheme.SelectionSize.Width / 2, bounds.Y, ambientTheme.SelectionSize.Width, ambientTheme.SelectionSize.Height); grabHandles[1] = new Rectangle(bounds.X + bounds.Width / 2 - ambientTheme.SelectionSize.Width / 2, bounds.Bottom - ambientTheme.SelectionSize.Height, ambientTheme.SelectionSize.Width, ambientTheme.SelectionSize.Height); ActivityDesignerPaint.DrawGrabHandles(graphics, grabHandles, this.isPrimarySelectionGlyph); } public override bool IsPrimarySelection { get { return this.isPrimarySelectionGlyph; } } } #endregion } #endregion }