static void SetConnectorSrcDestConnectionPoints(Connector connector, ConnectionPoint srcConnectionPoint, ConnectionPoint destConnectionPoint) { FreeFormPanel.SetSourceConnectionPoint(connector, srcConnectionPoint); FreeFormPanel.SetDestinationConnectionPoint(connector, destConnectionPoint); srcConnectionPoint.AttachedConnectors.Add(connector); destConnectionPoint.AttachedConnectors.Add(connector); }
public static Point CalculateDropLocation(Point mousePosition, Point originalDropLocation, Connector connector, Size droppedSize, HashSet<Point> shapeLocations) { UIElement srcShape = FreeFormPanel.GetSourceConnectionPoint(connector).ParentDesigner; UIElement destShape = FreeFormPanel.GetDestinationConnectionPoint(connector).ParentDesigner; Point srcLocation = FreeFormPanel.GetLocation(srcShape); Point destLocation = FreeFormPanel.GetLocation(destShape); Size srcSize = FreeFormPanel.GetChildSize(srcShape); Size destSize = FreeFormPanel.GetChildSize(destShape); return CalculateDropLocation(mousePosition, originalDropLocation, droppedSize, srcLocation, destLocation, srcSize, destSize, shapeLocations); }
// The method will return the CaseKey if any. // referenceUpdatedModelItems: say A linked to B by linker C, there is a relationship: // A.Properties["Relation"] = B. // When delete the linker C, A will be updated like, A.Properties["Relation"] = null; // In multiple drag/drop, the A.Properties["Relation"] is set correctly before coming // here, which means we should not set the value again, otherwise the correct, // value which is set previously, will be removed. internal IFlowSwitchLink DeleteLink(Connector link, bool isMoveOrAutoSplit = false, HashSet<ModelItem> referenceUpdatedModelItems = null) { IFlowSwitchLink caseKey = null; using (EditingScope deleteLinkEditingScope = ((IModelTreeItem)this.ModelItem).ModelTreeManager.CreateEditingScope(SR.FCDeleteLink)) { caseKey = DeleteLinkImpl(link, isMoveOrAutoSplit, referenceUpdatedModelItems); deleteLinkEditingScope.Complete(); } return caseKey; }
internal int DeleteConnectorModelItem(Connector connector, bool rerouting = false) { ModelItem connectorModelItem = StateContainerEditor.GetConnectorModelItem(connector); if (!rerouting) { if (connector is ConnectorWithStartDot) { connector.StartDot.MouseDown -= new MouseButtonEventHandler(OnConnectorStartDotMouseDown); connector.StartDot.MouseUp -= new MouseButtonEventHandler(OnConnectorStartDotMouseUp); } connector.GotKeyboardFocus -= new KeyboardFocusChangedEventHandler(OnConnectorGotKeyboardFocus); connector.RequestBringIntoView -= new RequestBringIntoViewEventHandler(OnConnectorRequestBringIntoView); connector.GotFocus -= new RoutedEventHandler(OnConnectorGotFocus); connector.MouseDoubleClick -= new MouseButtonEventHandler(OnConnectorMouseDoubleClick); connector.MouseDown -= new MouseButtonEventHandler(OnConnectorMouseDown); connector.KeyDown -= new KeyEventHandler(OnConnectorKeyDown); connector.ContextMenuOpening -= new ContextMenuEventHandler(OnConnectorContextMenuOpening); connector.Unloaded -= new RoutedEventHandler(OnConnectorUnloaded); } int removedIndex = InvalidIndex; if (connectorModelItem.ItemType == typeof(Transition)) { ModelItemCollection transitions = StateContainerEditor.GetParentStateModelItemForTransition(connectorModelItem).Properties[StateDesigner.TransitionsPropertyName].Collection; removedIndex = transitions.IndexOf(connectorModelItem); Fx.Assert(removedIndex >= 0, "can't find the connector ModelItem in collection"); transitions.Remove(connectorModelItem); } // Connector from initial node else if (connectorModelItem.ItemType == typeof(StateMachine)) { using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.ClearInitialState)) { connectorModelItem.Properties[StateMachineDesigner.InitialStatePropertyName].SetValue(null); if (!rerouting) { this.ViewStateService.StoreViewStateWithUndo(connectorModelItem, ConnectorLocationViewStateKey, null); } es.Complete(); } } return removedIndex; }
static void SetConnectorLabel(Connector connector, ModelItem connectorModelItem) { connector.SetBinding(Connector.LabelTextProperty, new Binding() { Source = connectorModelItem, Path = new PropertyPath("DisplayName") }); TextBlock toolTip = new TextBlock(); toolTip.SetBinding(TextBlock.TextProperty, new Binding() { Source = connectorModelItem, Path = new PropertyPath("DisplayName"), StringFormat = TransitionNameToolTip + Environment.NewLine + SR.EditTransitionTooltip + Environment.NewLine + SR.CopyTransitionToolTip }); connector.SetLabelToolTip(toolTip); }
public ConnectorEditor(FreeFormPanel panel, Connector connector) { if (panel == null) { throw FxTrace.Exception.AsError(new ArgumentNullException("panel")); } if (connector == null) { throw FxTrace.Exception.AsError(new ArgumentNullException("connector")); } this.editPoints = new List<EditPoint>(); this.parentPanel = panel; this.editedConnector = connector; this.activeEditPoint = null; connector.IsSelected = true; // When the ConnectorEditor is active, we allow reconnecting the start point of the Connector instead // of creating a new transition that shares the same trigger. So we need to disable tooltips and // highlighting effects for all overlapping start dots. this.SetIsHitTestVisibleForOverlappingStartDots(false); DisplayEditPoints(); }
public static void CalculateEntryExitEdges(Point mousePosition, Connector connector, out EdgeLocation entryEdge, out EdgeLocation exitEdge) { UIElement srcShape = FreeFormPanel.GetSourceConnectionPoint(connector).ParentDesigner; UIElement destShape = FreeFormPanel.GetDestinationConnectionPoint(connector).ParentDesigner; Point srcLocation = FreeFormPanel.GetLocation(srcShape); Point destLocation = FreeFormPanel.GetLocation(destShape); Size srcSize = FreeFormPanel.GetChildSize(srcShape); Size destSize = FreeFormPanel.GetChildSize(destShape); Point srcCenter = new Point(srcLocation.X + (srcSize.Width / 2), srcLocation.Y + (srcSize.Height / 2)); Point destCenter = new Point(destLocation.X + (destSize.Width / 2), destLocation.Y + (destSize.Height / 2)); entryEdge = CalculateEdgeLocation(mousePosition, srcCenter); exitEdge = CalculateEdgeLocation(mousePosition, destCenter); if (exitEdge == entryEdge) { switch (entryEdge) { case EdgeLocation.Top: exitEdge = EdgeLocation.Bottom; break; case EdgeLocation.Bottom: exitEdge = EdgeLocation.Top; break; case EdgeLocation.Left: exitEdge = EdgeLocation.Right; break; case EdgeLocation.Right: exitEdge = EdgeLocation.Left; break; } } }
private void OnFlowchartGridKeyDown(object sender, KeyEventArgs e) { if (srcConnectionPoint != null) { // Ignore KeyBoard input when creating connector. e.Handled = true; return; } Selection currentSelection = this.Context.Items.GetValue<Selection>(); if (e.Key == Key.Delete && this.selectedConnector != null && currentSelection.SelectionCount <= 1) { // process the delete if only the connector is selected ModelItem primarySelection = currentSelection.PrimarySelection; //Delete connector ModelItem linkModelItem = FlowchartDesigner.GetLinkModelItem(this.selectedConnector); if ((primarySelection == null && !IsLinkModelItemSelectable(linkModelItem)) || object.Equals(primarySelection, linkModelItem)) { DeleteLink(this.selectedConnector); this.selectedConnector = null; e.Handled = true; } } else if ((new List<Key> { Key.Left, Key.Right, Key.Up, Key.Down }).Contains(e.Key) && currentSelection.SelectedObjects.All<ModelItem>((p) => { return this.modelElement.ContainsKey(p); })) { KeyboardMove(e.Key); e.Handled = true; } }
// 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); } }
Point CalculateDropLocationForAutoSplit(Point mousePosition, Point originalDropLocation, Connector connector, Size droppedSize) { return AutoSplitHelper.CalculateDropLocation(mousePosition, originalDropLocation, connector, droppedSize, this.shapeLocations); }
// 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; }
void Reroute(Connector connector, bool withUndo) { ConnectionPoint source = FreeFormPanel.GetSourceConnectionPoint(connector); ConnectionPoint destination = FreeFormPanel.GetDestinationConnectionPoint(connector); //Nulling out the PointCollection so that it doesn't interfere in line routing. connector.Points = new PointCollection(); PointCollection viewState = new PointCollection(ConnectorRouter.Route(this.panel, source, destination)); StoreConnectorViewState(FlowchartDesigner.GetLinkModelItem(connector), viewState, source, withUndo); }
void ClearSelectedConnector() { if (this.panel.connectorEditor != null && this.panel.connectorEditor.Connector == this.selectedConnector) { this.panel.RemoveConnectorEditor(); } this.selectedConnector = null; }
//This is to keep this.selectedConnector upto date. //Eg. cases included 1. create a link, select it and undo, 2. Move a link from one shape to another. void OnFreeFormPanelLayoutUpdated(object sender, EventArgs e) { if (!this.panel.Children.Contains(this.selectedConnector)) { this.selectedConnector = null; } }
void SetConnectorLabelToolTip(Connector connector, BindingBase binding) { connector.SetBinding(Connector.LabelTextProperty, binding); ToolTip toolTip = new ToolTip(); toolTip.SetBinding(UserControl.ContentProperty, binding); connector.SetLabelToolTip(toolTip); }
void OnFreeFormPanelConnectorMoved(object sender, ConnectorMovedEventArgs e) { Fx.Assert(this.panel != null, "This code should not be hit if panel is null"); Connector movedConnector = sender as Connector; int movedEndConnectorPointIndex = movedConnector.Points.Count - 1; int newEndConnectorPointIndex = e.NewConnectorLocation.Count - 1; if (movedConnector != null) { Fx.Assert(e.NewConnectorLocation.Count > 0, "Invalid connector editor"); if (!e.NewConnectorLocation[0].Equals(movedConnector.Points[0])) { //srcMoved ConnectionPoint destConnPoint = FreeFormPanel.GetDestinationConnectionPoint(movedConnector); UpdateFlowchartOnLinkVisualMoved(destConnPoint, e.NewConnectorLocation[0], movedConnector, false); } else if (!e.NewConnectorLocation[newEndConnectorPointIndex].Equals(movedConnector.Points[movedEndConnectorPointIndex])) { //DestMoved ConnectionPoint srcConnPoint = FreeFormPanel.GetSourceConnectionPoint(movedConnector); Point destPoint = e.NewConnectorLocation[newEndConnectorPointIndex]; UpdateFlowchartOnLinkVisualMoved(srcConnPoint, destPoint, movedConnector, true); } this.selectedConnector = movedConnector; } }
// 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; }
void OnStateContainerGridPreviewMouseDown(object sender, MouseButtonEventArgs e) { this.selectedConnector = null; }
static bool IsConnectorFromInitialNode(Connector connector) { return GetConnectorModelItem(connector).ItemType == typeof(StateMachine); }
void Remove(Connector connector) { ConnectionPoint srcConnectionPoint = FreeFormPanel.GetSourceConnectionPoint(connector); ConnectionPoint destConnectionPoint = FreeFormPanel.GetDestinationConnectionPoint(connector); // Update ConnectionPoints srcConnectionPoint.AttachedConnectors.Remove(connector); destConnectionPoint.AttachedConnectors.Remove(connector); StateContainerEditor stateMachineContainer = this.GetStateMachineContainerEditor(); stateMachineContainer.panel.Children.Remove(connector); if (stateMachineContainer.selectedConnector == connector) { stateMachineContainer.ClearSelectedConnector(); } if (connector is ConnectorWithStartDot) { connector.StartDot.MouseDown -= new MouseButtonEventHandler(OnConnectorStartDotMouseDown); connector.StartDot.MouseUp -= new MouseButtonEventHandler(OnConnectorStartDotMouseUp); } connector.GotKeyboardFocus -= new KeyboardFocusChangedEventHandler(OnConnectorGotKeyboardFocus); connector.RequestBringIntoView -= new RequestBringIntoViewEventHandler(OnConnectorRequestBringIntoView); connector.GotFocus -= new RoutedEventHandler(OnConnectorGotFocus); connector.MouseDoubleClick -= new MouseButtonEventHandler(OnConnectorMouseDoubleClick); connector.MouseDown -= new MouseButtonEventHandler(OnConnectorMouseDown); connector.KeyDown -= new KeyEventHandler(OnConnectorKeyDown); connector.ContextMenuOpening -= new ContextMenuEventHandler(OnConnectorContextMenuOpening); connector.Unloaded -= new RoutedEventHandler(OnConnectorUnloaded); }
public void DoAutoSplit(DragEventArgs e, Connector connector) { bool immediatelyCommit = ModelItemHelper.CanCreateImmediateEditingScope(this.ModelItem); using (EditingScope scope = (EditingScope)this.ModelItem.BeginEdit(SR.AutoSplit, immediatelyCommit)) { ModelItem droppedModelItem = this.DoStateContainerGridDrop(e, AutoConnectDirections.None, connector); bool autoSplit = false; ConnectionPoint sourceConnectionPoint = FreeFormPanel.GetSourceConnectionPoint(connector); ConnectionPoint destinationConnectionPoint = FreeFormPanel.GetDestinationConnectionPoint(connector); if (droppedModelItem != null) { ModelItem oldConnectorModelItem = StateContainerEditor.GetConnectorModelItem(connector); int index = this.DeleteConnectorModelItem(connector); bool autoConnected = this.DoAutoConnect(sourceConnectionPoint.ParentDesigner, droppedModelItem, oldConnectorModelItem.GetCurrentValue() as Transition, index) != null; if (autoConnected) { ModelItem destinationModelItem = ((VirtualizedContainerService.VirtualizingContainer)destinationConnectionPoint.ParentDesigner).ModelItem; ModelItem stateMachineModelItem = GetStateMachineModelItem(destinationModelItem); droppedModelItem.Properties[StateDesigner.TransitionsPropertyName].Collection.Add(new Transition() { DisplayName = StateContainerEditor.GenerateTransitionName(stateMachineModelItem), To = destinationModelItem.GetCurrentValue() as State }); autoSplit = true; } } if (autoSplit) { // Auto-split generates 4 changes: 1) drop state, 2) remove the old transition, 3) create a transition from the source state // to the dropped state, and 4) create a transition from the dropped state to the destination state. // Step 1 may result in creating the visual of all outgoing transition from the dropped state. Step 4) also creates the visual // of the new transition from the dropped state. So the visual of the transition will be created twice. To solve that problem, // we need to suppress adding connector when adding state visual (in the UI reaction for step 1). // And to support redo, we must place the suppression in the undo stack. this.Context.Services.GetService<ModelTreeManager>().AddToCurrentEditingScope(new SuppressAddingConnectorWhenAddingStateVisual()); this.activeSrcConnectionPointForAutoSplit = sourceConnectionPoint; this.activeDestConnectionPointForAutoSplit = destinationConnectionPoint; AutoSplitHelper.CalculateEntryExitEdges(e.GetPosition(this.panel), connector, out this.entryEdgeForAutoSplit, out this.exitEdgeForAutoSplit); scope.Complete(); } else { scope.Revert(); } } }
private void OnFlowchartGridPreviewMouseDown(object sender, MouseButtonEventArgs e) { this.selectedConnector = null; }
public void DoAutoSplit(DragEventArgs e, Connector connector) { bool immediatelyCommit = ModelItemHelper.CanCreateImmediateEditingScope(this.ModelItem); using (EditingScope scope = (EditingScope)this.ModelItem.BeginEdit(SR.AutoSplit, immediatelyCommit)) { ModelItem droppedModelItem = this.DoFlowchartGridDrop(e, AutoConnectDirections.None, connector); bool autoSplit = false; ModelItem sourceModelItem = null; ModelItem destinationModelItem = null; if (droppedModelItem != null) { this.StoreConnectorViewState(connector, true); IFlowSwitchLink flowSwitchLink = this.DeleteLink(connector, true); bool linkCreated = true; string message = string.Empty; UIElement srcDesigner = FreeFormPanel.GetSourceConnectionPoint(connector).ParentDesigner; UIElement destDesigner = FreeFormPanel.GetDestinationConnectionPoint(connector).ParentDesigner; if (srcDesigner is StartSymbol) { sourceModelItem = this.ModelItem; this.ModelItem.Properties["StartNode"].SetValue(droppedModelItem); } else if (srcDesigner is VirtualizedContainerService.VirtualizingContainer) { sourceModelItem = ((VirtualizedContainerService.VirtualizingContainer)srcDesigner).ModelItem; ModelItem srcFlowNodeModelItem = sourceModelItem; if (!IsFlowNode(srcFlowNodeModelItem)) { srcFlowNodeModelItem = this.GetParentFlowStepModelItem(srcFlowNodeModelItem); } Fx.Assert(IsFlowNode(srcFlowNodeModelItem), "srcFlowNodeModelItem should be a FlowNode"); if (typeof(FlowStep) == srcFlowNodeModelItem.ItemType) { srcFlowNodeModelItem.Properties["Next"].SetValue(droppedModelItem); } else if (typeof(FlowDecision) == srcFlowNodeModelItem.ItemType && FreeFormPanel.GetSourceConnectionPoint(connector).Equals(GetTrueConnectionPoint(srcDesigner))) { srcFlowNodeModelItem.Properties["True"].SetValue(droppedModelItem); } else if (typeof(FlowDecision) == srcFlowNodeModelItem.ItemType && FreeFormPanel.GetSourceConnectionPoint(connector).Equals(GetFalseConnectionPoint(srcDesigner))) { srcFlowNodeModelItem.Properties["False"].SetValue(droppedModelItem); } else if (GenericFlowSwitchHelper.IsGenericFlowSwitch(srcFlowNodeModelItem.ItemType)) { linkCreated = CreateFlowSwitchLink(FreeFormPanel.GetSourceConnectionPoint(connector), srcFlowNodeModelItem, droppedModelItem, flowSwitchLink, null, ref message); } } if (linkCreated && string.IsNullOrEmpty(message)) { destinationModelItem = ((VirtualizedContainerService.VirtualizingContainer)destDesigner).ModelItem; ModelItem destFlowNodeModelItem = destinationModelItem; if (!IsFlowNode(destFlowNodeModelItem)) { destFlowNodeModelItem = this.GetParentFlowStepModelItem(destFlowNodeModelItem); } Fx.Assert(IsFlowNode(destFlowNodeModelItem), "destFlowNodeModelItem should be a FlowNode"); if (droppedModelItem.ItemType == typeof(FlowStep)) { droppedModelItem.Properties["Next"].SetValue(destFlowNodeModelItem); autoSplit = true; } else if (GenericFlowSwitchHelper.IsGenericFlowSwitch(droppedModelItem.ItemType)) { droppedModelItem.Properties["Default"].SetValue(destFlowNodeModelItem); autoSplit = true; } else if (droppedModelItem.ItemType == typeof(FlowDecision)) { droppedModelItem.Properties["True"].SetValue(destFlowNodeModelItem); autoSplit = true; } } } if (autoSplit) { Fx.Assert(sourceModelItem != null, "sourceModelItem != null"); Fx.Assert(destinationModelItem != null, "destinationModelItem != null"); int srcIndex = GetConnectionPointIndex(this.GetView(sourceModelItem), FreeFormPanel.GetSourceConnectionPoint(connector)); int desIndex = GetConnectionPointIndex(this.GetView(destinationModelItem), FreeFormPanel.GetDestinationConnectionPoint(connector)); EdgeLocation entryEdgeForAutoSplit; EdgeLocation exitEdgeForAutoSplit; AutoSplitHelper.CalculateEntryExitEdges(e.GetPosition(this.panel), connector, out entryEdgeForAutoSplit, out exitEdgeForAutoSplit); FlowchartDesigner.SetAutoSplitDataWithUndo( this.ModelItem, sourceModelItem, destinationModelItem, srcIndex, desIndex, entryEdgeForAutoSplit, exitEdgeForAutoSplit); scope.Complete(); } else { scope.Revert(); } } }
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(); } }
void UpdateFlowchartOnLinkVisualMoved(ConnectionPoint knownConnectionPoint, Point newPoint, Connector movedConnector, bool isSourceKnown) { Fx.Assert(this.panel != null, "This code should not be hit if panel is null"); HitTestResult hitTestResult = VisualTreeHelper.HitTest(this.panel, newPoint); if (hitTestResult == null) { return; } //Test if the last connectionPoint hit, is the new location for the connector. UIElement newViewElement = null; ConnectionPoint newConnectionPoint = null; //The case where the link is dropped on a connectionpoint. if (this.lastConnectionPointMouseUpElement != null) { newConnectionPoint = this.ConnectionPointHitTest(this.lastConnectionPointMouseUpElement, newPoint); if (newConnectionPoint != null) { newViewElement = this.lastConnectionPointMouseUpElement; } } //The case where the link is dropped on a shape. if (newViewElement == null) { newViewElement = VisualTreeUtils.FindVisualAncestor<StartSymbol>(hitTestResult.VisualHit); if (newViewElement == null) { newViewElement = VisualTreeUtils.FindVisualAncestor<VirtualizedContainerService.VirtualizingContainer>(hitTestResult.VisualHit); } } if (newViewElement != null) { if (this.panel.Children.Contains(newViewElement)) { using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.FCLinkMove)) { //Delete the existing link and keep the caseKey IFlowSwitchLink oldCaseKey = this.DeleteLink(movedConnector, true); //Create new link bool linkCreated = false; string errorMessage = string.Empty; if (isSourceKnown) { if (newConnectionPoint == null) { linkCreated = CreateLinkGesture(knownConnectionPoint, newViewElement, newPoint, out errorMessage, true, oldCaseKey); } else { linkCreated = CreateLinkGesture(knownConnectionPoint, newConnectionPoint, out errorMessage, true, oldCaseKey); } } else { //If the Link source is dropped onto itself, we need to set the isLinkValidDueToLinkMove flag. bool isLinkValidDueToLinkMove = FreeFormPanel.GetSourceConnectionPoint(movedConnector).ParentDesigner.Equals(newViewElement); if (newConnectionPoint == null) { linkCreated = CreateLinkGesture(newViewElement, knownConnectionPoint, newPoint, out errorMessage, isLinkValidDueToLinkMove, oldCaseKey); } else { linkCreated = CreateLinkGesture(newConnectionPoint, knownConnectionPoint, out errorMessage, isLinkValidDueToLinkMove, oldCaseKey); } } if (!linkCreated) { if (!errorMessage.Equals(string.Empty)) { ErrorReporting.ShowErrorMessage(errorMessage); } es.Revert(); } else { es.Complete(); } } } } }
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(); } }
void SetConnectorLabel(Connector connector, ConnectionPoint srcConnPoint, ModelItem linkModelItem) { BindingBase labelBinding = null; if (typeof(FlowDecision).IsAssignableFrom(linkModelItem.ItemType)) { if (FlowchartDesigner.GetTrueConnectionPoint(srcConnPoint.ParentDesigner).Equals(srcConnPoint)) { labelBinding = new Binding { Source = linkModelItem, Path = new PropertyPath("TrueLabel") }; } else { labelBinding = new Binding { Source = linkModelItem, Path = new PropertyPath("FalseLabel") }; } SetConnectorLabelToolTip(connector, labelBinding); } else if (typeof(IFlowSwitchLink).IsAssignableFrom(linkModelItem.ItemType)) { IFlowSwitchLink flowSwitchLink = (IFlowSwitchLink)linkModelItem.GetCurrentValue(); labelBinding = flowSwitchLink.CreateConnectorLabelTextBinding(); SetConnectorLabelToolTip(connector, labelBinding); } }
void OnConnectorGotFocus(object sender, RoutedEventArgs e) { Connector clickedLine = e.Source as Connector; DesignerView designerView = this.Context.Services.GetService<DesignerView>(); if (!designerView.IsMultipleSelectionMode) { if (this.panel.connectorEditor == null || !clickedLine.Equals(this.panel.connectorEditor.Connector)) { this.panel.RemoveConnectorEditor(); this.panel.connectorEditor = new ConnectorEditor(this.panel, clickedLine); } if (this.panel.Children.Contains(clickedLine)) { this.updatingSelectedConnector = true; ModelItem lineModelItem = FlowchartDesigner.GetLinkModelItem(clickedLine); Selection newSelection = new Selection(); // If the linkModelItem is FlowDecision or Flowchart, we don't want to add it to the selection if (IsLinkModelItemSelectable(lineModelItem)) { newSelection = new Selection(lineModelItem); } this.Context.Items.SetValue(newSelection); this.selectedConnector = clickedLine; this.updatingSelectedConnector = false; e.Handled = true; } } }
public FlowchartDesigner() { InitializeComponent(); this.modelElement = new Dictionary<ModelItem, UIElement>(); this.flowNodeToUIElement = new Dictionary<ModelItem, UIElement>(); this.shapeLocations = new HashSet<Point>(); this.selectedConnector = null; ConstructSetAsStartNodeMenuItem(); this.Loaded += (s, e) => { this.isLoaded = true; if (this.ShowExpanded) { ((ICompositeViewEvents)this).RegisterDefaultCompositeView(this); } DesignerView designerView = this.Context.Services.GetService<DesignerView>() as DesignerView; if (!designerView.ContextMenu.Items.Contains(setAsStartNode)) { designerView.ContextMenu.Items.Add(setAsStartNode); } WorkflowCommandExtensionItem item = this.Context.Items.GetValue<WorkflowCommandExtensionItem>(); if (item != null) { if (item.CommandExtensionCallback is DefaultCommandExtensionCallback) { this.InputBindings.Add(new KeyBinding(FlowchartDesignerCommands.ConnectNodesCommand, new DefaultCommandExtensionCallback.ChordKeyGesture(Key.E, Key.F))); } } Selection.Subscribe(Context, OnSelectionChanged); }; this.Unloaded += (s, e) => { this.isLoaded = false; if (object.Equals(this.DefaultCompositeView, this)) { ((ICompositeViewEvents)this).UnregisterDefaultCompositeView(this); } DesignerView designerView = this.Context.Services.GetService<DesignerView>() as DesignerView; designerView.ContextMenu.Items.Remove(setAsStartNode); Selection.Unsubscribe(Context, OnSelectionChanged); }; }
void StoreConnectorViewState(Connector connector, bool isUndoableViewState) { //This method will be called whenever the FreeFormPanel raises a location changed event on a connector. //Such location changed events are a result of changes already commited in the UI. Hence we do not want to react to such view state changes. //Using internalViewStateChange flag for that purpose. this.internalViewStateChange = true; this.StoreConnectorViewState(FlowchartDesigner.GetLinkModelItem(connector), connector.Points, FreeFormPanel.GetSourceConnectionPoint(connector), isUndoableViewState); this.internalViewStateChange = false; }