[reflection] Coop handles icalls in System.Reflection and System.RuntimeTypeHandle...
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / Toolbox / ToolboxControl.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4
5
6 namespace System.Activities.Presentation.Toolbox
7 {
8     using System;
9     using System.Activities.Presentation.View;
10     using System.Collections.Generic;
11     using System.Collections.Specialized;
12     using System.ComponentModel;
13     using System.Diagnostics.CodeAnalysis;
14     using System.Drawing.Design;
15     using System.Runtime;
16     using System.Windows;
17     using System.Windows.Controls;
18     using System.Windows.Input;
19     using System.Windows.Markup;
20
21     // This class is responsible for rendering cate----ezed tools collection
22     // It also provides methods for notifing user about tool selection/creation events
23
24     [TemplatePart(Name = "PART_SearchBox"), TemplatePart(Name = "PART_Tools")]
25     [ContentProperty("Categories")]
26     sealed public partial class ToolboxControl : Control
27     {
28         public static readonly DependencyProperty ToolboxFileProperty =
29                 DependencyProperty.Register("ToolboxFile",
30                 typeof(string),
31                 typeof(ToolboxControl),
32                 new PropertyMetadata(
33                 string.Empty,
34                 new PropertyChangedCallback(OnToolboxFileChanged)));
35
36         static readonly DependencyPropertyKey SelectedToolPropertyKey =
37                 DependencyProperty.RegisterReadOnly("SelectedTool",
38                 typeof(ToolboxItem),
39                 typeof(ToolboxControl),
40                 new PropertyMetadata(
41                 null,
42                 new PropertyChangedCallback(OnToolSelected)));
43
44         public static readonly DependencyProperty SelectedToolProperty = SelectedToolPropertyKey.DependencyProperty;
45
46         public static readonly DependencyProperty ToolItemStyleProperty =
47                 DependencyProperty.Register("ToolItemStyle",
48                 typeof(Style),
49                 typeof(ToolboxControl),
50                 new UIPropertyMetadata(null));
51
52         public static readonly DependencyProperty CategoryItemStyleProperty =
53                 DependencyProperty.Register("CategoryItemStyle",
54                 typeof(Style),
55                 typeof(ToolboxControl),
56                 new UIPropertyMetadata(null));
57
58         public static readonly DependencyProperty ToolTemplateProperty =
59                 DependencyProperty.Register("ToolTemplate",
60                 typeof(DataTemplate),
61                 typeof(ToolboxControl),
62                 new UIPropertyMetadata(null));
63
64         public static readonly DependencyProperty CategoryTemplateProperty =
65                 DependencyProperty.Register("CategoryTemplate",
66                 typeof(DataTemplate),
67                 typeof(ToolboxControl),
68                 new UIPropertyMetadata(null));
69
70         public static readonly RoutedEvent ToolCreatedEvent =
71                 EventManager.RegisterRoutedEvent("ToolCreated",
72                 RoutingStrategy.Bubble,
73                 typeof(ToolCreatedEventHandler),
74                 typeof(ToolboxControl));
75
76         public static readonly RoutedEvent ToolSelectedEvent =
77                 EventManager.RegisterRoutedEvent("ToolSelected",
78                 RoutingStrategy.Bubble,
79                 typeof(RoutedEventHandler),
80                 typeof(ToolboxControl));
81
82
83         internal TextBox searchBox;
84         TreeView toolsTreeView;
85         ToolboxCategoryItems categories;
86
87         [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
88         static ToolboxControl()
89         {
90             DefaultStyleKeyProperty.OverrideMetadata(typeof(ToolboxControl), new FrameworkPropertyMetadata(typeof(ToolboxControl)));
91         }
92
93         public ToolboxControl()
94         {
95             var callback = new NotifyCollectionChangedEventHandler(this.OnCategoryCollectionChanged);
96             this.categories = new ToolboxCategoryItems(callback);
97         }
98
99         public event ToolCreatedEventHandler ToolCreated
100         {
101             add
102             {
103                 AddHandler(ToolCreatedEvent, value);
104             }
105             remove
106             {
107                 RemoveHandler(ToolCreatedEvent, value);
108             }
109         }
110
111         public event RoutedEventHandler ToolSelected
112         {
113             add
114             {
115                 AddHandler(ToolSelectedEvent, value);
116             }
117             remove
118             {
119                 RemoveHandler(ToolSelectedEvent, value);
120             }
121         }
122
123         [Fx.Tag.KnownXamlExternal]
124         [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
125         [SuppressMessage(FxCop.Category.Usage, "CA2227:CollectionPropertiesShouldBeReadOnly",
126             Justification = "The setter implemenation is required for XAML support. The setter doesn't replace the collection instance, but copies its content to internal collection")]
127         public ToolboxCategoryItems Categories
128         {
129             get { return this.categories; }
130             set 
131             {
132                 this.categories.Clear();
133                 if (null != value)
134                 {
135                     foreach (var category in value)
136                     {
137                         this.categories.Add(category);
138                     }
139                 }
140             }
141         }
142
143         public string ToolboxFile
144         {
145             get { return (string)GetValue(ToolboxFileProperty); }
146             set { SetValue(ToolboxFileProperty, value); }
147         }
148
149         [Fx.Tag.KnownXamlExternal]
150         public ToolboxItem SelectedTool
151         {
152             get { return (ToolboxItem)GetValue(SelectedToolProperty); }
153             private set { SetValue(SelectedToolPropertyKey, value); }
154         }
155
156         [Fx.Tag.KnownXamlExternal]
157         public Style ToolItemStyle
158         {
159             get { return (Style)GetValue(ToolItemStyleProperty); }
160             set { SetValue(ToolItemStyleProperty, value); }
161         }
162
163         [Fx.Tag.KnownXamlExternal]
164         public Style CategoryItemStyle
165         {
166             get { return (Style)GetValue(CategoryItemStyleProperty); }
167             set { SetValue(CategoryItemStyleProperty, value); }
168         }
169
170         [Fx.Tag.KnownXamlExternal]
171         public DataTemplate ToolTemplate
172         {
173             get { return (DataTemplate)GetValue(ToolTemplateProperty); }
174             set { SetValue(ToolTemplateProperty, value); }
175         }
176
177         [Fx.Tag.KnownXamlExternal]
178         public DataTemplate CategoryTemplate
179         {
180             get { return (DataTemplate)GetValue(CategoryTemplateProperty); }
181             set { SetValue(CategoryTemplateProperty, value); }
182         }
183
184         [Fx.Tag.KnownXamlExternal]
185         public WorkflowDesigner AssociatedDesigner
186         {
187             get;
188             set;
189         }
190
191         static void OnToolboxFileChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
192         {
193             ToolboxControl toolboxControl = sender as ToolboxControl;
194             string fileName = args.NewValue as string;
195             if (null == toolboxControl || null == fileName)
196             {
197                 throw FxTrace.Exception.AsError(new ArgumentNullException(null == toolboxControl ? "toolboxControl" : "fileName"));
198             }
199
200             try
201             {
202                 ToolboxItemLoader loader = ToolboxItemLoader.GetInstance();
203                 loader.LoadToolboxItems(fileName, toolboxControl.categories, false);
204             }
205             catch
206             {
207                 if (!DesignerProperties.GetIsInDesignMode(toolboxControl))
208                 {
209                     throw;
210                 }
211             }
212         }
213
214         static void OnToolSelected(DependencyObject sender, DependencyPropertyChangedEventArgs args)
215         {
216             ToolboxControl toolboxControl = sender as ToolboxControl;
217             if (null == toolboxControl)
218             {
219                 throw FxTrace.Exception.AsError(new ArgumentNullException("sender"));
220             }
221             if (null != toolboxControl.SelectedTool)
222             {
223                 toolboxControl.RaiseEvent(new RoutedEventArgs(ToolSelectedEvent, toolboxControl));
224             }
225         }
226
227         public override void OnApplyTemplate()
228         {
229             base.OnApplyTemplate();
230             //template is applied, look for required controls within it
231             this.searchBox = this.Template.FindName("PART_SearchBox", this) as TextBox;
232             this.toolsTreeView = this.Template.FindName("PART_Tools", this) as TreeView;
233             //if tools tree view exists - assign style and container selectors (there are different styles
234             //for Cateogries and Tools
235             if (null != this.toolsTreeView)
236             {
237                 this.toolsTreeView.ItemsSource = this.Categories;
238                 this.toolsTreeView.ItemContainerStyleSelector = new TreeViewContainerStyleSelector(this);
239                 this.toolsTreeView.ItemTemplateSelector = new TreeViewTemplateSelector(this);
240                 this.toolsTreeView.SelectedItemChanged += (s, e) =>
241                     {
242                         var toolWrapper = e.NewValue as ToolboxItemWrapper;
243                         this.SelectedTool = toolWrapper != null ? toolWrapper.ToolboxItem : null;
244                     };
245             }
246         }
247
248         protected override void OnPreviewKeyDown(KeyEventArgs e)
249         {
250             switch (e.Key)
251             {
252                 case Key.Up:
253                 case Key.Down:
254                     if (null != this.searchBox && 
255                         e.OriginalSource == this.searchBox && 
256                         null != this.toolsTreeView)
257                     {
258                         this.toolsTreeView.Focus();
259                     }
260                     break;
261
262                 case Key.Enter:
263                     ToolboxItemCreated();
264                     e.Handled = true;
265                     break;
266
267                 default:
268                     if (null != this.searchBox && e.Source != this.searchBox)
269                     {
270                         if (((e.Key >= Key.A && e.Key <= Key.Z) || (e.Key >= Key.D0 && e.Key <= Key.D9)) &&
271                             (e.KeyboardDevice.Modifiers == ModifierKeys.None || e.KeyboardDevice.Modifiers == ModifierKeys.Shift))
272                         {
273                             this.searchBox.Focus();
274                         }
275                     }
276                     break;
277             }
278             base.OnPreviewKeyDown(e);
279         }
280
281         void OnCategoryCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
282         {
283             switch (e.Action)
284             {
285                 case NotifyCollectionChangedAction.Add:
286                     foreach (ToolboxCategory category in e.NewItems)
287                     {
288                         if (null == category)
289                         {
290                             throw FxTrace.Exception.ArgumentNull("category");
291                         }
292
293                         var listener = new NotifyCollectionChangedEventHandler(OnToolsCollectionChange);
294                         category.HandleToolCollectionNotification(listener, true);
295
296                         var items = new List<ToolboxItemWrapper>();
297                         foreach (ToolboxItemWrapper toolWrapper in category.Tools)
298                         {
299                             items.Add(toolWrapper);
300                         }
301                         OnToolsCollectionChange(category,
302                             new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, items, 0));
303                     }
304                     break;
305
306                 default:
307                     break;
308             }
309             if (null != this.toolsTreeView)
310             {
311                 this.toolsTreeView.ItemsSource = null;
312                 this.toolsTreeView.ItemsSource = this.categories;
313             }
314         }
315
316
317         void OnToolsCollectionChange(object sender, NotifyCollectionChangedEventArgs args)
318         {
319             switch (args.Action)
320             {
321                 case NotifyCollectionChangedAction.Add:
322                     foreach (ToolboxItemWrapper tool in args.NewItems)
323                     {
324                         if (null == tool)
325                         {
326                             throw FxTrace.Exception.ArgumentNull("tool");
327                         }
328                         tool.PropertyChanged += new PropertyChangedEventHandler(OnToolPropertyChanged);
329                         OnToolPropertyChanged(tool, null);
330                     }
331                     break;
332
333                 default:
334                     break;
335             }
336         }
337
338         void OnToolPropertyChanged(object sender, PropertyChangedEventArgs e)
339         {
340             try
341             {
342                 ToolboxItemWrapper tool = (ToolboxItemWrapper)sender;
343                 tool.ResolveToolboxItem();
344             }
345             catch
346             {
347                 if (!DesignerProperties.GetIsInDesignMode(this))
348                 {
349                     throw;
350                 }
351             }
352         }
353
354         internal void OnToolMouseMove(object sender, MouseEventArgs args)
355         {
356             ToolboxItem tool;
357             ToolboxItemWrapper toolWrapper;
358             if (args.LeftButton == MouseButtonState.Pressed && TryGetSelectedToolboxItem(out tool, out toolWrapper))
359             {
360                 IDataObject dataObject = toolWrapper.DataObject ?? new DataObject();
361                 dataObject.SetData(DragDropHelper.WorkflowItemTypeNameFormat, toolWrapper.Type.AssemblyQualifiedName);
362                 DragDrop.DoDragDrop(this, dataObject, DragDropEffects.Link | DragDropEffects.Copy);
363             }
364         }
365
366         internal void OnTreeViewDoubleClick(object sender, MouseEventArgs args)
367         {
368             ToolboxItemCreated();
369         }
370
371         void ToolboxItemCreated()
372         {
373             ToolboxItem tool;
374             ToolboxItemWrapper toolWrapper;
375             if (TryGetSelectedToolboxItem(out tool, out toolWrapper))
376             {
377                 if (null != this.AssociatedDesigner && null != this.AssociatedDesigner.Context)
378                 {
379                     DesignerView target = this.AssociatedDesigner.Context.Services.GetService<DesignerView>();
380                     IDataObject dataObject = toolWrapper.DataObject ?? new DataObject();
381                     dataObject.SetData(DragDropHelper.WorkflowItemTypeNameFormat, toolWrapper.Type.AssemblyQualifiedName);
382                     ((RoutedCommand)DesignerView.CreateWorkflowElementCommand).Execute(dataObject, target);
383                 }
384                 ToolCreatedEventArgs args = new ToolCreatedEventArgs(ToolCreatedEvent, this, tool.CreateComponents());
385                 RaiseEvent(args);
386             }
387         }
388
389         bool TryGetSelectedToolboxItem(out ToolboxItem toolboxItem, out ToolboxItemWrapper toolboxItemWrapper)
390         {
391             toolboxItem = null;
392             toolboxItemWrapper = null;
393             if (null != this.toolsTreeView && null != this.toolsTreeView.SelectedItem)
394             {
395                 ToolboxItemWrapper tool = this.toolsTreeView.SelectedItem as ToolboxItemWrapper;
396                 if (null != tool && null != tool.ToolboxItem)
397                 {
398                     toolboxItem = tool.ToolboxItem;
399                     toolboxItemWrapper = tool;
400
401                 }
402             }
403             return (null != toolboxItem);
404         }
405
406     }
407 }