Mono exception to SocketException
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Core.Presentation / System / Activities / Core / Presentation / FlowSwitchLink.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4
5 namespace System.Activities.Core.Presentation
6 {
7     using System;
8     using System.Activities.Presentation;
9     using System.Activities.Presentation.Model;
10     using System.Activities.Presentation.View;
11     using System.Activities.Statements;
12     using System.ComponentModel;
13     using System.Windows;
14     using System.Windows.Data;
15
16     abstract class FlowSwitchLink<T> : DependencyObject, IFlowSwitchLink
17     {
18         static DependencyProperty caseProperty = DependencyProperty.Register("Case", typeof(T), typeof(FlowSwitchLink<T>), new FrameworkPropertyMetadata(new PropertyChangedCallback(FlowSwitchLink<T>.OnCasePropertyChanged)));
19         static DependencyProperty isDefaultCaseProperty = DependencyProperty.Register("IsDefault", typeof(bool), typeof(FlowSwitchLink<T>), new FrameworkPropertyMetadata(new PropertyChangedCallback(FlowSwitchLink<T>.OnIsDefaultCasePropertyChanged)));
20
21         private FlowSwitch<T> parentFlowSwitch;
22         protected bool internalChange = false;
23         protected ModelItem flowSwitchModelItem;
24         const string DefaultConnectorViewStateKey = "Default";
25         const string CaseViewStateKeyAppendString = "Connector";
26         bool internalDefaultCaseChange = false;
27
28         public FlowSwitchLink(ModelItem flowSwitchMI, T caseValue, bool isDefault)
29         {
30             this.flowSwitchModelItem = flowSwitchMI;
31             object flowSwitch = this.flowSwitchModelItem.GetCurrentValue();
32             this.parentFlowSwitch = (FlowSwitch<T>)this.flowSwitchModelItem.GetCurrentValue();
33             this.internalChange = true;
34             this.internalDefaultCaseChange = true;
35             if (!isDefault)
36             {
37                 this.CaseObject = caseValue;
38             }
39             this.IsDefaultCase = isDefault;
40             this.internalDefaultCaseChange = false;
41             this.internalChange = false;
42         }
43
44         [BrowsableAttribute(false)]
45         public ModelItem ModelItem
46         { get; set; }
47
48         public CaseKeyValidationCallbackDelegate ValidateCaseKey
49         {
50             get
51             {
52                 return (object obj, out string reason) =>
53                 {
54                     return GenericFlowSwitchHelper.ValidateCaseKey(obj,
55                         this.flowSwitchModelItem.Properties["Cases"],
56                         typeof(T),
57                         out reason);
58                 };
59             }
60         }
61
62         [BrowsableAttribute(false)]
63         public FlowNode ParentFlowSwitch
64         {
65             get
66             {
67                 return this.parentFlowSwitch;
68             }
69             set
70             {
71                 this.parentFlowSwitch = value as FlowSwitch<T>;
72             }
73         }
74
75         public bool IsDefaultCase
76         {
77             get
78             {
79                 return (bool)GetValue(FlowSwitchLink<T>.isDefaultCaseProperty);
80             }
81             set
82             {
83                 SetValue(FlowSwitchLink<T>.isDefaultCaseProperty, value);
84             }
85         }
86
87         [Browsable(false)]
88         public string CaseName
89         {
90             get
91             {
92                 object value = GetValue(FlowSwitchLink<T>.caseProperty);
93                 return GenericFlowSwitchHelper.GetString((T)value, typeof(T));
94             }
95         }
96
97         [Browsable(false)]
98         public object CaseObject
99         {
100             get
101             {
102                 return GetValue(FlowSwitchLink<T>.caseProperty);
103             }
104             set
105             {
106                 SetValue(FlowSwitchLink<T>.caseProperty, value);
107             }
108         }
109         
110         [BrowsableAttribute(false)]
111         public T Case
112         {
113             get
114             {
115                 return (T)GetValue(FlowSwitchLink<T>.caseProperty);
116             }
117             set
118             {
119                 SetValue(FlowSwitchLink<T>.caseProperty, value);
120             }
121         }
122
123         DependencyProperty CaseProperty
124         {
125             get
126             {
127                 return caseProperty;
128             }
129         }
130
131         DependencyProperty IsDefaultCaseProperty
132         {
133             get
134             {
135                 return isDefaultCaseProperty;
136             }
137         }
138
139         [Browsable(false)]
140         public Type GenericType
141         {
142             get
143             {
144                 return typeof(T);
145             }
146         }
147
148         bool ContainsKey(object key)
149         {
150             return this.parentFlowSwitch.Cases.ContainsKey((T)key);
151         }
152
153         void OnIsDefaultPropertyChanged(DependencyPropertyChangedEventArgs e)
154         {
155             bool isUndoRedoInProgress = this.IsUndoRedoInProgress();
156
157             if (!this.internalDefaultCaseChange && !isUndoRedoInProgress)
158             {
159                 bool value = (bool)e.NewValue;
160                 bool oldValue = (bool)e.OldValue;
161
162                 if (value)
163                 {
164                     if (object.Equals(this.flowSwitchModelItem.Properties["Default"].Value, null))
165                     {
166                         using (EditingScope es = (EditingScope)this.flowSwitchModelItem.BeginEdit(SR.FlowSwitchCaseRenameEditingScopeDesc))
167                         {
168                             ModelItem flowNodeMI = GenericFlowSwitchHelper.GetCaseModelItem(this.flowSwitchModelItem.Properties["Cases"], this.CaseObject);
169                             GenericFlowSwitchHelper.RemoveCase(this.flowSwitchModelItem.Properties["Cases"], this.CaseObject);
170                             this.flowSwitchModelItem.Properties["Default"].SetValue(flowNodeMI);
171                             this.UpdateViewState(this.CaseName + CaseViewStateKeyAppendString, DefaultConnectorViewStateKey);
172                             this.internalChange = true;
173                             es.Complete();
174                         }
175                     }
176                     else
177                     {
178                         this.internalDefaultCaseChange = true;
179                         this.IsDefaultCase = oldValue;
180                         throw FxTrace.Exception.AsError(new InvalidOperationException(SR.DefaultCaseExists));
181                     }
182                 }
183                 else
184                 {
185                     if (oldValue)
186                     {
187                         using (EditingScope es = (EditingScope)this.flowSwitchModelItem.BeginEdit(SR.FlowSwitchCaseRenameEditingScopeDesc))
188                         {
189                             ModelItem defaultCase = this.flowSwitchModelItem.Properties["Default"].Value;
190                             object uniqueCase = null;
191                             string errorMessage = string.Empty;
192                             Type typeArgument = typeof(T);
193                             if (GenericFlowSwitchHelper.CanBeGeneratedUniquely(typeArgument))
194                             {
195                                 string caseName = GenericFlowSwitchHelper.GetCaseName(this.flowSwitchModelItem.Properties["Cases"], typeArgument, out errorMessage);
196                                 if (!string.IsNullOrEmpty(errorMessage))
197                                 {
198                                     this.internalDefaultCaseChange = true;
199                                     this.IsDefaultCase = oldValue;
200                                     throw FxTrace.Exception.AsError(new InvalidOperationException(errorMessage));
201                                 }
202                                 uniqueCase = GenericFlowSwitchHelper.GetObject(caseName, typeArgument);
203
204                             }
205                             else
206                             {
207                                 FlowSwitchCaseEditorDialog editor = new FlowSwitchCaseEditorDialog(this.flowSwitchModelItem, ((WorkflowViewElement)this.flowSwitchModelItem.View).Context, this.flowSwitchModelItem.View, SR.ChangeCaseValue, this.flowSwitchModelItem.ItemType.GetGenericArguments()[0]);
208                                 editor.WindowSizeToContent = SizeToContent.WidthAndHeight;
209
210                                 if (!editor.ShowOkCancel())
211                                 {
212                                     this.internalDefaultCaseChange = true;
213                                     this.IsDefaultCase = oldValue;
214                                     return;
215                                 }
216                                 uniqueCase = editor.Case;
217                                 if (GenericFlowSwitchHelper.ContainsCaseKey(this.flowSwitchModelItem.Properties["Cases"], uniqueCase))
218                                 {
219                                     this.internalDefaultCaseChange = true;
220                                     this.IsDefaultCase = oldValue;
221                                     throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidFlowSwitchCaseMessage));
222                                 }
223                             }
224
225                             this.flowSwitchModelItem.Properties["Default"].SetValue(null);
226                             this.flowSwitchModelItem.Properties[FlowSwitchLabelFeature.DefaultCaseDisplayNamePropertyName].SetValue(FlowSwitchLabelFeature.DefaultCaseDisplayNameDefaultValue);
227                             
228                             this.internalChange = true;
229                             if (typeof(string) != typeof(T))
230                             {
231                                 this.ModelItem.Properties["Case"].SetValue(uniqueCase);
232                                 GenericFlowSwitchHelper.AddCase(this.flowSwitchModelItem.Properties["Cases"], uniqueCase, defaultCase.GetCurrentValue());
233                             }
234                             else
235                             {
236                                 this.ModelItem.Properties["Case"].SetValue(uniqueCase);
237                                 GenericFlowSwitchHelper.AddCase(this.flowSwitchModelItem.Properties["Cases"], uniqueCase, defaultCase.GetCurrentValue());
238                             }
239                             this.UpdateViewState(DefaultConnectorViewStateKey, GenericFlowSwitchHelper.GetString(uniqueCase, typeof(T)) + CaseViewStateKeyAppendString);
240                             es.Complete();
241                             this.internalChange = false;
242                         }
243                         this.internalDefaultCaseChange = false;
244                     }
245                 }
246             }
247             this.internalDefaultCaseChange = false;
248         }
249
250         protected bool IsUndoRedoInProgress()
251         {
252             bool isUndoRedoInProgress;
253             WorkflowViewElement designer = (WorkflowViewElement)this.flowSwitchModelItem.View;
254             if (designer == null)
255             {
256                 isUndoRedoInProgress = false;
257             }
258             else
259             {
260                 isUndoRedoInProgress = designer.Context.Services.GetService<UndoEngine>().IsUndoRedoInProgress;
261             }
262             return isUndoRedoInProgress;
263         }
264
265         void OnCasePropertyChanged(DependencyPropertyChangedEventArgs e)
266         {
267             bool isUndoRedoInProgress = this.IsUndoRedoInProgress();
268
269             if (!this.internalChange && !isUndoRedoInProgress)
270             {
271                 T oldValue = (T)e.OldValue;
272                 T newValue = (T)e.NewValue;
273
274                 if (newValue is string && newValue != null)
275                 {
276                     newValue = (T)((object)((string)((object)newValue)).Trim());
277                 }
278
279                 string oldViewStateKey = string.Empty;
280                 if (!this.ContainsKey(newValue))
281                 {
282                     using (EditingScope es = (EditingScope)this.flowSwitchModelItem.BeginEdit(SR.FlowSwitchCaseRenameEditingScopeDesc))
283                     {
284                         ModelItem flowElementMI = null;
285
286                         flowElementMI = GenericFlowSwitchHelper.GetCaseModelItem(this.flowSwitchModelItem.Properties["Cases"], oldValue);
287                         GenericFlowSwitchHelper.RemoveCase(this.flowSwitchModelItem.Properties["Cases"], oldValue);
288                         oldViewStateKey = GenericFlowSwitchHelper.GetString(oldValue, typeof(T)) + CaseViewStateKeyAppendString;
289                         //Add the new value
290                         GenericFlowSwitchHelper.AddCase(this.flowSwitchModelItem.Properties["Cases"], newValue, flowElementMI.GetCurrentValue());
291                         //Update the viewstate for the flowswitch.
292                         this.UpdateViewState(oldViewStateKey, GenericFlowSwitchHelper.GetString(newValue, typeof(T)) + CaseViewStateKeyAppendString);
293                         //Making sure the value for Case is always trimmed.
294                         this.internalChange = true;
295                         this.ModelItem.Properties["Case"].SetValue(newValue);
296                         es.Complete();
297                     }
298                 }
299                 else
300                 {
301                     this.internalChange = true;
302                     this.CaseObject = oldValue;
303                     throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidFlowSwitchCaseMessage));
304                 }
305             }
306             this.internalChange = false;
307         }
308
309         void UpdateViewState(string oldValue, string newValue)
310         {
311             EditingContext context = this.flowSwitchModelItem.GetEditingContext();
312             ViewStateService viewStateService = (ViewStateService)context.Services.GetService(typeof(ViewStateService));
313             if (viewStateService != null)
314             {
315                 object viewState = viewStateService.RetrieveViewState(this.flowSwitchModelItem, oldValue);
316                 if (viewState != null)
317                 {
318                     viewStateService.StoreViewStateWithUndo(this.flowSwitchModelItem, oldValue, null);
319                     viewStateService.StoreViewStateWithUndo(this.flowSwitchModelItem, newValue, viewState);
320                 }
321             }
322         }
323
324         static void OnCasePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
325         {
326             FlowSwitchLink<T> link = (FlowSwitchLink<T>)dependencyObject;
327             link.OnCasePropertyChanged(e);
328         }
329
330         static void OnIsDefaultCasePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
331         {
332             FlowSwitchLink<T> link = (FlowSwitchLink<T>)dependencyObject;
333             link.OnIsDefaultPropertyChanged(e);
334         }
335
336         public virtual MultiBinding CreateConnectorLabelTextBinding()
337         {
338             return new MultiBinding
339             {
340                 Converter = new FlowSwitchLinkMultiValueConverter(),
341                 ConverterParameter = this.CaseProperty.PropertyType,
342                 Bindings = 
343                 {
344                     new Binding { Source = this, Mode = BindingMode.OneWay, Path = new PropertyPath(this.CaseProperty) },
345                     new Binding { Source = this, Mode = BindingMode.OneWay, Path = new PropertyPath(this.IsDefaultCaseProperty) },
346                 },
347             };
348         }
349     }
350
351     class FlowSwitchDefaultLink<T> : FlowSwitchLink<T>, IFlowSwitchDefaultLink
352     {
353         static DependencyProperty defaultCaseDisplayNameProperty = DependencyProperty.Register(FlowSwitchLabelFeature.DefaultCaseDisplayNamePropertyName, typeof(string), typeof(FlowSwitchDefaultLink<T>), new FrameworkPropertyMetadata(new PropertyChangedCallback(FlowSwitchDefaultLink<T>.OnDefaultCaseDisplayNamePropertyChanged)));
354
355         public FlowSwitchDefaultLink(ModelItem flowSwitchMI, T caseValue, bool isDefault)
356             : base(flowSwitchMI, caseValue, isDefault)
357         {
358             this.internalChange = true;
359             this.DefaultCaseDisplayName = (string)this.flowSwitchModelItem.Properties[FlowSwitchLabelFeature.DefaultCaseDisplayNamePropertyName].Value.GetCurrentValue();
360             this.internalChange = false;
361         }
362
363         public string DefaultCaseDisplayName
364         {
365             get
366             {
367                 return (string)GetValue(FlowSwitchDefaultLink<T>.defaultCaseDisplayNameProperty);
368             }
369             set
370             {
371                 SetValue(FlowSwitchDefaultLink<T>.defaultCaseDisplayNameProperty, value);
372             }
373         }
374
375         DependencyProperty DefaultCaseDisplayNameProperty
376         {
377             get
378             {
379                 return defaultCaseDisplayNameProperty;
380             }
381         }
382
383         void OnDefaultCaseDisplayNamePropertyChanged(DependencyPropertyChangedEventArgs e)
384         {
385             bool isUndoRedoInProgress = this.IsUndoRedoInProgress();
386             if (!this.internalChange && !isUndoRedoInProgress)
387             {
388                 string newValue = (string)e.NewValue;
389                 this.internalChange = true;
390                 using (ModelEditingScope scope = this.flowSwitchModelItem.BeginEdit(SR.FlowSwitchDefaultCaseDisplayNameEditingScopeDesc))
391                 {
392                     this.flowSwitchModelItem.Properties[FlowSwitchLabelFeature.DefaultCaseDisplayNamePropertyName].SetValue(newValue);
393                     scope.Complete();
394                 }
395                 this.internalChange = false;
396             }
397         }
398
399         static void OnDefaultCaseDisplayNamePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
400         {
401             FlowSwitchDefaultLink<T> link = (FlowSwitchDefaultLink<T>)dependencyObject;
402             link.OnDefaultCaseDisplayNamePropertyChanged(e);
403         }
404
405         public override MultiBinding CreateConnectorLabelTextBinding()
406         {
407             MultiBinding result = base.CreateConnectorLabelTextBinding();
408             result.Bindings.Add(new Binding { Source = this, Mode = BindingMode.OneWay, Path = new PropertyPath(this.DefaultCaseDisplayNameProperty) });
409             return result;
410         }
411     }
412
413     class FlowSwitchCaseLink<T> : FlowSwitchLink<T>
414     {
415         public FlowSwitchCaseLink(ModelItem flowSwitchMI, T caseValue, bool isDefault)
416             : base(flowSwitchMI, caseValue, isDefault)
417         {
418         }
419
420         [BrowsableAttribute(true)]
421         public new T Case
422         {
423             get { return base.Case; }
424             set { base.Case = value; }
425         }
426     }
427 }