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