Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Workflow.ComponentModel / Shared / Walker.cs
1 // Copyright (c) Microsoft Corporation. All rights reserved. 
2 //  
3 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
4 // WHETHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
5 // WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 
6 // THE ENTIRE RISK OF USE OR RESULTS IN CONNECTION WITH THE USE OF THIS CODE 
7 // AND INFORMATION REMAINS WITH THE USER. 
8
9
10 /*********************************************************************
11  * NOTE: A copy of this file exists at: WF\Activities\Common
12  * The two files must be kept in sync.  Any change made here must also
13  * be made to WF\Activities\Common\Walker.cs
14 *********************************************************************/
15 namespace System.Workflow.ComponentModel
16 {
17     #region Imports
18
19     using System;
20     using System.Collections;
21     using System.Collections.Generic;
22     using System.Reflection;
23     using System.ComponentModel;
24     using System.Diagnostics.CodeAnalysis;
25
26     #endregion
27
28     // Returns true to continue the walk, false to stop.
29     internal delegate void WalkerEventHandler(Walker walker, WalkerEventArgs eventArgs);
30
31     internal enum WalkerAction
32     {
33         Continue = 0,
34         Skip = 1,
35         Abort = 2
36     }
37     #region Class WalkerEventArgs
38
39     internal sealed class WalkerEventArgs : EventArgs
40     {
41         private Activity currentActivity = null;
42         private object currentPropertyOwner = null;
43         private PropertyInfo currentProperty = null;
44         private object currentValue = null;
45         private WalkerAction action = WalkerAction.Continue;
46
47         internal WalkerEventArgs(Activity currentActivity)
48         {
49             this.currentActivity = currentActivity;
50             this.currentPropertyOwner = null;
51             this.currentProperty = null;
52             this.currentValue = null;
53         }
54
55         internal WalkerEventArgs(Activity currentActivity, object currentValue, PropertyInfo currentProperty, object currentPropertyOwner)
56             : this(currentActivity)
57         {
58             this.currentPropertyOwner = currentPropertyOwner;
59             this.currentProperty = currentProperty;
60             this.currentValue = currentValue;
61         }
62
63         public WalkerAction Action
64         {
65             get
66             {
67                 return this.action;
68             }
69             set
70             {
71                 this.action = value;
72             }
73         }
74
75         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
76         public PropertyInfo CurrentProperty
77         {
78             get
79             {
80                 return this.currentProperty;
81             }
82         }
83
84         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
85         public object CurrentPropertyOwner
86         {
87             get
88             {
89                 return this.currentPropertyOwner;
90             }
91         }
92
93         [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
94         public object CurrentValue
95         {
96             get
97             {
98                 return this.currentValue;
99             }
100         }
101
102         public Activity CurrentActivity
103         {
104             get
105             {
106                 return this.currentActivity;
107             }
108         }
109     }
110
111     #endregion
112
113     internal sealed class Walker
114     {
115         #region Members
116
117         internal event WalkerEventHandler FoundActivity;
118         internal event WalkerEventHandler FoundProperty;
119         private bool useEnabledActivities = false;
120
121         #endregion
122
123         #region Methods
124
125         public Walker()
126             : this(false)
127         {
128         }
129
130         public Walker(bool useEnabledActivities)
131         {
132             this.useEnabledActivities = useEnabledActivities;
133         }
134
135         public void Walk(Activity seedActivity)
136         {
137             Walk(seedActivity, true);
138         }
139
140         public void Walk(Activity seedActivity, bool walkChildren)
141         {
142             Queue queue = new Queue();
143
144             queue.Enqueue(seedActivity);
145             while (queue.Count > 0)
146             {
147                 Activity activity = queue.Dequeue() as Activity;
148
149                 if (FoundActivity != null)
150                 {
151                     WalkerEventArgs args = new WalkerEventArgs(activity);
152                     FoundActivity(this, args);
153                     if (args.Action == WalkerAction.Abort)
154                         return;
155                     if (args.Action == WalkerAction.Skip)
156                         continue;
157                 }
158
159                 if (FoundProperty != null)
160                 {
161                     if (!WalkProperties(activity))
162                         return;
163                 }
164
165                 if (walkChildren && activity is CompositeActivity)
166                 {
167                     if (useEnabledActivities)
168                     {
169                         foreach (Activity activity2 in Design.Helpers.GetAllEnabledActivities((CompositeActivity)activity))
170                             queue.Enqueue(activity2);
171                     }
172                     else
173                     {
174                         foreach (Activity activity2 in ((CompositeActivity)activity).Activities)
175                             queue.Enqueue(activity2);
176                     }
177                 }
178             }
179         }
180
181         private bool WalkProperties(Activity seedActivity)
182         {
183             return WalkProperties(seedActivity as Activity, seedActivity);
184         }
185
186         public bool WalkProperties(Activity activity, object obj)
187         {
188             Activity currentActivity = obj as Activity;
189
190             PropertyInfo[] props = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
191             foreach (PropertyInfo prop in props)
192             {
193                 // !!Work around: no indexer property walking
194                 if (prop.GetIndexParameters() != null && prop.GetIndexParameters().Length > 0)
195                     continue;
196
197                 DesignerSerializationVisibility visibility = GetSerializationVisibility(prop);
198                 if (visibility == DesignerSerializationVisibility.Hidden)
199                     continue;
200
201                 //Try to see if we have dynamic property associated with the object on the same object
202                 //if so then we should compare if the dynamic property values match with the property type
203                 //if not we bail out
204                 object propValue = null;
205                 DependencyProperty dependencyProperty = DependencyProperty.FromName(prop.Name, obj.GetType());
206                 if (dependencyProperty != null && currentActivity != null)
207                 {
208                     if (currentActivity.IsBindingSet(dependencyProperty))
209                         propValue = currentActivity.GetBinding(dependencyProperty);
210                     else
211                         propValue = currentActivity.GetValue(dependencyProperty);
212                 }
213                 else
214                 {
215                     try
216                     {
217                         propValue = prop.CanRead ? prop.GetValue(obj, null) : null;
218                     }
219                     catch
220                     {
221                         // Eat exceptions that occur while invoking the getter.
222                     }
223                 }
224
225                 if (FoundProperty != null)
226                 {
227                     WalkerEventArgs args = new WalkerEventArgs(activity, propValue, prop, obj);
228                     FoundProperty(this, args);
229                     if (args.Action == WalkerAction.Skip)
230                         continue;
231                     else if (args.Action == WalkerAction.Abort)
232                         return false;
233                 }
234
235                 if (propValue is IList)
236                 {
237                     //We do not need to reflect on the properties of the list
238                     foreach (object childObj in (IList)propValue)
239                     {
240                         if (FoundProperty != null)
241                         {
242                             WalkerEventArgs args = new WalkerEventArgs(activity, childObj, null, propValue);
243                             FoundProperty(this, args);
244                             if (args.Action == WalkerAction.Skip)
245                                 continue;
246                             else if (args.Action == WalkerAction.Abort)
247                                 return false;
248                         }
249                         if (childObj != null && IsBrowsableType(childObj.GetType()))
250                         {
251                             if (!WalkProperties(activity, childObj))
252                                 return false;
253                         }
254                     }
255                 }
256                 else if (propValue != null && IsBrowsableType(propValue.GetType()))
257                 {
258                     if (!WalkProperties(activity, propValue))
259                         return false;
260                 }
261             }
262             return true;
263         }
264
265         private static DesignerSerializationVisibility GetSerializationVisibility(PropertyInfo prop)
266         {
267             // work around!!! for Activities collection
268             if (prop.DeclaringType == typeof(CompositeActivity) && string.Equals(prop.Name, "Activities", StringComparison.Ordinal))
269                 return DesignerSerializationVisibility.Hidden;
270
271             DesignerSerializationVisibility visibility = DesignerSerializationVisibility.Visible;
272             DesignerSerializationVisibilityAttribute[] visibilityAttrs = (DesignerSerializationVisibilityAttribute[])prop.GetCustomAttributes(typeof(DesignerSerializationVisibilityAttribute), true);
273             if (visibilityAttrs.Length > 0)
274                 visibility = visibilityAttrs[0].Visibility;
275
276             return visibility;
277         }
278
279         private static bool IsBrowsableType(Type type)
280         {
281             bool browsable = false;
282             BrowsableAttribute[] browsableAttrs = (BrowsableAttribute[])type.GetCustomAttributes(typeof(BrowsableAttribute), true);
283             if (browsableAttrs.Length > 0)
284                 browsable = browsableAttrs[0].Browsable;
285             return browsable;
286         }
287         #endregion
288     }
289 }