Point CalculateDropLocationForAutoConnect(AutoConnectDirections autoConnectDirection, Size droppedSize)
 {
     return AutoConnectHelper.CalculateDropLocation(droppedSize, this.panel.CurrentAutoConnectTarget, autoConnectDirection, this.shapeLocations);
 }
 void PerformInternalMove(UIElement movedElement, Point newPoint, Point? shapeAnchorPoint,
     AutoConnectDirections autoConnectDirection, Connector connectorToSplit)
 {
     using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.FCLinkMove))
     {
         RemoveAdorner(movedElement, typeof(ConnectionPointsAdorner));
         Point shapeLocation;
         Size size = FreeFormPanel.GetChildSize(movedElement);
         if (autoConnectDirection != AutoConnectDirections.None)
         {
             shapeLocation = this.CalculateDropLocationForAutoConnect(autoConnectDirection, size);
         }
         else if (shapeAnchorPoint.HasValue)
         {
             shapeLocation = SnapVisualToGrid(movedElement, newPoint, shapeAnchorPoint.Value, true);
         }
         else
         {
             Fx.Assert(newPoint.X.IsNoLessThan(0) && newPoint.Y.IsNoLessThan(0),
                 "newPoint is negative");
             shapeLocation = newPoint;
         }
         if (connectorToSplit != null)
         {
             shapeLocation = this.CalculateDropLocationForAutoSplit(newPoint, shapeLocation, connectorToSplit, size);
         }
         StoreShapeViewState(movedElement, shapeLocation);
         RerouteAttachedConnectors(movedElement);
         es.Complete();
     }
 }
        // Returns the last dropped item - used for auto-connect and auto-split where only one item is allowed
        ModelItem DoFlowchartGridDrop(DragEventArgs e, AutoConnectDirections autoConnectDirection, Connector connectorToSplit)
        {
            ModelItem droppedModelItem = null;
            ModelItem newFlowStepMI = null;
            e.Effects = DragDropEffects.None;
            IEnumerable<object> droppedObjects = DragDropHelper.GetDroppedObjects(this, e, Context);
            //Marking the event as being handled. In whichever case we want to route the event, it will be unmarked explicitly.
            e.Handled = true;
            List<WorkflowViewElement> movedViewElements = new List<WorkflowViewElement>();
            ShapeOffsetter shapeOffsetter = new ShapeOffsetter();
            Dictionary<WorkflowViewElement, Point> relativeLocations = DragDropHelper.GetDraggedViewElementRelativeLocations(e);
            ModelItem modelItemDroppedFromToolBox = null;
            Dictionary<object, FlowNode> objToNewFlowNodeMap = null;
            Dictionary<FlowNode, ModelItem> flowNodeModelItemMap = null;
            Dictionary<FlowNode, FlowNode> oldNewFlowNodeMap = null;
            this.PrepareForDrop(droppedObjects,
                out objToNewFlowNodeMap,
                out flowNodeModelItemMap,
                out oldNewFlowNodeMap);
            bool shouldStoreCurrentSizeViewState = true;
            foreach (object droppedObject in droppedObjects)
            {
                if (droppedObject == null)
                {
                    continue;
                }
                droppedModelItem = droppedObject as ModelItem;

                // archor point
                Point anchorPoint = DragDropHelper.GetDragDropAnchorPoint(e);


                ICompositeView srcContainer = droppedModelItem != null
                    ? DragDropHelper.GetCompositeView(droppedModelItem.View as WorkflowViewElement) as ICompositeView
                    : null;
                bool keepRelativePosition = srcContainer is FlowchartDesigner;
                // This is the case of dragging from toolbox
                if (anchorPoint.X < 0 && anchorPoint.Y < 0)
                {
                    keepRelativePosition = false;
                }

                // This is the case of dragging from the designer surface
                else if (droppedModelItem != null)
                {
                    WorkflowViewElement view = (WorkflowViewElement)droppedModelItem.View;
                    anchorPoint.Offset(-relativeLocations[view].X, -relativeLocations[view].Y);
                }


                if (droppedModelItem != null && srcContainer != null && srcContainer.Equals(this))
                {
                    if (shouldStoreCurrentSizeViewState)
                    {
                        // Moving may change the size of flowchart; need this to undo the size change.
                        this.StoreCurrentSizeViewStateWithUndo();
                        shouldStoreCurrentSizeViewState = false;
                    }
                    //InternalMove
                    PerformInternalMove(modelElement[droppedModelItem], e.GetPosition(this.panel), anchorPoint, autoConnectDirection, connectorToSplit);
                }
                else
                {
                    //External model Item drop.
                    if (droppedModelItem != null)
                    {
                        if ((IsFlowStepAction(droppedModelItem)
                            || IsFlowNode(droppedModelItem))
                            && !IsParentOf(droppedModelItem, this.ModelItem))
                        {
                            if (shouldStoreCurrentSizeViewState)
                            {
                                // Drop may change the size of flowchart; need this to undo the size change.
                                this.StoreCurrentSizeViewStateWithUndo();
                                shouldStoreCurrentSizeViewState = false;
                            }

                            FlowNode flowElement = objToNewFlowNodeMap[droppedObject];
                            ModelItem flowElementMI;
                            if (flowNodeModelItemMap.TryGetValue(flowElement, out flowElementMI))
                            {
                                // FlowNode comes from some other flowchart. 
                                this.ModelItem.Properties["Nodes"].Collection.Add(flowElementMI);
                            }
                            else
                            {
                                // FlowNode is a new created one, which means this is an Activity dragged
                                // from somewhere else, outside of Flowchart.
                                flowElementMI = this.ModelItem.Properties["Nodes"].Collection.Add(flowElement);
                                flowNodeModelItemMap[flowElement] = flowElementMI;
                            }
                            newFlowStepMI = flowElementMI;
                        }
                        else
                        {
                            //We want to route the event in the case that the flowchart is dropped upon itself.
                            if (droppedModelItem.Equals(this.ModelItem))
                            {
                                e.Handled = false;
                            }
                            //Don't add anything for what is neither a Activity nor a flowlink.
                            continue;
                        }

                        if (droppedModelItem != null && droppedModelItem.View != null)
                        {
                            movedViewElements.Add((WorkflowViewElement)droppedModelItem.View);
                        }

                        // the external item may come from other panel (sequence) which is already given
                        // a size by its previous layout panel.  That might give an inaccurate size to the
                        // dropped object (i.e. Bug 198290).  Therefore, when the object is dropped externally
                        // the FC should erases its previous hint size, forcing the FC to recompute an appropriate
                        // size based on the workflowelementview size.
                        VirtualizedContainerService.SetHintSize(droppedModelItem.GetCurrentValue(), null);
                    }
                    //Tool box drop.
                    else
                    {
                        if (typeof(Activity).IsAssignableFrom(droppedObject.GetType()))
                        {
                            FlowStep flowStep = new FlowStep();
                            flowStep.Action = (Activity)droppedObject;
                            if (shouldStoreCurrentSizeViewState)
                            {
                                // Drop may change the size of flowchart; need this to undo the size change.
                                this.StoreCurrentSizeViewStateWithUndo();
                                shouldStoreCurrentSizeViewState = false;
                            }

                            newFlowStepMI = this.ModelItem.Properties["Nodes"].Collection.Add(flowStep);
                            droppedModelItem = newFlowStepMI.Properties["Action"].Value;
                        }
                        else if (typeof(FlowNode).IsAssignableFrom(droppedObject.GetType()))
                        {
                            if (shouldStoreCurrentSizeViewState)
                            {
                                // Drop may change the size of flowchart; need this to undo the size change.
                                this.StoreCurrentSizeViewStateWithUndo();
                                shouldStoreCurrentSizeViewState = false;
                            }
                            droppedModelItem = this.ModelItem.Properties["Nodes"].Collection.Add(droppedObject);
                            newFlowStepMI = droppedModelItem;
                        }

                        // Now,  toolbox drop doesn't support multiple drop
                        // If multi-drop from tool box, use an array here.
                        modelItemDroppedFromToolBox = droppedModelItem;
                        keepRelativePosition = false;
                    } // tool box 

                    WorkflowViewElement view = droppedModelItem.View as WorkflowViewElement;
                    if (view == null || view.ExpandState)
                    {
                        //Creating a new view to get the size of collapsed view.
                        view = this.ViewService.GetView(droppedModelItem) as WorkflowViewElement;
                        ViewUtilities.MeasureView(view, true);
                    }

                    if (view != null)
                    {
                        PostDropUpdateViewState(view,
                            newFlowStepMI,
                            autoConnectDirection,
                            connectorToSplit,
                            e.GetPosition(this.panel),
                            anchorPoint,
                            keepRelativePosition,
                            shapeOffsetter);
                    }
                } // external move
            } // foreach

            // Remap references.
            // The re-map here is different from the remaping in copy/paste.
            // In copy paste, all the values are copied. but here, some value are
            // set by Properties["key"].SetValue().
            // Don't move this into PrepareMove. Some value setting is added to 
            // Change. So the operation here will decide the order of Change.Apply().
            // PropertyChange in some case, must happen after ModelItem is moved to 
            // new places.
            foreach (FlowNode flowNode in oldNewFlowNodeMap.Keys)
            {
                UpdateCloneReferenceByModelItem(flowNode, flowNodeModelItemMap, oldNewFlowNodeMap);
            }

            DragDropHelper.SetDragDropMovedViewElements(e, movedViewElements);
            
            //Backward compatibility for 4.0
            if (droppedObjects.Count() == 1 && movedViewElements.Count == 1)
            {
                #pragma warning disable 618
                DragDropHelper.SetDragDropCompletedEffects(e, DragDropEffects.Move);
                #pragma warning restore 618
            }

            if (modelItemDroppedFromToolBox != null)
            {
                // if it is dropped from toolbox, select
                this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (Action)(() =>
                {
                    UIElement view = (UIElement)(modelItemDroppedFromToolBox.View);
                    if (view != null)
                    {
                        Keyboard.Focus(view);
                        Selection.SelectOnly(this.Context, modelItemDroppedFromToolBox);
                    }
                }));
            }

            if (droppedModelItem != null)
            {
                if (IsFlowNode(droppedModelItem))
                {
                    return droppedModelItem;
                }
                else if (IsFlowStepAction(droppedModelItem))
                {
                    if (newFlowStepMI != null)
                    {
                        return newFlowStepMI;
                    }
                    else
                    {
                        return this.GetParentFlowStepModelItem(droppedModelItem);
                    }
                }
                return null;
            }

            return null;
        }
 private AutoConnectDirections GetAutoConnectDirections(AutoConnectDirections directions, List<DependencyObject> childShapes, DependencyObject target)
 {
     directions = AutoConnectDirections.Top | AutoConnectDirections.Bottom | AutoConnectDirections.Left | AutoConnectDirections.Right;
     List<Rect> hitTestRects = CreateHitTestRects(FreeFormPanel.GetLocation(target), FreeFormPanel.GetChildSize(target));
     this.RemoveDirectionsOutsideOfPanel(hitTestRects, ref directions);
     RemoveDirectionsInCollision(childShapes, target, hitTestRects, ref directions);
     return directions;
 }
 private void AddDropTargets(DragEventArgs e, UIElement adornedElement, AutoConnectDirections directions)
 {
     AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(adornedElement);
     Fx.Assert(adornerLayer != null, "AdornerLayer should not be null.");
     adornerLayer.Add(new AutoConnectAdorner(adornedElement, this.panel, (directions & this.panel.AutoConnectContainer.GetDirectionsAllowed(e, adornedElement))));
     this.CurrentTarget = adornedElement;
 }
 protected override void OnDragLeave(DragEventArgs e)
 {
     base.OnDragLeave(e);
     this.highlightedDirection = AutoConnectDirections.None;
     this.InvalidateVisual();
 }
 // Check if hit test rects are completely within the FreeFormPanel rect, and remove that direction in case it's not.
 private void RemoveDirectionsOutsideOfPanel(List<Rect> hitTestRects, ref AutoConnectDirections directions)
 {
     Rect panelRect = new Rect(0, 0, this.panel.Width, this.panel.Height);
     for (int i = 0; i < hitTestRects.Count; i++)
     {
         if (!panelRect.Contains(hitTestRects[i]))
         {
             directions &= ~AutoConnectHelper.GetAutoConnectDirection(i);
         }
     }
 }
        internal static EdgeLocation AutoConnectDirection2EdgeLocation(AutoConnectDirections direction)
        {
            EdgeLocation edgeLocation = EdgeLocation.Right;
            switch (direction)
            {
                case AutoConnectDirections.Left:
                    edgeLocation = EdgeLocation.Left;
                    break;
                case AutoConnectDirections.Right:
                    edgeLocation = EdgeLocation.Right;
                    break;
                case AutoConnectDirections.Top:
                    edgeLocation = EdgeLocation.Top;
                    break;
                case AutoConnectDirections.Bottom:
                    edgeLocation = EdgeLocation.Bottom;
                    break;
            }

            return edgeLocation;
        }
        internal DependencyObject FindTarget(Point point, DependencyObject dragged, out AutoConnectDirections directions)
        {
            directions = AutoConnectDirections.None;
            List<DependencyObject> childShapes = this.panel.GetChildShapes(dragged);
            DependencyObject target = GetShapeContainingPoint(point, childShapes);

            if (target != null)
            {
                directions = this.GetAutoConnectDirections(directions, childShapes, target);
            }

            return target;
        }
        public void DoAutoConnect(DragEventArgs e, UIElement targetElement, AutoConnectDirections direction)
        {
            UIElement sourceElement = targetElement;
            bool immediatelyCommit = ModelItemHelper.CanCreateImmediateEditingScope(this.ModelItem);

            using (EditingScope scope = (EditingScope)this.ModelItem.BeginEdit(SR.AutoConnect, immediatelyCommit))
            {
                ModelItem connectorModelItem = null;
                Point location = e.GetPosition(sourceElement);
                ModelItem droppedModelItem = this.DoStateContainerGridDrop(e, direction, null);
                if (droppedModelItem != null)
                {
                    connectorModelItem = this.DoAutoConnect(sourceElement, droppedModelItem, null);
                }

                if (connectorModelItem != null)
                {
                    EdgeLocation edgeLocation = AutoConnectHelper.AutoConnectDirection2EdgeLocation(direction);
                    this.GetStateMachineContainerEditor().activeSrcConnectionPoint = this.GetSourceConnectionPointForAutoConnect(sourceElement, edgeLocation);
                    ModelItem sourceModelItem = TryGetModelItemFromView(sourceElement);
                    Fx.Assert(sourceModelItem != null, "sourceModelItem");

                    // add a custom change inside a new editing scope since current editing scope an immediate editing scope
                    using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.AutoConnect, false))
                    {
                        es.Changes.Add(new StoreAutoConnectorViewStateChange(
                            this.ModelItem, sourceModelItem, droppedModelItem, connectorModelItem, edgeLocation));
                        es.Complete();
                    }
                    scope.Complete();
                }
                else
                {
                    scope.Revert();
                }
            }
        }
        internal static Point CalculateDropLocation(Size droppedSize, DependencyObject autoConnectTarget, AutoConnectDirections direction, HashSet<Point> shapeLocations)
        {
            Point dropPoint = new Point(-1, -1);
            if (autoConnectTarget != null)
            {
                Point location = FreeFormPanel.GetLocation(autoConnectTarget);
                Size size = FreeFormPanel.GetChildSize(autoConnectTarget);
                switch (direction)
                {
                    case AutoConnectDirections.Left:
                        dropPoint = new Point(location.X - DropPointOffset - droppedSize.Width, location.Y + ((size.Height - droppedSize.Height) / 2));
                        break;
                    case AutoConnectDirections.Right:
                        dropPoint = new Point(location.X + size.Width + DropPointOffset, location.Y + ((size.Height - droppedSize.Height) / 2));
                        break;
                    case AutoConnectDirections.Top:
                        dropPoint = new Point(location.X + ((size.Width - droppedSize.Width) / 2), location.Y - DropPointOffset - droppedSize.Height);
                        break;
                    case AutoConnectDirections.Bottom:
                        dropPoint = new Point(location.X + ((size.Width - droppedSize.Width) / 2), location.Y + DropPointOffset + size.Height);
                        break;
                    default:
                        Fx.Assert(false, "Should not be here");
                        break;
                }

                dropPoint = new Point(dropPoint.X < 0 ? 0 : dropPoint.X, dropPoint.Y < 0 ? 0 : dropPoint.Y);
                if (shapeLocations != null)
                {
                    while (shapeLocations.Contains(dropPoint))
                    {
                        dropPoint.Offset(FreeFormPanel.GridSize, FreeFormPanel.GridSize);
                    }
                }
            }

            return dropPoint;
        }
        void PerformInternalMove(UIElement movedElement, Point newPoint, Point? shapeAnchorPoint, AutoConnectDirections autoConnectDirection, Connector connectorToSplit)
        {
            using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.ItemMove))
            {
                StoreShapeSizeWithUndoRecursively(this.ModelItem);
                this.RemoveConnectionPointsAdorner(movedElement);
                Point newLocation;
                Size size = FreeFormPanel.GetChildSize(movedElement);
                if (autoConnectDirection != AutoConnectDirections.None)
                {
                    newLocation = this.CalculateDropLocationForAutoConnect(autoConnectDirection, size);
                }
                else if (shapeAnchorPoint.HasValue)
                {
                    newLocation = SnapVisualToGrid(movedElement, newPoint, shapeAnchorPoint.Value, true);
                }
                else
                {
                    Fx.Assert(newPoint.X.IsNoLessThan(0) && newPoint.Y.IsNoLessThan(0),
                        "newPoint is negative");
                    newLocation = newPoint;
                }
                if (connectorToSplit != null)
                {
                    newLocation = this.CalculateDropLocationForAutoSplit(newPoint, newLocation, connectorToSplit, size);
                }
                ModelItem modelItem = GetModelItemFromView(movedElement);
                object viewState = this.ViewStateService.RetrieveViewState(modelItem, ShapeLocationViewStateKey);
                if (viewState != null)
                {
                    Point oldLocation = (Point)viewState;
                    // To make sure the connectors are still connected to the connection points.
                    // We don't need to offset non-contained connectors because internal move
                    // won't cause the connectors to be recreated and we have code in FreeFormPanel
                    // to guarantee that connectors will still be connected to the connection points
                    this.OffsetConnectorViewState(movedElement, oldLocation, newLocation, false);
                }
                else
                {
                    this.StoreAttachedConnectorViewStates(movedElement);
                }

                this.StoreShapeLocationViewState(movedElement, newLocation);
                // To make sure the connector changes are undoable
                this.panel.RemoveConnectorEditor();

                es.Complete();
            }
        }
        // Returns the last dropped item - used for auto-connect and auto-split where only one item is allowed
        ModelItem DoStateContainerGridDrop(DragEventArgs e, AutoConnectDirections autoConnectDirection, Connector connectorToSplit)
        {
            ModelItem droppedModelItem = null;
            e.Effects = DragDropEffects.None;
            IEnumerable<object> droppedObjects = DragDropHelper.GetDroppedObjects(this, e, Context);
            // Marking the event as being handled. In whichever case we want to route the event, it will be unmarked explicitly.
            e.Handled = true;
            List<ModelItem> modelItemsToSelect = new List<ModelItem>();

            Dictionary<WorkflowViewElement, Point> relativeLocations = DragDropHelper.GetDraggedViewElementRelativeLocations(e);
            foreach (object droppedObject in droppedObjects)
            {
                if (droppedObject != null)
                {
                    droppedModelItem = droppedObject as ModelItem;
                    bool isAnchorPointValid = true;
                    Point anchorPoint = DragDropHelper.GetDragDropAnchorPoint(e);

                    // This is the case of dragging from toolbox
                    if (anchorPoint.X < 0 && anchorPoint.Y < 0)
                    {
                        isAnchorPointValid = false;
                    }
                    // This is the case of dragging from the designer surface
                    else if (droppedModelItem != null)
                    {
                        WorkflowViewElement view = droppedModelItem.View as WorkflowViewElement;
                        anchorPoint.Offset(-relativeLocations[view].X, -relativeLocations[view].Y);
                    }

                    StateContainerEditor srcContainer = droppedModelItem != null
                        ? DragDropHelper.GetCompositeView(droppedModelItem.View as WorkflowViewElement) as StateContainerEditor
                        : null;
                    bool externalDrop = false;
                    if (droppedModelItem != null && srcContainer != null && srcContainer.Equals(this))
                    {
                        // Internal move
                        PerformInternalMove(this.modelItemToUIElement[droppedModelItem], e.GetPosition(this.panel), anchorPoint, autoConnectDirection, connectorToSplit);
                    }
                    else
                    {
                        // External model Item drop
                        if (droppedModelItem != null)
                        {
                            if (droppedModelItem.ItemType == typeof(State) && this.ModelItem.ItemType == typeof(StateMachine))
                            {
                                this.InsertState(droppedModelItem);
                                externalDrop = true;
                            }
                        }
                        // Toolbox drop.
                        else
                        {
                            if (droppedObject.GetType() == typeof(State))
                            {
                                if (((State)droppedObject).DisplayName == null)
                                {
                                    ((State)droppedObject).DisplayName = GenerateStateName();
                                }

                                droppedModelItem = InsertState(droppedObject);
                            }
                            else if (droppedObject.GetType() == typeof(FinalState))
                            {
                                droppedModelItem = InsertState(new State()
                                {
                                    DisplayName = DefaultFinalStateDisplayName,
                                    IsFinal = true
                                });
                            }
                        }
                        if (droppedModelItem != null)
                        {
                            modelItemsToSelect.Add(droppedModelItem);
                            UIElement view = null;
                            if (this.modelItemToUIElement.ContainsKey(droppedModelItem))
                            {
                                view = this.modelItemToUIElement[droppedModelItem];
                            }
                            else
                            {
                                view = droppedModelItem.View as WorkflowViewElement;
                                if (view == null)
                                {
                                    view = this.Context.Services.GetService<ViewService>().GetView(droppedModelItem) as WorkflowViewElement;
                                    ViewUtilities.MeasureView(view as WorkflowViewElement, true);
                                }
                            }
                            // If drag anchor point is beyond the size of the shape being dropped,
                            if (anchorPoint.X > view.DesiredSize.Width || anchorPoint.Y > view.DesiredSize.Height)
                            {
                                isAnchorPointValid = false;
                            }
                            Point shapeLocation;
                            if (autoConnectDirection != AutoConnectDirections.None)
                            {
                                shapeLocation = this.CalculateDropLocationForAutoConnect(autoConnectDirection, new Size(DefaultStateDesignerWidth, DefaultStateDesignerHeight));
                            }
                            else
                            {
                                shapeLocation = StateContainerEditor.SnapVisualToGrid(view, e.GetPosition(this.panel), anchorPoint, isAnchorPointValid);
                            }
                            if (connectorToSplit != null)
                            {
                                shapeLocation = this.CalculateDropLocationForAutoSplit(e.GetPosition(this.panel), shapeLocation, connectorToSplit, new Size(DefaultStateDesignerWidth, DefaultStateDesignerHeight));
                            }
                            object viewState = this.ViewStateService.RetrieveViewState(droppedModelItem, ShapeLocationViewStateKey);
                            if (externalDrop)
                            {
                                Fx.Assert(viewState != null, "item dropped from external should already have view states");
                                Fx.Assert(droppedModelItem.View != null, "item dropped from extenal should already have view");
                                VirtualizedContainerService.VirtualizingContainer container = VisualTreeUtils.FindVisualAncestor<VirtualizedContainerService.VirtualizingContainer>(droppedModelItem.View);
                                Fx.Assert(container != null, "container should not be null");
                                Point oldLocation = (Point)viewState;
                                oldLocation = srcContainer.panel.GetLocationRelativeToOutmostPanel(oldLocation);
                                Point newLocation = this.panel.GetLocationRelativeToOutmostPanel(shapeLocation);
                                // To make sure the connectors are still connected to the connection points
                                OffsetConnectorViewState(container, oldLocation, newLocation, true);
                            }
                            this.StoreShapeLocationViewState(droppedModelItem, shapeLocation);
                        }
                    }
                }
            }

            DragDropHelper.SetDragDropMovedViewElements(e, new WorkflowViewElement[] { });
            this.Dispatcher.BeginInvoke(() =>
                {
                    bool first = true;
                    foreach (ModelItem modelItem in modelItemsToSelect)
                    {
                        if (first)
                        {
                            Keyboard.Focus((IInputElement)modelItem.View);
                            Selection.SelectOnly(this.Context, modelItem);
                            first = false;
                        }
                        else
                        {
                            Selection.Union(this.Context, modelItem);
                        }
                    }
                },
                DispatcherPriority.ApplicationIdle);

            return droppedModelItem;
        }
        public AutoConnectAdorner(UIElement adornedElement, FreeFormPanel panel, AutoConnectDirections directions) 
            : base(adornedElement)
        {
            this.panel = panel;
            this.directions = directions;

            Size size = FreeFormPanel.GetChildSize(this.AdornedElement);
            this.adornedElementRect = new Rect(new Point(0, 0), size);
            this.hitTestRects = new Rect[] 
            { 
                new Rect(-HitTestHeight, (size.Height / 2) - (HitTestWidth / 2), HitTestHeight, HitTestWidth),
                new Rect(size.Width, (size.Height / 2) - (HitTestWidth / 2), HitTestHeight, HitTestWidth),
                new Rect((size.Width / 2) - (HitTestWidth / 2), -HitTestHeight, HitTestWidth, HitTestHeight),
                new Rect((size.Width / 2) - (HitTestWidth / 2), size.Height, HitTestWidth, HitTestHeight)
            };

            this.renderGeometries = new PathGeometry[]
            {
                new PathGeometry() 
                { 
                    Figures =
                    {
                        new PathFigure()
                        {
                            StartPoint = new Point(-DropTargetOffset - TriangleHeight, size.Height / 2), Segments = 
                            { 
                                new LineSegment() { Point = new Point(-DropTargetOffset, (size.Height / 2) - (TriangleBaseLength / 2)) },
                                new LineSegment() { Point = new Point(-DropTargetOffset, (size.Height / 2) + (TriangleBaseLength / 2)) },
                                new LineSegment() { Point = new Point(-DropTargetOffset - TriangleHeight, size.Height / 2) }
                            }
                        }
                    } 
                },
                new PathGeometry() 
                { 
                    Figures =
                    {
                        new PathFigure()
                        {
                            StartPoint = new Point(size.Width + DropTargetOffset, (size.Height / 2) - (TriangleBaseLength / 2)), Segments = 
                            { 
                                new LineSegment() { Point = new Point(size.Width + DropTargetOffset + TriangleHeight, size.Height / 2) },
                                new LineSegment() { Point = new Point(size.Width + DropTargetOffset, (size.Height / 2) + (TriangleBaseLength / 2)) },
                                new LineSegment() { Point = new Point(size.Width + DropTargetOffset, (size.Height / 2) - (TriangleBaseLength / 2)) }
                            }
                        }
                    }
                },
                new PathGeometry() 
                { 
                    Figures =
                    {
                        new PathFigure()
                        {
                            StartPoint = new Point((size.Width / 2) - (TriangleBaseLength / 2), -DropTargetOffset), Segments = 
                            { 
                                new LineSegment() { Point = new Point((size.Width / 2), -DropTargetOffset - TriangleHeight) },
                                new LineSegment() { Point = new Point((size.Width / 2) + (TriangleBaseLength / 2), -DropTargetOffset) },
                                new LineSegment() { Point = new Point((size.Width / 2) - (TriangleBaseLength / 2), -DropTargetOffset) }
                            }
                        }
                    }
                },
                new PathGeometry() 
                { 
                    Figures = 
                    {
                        new PathFigure()
                        {
                            StartPoint = new Point((size.Width / 2) - (TriangleBaseLength / 2), size.Height + DropTargetOffset), Segments = 
                            { 
                                new LineSegment() { Point = new Point((size.Width / 2) + (TriangleBaseLength / 2), size.Height + DropTargetOffset) },
                                new LineSegment() { Point = new Point((size.Width / 2), size.Height + TriangleHeight + DropTargetOffset) },
                                new LineSegment() { Point = new Point((size.Width / 2) - (TriangleBaseLength / 2), size.Height + DropTargetOffset) }
                            }
                        }
                    }
                }
            };
        }
        // Move the object to correct position after drop
        private void PostDropUpdateViewState(WorkflowViewElement view,
            ModelItem flownodeMI,
            AutoConnectDirections autoConnectDirection,
            Connector connectorToSplit,
            Point newPoint,
            Point anchorPoint,
            bool keepRelativePosition,
            ShapeOffsetter shapeOffsetter)
        {
            Fx.Assert((view != null && flownodeMI != null),
            "movedItem != null && flownodeMI != null");
            Point shapeLocationPtr;
            if (autoConnectDirection != AutoConnectDirections.None)
            {
                shapeLocationPtr = this.CalculateDropLocationForAutoConnect(autoConnectDirection, view.DesiredSize);
            }
            else
            {
                shapeLocationPtr = SnapVisualToGrid(view, newPoint, anchorPoint, keepRelativePosition);
                if (!keepRelativePosition)
                {
                    // To avoid overlaps
                    shapeLocationPtr = shapeOffsetter.OffsetShapeLocation(shapeLocationPtr);
                }
            }

            if (connectorToSplit != null)
            {
                shapeLocationPtr = this.CalculateDropLocationForAutoSplit(newPoint, shapeLocationPtr, connectorToSplit, view.DesiredSize);
            }

            // 
            if (keepRelativePosition)
            {
                this.OffsetDroppedItemToNewPosition(flownodeMI, shapeLocationPtr);
            }
            else
            {
                this.StoreShapeViewState(flownodeMI, shapeLocationPtr);
            }
        }
        // Check if hit test rects collide with any children of the FreeFormPanel, and remove that direction in case a collision is found.
        private static void RemoveDirectionsInCollision(List<DependencyObject> childShapes, DependencyObject target, List<Rect> hitTestRects, ref AutoConnectDirections directions)
        {
            foreach (DependencyObject shape in childShapes)
            {
                if (directions == AutoConnectDirections.None)
                {
                    break;
                }

                if (object.Equals(shape, target))
                {
                    continue;
                }

                Point shapeLocation = FreeFormPanel.GetLocation(shape);
                Size shapeSize = FreeFormPanel.GetChildSize(shape);
                Rect shapeRect = new Rect(shapeLocation, shapeSize);
                for (int i = 0; i < hitTestRects.Count; i++)
                {
                    if (hitTestRects[i].IntersectsWith(shapeRect))
                    {
                        directions &= ~AutoConnectHelper.GetAutoConnectDirection(i);
                    }
                }
            }
        }
        public void DoAutoConnect(DragEventArgs e, UIElement targetElement, AutoConnectDirections direction)
        {
            UIElement sourceElement = targetElement;
            bool immediatelyCommit = ModelItemHelper.CanCreateImmediateEditingScope(this.ModelItem);

            using (EditingScope scope = (EditingScope)this.ModelItem.BeginEdit(SR.AutoConnect, immediatelyCommit))
            {
                ModelItem droppedModelItem = this.DoFlowchartGridDrop(e, direction, null);
                bool autoConnected = false;
                if (droppedModelItem != null)
                {
                    ModelItem sourceModelItem = this.GetSourceModelItemForAutoConnect(sourceElement);
                    if (sourceModelItem != null)
                    {
                        if (sourceModelItem.ItemType == typeof(FlowStep))
                        {
                            sourceModelItem.Properties["Next"].SetValue(droppedModelItem);
                            autoConnected = true;
                        }
                        else if (sourceModelItem.ItemType == typeof(FlowDecision))
                        {
                            if (direction == AutoConnectDirections.Left)
                            {
                                sourceModelItem.Properties["True"].SetValue(droppedModelItem);
                                autoConnected = true;
                            }
                            else if (direction == AutoConnectDirections.Right)
                            {
                                sourceModelItem.Properties["False"].SetValue(droppedModelItem);
                                autoConnected = true;
                            }
                        }
                        else if (GenericFlowSwitchHelper.IsGenericFlowSwitch(sourceModelItem.ItemType))
                        {
                            string message = string.Empty;
                            autoConnected = this.CreateFlowSwitchLink(this.srcConnectionPointForAutoConnect, sourceModelItem, droppedModelItem, null, null, ref message);
                        }
                        else if (sourceModelItem.ItemType == typeof(StartNode))
                        {
                            this.ModelItem.Properties["StartNode"].SetValue(droppedModelItem);
                            autoConnected = true;
                        }
                    }
                }
                if (autoConnected)
                {
                    this.srcConnectionPointForAutoConnect = this.GetSourceConnectionPointForAutoConnect(sourceElement, AutoConnectHelper.AutoConnectDirection2EdgeLocation(direction));
                    scope.Complete();
                }
                else
                {
                    scope.Revert();
                }
            }
        }
 internal void UpdateHighlightedDirection(Point position)
 {
     Size size = FreeFormPanel.GetChildSize(this.AdornedElement);
     if (position.X < 0 && this.highlightedDirection != AutoConnectDirections.Left)
     {
         this.highlightedDirection = AutoConnectDirections.Left;
         this.InvalidateVisual();
     }
     else if (position.X > size.Width && this.highlightedDirection != AutoConnectDirections.Right)
     {
         this.highlightedDirection = AutoConnectDirections.Right;
         this.InvalidateVisual();
     }
     else if (position.Y < 0 && this.highlightedDirection != AutoConnectDirections.Top)
     {
         this.highlightedDirection = AutoConnectDirections.Top;
         this.InvalidateVisual();
     }
     else if (position.Y > size.Height && this.highlightedDirection != AutoConnectDirections.Bottom)
     {
         this.highlightedDirection = AutoConnectDirections.Bottom;
         this.InvalidateVisual();
     }
 }