1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //-----------------------------------------------------------------------------
5 namespace System.Activities.Core.Presentation
7 using System.Activities.Presentation;
8 using System.Activities.Presentation.FreeFormEditing;
9 using System.Activities.Presentation.Model;
10 using System.Activities.Presentation.View;
11 using System.Activities.Statements;
12 using System.Diagnostics;
15 using System.Windows.Controls;
16 using System.Windows.Input;
17 using System.Windows.Media;
19 partial class StateContainerEditor
21 internal int DeleteConnectorModelItem(Connector connector, bool rerouting = false)
23 ModelItem connectorModelItem = StateContainerEditor.GetConnectorModelItem(connector);
27 if (connector is ConnectorWithStartDot)
29 connector.StartDot.MouseDown -= new MouseButtonEventHandler(OnConnectorStartDotMouseDown);
30 connector.StartDot.MouseUp -= new MouseButtonEventHandler(OnConnectorStartDotMouseUp);
33 connector.GotKeyboardFocus -= new KeyboardFocusChangedEventHandler(OnConnectorGotKeyboardFocus);
34 connector.RequestBringIntoView -= new RequestBringIntoViewEventHandler(OnConnectorRequestBringIntoView);
35 connector.GotFocus -= new RoutedEventHandler(OnConnectorGotFocus);
36 connector.MouseDoubleClick -= new MouseButtonEventHandler(OnConnectorMouseDoubleClick);
37 connector.MouseDown -= new MouseButtonEventHandler(OnConnectorMouseDown);
38 connector.KeyDown -= new KeyEventHandler(OnConnectorKeyDown);
39 connector.ContextMenuOpening -= new ContextMenuEventHandler(OnConnectorContextMenuOpening);
40 connector.Unloaded -= new RoutedEventHandler(OnConnectorUnloaded);
43 int removedIndex = InvalidIndex;
44 if (connectorModelItem.ItemType == typeof(Transition))
46 ModelItemCollection transitions = StateContainerEditor.GetParentStateModelItemForTransition(connectorModelItem).Properties[StateDesigner.TransitionsPropertyName].Collection;
47 removedIndex = transitions.IndexOf(connectorModelItem);
48 Fx.Assert(removedIndex >= 0, "can't find the connector ModelItem in collection");
49 transitions.Remove(connectorModelItem);
51 // Connector from initial node
52 else if (connectorModelItem.ItemType == typeof(StateMachine))
54 using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.ClearInitialState))
56 connectorModelItem.Properties[StateMachineDesigner.InitialStatePropertyName].SetValue(null);
59 this.ViewStateService.StoreViewStateWithUndo(connectorModelItem, ConnectorLocationViewStateKey, null);
67 void DeleteState(ModelItem stateModelItem, bool clearInitialState)
69 Fx.Assert(this.ModelItem.ItemType == typeof(StateMachine), "Should only delete states with StateMachine.");
71 this.ModelItem.Properties[StateMachineDesigner.StatesPropertyName].Collection.Remove(stateModelItem);
72 if (clearInitialState &&
73 this.ModelItem.ItemType == typeof(StateMachine) &&
74 stateModelItem == this.ModelItem.Properties[StateMachineDesigner.InitialStatePropertyName].Value)
76 this.ModelItem.Properties[StateMachineDesigner.InitialStatePropertyName].SetValue(null);
77 this.ViewStateService.StoreViewStateWithUndo(this.ModelItem, ConnectorLocationViewStateKey, null);
81 // referenceTransitionModelItem is used when a connector is re-linked.
82 void CreateTransition(ConnectionPoint sourceConnPoint, ConnectionPoint destConnPoint, ModelItem referenceTransitionModelItem, bool isSourceMoved)
84 VirtualizedContainerService.VirtualizingContainer srcDesigner = sourceConnPoint.ParentDesigner as VirtualizedContainerService.VirtualizingContainer;
85 Fx.Assert(srcDesigner != null, "srcDesigner should not be null.");
86 VirtualizedContainerService.VirtualizingContainer destDesigner = destConnPoint.ParentDesigner as VirtualizedContainerService.VirtualizingContainer;
87 Fx.Assert(destDesigner != null, "destDesigner should not be null.");
89 ModelItem srcModelItem = srcDesigner.ModelItem;
90 ModelItem destModelItem = destDesigner.ModelItem;
91 ModelItem transitionModelItem = null;
93 // We are moving the connector.
94 if (referenceTransitionModelItem != null && referenceTransitionModelItem.ItemType == typeof(Transition))
96 transitionModelItem = referenceTransitionModelItem;
97 // We are moving the start of the connector. We only preserve the trigger if it is not shared.
100 Transition referenceTransition = referenceTransitionModelItem.GetCurrentValue() as Transition;
101 ModelItem stateModelItem = GetParentStateModelItemForTransition(referenceTransitionModelItem);
102 State state = stateModelItem.GetCurrentValue() as State;
103 bool isTriggerShared = false;
104 foreach (Transition transition in state.Transitions)
106 if (transition != referenceTransition && transition.Trigger == referenceTransition.Trigger)
108 isTriggerShared = true;
114 transitionModelItem.Properties[TransitionDesigner.TriggerPropertyName].SetValue(null);
117 transitionModelItem.Properties[TransitionDesigner.ToPropertyName].SetValue(destModelItem);
118 srcModelItem.Properties[StateDesigner.TransitionsPropertyName].Collection.Add(transitionModelItem);
120 // We are creating a new connector.
123 ModelItem stateMachineModelItem = GetStateMachineModelItem(srcModelItem);
124 Transition newTransition = new Transition() { DisplayName = StateContainerEditor.GenerateTransitionName(stateMachineModelItem) };
125 newTransition.To = destModelItem.GetCurrentValue() as State;
126 // Assign the shared trigger.
127 if (sourceConnPoint.AttachedConnectors.Count > 0)
129 Connector connector = sourceConnPoint.AttachedConnectors[0];
130 Transition existingTransition = StateContainerEditor.GetConnectorModelItem(connector).GetCurrentValue() as Transition;
131 newTransition.Trigger = existingTransition.Trigger;
133 transitionModelItem = srcModelItem.Properties[StateDesigner.TransitionsPropertyName].Collection.Add(newTransition);
135 if (transitionModelItem != null)
137 // if the transition connection is re-routed, the SrcConnPointIndex needs to be updated.
138 PointCollection connectorViewState = new PointCollection(ConnectorRouter.Route(this.panel, sourceConnPoint, destConnPoint));
139 int srcConnectionPointIndex = StateContainerEditor.GetConnectionPoints(sourceConnPoint.ParentDesigner).IndexOf(sourceConnPoint);
140 int destConnectionPointIndex = StateContainerEditor.GetConnectionPoints(destConnPoint.ParentDesigner).IndexOf(destConnPoint);
141 this.StoreConnectorLocationViewState(transitionModelItem, connectorViewState, true);
142 this.ViewStateService.StoreViewStateWithUndo(transitionModelItem, SrcConnectionPointIndexStateKey, srcConnectionPointIndex);
143 this.ViewStateService.StoreViewStateWithUndo(transitionModelItem, DestConnectionPointIndexStateKey, destConnectionPointIndex);
147 // referenceConnector is used when we are re-linking the connector.
148 internal ConnectorCreationResult CreateConnectorGesture(ConnectionPoint sourceConnectionPoint, ConnectionPoint destConnectionPoint, Connector referenceConnector, bool isConnectorStartMoved)
150 Fx.Assert(sourceConnectionPoint != null, "sourceConnectionPoint is null.");
151 Fx.Assert(destConnectionPoint != null, "destConnectionPoint is null.");
152 ConnectorCreationResult result = ConnectorCreationResult.OtherFailure;
153 if (destConnectionPoint.PointType != ConnectionPointKind.Outgoing && sourceConnectionPoint.PointType != ConnectionPointKind.Incoming)
155 if (sourceConnectionPoint.ParentDesigner is VirtualizedContainerService.VirtualizingContainer)
157 //bool sameDestination = false;
158 ModelItem refTransitionModelItem = null;
159 if (referenceConnector != null)
161 refTransitionModelItem = StateContainerEditor.GetConnectorModelItem(referenceConnector);
164 using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.CreateTransition))
166 if (refTransitionModelItem != null)
168 this.CreateTransition(sourceConnectionPoint, destConnectionPoint, refTransitionModelItem, isConnectorStartMoved);
172 this.CreateTransition(sourceConnectionPoint, destConnectionPoint, null, false);
174 result = ConnectorCreationResult.Success;
178 else if (sourceConnectionPoint.ParentDesigner is StartSymbol)
180 ModelItem stateModelItem = ((VirtualizedContainerService.VirtualizingContainer)destConnectionPoint.ParentDesigner).ModelItem;
182 if (IsFinalState(stateModelItem))
184 result = ConnectorCreationResult.CannotSetFinalStateAsInitialState;
188 using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.SetInitialState))
190 this.StateMachineModelItem.Properties[StateMachineDesigner.InitialStatePropertyName].SetValue(stateModelItem);
191 PointCollection connectorViewState = new PointCollection(ConnectorRouter.Route(this.panel, sourceConnectionPoint, destConnectionPoint));
192 this.StoreConnectorLocationViewState(this.StateMachineModelItem, connectorViewState, true);
193 result = ConnectorCreationResult.Success;
202 internal ConnectorCreationResult CreateConnectorGesture(ConnectionPoint sourceConnectionPoint, UIElement dest, Connector referenceConnector, bool isConnectorStartMoved)
204 ConnectionPoint destConnectionPoint = null;
205 if (this.activeConnectionPoint != null)
207 destConnectionPoint = this.activeConnectionPoint;
211 destConnectionPoint = GetClosestDestConnectionPoint(sourceConnectionPoint, dest);
214 if (destConnectionPoint != null)
216 return CreateConnectorGesture(sourceConnectionPoint, destConnectionPoint, referenceConnector, isConnectorStartMoved);
218 return ConnectorCreationResult.OtherFailure;
221 internal ConnectorCreationResult CreateConnectorGesture(UIElement source, ConnectionPoint destConnectionPoint, Connector referenceConnector, bool isConnectorStartMoved)
223 ConnectionPoint sourceConnectionPoint = null;
224 if (this.activeConnectionPoint != null)
226 sourceConnectionPoint = this.activeConnectionPoint;
230 sourceConnectionPoint = GetClosestSrcConnectionPoint(source, destConnectionPoint);
233 if (sourceConnectionPoint != null)
235 return CreateConnectorGesture(sourceConnectionPoint, destConnectionPoint, referenceConnector, isConnectorStartMoved);
237 return ConnectorCreationResult.OtherFailure;
240 void StoreShapeLocationViewState(UIElement view, Point newLocation)
242 ModelItem storageModelItem = null;
243 if (view is StartSymbol)
245 storageModelItem = this.ModelItem;
247 else if (view is VirtualizedContainerService.VirtualizingContainer)
249 storageModelItem = ((VirtualizedContainerService.VirtualizingContainer)view).ModelItem;
251 StoreShapeLocationViewState(storageModelItem, newLocation);
254 void StoreShapeLocationViewState(ModelItem storageModelItem, Point newLocation)
256 if (this.ViewStateService.RetrieveViewState(storageModelItem, ShapeLocationViewStateKey) != null)
258 this.ViewStateService.StoreViewStateWithUndo(storageModelItem, ShapeLocationViewStateKey, newLocation);
262 this.ViewStateService.StoreViewState(storageModelItem, ShapeLocationViewStateKey, newLocation);
266 void StoreConnectorLocationViewState(ModelItem connectorModelItem, PointCollection viewState, bool isUndoableViewState)
268 if (isUndoableViewState)
270 this.ViewStateService.StoreViewStateWithUndo(connectorModelItem, ConnectorLocationViewStateKey, viewState);
274 this.ViewStateService.StoreViewState(connectorModelItem, ConnectorLocationViewStateKey, viewState);
278 void StoreConnectorLocationViewState(Connector connector, bool isUndoableViewState)
280 //This method will be called whenever the FreeFormPanel raises a location changed event on a connector.
281 //Such location changed events are a result of changes already committed in the UI. Hence we do not want to react to such view state changes.
282 //Using internalViewStateChange flag for that purpose.
283 this.internalViewStateChange = true;
284 this.StoreConnectorLocationViewState(StateContainerEditor.GetConnectorModelItem(connector), connector.Points, isUndoableViewState);
285 this.internalViewStateChange = false;
288 // While adding an new StateContainer inside an outer StateContainer, the outter StateContainer size might change.
289 // InsertState would recursively stores the outer containers before the insertion happens, and capture the size within a single EditingScope to facilitate Undo.
290 ModelItem InsertState(Object droppedObject)
292 ModelItem droppedModelItem = null;
293 Fx.Assert(this.ModelItem.ItemType == typeof(StateMachine), "Should only drop state with StateMachine.");
294 using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(System.Activities.Presentation.SR.CollectionAddEditingScopeDescription))
296 StoreShapeSizeWithUndoRecursively(this.ModelItem);
297 droppedModelItem = this.ModelItem.Properties[StateMachineDesigner.StatesPropertyName].Collection.Add(droppedObject);
300 return droppedModelItem;
303 // Recursively store the current StateContainerHeight and StateContainerWidth of the target StateContainer and its ancestors to the current editing scope,
304 // up to the StateMachine instance.
305 internal void StoreShapeSizeWithUndoRecursively(ModelItem modelItem)
307 if (modelItem.ItemType == typeof(State))
309 ModelItem parent = GetStateMachineModelItem(modelItem);
312 // State can be dropped to a non-StateMachine container (Bug 220966)
313 // so a null check is needed.
314 StoreShapeSizeWithUndoRecursively(parent);
318 if (modelItem.ItemType == typeof(State) || modelItem.ItemType == typeof(StateMachine))
320 this.ViewStateService.StoreViewStateWithUndo(
322 StateContainerWidthViewStateKey,
323 this.ViewStateService.RetrieveViewState(modelItem, StateContainerWidthViewStateKey));
325 this.ViewStateService.StoreViewStateWithUndo(
327 StateContainerHeightViewStateKey,
328 this.ViewStateService.RetrieveViewState(modelItem, StateContainerHeightViewStateKey));