[runtime] Fix corlib out of date error with disabled COM
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / View / Selection.cs
1 namespace System.Activities.Presentation.View {
2
3     using System.Runtime;
4     using System.Diagnostics.CodeAnalysis;
5     using System.Activities.Presentation;
6     using System.Activities.Presentation.Model;
7
8     using System.Activities.Presentation.Internal.Properties;
9
10     using System;
11     using System.Collections;
12     using System.Collections.Generic;
13     using System.ComponentModel;
14
15     /// <summary>
16     /// The Selection class defines a selection of objects.  Selections
17     /// consist of zero or more objects.  The first object in a selection
18     /// is defined as the "primary" selection, which is used when
19     /// one object in a group must be used as a key.
20     /// </summary>
21     [SuppressMessage(FxCop.Category.Naming, "CA1724:TypeNamesShouldNotMatchNamespaces",
22         Justification = "Code imported from Cider; keeping changes to a minimum as it impacts xaml files as well")]
23     public class Selection : ContextItem
24     {
25
26         private ICollection<ModelItem> _selectedObjects;
27
28         /// <summary>
29         /// Creates an empty Selection object.
30         /// </summary>
31         public Selection() {
32             _selectedObjects = new ModelItem[0];
33         }
34
35         /// <summary>
36         /// Creates a collection object comprising the given
37         /// selected objects.  The first object in the enumeration
38         /// is considered the "primary" selection.
39         /// </summary>
40         /// <param name="selectedObjects">An enumeration of objects that should be selected.</param>
41         /// <exception cref="ArgumentNullException">If selectedObjects is null.</exception>
42         public Selection(IEnumerable<ModelItem> selectedObjects) {
43             if (selectedObjects == null) {
44                 throw FxTrace.Exception.ArgumentNull("selectedObjects");
45             }
46
47             List<ModelItem> selection = new List<ModelItem>();
48             selection.AddRange(selectedObjects);
49             _selectedObjects = selection;
50         }
51
52         /// <summary>
53         /// Creates a collection object comprising the given
54         /// selected objects.  The first object in the enumeration
55         /// is considered the "primary" selection.
56         /// </summary>
57         /// <param name="selectedObjects">An enumeration of objects that should be selected.</param>
58         /// <param name="match">If provided, only those objects in selectedObjects that match the predicate will be added to the selection.</param>
59         /// <exception cref="ArgumentNullException">If selectedObjects or match is null.</exception>
60         public Selection(IEnumerable<ModelItem> selectedObjects, Predicate<ModelItem> match) {
61             if (selectedObjects == null) throw FxTrace.Exception.ArgumentNull("selectedObjects");
62             if (match == null) throw FxTrace.Exception.ArgumentNull("match");
63
64             List<ModelItem> selection = new List<ModelItem>();
65             foreach (ModelItem o in selectedObjects) {
66                 if (match(o)) {
67                     selection.Add(o);
68                 }
69             }
70
71             _selectedObjects = selection;
72         }
73
74         /// <summary>
75         /// Creates a collection object comprising the given
76         /// selected objects.  The first object in the enumeration
77         /// is considered the "primary" selection.
78         /// </summary>
79         /// <param name="selectedObjects">An enumeration of objects that should be selected.</param>
80         /// <exception cref="ArgumentNullException">If selectedObjects is null.</exception>
81         public Selection(IEnumerable selectedObjects) {
82             if (selectedObjects == null) throw FxTrace.Exception.ArgumentNull("selectedObjects");
83
84             List<ModelItem> selection = new List<ModelItem>();
85             foreach (object o in selectedObjects) {
86                 ModelItem item = o as ModelItem;
87                 if (item != null) {
88                     selection.Add(item);
89                 }
90             }
91
92             _selectedObjects = selection;
93         }
94
95         /// <summary>
96         /// Creates a collection object comprising the given
97         /// selected objects.  The first object in the enumeration
98         /// is considered the "primary" selection.
99         /// </summary>
100         /// <param name="selectedObjects">An enumeration of objects that should be selected.</param>
101         /// <param name="match">If provided, only those objects in selectedObjects that match the predicate will be added to the selection.</param>
102         /// <exception cref="ArgumentNullException">If selectedObjects is null.</exception>
103         public Selection(IEnumerable selectedObjects, Predicate<ModelItem> match) {
104             if (selectedObjects == null) throw FxTrace.Exception.ArgumentNull("selectedObjects");
105             if (match == null) throw FxTrace.Exception.ArgumentNull("match");
106
107             List<ModelItem> selection = new List<ModelItem>();
108             foreach (object o in selectedObjects) {
109                 ModelItem item = o as ModelItem;
110                 if (item != null && match(item)) {
111                     selection.Add(item);
112                 }
113             }
114
115             _selectedObjects = selection;
116         }
117
118         /// <summary>
119         /// Creates a collection object comprising the given
120         /// objects.  The first object is considered the "primary"
121         /// selection.
122         /// </summary>
123         /// <param name="selectedObjects">A parameter array of objects that should be selected.</param>
124         /// <exception cref="ArgumentNullException">If selectedObjects is null.</exception>
125         public Selection(params ModelItem[] selectedObjects)
126             : this((IEnumerable<ModelItem>)selectedObjects) {
127         }
128
129         /// <summary>
130         /// The primary selection.  Some functions require a "key"
131         /// element.  For example, an "align lefts" command needs
132         /// to know which element's "left" to align to.
133         /// </summary>
134         public ModelItem PrimarySelection {
135             get {
136                 foreach (ModelItem obj in _selectedObjects) {
137                     return obj;
138                 }
139
140                 return null;
141             }
142         }
143
144         /// <summary>
145         /// The enumeration of selected objects.
146         /// </summary>
147         public IEnumerable<ModelItem> SelectedObjects {
148             get {
149                 return _selectedObjects;
150             }
151         }
152
153         /// <summary>
154         /// The number of objects that are currently selected into
155         /// this selection.
156         /// </summary>
157         public int SelectionCount {
158             get { return _selectedObjects.Count; }
159         }
160
161         /// <summary>
162         /// Override of ContextItem's ItemType
163         /// property.  The ItemType of Selection is
164         /// always "typeof(Selection)".
165         /// </summary>
166         public sealed override Type ItemType {
167             get {
168                 return typeof(Selection);
169             }
170         }
171         
172         
173         /// <summary>
174         /// Selection helper method.  This takes the existing selection in the
175         /// context and selects an item into it.  If the item is already in the
176         /// selection the selection is preserved and the item is promoted
177         /// to the primary selection.
178         /// </summary>
179         /// <param name="context">The editing context to apply this selection change to.</param>
180         /// <param name="itemToSelect">The item to select.</param>
181         /// <returns>A Selection object that contains the new selection.</returns>
182         /// <exception cref="ArgumentNullException">If context or itemToSelect is null.</exception>
183         public static Selection Select(EditingContext context, ModelItem itemToSelect) {
184
185             if (context == null) throw FxTrace.Exception.ArgumentNull("context");
186             if (itemToSelect == null) throw FxTrace.Exception.ArgumentNull("itemToSelect");
187
188             Selection existing = context.Items.GetValue<Selection>();
189
190             // short cut if we're already in the right state.
191             if (existing.PrimarySelection == itemToSelect) {
192                 return existing;
193             }
194
195             Selection selection = null;
196
197             foreach (ModelItem obj in existing.SelectedObjects) {
198                 if (obj == itemToSelect) {
199                     List<ModelItem> list = new List<ModelItem>(existing.SelectedObjects);
200                     list.Remove(itemToSelect);
201                     list.Insert(0, itemToSelect);
202                     selection = new Selection(list);
203                 }
204             }
205
206             if (selection == null) {
207                 selection = new Selection(itemToSelect);
208             }
209             
210             context.Items.SetValue(selection);
211             return selection;
212         }
213
214         /// <summary>
215         /// Selection helper method.  This sets itemToSelect into the selection.
216         /// Any existing items are deselected.
217         /// </summary>
218         /// <param name="context">The editing context to apply this selection change to.</param>
219         /// <param name="itemToSelect">The item to select.</param>
220         /// <returns>A Selection object that contains the new selection.</returns>
221         /// <exception cref="ArgumentNullException">If context or itemToSelect is null.</exception>
222         public static Selection SelectOnly(EditingContext context, ModelItem itemToSelect) {
223
224             if (context == null) throw FxTrace.Exception.ArgumentNull("context");
225             if (itemToSelect == null) throw FxTrace.Exception.ArgumentNull("itemToSelect");
226
227             // Check to see if only this object is selected.  If so, bail.
228             Selection existing = context.Items.GetValue<Selection>();
229             if (existing.PrimarySelection == itemToSelect) {
230                 IEnumerator<ModelItem> en = existing.SelectedObjects.GetEnumerator();
231                 en.MoveNext();
232                 if (!en.MoveNext()) {
233                     return existing;
234                 }
235             }
236
237             DesignerPerfEventProvider designerPerfEventProvider = context.Services.GetService<DesignerPerfEventProvider>();
238             if (designerPerfEventProvider != null)
239             {
240                 designerPerfEventProvider.SelectionChangedStart();
241             }
242
243             Selection selection = new Selection(itemToSelect);
244             context.Items.SetValue(selection);
245             return selection;
246         }
247
248         /// <summary>
249         /// Helper method that subscribes to selection change events.
250         /// </summary>
251         /// <param name="context">The editing context to listen to.</param>
252         /// <param name="handler">The handler to be invoked when the selection changes.</param>
253         public static void Subscribe(EditingContext context, SubscribeContextCallback<Selection> handler) {
254             if (context == null) throw FxTrace.Exception.ArgumentNull("context");
255             if (handler == null) throw FxTrace.Exception.ArgumentNull("handler");
256             context.Items.Subscribe<Selection>(handler);
257         }
258
259         /// <summary>
260         /// Selection helper method.  This takes the existing selection in the
261         /// context and creates a new selection that contains the toggled
262         /// state of the item.  If the item is to be
263         /// added to the selection, it is added as the primary selection.
264         /// </summary>
265         /// <param name="context">The editing context to apply this selection change to.</param>
266         /// <param name="itemToToggle">The item to toggle selection for.</param>
267         /// <returns>A Selection object that contains the new selection.</returns>
268         /// <exception cref="ArgumentNullException">If context or itemToToggle is null.</exception>
269         public static Selection Toggle(EditingContext context, ModelItem itemToToggle) {
270             
271             if (context == null) throw FxTrace.Exception.ArgumentNull("context");
272             if (itemToToggle == null) throw FxTrace.Exception.ArgumentNull("itemToToggle");
273
274             Selection existing = context.Items.GetValue<Selection>();
275
276             // Is the item already in the selection?  If so, remove it.
277             // If not, add it to the beginning.
278
279             List<ModelItem> list = new List<ModelItem>(existing.SelectedObjects);
280             if (list.Contains(itemToToggle)) {
281                 list.Remove(itemToToggle);
282             }
283             else {
284                 list.Insert(0, itemToToggle);
285             }
286
287             Selection selection = new Selection(list);
288             context.Items.SetValue(selection);
289             return selection;
290         }
291
292         /// <summary>
293         /// Selection helper method.  This takes the existing selection in the
294         /// context and creates a new selection that contains the original
295         /// selection and the itemToAdd.  If itemToAdd is already in the 
296         /// original selection it is promoted to the primary selection.
297         /// </summary>
298         /// <param name="context">The editing context to apply this selection change to.</param>
299         /// <param name="itemToAdd">The item to add to the selection.</param>
300         /// <returns>A Selection object that contains the new selection.</returns>
301         /// <exception cref="ArgumentNullException">If context or itemToAdd is null.</exception>
302         public static Selection Union(EditingContext context, ModelItem itemToAdd) {
303
304             if (context == null) throw FxTrace.Exception.ArgumentNull("context");
305             if (itemToAdd == null) throw FxTrace.Exception.ArgumentNull("itemToAdd");
306
307             Selection existing = context.Items.GetValue<Selection>();
308
309             // short cut if we're already in the right state.
310             if (existing.PrimarySelection == itemToAdd) {
311                 return existing;
312             }
313
314             // Is the item already in the selection?  If not, add it.
315             List<ModelItem> list = new List<ModelItem>(existing.SelectedObjects);
316             if (list.Contains(itemToAdd)) {
317                 list.Remove(itemToAdd);
318             }
319
320             list.Insert(0, itemToAdd);
321             Selection selection = new Selection(list);
322             context.Items.SetValue(selection);
323             return selection;
324         }
325
326         internal static bool MultipleObjectsSelected(EditingContext context)
327         {
328             Selection selection = context.Items.GetValue<Selection>();
329             if (selection != null && selection.SelectionCount > 1)
330             {
331                 return true;
332             }
333             return false;
334         }
335
336         internal static bool IsSelection(ModelItem item)
337         {
338             PropertyDescriptor descriptor = TypeDescriptor.GetProperties(item)["IsSelection"];
339             if (descriptor != null)
340             {
341                 return (bool)descriptor.GetValue(item);
342             }
343             return false;
344         }
345
346         internal static bool IsPrimarySelection(ModelItem item)
347         {
348             PropertyDescriptor descriptor = TypeDescriptor.GetProperties(item)["IsPrimarySelection"];
349             if (descriptor != null)
350             {
351                 return (bool)descriptor.GetValue(item);
352             }
353             return false;
354         }
355
356         /// <summary>
357         /// Helper method that removes a previously added selection change event.
358         /// </summary>
359         /// <param name="context">The editing context to listen to.</param>
360         /// <param name="handler">The handler to be invoked when the selection changes.</param>
361         public static void Unsubscribe(EditingContext context, SubscribeContextCallback<Selection> handler) {
362             if (context == null) throw FxTrace.Exception.ArgumentNull("context");
363             if (handler == null) throw FxTrace.Exception.ArgumentNull("handler");
364             context.Items.Unsubscribe<Selection>(handler);
365         }
366     }
367 }