Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Activities.Core.Presentation / System / Activities / Core / Presentation / StateContainerEditor.ModelChanges.cs
1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4
5 namespace System.Activities.Core.Presentation
6 {
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;
13     using System.Runtime;
14     using System.Windows;
15     using System.Windows.Controls;
16     using System.Windows.Input;
17     using System.Windows.Media;
18
19     partial class StateContainerEditor
20     {
21         internal int DeleteConnectorModelItem(Connector connector, bool rerouting = false)
22         {
23             ModelItem connectorModelItem = StateContainerEditor.GetConnectorModelItem(connector);
24
25             if (!rerouting)
26             {
27                 if (connector is ConnectorWithStartDot)
28                 {
29                     connector.StartDot.MouseDown -= new MouseButtonEventHandler(OnConnectorStartDotMouseDown);
30                     connector.StartDot.MouseUp -= new MouseButtonEventHandler(OnConnectorStartDotMouseUp);
31                 }
32
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);
41             }
42
43             int removedIndex = InvalidIndex;
44             if (connectorModelItem.ItemType == typeof(Transition))
45             {
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);
50             }
51             // Connector from initial node
52             else if (connectorModelItem.ItemType == typeof(StateMachine))
53             {
54                 using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.ClearInitialState))
55                 {
56                     connectorModelItem.Properties[StateMachineDesigner.InitialStatePropertyName].SetValue(null);
57                     if (!rerouting)
58                     {
59                         this.ViewStateService.StoreViewStateWithUndo(connectorModelItem, ConnectorLocationViewStateKey, null);
60                     }
61                     es.Complete();
62                 }
63             }
64             return removedIndex;
65         }
66
67         void DeleteState(ModelItem stateModelItem, bool clearInitialState)
68         {
69             Fx.Assert(this.ModelItem.ItemType == typeof(StateMachine), "Should only delete states with StateMachine.");
70
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)
75             {
76                 this.ModelItem.Properties[StateMachineDesigner.InitialStatePropertyName].SetValue(null);
77                 this.ViewStateService.StoreViewStateWithUndo(this.ModelItem, ConnectorLocationViewStateKey, null);
78             }
79         }
80
81         // referenceTransitionModelItem is used when a connector is re-linked.
82         void CreateTransition(ConnectionPoint sourceConnPoint, ConnectionPoint destConnPoint, ModelItem referenceTransitionModelItem, bool isSourceMoved)
83         {
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.");
88
89             ModelItem srcModelItem = srcDesigner.ModelItem;
90             ModelItem destModelItem = destDesigner.ModelItem;
91             ModelItem transitionModelItem = null;
92
93             // We are moving the connector.
94             if (referenceTransitionModelItem != null && referenceTransitionModelItem.ItemType == typeof(Transition))
95             {
96                 transitionModelItem = referenceTransitionModelItem;
97                 // We are moving the start of the connector. We only preserve the trigger if it is not shared.
98                 if (isSourceMoved)
99                 {
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)
105                     {
106                         if (transition != referenceTransition && transition.Trigger == referenceTransition.Trigger)
107                         {
108                             isTriggerShared = true;
109                             break;
110                         }
111                     }
112                     if (isTriggerShared)
113                     {
114                         transitionModelItem.Properties[TransitionDesigner.TriggerPropertyName].SetValue(null);
115                     }
116                 }
117                 transitionModelItem.Properties[TransitionDesigner.ToPropertyName].SetValue(destModelItem);
118                 srcModelItem.Properties[StateDesigner.TransitionsPropertyName].Collection.Add(transitionModelItem);
119             }
120             // We are creating a new connector. 
121             else
122             {
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)
128                 {
129                     Connector connector = sourceConnPoint.AttachedConnectors[0];
130                     Transition existingTransition = StateContainerEditor.GetConnectorModelItem(connector).GetCurrentValue() as Transition;
131                     newTransition.Trigger = existingTransition.Trigger;
132                 }
133                 transitionModelItem = srcModelItem.Properties[StateDesigner.TransitionsPropertyName].Collection.Add(newTransition);
134             }
135             if (transitionModelItem != null)
136             {
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);
144             }
145         }
146
147         // referenceConnector is used when we are re-linking the connector.
148         internal ConnectorCreationResult CreateConnectorGesture(ConnectionPoint sourceConnectionPoint, ConnectionPoint destConnectionPoint, Connector referenceConnector, bool isConnectorStartMoved)
149         {
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)
154             {
155                 if (sourceConnectionPoint.ParentDesigner is VirtualizedContainerService.VirtualizingContainer)
156                 {
157                     //bool sameDestination = false;
158                     ModelItem refTransitionModelItem = null;
159                     if (referenceConnector != null)
160                     {
161                         refTransitionModelItem = StateContainerEditor.GetConnectorModelItem(referenceConnector);
162                     }
163
164                     using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.CreateTransition))
165                     {
166                         if (refTransitionModelItem != null)
167                         {
168                             this.CreateTransition(sourceConnectionPoint, destConnectionPoint, refTransitionModelItem, isConnectorStartMoved);
169                         }
170                         else
171                         {
172                             this.CreateTransition(sourceConnectionPoint, destConnectionPoint, null, false);
173                         }
174                         result = ConnectorCreationResult.Success;
175                         es.Complete();
176                     }
177                 }
178                 else if (sourceConnectionPoint.ParentDesigner is StartSymbol)
179                 {
180                     ModelItem stateModelItem = ((VirtualizedContainerService.VirtualizingContainer)destConnectionPoint.ParentDesigner).ModelItem;
181
182                     if (IsFinalState(stateModelItem))
183                     {
184                         result = ConnectorCreationResult.CannotSetFinalStateAsInitialState;
185                     }
186                     else
187                     {
188                         using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.SetInitialState))
189                         {
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;
194                             es.Complete();
195                         }
196                     }
197                 }
198             }
199             return result;
200         }
201
202         internal ConnectorCreationResult CreateConnectorGesture(ConnectionPoint sourceConnectionPoint, UIElement dest, Connector referenceConnector, bool isConnectorStartMoved)
203         {
204             ConnectionPoint destConnectionPoint = null;
205             if (this.activeConnectionPoint != null)
206             {
207                 destConnectionPoint = this.activeConnectionPoint;
208             }
209             else
210             {
211                 destConnectionPoint = GetClosestDestConnectionPoint(sourceConnectionPoint, dest);
212             }
213             
214             if (destConnectionPoint != null)
215             {
216                 return CreateConnectorGesture(sourceConnectionPoint, destConnectionPoint, referenceConnector, isConnectorStartMoved);
217             }
218             return ConnectorCreationResult.OtherFailure;
219         }
220
221         internal ConnectorCreationResult CreateConnectorGesture(UIElement source, ConnectionPoint destConnectionPoint, Connector referenceConnector, bool isConnectorStartMoved)
222         {
223             ConnectionPoint sourceConnectionPoint = null;
224             if (this.activeConnectionPoint != null)
225             {
226                 sourceConnectionPoint = this.activeConnectionPoint;
227             }
228             else
229             {
230                 sourceConnectionPoint = GetClosestSrcConnectionPoint(source, destConnectionPoint);
231             }
232
233             if (sourceConnectionPoint != null)
234             {
235                 return CreateConnectorGesture(sourceConnectionPoint, destConnectionPoint, referenceConnector, isConnectorStartMoved);
236             }
237             return ConnectorCreationResult.OtherFailure;
238         }
239
240         void StoreShapeLocationViewState(UIElement view, Point newLocation)
241         {
242             ModelItem storageModelItem = null;
243             if (view is StartSymbol)
244             {
245                 storageModelItem = this.ModelItem;
246             }
247             else if (view is VirtualizedContainerService.VirtualizingContainer)
248             {
249                 storageModelItem = ((VirtualizedContainerService.VirtualizingContainer)view).ModelItem;
250             }
251             StoreShapeLocationViewState(storageModelItem, newLocation);
252         }
253
254         void StoreShapeLocationViewState(ModelItem storageModelItem, Point newLocation)
255         {
256             if (this.ViewStateService.RetrieveViewState(storageModelItem, ShapeLocationViewStateKey) != null)
257             {
258                 this.ViewStateService.StoreViewStateWithUndo(storageModelItem, ShapeLocationViewStateKey, newLocation);
259             }
260             else
261             {
262                 this.ViewStateService.StoreViewState(storageModelItem, ShapeLocationViewStateKey, newLocation);
263             }
264         }
265         
266         void StoreConnectorLocationViewState(ModelItem connectorModelItem, PointCollection viewState, bool isUndoableViewState)
267         {
268             if (isUndoableViewState)
269             {
270                 this.ViewStateService.StoreViewStateWithUndo(connectorModelItem, ConnectorLocationViewStateKey, viewState);
271             }
272             else
273             {
274                 this.ViewStateService.StoreViewState(connectorModelItem, ConnectorLocationViewStateKey, viewState);
275             }
276         }
277
278         void StoreConnectorLocationViewState(Connector connector, bool isUndoableViewState)
279         {
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;
286         }
287
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)
291         {
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))
295             {
296                 StoreShapeSizeWithUndoRecursively(this.ModelItem);
297                 droppedModelItem = this.ModelItem.Properties[StateMachineDesigner.StatesPropertyName].Collection.Add(droppedObject);
298                 es.Complete();
299             }
300             return droppedModelItem;
301         }
302
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)
306         {
307             if (modelItem.ItemType == typeof(State))
308             {
309                 ModelItem parent = GetStateMachineModelItem(modelItem);
310                 if (null != parent)
311                 {
312                     // State can be dropped to a non-StateMachine container (Bug 220966)
313                     // so a null check is needed.
314                     StoreShapeSizeWithUndoRecursively(parent);
315                 }
316             }
317
318             if (modelItem.ItemType == typeof(State) || modelItem.ItemType == typeof(StateMachine))
319             {
320                 this.ViewStateService.StoreViewStateWithUndo(
321                     modelItem,
322                     StateContainerWidthViewStateKey,
323                     this.ViewStateService.RetrieveViewState(modelItem, StateContainerWidthViewStateKey));
324
325                 this.ViewStateService.StoreViewStateWithUndo(
326                     modelItem,
327                     StateContainerHeightViewStateKey,
328                     this.ViewStateService.RetrieveViewState(modelItem, StateContainerHeightViewStateKey));
329             }
330         }
331     }
332 }