File: Designers\StateDesignerConnector.cs
Project: ndp\cdf\src\WF\Activities\System.Workflow.Activities.csproj (System.Workflow.Activities)
namespace System.Workflow.Activities
{
    using System;
    using System.Text;
    using System.Reflection;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.CodeDom;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Drawing.Design;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Diagnostics;
    using System.IO;
    using System.Windows.Forms;
    using System.Workflow.ComponentModel;
    using System.Workflow.ComponentModel.Design;
    using System.Runtime.Serialization;
    using System.Workflow.ComponentModel.Serialization;
    using System.ComponentModel.Design.Serialization;
    using System.Xml;
 
    [DesignerSerializer(typeof(StateDesignerConnectorLayoutSerializer), typeof(WorkflowMarkupSerializer))]
    internal class StateDesignerConnector : Connector
    {
        internal const int ConnectorPadding = 10;
 
        private string _setStateName;
        private string _eventHandlerName;
        private string _sourceStateName;
        private string _targetStateName;
 
        internal StateDesignerConnector(ConnectionPoint source, ConnectionPoint target)
            : base(source, target)
        {
        }
 
        private StateDesigner RootStateDesigner
        {
            get
            {
                StateDesigner stateDesigner = (StateDesigner)this.ParentDesigner;
                while (true && stateDesigner != null)
                {
                    StateDesigner parentStateDesigner = stateDesigner.ParentDesigner as StateDesigner;
                    if (parentStateDesigner == null)
                        break;
 
                    stateDesigner = parentStateDesigner;
                }
                return stateDesigner;
            }
        }
 
        internal string SetStateName
        {
            get
            {
                return _setStateName;
            }
            set
            {
                _setStateName = value;
            }
        }
 
        internal string EventHandlerName
        {
            get
            {
                return _eventHandlerName;
            }
            set
            {
                _eventHandlerName = value;
            }
        }
 
        internal string SourceStateName
        {
            get
            {
                return _sourceStateName;
            }
            set
            {
                _sourceStateName = value;
            }
        }
 
        internal string TargetStateName
        {
            get
            {
                return _targetStateName;
            }
            set
            {
                _targetStateName = value;
            }
        }
 
        internal void ClearConnectorSegments()
        {
            this.SetConnectorSegments(new Collection<Point>());
        }
 
        protected override void OnLayout(ActivityDesignerLayoutEventArgs e)
        {
            if (!this.RootStateDesigner.HasActiveDesigner)
                base.OnLayout(e);
        }
 
        protected override ICollection<Rectangle> ExcludedRoutingRectangles
        {
            get
            {
                StateDesigner sourceStateDesigner = (StateDesigner)this.Source.AssociatedDesigner;
                List<Rectangle> excluded = new List<Rectangle>(base.ExcludedRoutingRectangles);
                if (sourceStateDesigner.IsRootDesigner)
                {
                    excluded.AddRange(sourceStateDesigner.EventHandlersBounds);
                }
                return excluded.AsReadOnly();
            }
        }
 
        public override bool HitTest(Point point)
        {
            if (this.RootStateDesigner != null && this.RootStateDesigner.ActiveDesigner != null)
                return false;
 
            return base.HitTest(point);
        }
 
        protected override void OnPaintEdited(ActivityDesignerPaintEventArgs e, Point[] segments, Point[] segmentEditPoints)
        {
            if (this.RootStateDesigner != null && this.RootStateDesigner.ActiveDesigner != null)
                return; // we don't draw connectors in the EventDriven view
 
            StateMachineTheme theme = e.DesignerTheme as StateMachineTheme;
            if (theme != null)
            {
                using (Pen lineEditPen = new Pen(WorkflowTheme.CurrentTheme.AmbientTheme.SelectionForeColor, 1))
                {
                    lineEditPen.DashStyle = DashStyle.Dash;
                    e.Graphics.DrawLines(lineEditPen, segments);
 
                    if (Source != null)
                        Source.OnPaint(e, false);
 
                    for (int i = 1; i < segments.Length - 1; i++)
                        PaintEditPoints(e, segments[i], false);
 
                    for (int i = 0; i < segmentEditPoints.Length; i++)
                        PaintEditPoints(e, segmentEditPoints[i], true);
 
                    if (Target != null)
                        Target.OnPaint(e, false);
                }
            }
        }
 
        protected override void OnPaintSelected(ActivityDesignerPaintEventArgs e, bool primarySelection, Point[] segmentEditPoints)
        {
            if (this.RootStateDesigner != null && this.RootStateDesigner.ActiveDesigner != null)
                return; // we don't draw connectors in the EventDriven view
 
            StateMachineTheme theme = e.DesignerTheme as StateMachineTheme;
            if (theme != null)
            {
                Size arrowCapSize = new Size(theme.ConnectorSize.Width / 5, theme.ConnectorSize.Height / 5);
                Size maxCapSize = theme.ConnectorSize;
 
                using (Pen lineSelectionPen = new Pen(WorkflowTheme.CurrentTheme.AmbientTheme.SelectionForeColor, 1))
                {
                    StateMachineDesignerPaint.DrawConnector(e.Graphics,
                        lineSelectionPen,
                        new List<Point>(ConnectorSegments).ToArray(),
                        arrowCapSize,
                        maxCapSize,
                        theme.ConnectorStartCap,
                        theme.ConnectorEndCap);
                }
 
                if (this.Source != null)
                    this.Source.OnPaint(e, false);
 
                ReadOnlyCollection<Point> endSegmentEditPoints = ConnectorSegments;
                for (int i = 1; i < endSegmentEditPoints.Count - 1; i++)
                    PaintEditPoints(e, endSegmentEditPoints[i], false);
 
                for (int i = 0; i < segmentEditPoints.Length; i++)
                    PaintEditPoints(e, segmentEditPoints[i], true);
 
                if (this.Target != null)
                    this.Target.OnPaint(e, false);
            }
        }
 
        protected override void OnPaint(ActivityDesignerPaintEventArgs e)
        {
            if (this.RootStateDesigner != null && this.RootStateDesigner.ActiveDesigner != null)
                return; // we don't draw connectors in the EventDriven view
 
            StateMachineTheme theme = e.DesignerTheme as StateMachineTheme;
            if (theme != null)
            {
                Size arrowCapSize = new Size(theme.ConnectorSize.Width / 5, theme.ConnectorSize.Height / 5);
                Size maxCapSize = theme.ConnectorSize;
 
                StateMachineDesignerPaint.DrawConnector(e.Graphics,
                    theme.ConnectorPen,
                    new List<Point>(ConnectorSegments).ToArray(),
                    arrowCapSize,
                    maxCapSize,
                    theme.ConnectorStartCap,
                    theme.ConnectorEndCap);
            }
        }
 
        private void PaintEditPoints(ActivityDesignerPaintEventArgs e, Point point, bool drawMidSegmentEditPoint)
        {
            Size size = (Source != null) ? Source.Bounds.Size : Size.Empty;
            if (!size.IsEmpty)
            {
                Rectangle bounds = new Rectangle(point.X - size.Width / 2, point.Y - size.Height / 2, size.Width, size.Height);
                if (drawMidSegmentEditPoint)
                {
                    using (GraphicsPath path = new GraphicsPath())
                    {
                        path.AddLine(new Point(bounds.Left + bounds.Width / 2, bounds.Top), new Point(bounds.Right, bounds.Top + bounds.Height / 2));
                        path.AddLine(new Point(bounds.Right, bounds.Top + bounds.Height / 2), new Point(bounds.Left + bounds.Width / 2, bounds.Bottom));
                        path.AddLine(new Point(bounds.Left + bounds.Width / 2, bounds.Bottom), new Point(bounds.Left, bounds.Top + bounds.Height / 2));
                        path.AddLine(new Point(bounds.Left, bounds.Top + bounds.Height / 2), new Point(bounds.Left + bounds.Width / 2, bounds.Top));
 
                        e.Graphics.FillPath(Brushes.White, path);
                        e.Graphics.DrawPath(e.AmbientTheme.SelectionForegroundPen, path);
                    }
                }
                else
                {
                    bounds.Inflate(-1, -1);
                    e.Graphics.FillEllipse(e.AmbientTheme.SelectionForegroundBrush, bounds);
                }
            }
        }
    }
 
    #region StateDesignerConnectorLayoutSerializer
    internal class StateDesignerConnectorLayoutSerializer : ConnectorLayoutSerializer
    {
        protected override PropertyInfo[] GetProperties(WorkflowMarkupSerializationManager serializationManager, object obj)
        {
            if (serializationManager == null)
                throw new ArgumentNullException("serializationManager");
            if (obj == null)
                throw new ArgumentNullException("obj");
 
            List<PropertyInfo> properties = new List<PropertyInfo>(base.GetProperties(serializationManager, obj));
            properties.Add(typeof(StateDesignerConnector).GetProperty("SetStateName", BindingFlags.Instance | BindingFlags.NonPublic));
            properties.Add(typeof(StateDesignerConnector).GetProperty("SourceStateName", BindingFlags.Instance | BindingFlags.NonPublic));
            properties.Add(typeof(StateDesignerConnector).GetProperty("TargetStateName", BindingFlags.Instance | BindingFlags.NonPublic));
            properties.Add(typeof(StateDesignerConnector).GetProperty("EventHandlerName", BindingFlags.Instance | BindingFlags.NonPublic));
            return properties.ToArray();
        }
 
        protected override object CreateInstance(WorkflowMarkupSerializationManager serializationManager, Type type)
        {
            if (serializationManager == null)
                throw new ArgumentNullException("serializationManager");
            if (type == null)
                throw new ArgumentNullException("type");
 
            StateDesignerConnector connector = null;
 
            IReferenceService referenceService = serializationManager.GetService(typeof(IReferenceService)) as IReferenceService;
            FreeformActivityDesigner freeformDesigner = serializationManager.Context[typeof(FreeformActivityDesigner)] as FreeformActivityDesigner;
            if (freeformDesigner != null && referenceService != null)
            {
                StateDesigner.DesignerLayoutConnectionPoint sourceConnection = null;
                ConnectionPoint targetConnection = null;
                StateDesigner.TransitionInfo transitionInfo = null;
                StateDesigner rootStateDesigner = null;
 
                try
                {
                    Dictionary<string, string> constructionArguments = GetConnectorConstructionArguments(serializationManager, type);
 
                    if (constructionArguments.ContainsKey("EventHandlerName") &&
                        constructionArguments.ContainsKey("SetStateName") &&
                        constructionArguments.ContainsKey("TargetStateName"))
                    {
                        CompositeActivity eventHandler = (CompositeActivity)referenceService.GetReference(constructionArguments["EventHandlerName"] as string);
                        SetStateActivity setState = (SetStateActivity)referenceService.GetReference(constructionArguments["SetStateName"] as string);
                        StateActivity targetState = (StateActivity)referenceService.GetReference(constructionArguments["TargetStateName"] as string);
                        transitionInfo = new StateDesigner.TransitionInfo(setState, eventHandler);
                        transitionInfo.TargetState = targetState;
                    }
 
                    if (constructionArguments.ContainsKey("SourceActivity") &&
                        constructionArguments.ContainsKey("SourceConnectionIndex") &&
                        constructionArguments.ContainsKey("SourceConnectionEdge") &&
                        constructionArguments.ContainsKey("EventHandlerName"))
                    {
                        StateDesigner sourceDesigner = (StateDesigner)StateDesigner.GetDesigner(referenceService.GetReference(constructionArguments["SourceActivity"] as string) as Activity);
                        CompositeActivity eventHandler = (CompositeActivity)referenceService.GetReference(constructionArguments["EventHandlerName"] as string);
                        rootStateDesigner = sourceDesigner.RootStateDesigner;
                        DesignerEdges sourceEdge = (DesignerEdges)Enum.Parse(typeof(DesignerEdges), constructionArguments["SourceConnectionEdge"] as string);
                        int sourceIndex = Convert.ToInt32(constructionArguments["SourceConnectionIndex"] as string, System.Globalization.CultureInfo.InvariantCulture);
                        if (sourceDesigner != null && eventHandler != null && sourceEdge != DesignerEdges.None && sourceIndex >= 0)
                            sourceConnection = new StateDesigner.DesignerLayoutConnectionPoint(sourceDesigner, sourceIndex, eventHandler, sourceEdge);
                    }
 
                    if (constructionArguments.ContainsKey("TargetActivity") &&
                        constructionArguments.ContainsKey("TargetConnectionIndex") &&
                        constructionArguments.ContainsKey("TargetConnectionEdge"))
                    {
                        ActivityDesigner targetDesigner = StateDesigner.GetDesigner(referenceService.GetReference(constructionArguments["TargetActivity"] as string) as Activity);
                        DesignerEdges targetEdge = (DesignerEdges)Enum.Parse(typeof(DesignerEdges), constructionArguments["TargetConnectionEdge"] as string);
                        int targetIndex = Convert.ToInt32(constructionArguments["TargetConnectionIndex"] as string, System.Globalization.CultureInfo.InvariantCulture);
                        if (targetDesigner != null && targetEdge != DesignerEdges.None && targetIndex >= 0)
                            targetConnection = new ConnectionPoint(targetDesigner, targetEdge, targetIndex);
                    }
                }
                catch
                {
                }
 
                if (transitionInfo != null && sourceConnection != null && targetConnection != null)
                {
                    connector = rootStateDesigner.FindConnector(transitionInfo);
                    if (connector == null)
                    {
                        rootStateDesigner.AddingSetState = false;
                        try
                        {
                            connector = freeformDesigner.AddConnector(sourceConnection, targetConnection) as StateDesignerConnector;
                        }
                        finally
                        {
                            rootStateDesigner.AddingSetState = true;
                        }
                    }
                    else
                    {
                        connector.Source = sourceConnection;
                        connector.Target = targetConnection;
                        connector.ClearConnectorSegments();
                    }
                }
            }
 
            return connector;
        }
    }
    #endregion
}