3446319cac57cbf425db36324a720ad2a9e4d98c
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Core.Presentation / System / Activities / Core / Presentation / InvokeDelegateValidationFeature.cs
1 //----------------------------------------------------------------
2 // <copyright company="Microsoft Corporation">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //----------------------------------------------------------------
6
7 namespace System.Activities.Core.Presentation
8 {
9     using System.Activities.Expressions;
10     using System.Activities.Presentation;
11     using System.Activities.Presentation.Metadata;
12     using System.Activities.Presentation.Model;
13     using System.Activities.Statements;
14     using System.Activities.Validation;
15     using System.Collections.Generic;
16     using System.Collections.ObjectModel;
17     using System.Globalization;
18     using System.Reflection;
19     using System.Runtime;
20     using System.Text;
21
22     internal class InvokeDelegateValidationFeature : DesignTimeValidationFeature
23     {
24         private List<Constraint> constraints;
25         private EditingContext editingContext;
26
27         protected override Type ApplyTo
28         {
29             get { return typeof(InvokeDelegate); }
30         }
31
32         protected override IList<Constraint> DesignTimeConstraints
33         {
34             get
35             {
36                 if (this.constraints == null)
37                 {
38                     this.constraints = new List<Constraint> { this.CreateCheckDelegateRule(this.editingContext) };
39                 }
40
41                 return this.constraints;
42             }
43         }
44
45         public override void Initialize(EditingContext context, Type modelType)
46         {
47             this.editingContext = context;
48             base.Initialize(context, modelType);
49         }
50
51         private Constraint CreateCheckDelegateRule(EditingContext editingContext)
52         {
53             DelegateInArgument<InvokeDelegate> invokeDelegate = new DelegateInArgument<InvokeDelegate>();
54             DelegateInArgument<ValidationContext> context = new DelegateInArgument<ValidationContext>();
55
56             return new Constraint<InvokeDelegate>
57             {
58                 Body = new ActivityAction<InvokeDelegate, ValidationContext>
59                 {
60                     Argument1 = invokeDelegate,
61                     Argument2 = context,
62                     Handler = new CheckDelegateRule
63                     {
64                         Activity = invokeDelegate,
65                         EditingContext = editingContext,
66                     }
67                 }
68             };
69         }
70
71         private class CheckDelegateRule : NativeActivity
72         {
73             public CheckDelegateRule()
74             {
75                 this.WarningMessageVariable = new Variable<string>();
76                 this.ErrorMessageVariable = new Variable<string>();
77                 this.ShowWarning = new AssertValidation()
78                 {
79                     Assertion = false,
80                     IsWarning = true,
81                     Message = new VariableValue<string> { Variable = this.WarningMessageVariable }
82                 };
83                 this.ShowError = new AssertValidation()
84                 {
85                     Assertion = false,
86                     IsWarning = false,
87                     Message = new VariableValue<string> { Variable = this.ErrorMessageVariable }
88                 };
89             }
90
91             [RequiredArgument]
92             public InArgument<InvokeDelegate> Activity { get; set; }
93
94             public EditingContext EditingContext { get; set; }
95
96             private Variable<string> WarningMessageVariable { get; set; }
97
98             private Variable<string> ErrorMessageVariable { get; set; }
99
100             private AssertValidation ShowWarning { get; set; }
101
102             private AssertValidation ShowError { get; set; }
103
104             protected override void CacheMetadata(NativeActivityMetadata metadata)
105             {
106                 RuntimeArgument activityArgument = new RuntimeArgument("Activity", typeof(InvokeDelegate), ArgumentDirection.In, true);
107                 metadata.Bind(this.Activity, activityArgument);
108                 metadata.SetArgumentsCollection(new Collection<RuntimeArgument> { activityArgument });
109
110                 metadata.AddImplementationChild(this.ShowWarning);
111                 metadata.AddImplementationChild(this.ShowError);
112                 metadata.AddImplementationVariable(this.WarningMessageVariable);
113                 metadata.AddImplementationVariable(this.ErrorMessageVariable);
114             }
115
116             protected override void Execute(NativeActivityContext context)
117             {
118                 StringBuilder errorBuilder = new StringBuilder();
119                 InvokeDelegate activity = this.Activity.Get(context);
120
121                 string reference = PropertyReferenceUtilities.GetPropertyReference(activity, "Delegate");
122
123                 if (reference != null)
124                 {
125                     DynamicActivityProperty property = null;
126
127                     ModelTreeManager manager = this.EditingContext.Services.GetService<ModelTreeManager>();
128                     if (manager.Root.ItemType == typeof(ActivityBuilder))
129                     {
130                         property = DynamicActivityPropertyUtilities.Find(manager.Root.Properties["Properties"].Collection, reference);
131                     }
132
133                     if (property == null)
134                     {
135                         this.EmitValidationError(context, string.Format(CultureInfo.CurrentUICulture, SR.PropertyReferenceNotResolved, reference));
136                         return;
137                     }
138
139                     if (property.Type == typeof(ActivityDelegate))
140                     {
141                         this.EmitValidationWarning(context, string.Format(CultureInfo.CurrentUICulture, SR.PropertyIsNotAConcreteActivityDelegate, reference));
142                         return;
143                     }
144
145                     if (!property.Type.IsSubclassOf(typeof(ActivityDelegate)))
146                     {
147                         this.EmitValidationError(context, string.Format(CultureInfo.CurrentUICulture, SR.PropertyIsNotAnActivityDelegate, reference));
148                         return;
149                     }
150
151                     if (property.Type.IsAbstract)
152                     {
153                         this.EmitValidationWarning(context, string.Format(CultureInfo.CurrentUICulture, SR.PropertyIsNotAConcreteActivityDelegate, reference));
154                         return;
155                     }
156
157                     ActivityDelegateMetadata metadata = ActivityDelegateUtilities.GetMetadata(property.Type);
158
159                     if (activity.DelegateArguments.Count != metadata.Count)
160                     {
161                         this.EmitValidationWarning(context, SR.WrongNumberOfArgumentsForActivityDelegate);
162                         return;
163                     }
164
165                     foreach (ActivityDelegateArgumentMetadata expectedArgument in metadata)
166                     {
167                         Argument delegateArgument = null;
168
169                         if (activity.DelegateArguments.TryGetValue(expectedArgument.Name, out delegateArgument))
170                         {
171                             if ((expectedArgument.Direction == ActivityDelegateArgumentDirection.In && delegateArgument.Direction != ArgumentDirection.In) ||
172                                 (expectedArgument.Direction == ActivityDelegateArgumentDirection.Out && delegateArgument.Direction != ArgumentDirection.Out))
173                             {
174                                 errorBuilder.AppendFormat(CultureInfo.CurrentUICulture, SR.DelegateArgumentsDirectionalityMismatch, expectedArgument.Name, delegateArgument.Direction, expectedArgument.Direction);
175                             }
176
177                             if (delegateArgument.ArgumentType != expectedArgument.Type)
178                             {
179                                 if (expectedArgument.Direction == ActivityDelegateArgumentDirection.In)
180                                 {
181                                     if (!TypeHelper.AreTypesCompatible(delegateArgument.ArgumentType, expectedArgument.Type))
182                                     {
183                                         errorBuilder.AppendFormat(CultureInfo.CurrentUICulture, SR.DelegateInArgumentTypeMismatch, expectedArgument.Name, expectedArgument.Type, delegateArgument.ArgumentType);
184                                     }
185                                 }
186                                 else
187                                 {
188                                     if (!TypeHelper.AreTypesCompatible(expectedArgument.Type, delegateArgument.ArgumentType))
189                                     {
190                                         errorBuilder.AppendFormat(CultureInfo.CurrentUICulture, SR.DelegateOutArgumentTypeMismatch, expectedArgument.Name, expectedArgument.Type, delegateArgument.ArgumentType);
191                                     }
192                                 }
193                             }
194                         }
195                         else
196                         {
197                             errorBuilder.AppendFormat(CultureInfo.CurrentUICulture, SR.DelegateArgumentMissing, expectedArgument.Name);
198                         }
199                     }
200
201                     if (errorBuilder.Length > 0)
202                     {
203                         this.EmitValidationWarning(context, errorBuilder.ToString());
204                     }
205                 }
206             }
207
208             private void EmitValidationWarning(NativeActivityContext context, string message)
209             {
210                 this.WarningMessageVariable.Set(context, message);
211                 context.ScheduleActivity(this.ShowWarning);
212             }
213
214             private void EmitValidationError(NativeActivityContext context, string message)
215             {
216                 this.ErrorMessageVariable.Set(context, message);
217                 context.ScheduleActivity(this.ShowError);
218             }
219         }
220     }
221 }