[reflection] Coop handles icalls in System.Reflection and System.RuntimeTypeHandle...
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / ActivityDesigner.cs
1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //----------------------------------------------------------------
4
5 namespace System.Activities.Presentation
6 {
7     using System.Activities.Presentation.Annotations;
8     using System.Activities.Presentation.Model;
9     using System.Activities.Presentation.View;
10     using System.Collections.Generic;
11     using System.Collections.ObjectModel;
12     using System.ComponentModel;
13     using System.Diagnostics.CodeAnalysis;
14     using System.Runtime;
15     using System.Text;
16     using System.Windows;
17     using System.Windows.Controls;
18     using System.Windows.Data;
19     using System.Windows.Input;
20     using System.Windows.Media;
21     using System.Windows.Threading;
22
23     public class ActivityDesigner : WorkflowViewElement
24     {
25         UserControl defaultDisplayNameReadOnlyControl;
26         TextBox defaultDisplayNameBox;
27         bool defaultDisplayNameReadOnlyControlMouseDown;
28
29         private AnnotationManager annotationManager;
30
31         [Fx.Tag.KnownXamlExternal]
32         public DrawingBrush Icon
33         {
34             get { return (DrawingBrush)GetValue(IconProperty); }
35             set { SetValue(IconProperty, value); }
36         }
37
38         public static readonly DependencyProperty IconProperty =
39             DependencyProperty.Register("Icon", typeof(DrawingBrush), typeof(ActivityDesigner), new UIPropertyMetadata(null));
40
41         internal static readonly DependencyProperty ActivityDelegatesProperty = DependencyProperty.Register("ActivityDelegates", typeof(ObservableCollection<ActivityDelegateInfo>), typeof(ActivityDesigner));
42
43         internal static readonly DependencyProperty HasActivityDelegatesProperty = DependencyProperty.Register("HasActivityDelegates", typeof(bool), typeof(ActivityDesigner));
44
45         [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.InitializeReferenceTypeStaticFieldsInline,
46             Justification = "Calls to OverrideMetadata for a dependency property should be done in the static constructor.")]
47         static ActivityDesigner()
48         {
49             DefaultStyleKeyProperty.OverrideMetadata(typeof(ActivityDesigner), new FrameworkPropertyMetadata(typeof(ActivityDesigner)));
50         }
51
52         public ActivityDesigner()
53         {
54             this.Loaded += (sender, args) =>
55             {
56                 this.SetupDefaultIcon();
57                 this.annotationManager.Initialize();
58             };
59
60             this.Unloaded += (sender, args) =>
61             {
62                 this.annotationManager.Uninitialize();
63             };
64
65             this.annotationManager = new AnnotationManager(this);
66         }
67
68         internal ObservableCollection<ActivityDelegateInfo> ActivityDelegates
69         {
70             get { return (ObservableCollection<ActivityDelegateInfo>)GetValue(ActivityDelegatesProperty); }
71             set { SetValue(ActivityDelegatesProperty, value); }
72         }
73
74         internal bool HasActivityDelegates
75         {
76             get { return (bool)GetValue(HasActivityDelegatesProperty); }
77             set { SetValue(HasActivityDelegatesProperty, value); }
78         }
79
80         protected override void OnModelItemChanged(object newItem)
81         {
82             base.OnModelItemChanged(newItem);
83
84             this.PopulateActivityDelegates((ModelItem)newItem);
85         }
86
87         private void PopulateActivityDelegates(ModelItem modelItem)
88         {
89             if (this.ActivityDelegates == null)
90             {
91                 this.ActivityDelegates = new ObservableCollection<ActivityDelegateInfo>();
92             }
93             else
94             {
95                 this.ActivityDelegates.Clear();
96             }
97
98             List<ActivityDelegateInfo> list = ActivityDelegateUtilities.CreateActivityDelegateInfo(modelItem);
99
100             if (list.Count > 0)
101             {
102                 foreach (ActivityDelegateInfo entry in list)
103                 {
104                     this.ActivityDelegates.Add(entry);
105                 }
106
107                 this.HasActivityDelegates = true;
108             }
109             else
110             {
111                 this.HasActivityDelegates = false;
112             }
113         }
114
115         protected override string GetAutomationIdMemberName()
116         {
117             return "DisplayName";
118         }
119
120         protected internal override string GetAutomationItemStatus()
121         {
122             StringBuilder descriptiveText = new StringBuilder();
123
124             EmitPropertyValuePair(descriptiveText, "IsPrimarySelection");
125             EmitPropertyValuePair(descriptiveText, "IsSelection");
126             EmitPropertyValuePair(descriptiveText, "IsCurrentLocation");
127             EmitPropertyValuePair(descriptiveText, "IsCurrentContext");
128             EmitPropertyValuePair(descriptiveText, "IsBreakpointEnabled");
129             EmitPropertyValuePair(descriptiveText, "IsBreakpointBounded");
130             EmitPropertyValuePair(descriptiveText, "ValidationState");
131             descriptiveText.Append(base.GetAutomationItemStatus());
132
133             return descriptiveText.ToString();
134         }
135
136         void EmitPropertyValuePair(StringBuilder description, string propertyName)
137         {
138             PropertyDescriptor property = TypeDescriptor.GetProperties(this.ModelItem)[propertyName];
139             object propertyValue = (property == null) ? null : property.GetValue(this.ModelItem);
140             string propertyValueString = propertyValue == null ? "null" : propertyValue.ToString();
141             description.AppendFormat("{0}={1} ", propertyName, propertyValueString);
142         }
143
144         public override void OnApplyTemplate()
145         {
146             base.OnApplyTemplate();
147
148             if (this.defaultDisplayNameBox != null)
149             {
150                 this.defaultDisplayNameBox.LostFocus -= new RoutedEventHandler(OnDefaultDisplayNameBoxLostFocus);
151                 this.defaultDisplayNameBox.ContextMenuOpening -= new ContextMenuEventHandler(OnDefaultDisplayNameBoxContextMenuOpening);
152             }
153             if (this.defaultDisplayNameReadOnlyControl != null)
154             {
155                 this.defaultDisplayNameReadOnlyControl.MouseLeftButtonDown -= new MouseButtonEventHandler(OnDefaultDisplayNameReadOnlyControlMouseLeftButtonDown);
156                 this.defaultDisplayNameReadOnlyControl.GotKeyboardFocus -= new KeyboardFocusChangedEventHandler(OnDefaultDisplayNameReadOnlyControlGotKeyboardFocus);
157             }
158
159             this.defaultDisplayNameReadOnlyControl = this.Template.FindName("DisplayNameReadOnlyControl_6E8E4954_F6B2_4c6c_9E28_33A7A78F1E81", this) as UserControl;
160             this.defaultDisplayNameBox = this.Template.FindName("DisplayNameBox_570C5205_7195_4d4e_953A_8E4B57EF7E7F", this) as TextBox;
161
162             UIElement defaultAnnotationIndicator = this.Template.FindName("AnnotationIndicator_570C5205_7195_4d4e_953A_8E4B57EF7E7F", this) as UIElement;
163             DockedAnnotationDecorator defaultDockedAnnotationDecorator = this.Template.FindName("DockedAnnotationDecorator_570C5205_7195_4d4e_953A_8E4B57EF7E7F", this) as DockedAnnotationDecorator;
164
165             if (defaultAnnotationIndicator != null && defaultDockedAnnotationDecorator != null)
166             {
167                 this.annotationManager.AnnotationVisualProvider = new ActivityDesignerAnnotationVisualProvider(new UIElementToAnnotationIndicatorAdapter(defaultAnnotationIndicator), defaultDockedAnnotationDecorator);
168             }
169
170             if (this.defaultDisplayNameBox != null && this.defaultDisplayNameReadOnlyControl != null)
171             {
172                 this.defaultDisplayNameBox.LostFocus += new RoutedEventHandler(OnDefaultDisplayNameBoxLostFocus);
173                 this.defaultDisplayNameBox.ContextMenuOpening += new ContextMenuEventHandler(OnDefaultDisplayNameBoxContextMenuOpening);
174                 this.defaultDisplayNameReadOnlyControl.MouseLeftButtonDown += new MouseButtonEventHandler(OnDefaultDisplayNameReadOnlyControlMouseLeftButtonDown);
175                 this.defaultDisplayNameReadOnlyControl.GotKeyboardFocus += new KeyboardFocusChangedEventHandler(OnDefaultDisplayNameReadOnlyControlGotKeyboardFocus);
176             }
177
178             Border titleBar = this.Template.FindName("TitleBar_C36A1CF2_4B36_4F0D_B427_9825C2E110DE", this) as Border;
179             if (titleBar != null)
180             {
181                 this.DragHandle = titleBar;
182             }
183         }
184
185         void OnDefaultDisplayNameReadOnlyControlGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
186         {
187             if (this.defaultDisplayNameBox != null && this.defaultDisplayNameReadOnlyControl != null)
188             {
189                 DesignerView designerView = this.Context.Services.GetService<DesignerView>();
190                 if (!designerView.IsReadOnly && !designerView.IsMultipleSelectionMode)
191                 {
192                     this.EnterDisplayNameEditMode();
193                 }
194             }
195         }
196
197         void OnDefaultDisplayNameReadOnlyControlMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
198         {
199             this.defaultDisplayNameReadOnlyControlMouseDown = true;
200         }
201
202         void OnDefaultDisplayNameBoxLostFocus(object sender, RoutedEventArgs e)
203         {
204             if (this.defaultDisplayNameBox != null && this.defaultDisplayNameReadOnlyControl != null)
205             {
206                 this.ExitDisplayNameEditMode();
207             }
208         }
209
210         void OnDefaultDisplayNameBoxContextMenuOpening(object sender, ContextMenuEventArgs e)
211         {
212             // to disable the context menu
213             e.Handled = true;
214         }
215
216         protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
217         {
218             this.defaultDisplayNameReadOnlyControlMouseDown = false;
219             base.OnPreviewMouseDown(e);
220         }
221
222         protected override void OnMouseUp(MouseButtonEventArgs e)
223         {
224             // We have to check the defaultDisplayNameReadOnlyControlMouseDown flag to determine whether the mouse is clicked on 
225             // the defaultDisplayNameReadOnlyControl. This is because the mouse capture is set on the WorkflowViewElement in 
226             // OnMouseDown, and as a result MouseUp event is not fired on the defaultDisplayNameReadOnlyControl.
227             if (this.defaultDisplayNameBox != null && this.defaultDisplayNameReadOnlyControl != null &&
228                 this.defaultDisplayNameReadOnlyControlMouseDown)
229             {
230                 this.defaultDisplayNameReadOnlyControlMouseDown = false;
231                 DesignerView designerView = this.Context.Services.GetService<DesignerView>();
232                 if (!designerView.IsReadOnly)
233                 {
234                     this.EnterDisplayNameEditMode();
235                 }
236             }
237             base.OnMouseUp(e);
238         }
239
240         void EnterDisplayNameEditMode()
241         {
242             this.defaultDisplayNameBox.Visibility = Visibility.Visible;
243             this.defaultDisplayNameReadOnlyControl.Visibility = Visibility.Collapsed;
244             this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (Action)(() =>
245             {
246                 Keyboard.Focus(this.defaultDisplayNameBox);
247                 this.defaultDisplayNameBox.ScrollToHome();
248             }));
249         }
250
251         void ExitDisplayNameEditMode()
252         {
253             this.defaultDisplayNameReadOnlyControl.Visibility = Visibility.Visible;
254             this.defaultDisplayNameBox.Visibility = Visibility.Collapsed;
255         }
256
257         private void SetupDefaultIcon()
258         {
259             if (this.Icon == null)
260             {
261                 this.Icon = GetDefaultIcon();
262             }
263         }
264
265         internal DrawingBrush GetDefaultIcon()
266         {
267             DrawingBrush icon = null;
268
269             // Look for a named icon if this property is not set
270
271             if (this.ModelItem != null)
272             {
273                 string iconKey = this.ModelItem.ItemType.IsGenericType ? this.ModelItem.ItemType.GetGenericTypeDefinition().Name : this.ModelItem.ItemType.Name;
274                 int genericParamsIndex = iconKey.IndexOf('`');
275                 if (genericParamsIndex > 0)
276                 {
277                     iconKey = iconKey.Remove(genericParamsIndex);
278                 }
279                 iconKey = iconKey + "Icon";
280                 try
281                 {
282                     if (WorkflowDesignerIcons.IconResourceDictionary.Contains(iconKey))
283                     {
284                         object resourceItem = WorkflowDesignerIcons.IconResourceDictionary[iconKey];
285                         if (resourceItem is DrawingBrush)
286                         {
287                             icon = (DrawingBrush)resourceItem;
288                         }
289                     }
290                 }
291                 catch (ResourceReferenceKeyNotFoundException) { }
292                 catch (InvalidCastException) { }
293             }
294             if (icon == null)
295             {
296                 // as a last resort fall back to the default generic leaf activity icon.
297                 icon = WorkflowDesignerIcons.Activities.DefaultCustomActivity;
298             }
299
300             return icon;
301         }
302
303         protected internal override void OnEditAnnotation()
304         {
305             this.annotationManager.OnEditAnnotation();
306         }
307
308         private class ActivityDesignerAnnotationVisualProvider : IAnnotationVisualProvider
309         {
310             private DockedAnnotationDecorator decorator;
311             private IAnnotationIndicator indicator;
312             private IFloatingAnnotation floatingAnnotation;
313             private IDockedAnnotation dockedAnnotation;
314
315             public ActivityDesignerAnnotationVisualProvider(IAnnotationIndicator indicator, DockedAnnotationDecorator decorator)
316             {
317                 this.indicator = indicator;
318                 this.decorator = decorator;
319             }
320
321             public IAnnotationIndicator GetAnnotationIndicator()
322             {
323                 return this.indicator;
324             }
325
326             public IFloatingAnnotation GetFloatingAnnotation()
327             {
328                 if (this.floatingAnnotation == null)
329                 {
330                     this.floatingAnnotation = new FloatingAnnotationView();
331                 }
332
333                 return this.floatingAnnotation;
334             }
335
336             public IDockedAnnotation GetDockedAnnotation()
337             {
338                 if (this.dockedAnnotation == null)
339                 {
340                     DockedAnnotationView view = new DockedAnnotationView();
341
342                     Binding annotationTextbinding = new Binding("ModelItem.AnnotationText");
343                     view.SetBinding(DockedAnnotationView.AnnotationTextProperty, annotationTextbinding);
344
345                     Binding maxWidthBinding = new Binding("ActualWidth");
346                     maxWidthBinding.ElementName = "annotationWidthSetter";
347                     view.SetBinding(DockedAnnotationView.MaxWidthProperty, maxWidthBinding);
348
349                     this.dockedAnnotation = view;
350                     this.decorator.Child = view;
351                 }
352
353                 return this.dockedAnnotation;
354             }
355         }
356     }
357 }