Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.WorkflowServices / System / Workflow / Activities / Design / OperationPickerDialog.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4
5 namespace System.Workflow.Activities.Design
6 {
7     using System;
8     using System.Collections.Generic;
9     using System.ComponentModel;
10     using System.Drawing;
11     using System.Reflection;
12     using System.Runtime;
13     using System.ServiceModel;
14     using System.Windows.Forms;
15     using System.Windows.Forms.Design;
16     using System.Workflow.Activities;
17     using System.Workflow.ComponentModel;
18     using System.Workflow.ComponentModel.Design;
19
20     partial class OperationPickerDialog : Form
21     {
22         private OperationInfoBase selectedOperation;
23         private ServiceContractListItemList serviceContracts;
24         private IServiceProvider serviceProvider = null;
25
26         public OperationPickerDialog(IServiceProvider serviceProvider, bool allowNewContracts)
27         {
28             if (serviceProvider == null)
29             {
30                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serviceProvider");
31             }
32             this.serviceProvider = serviceProvider;
33             //Set dialog fonts
34             IUIService uisvc = (IUIService) this.serviceProvider.GetService(typeof(IUIService));
35             if (uisvc != null)
36             {
37                 this.Font = (Font) uisvc.Styles["DialogFont"];
38             }
39             InitializeComponent();
40             this.serviceContracts = new ServiceContractListItemList(this.operationsListBox);
41             this.operationsListBox.ServiceProvider = this.serviceProvider;
42             this.toolStripButton1.Visible = allowNewContracts;
43         }
44
45         public OperationInfoBase SelectedOperation
46         {
47             get
48             {
49                 return selectedOperation;
50             }
51             internal set
52             {
53                 if (value == null)
54                 {
55                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
56                 }
57                 selectedOperation = value;
58                 SelectServiceOperation(value);
59             }
60         }
61
62         public void AddServiceOperation(OperationInfoBase operationInfo, Activity implementingActivity)
63         {
64             if (operationInfo == null)
65             {
66                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operationInfo");
67             }
68
69             TypedOperationInfo typedOperationInfo = operationInfo as TypedOperationInfo;
70             OperationInfo workflowOperationInfo = operationInfo as OperationInfo;
71             string contractName = operationInfo.GetContractFullName(null);
72             // Do not add operation if the contractName is not valid. Not throwing here gives the user to fix 
73             // a broken contract/operation by selecting a different operation from the UI.
74             if (String.IsNullOrEmpty(contractName))
75             {
76                 return;
77             }
78             ServiceContractListItem serviceContract = this.serviceContracts.Find(contractName);
79
80             if (typedOperationInfo != null)
81             {
82                 if (serviceContract == null)
83                 {
84                     serviceContract = new ServiceContractListItem(this.operationsListBox);
85                     serviceContract.Validating += new CancelEventHandler(ServiceContractValidating);
86                     serviceContract.Name = contractName;
87                     serviceContract.ContractType = typedOperationInfo.ContractType;
88                     serviceContract.IsCustomContract = false;
89                     AddServiceContract(serviceContract);
90                 }
91
92                 TypedServiceOperationListItem operationItem = new TypedServiceOperationListItem();
93                 operationItem.Validating += new CancelEventHandler(ServiceOperationValidating);
94                 operationItem.Name = typedOperationInfo.Name;
95                 operationItem.Operation = typedOperationInfo;
96
97                 operationItem.ImplementingActivities.Add(implementingActivity);
98                 serviceContract.AddOperation(operationItem);
99             }
100             else if (workflowOperationInfo != null)
101             {
102                 if (serviceContract == null)
103                 {
104                     serviceContract = new ServiceContractListItem(this.operationsListBox);
105                     serviceContract.Validating += new CancelEventHandler(ServiceContractValidating);
106                     serviceContract.Name = workflowOperationInfo.ContractName;
107                     serviceContract.IsCustomContract = true;
108                     AddServiceContract(serviceContract);
109                 }
110                 WorkflowServiceOperationListItem workflowOperationItem = new WorkflowServiceOperationListItem();
111                 workflowOperationItem.Validating += new CancelEventHandler(ServiceOperationValidating);
112                 workflowOperationItem.Operation = workflowOperationInfo;
113                 workflowOperationItem.ImplementingActivities.Add(implementingActivity);
114                 serviceContract.AddOperation(workflowOperationItem);
115             }
116
117         }
118
119         protected override void OnHelpButtonClicked(CancelEventArgs e)
120         {
121             e.Cancel = true;
122             GetHelp();
123         }
124
125         protected override void OnHelpRequested(HelpEventArgs e)
126         {
127             e.Handled = true;
128             GetHelp();
129         }
130
131         private void AddHelpListItem()
132         {
133             if (this.operationsListBox.Items.Count == 0)
134             {
135                 this.operationsListBox.Items.Add(new HelpListItem());
136             }
137         }
138
139         private void addOperationButton_Click(object sender, EventArgs e)
140         {
141             ServiceContractListItem serviceContractListItem = this.operationsListBox.SelectedItem as ServiceContractListItem;
142             Fx.Assert(serviceContractListItem != null, "service contract list item cannot be null");
143             Fx.Assert(serviceContractListItem.IsCustomContract, " this should work only on a custom contract item");
144             WorkflowServiceOperationListItem newWorkflowServiceOperationListItem = serviceContractListItem.CreateOperation();
145             newWorkflowServiceOperationListItem.Validating += new CancelEventHandler(ServiceOperationValidating);
146             this.AddServiceOperation(newWorkflowServiceOperationListItem);
147             serviceContractListItem.SelectionOperation(newWorkflowServiceOperationListItem);
148         }
149
150         private void AddServiceContract(ServiceContractListItem serviceContractListItem)
151         {
152             String key = serviceContractListItem.Name;
153             if (this.serviceContracts.Find(key) == null)
154             {
155                 RemoveHelpListItem();
156                 serviceContracts.Add(serviceContractListItem);
157                 operationsListBox.Items.Add(serviceContractListItem);
158             }
159         }
160         private void AddServiceOperation(ServiceOperationListItem serviceOperation)
161         {
162             if (serviceOperation == null)
163             {
164                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serviceOperation");
165             }
166             String key = serviceOperation.ContractName;
167             ServiceContractListItem serviceContract = this.serviceContracts.Find(key);
168             serviceContract.AddOperation(serviceOperation);
169             serviceContract.SelectionOperation(serviceOperation);
170         }
171
172         private void cancelButton_Click(object sender, EventArgs e)
173         {
174             this.DialogResult = DialogResult.Cancel;
175             this.Close();
176         }
177
178         private void GetHelp()
179         {
180             DesignerHelpers.ShowHelpFromKeyword(this.serviceProvider, typeof(OperationPickerDialog).FullName + ".UI");
181         }
182         private List<MethodInfo> GetMethodsFromInterface(Type serviceContractInterfaceType)
183         {
184             List<MethodInfo> methodInfos = new List<MethodInfo>();
185             Queue<Type> interfacesQueue = new Queue<Type>();
186             List<Type> interfacesList = new List<Type>();
187             interfacesQueue.Enqueue(serviceContractInterfaceType);
188
189             while (interfacesQueue.Count > 0)
190             {
191                 Type currentInterfaceType = interfacesQueue.Dequeue();
192                 interfacesList.Add(currentInterfaceType);
193                 foreach (Type baseInteface in currentInterfaceType.GetInterfaces())
194                 {
195                     if (!interfacesList.Contains(baseInteface))
196                     {
197                         interfacesQueue.Enqueue(baseInteface);
198                     }
199                 }
200                 methodInfos.AddRange(currentInterfaceType.GetMethods());
201             }
202             return methodInfos;
203         }
204
205         private void ImportContract(Type serviceContractType)
206         {
207
208             foreach (MethodInfo methodInfo in GetMethodsFromInterface(serviceContractType))
209             {
210                 if (!ServiceOperationHelpers.IsValidServiceOperation(methodInfo))
211                 {
212                     continue;
213                 }
214                 TypedServiceOperationListItem operationItem = new TypedServiceOperationListItem();
215                 operationItem.Validating += new CancelEventHandler(ServiceOperationValidating);
216                 operationItem.Name = ServiceOperationHelpers.GetOperationName(this.serviceProvider, methodInfo);
217                 operationItem.Operation.ContractType = serviceContractType;
218                 operationItem.Operation.Name = ServiceOperationHelpers.GetOperationName(this.serviceProvider, methodInfo);
219                 this.AddServiceOperation(operationItem);
220             }
221         }
222
223         void ImportContractButtonClicked(object sender, EventArgs e)
224         {
225             using (TypeBrowserDialog typeBrowserDialog = new TypeBrowserDialog(serviceProvider as IServiceProvider, new ServiceContractsTypeFilterProvider(), "System.String"))
226             {
227                 typeBrowserDialog.ShowDialog();
228                 if (typeBrowserDialog.SelectedType != null)
229                 {
230                     ServiceContractListItem contractItem = new ServiceContractListItem(this.operationsListBox);
231                     contractItem.Validating += new CancelEventHandler(ServiceContractValidating);
232                     contractItem.Name = typeBrowserDialog.SelectedType.FullName;
233                     contractItem.ContractType = typeBrowserDialog.SelectedType;
234                     contractItem.IsCustomContract = false;
235                     CancelEventArgs cancelEventArgs = new CancelEventArgs();
236                     contractItem.Validating.Invoke(contractItem, cancelEventArgs);
237                     if (cancelEventArgs.Cancel)
238                     {
239                         return;
240                     }
241                     AddServiceContract(contractItem);
242
243                     ImportContract(typeBrowserDialog.SelectedType);
244                 }
245             }
246         }
247
248         void NewContractButtonClicked(object sender, EventArgs e)
249         {
250             ServiceContractListItem contractItem = this.serviceContracts.CreateWithUniqueName();
251             contractItem.Validating += new CancelEventHandler(ServiceContractValidating);
252             contractItem.IsCustomContract = true;
253             this.AddServiceContract(contractItem);
254             WorkflowServiceOperationListItem newWorkflowServiceOperationListItem = contractItem.CreateOperation();
255             newWorkflowServiceOperationListItem.Validating += new CancelEventHandler(ServiceOperationValidating);
256             this.AddServiceOperation(newWorkflowServiceOperationListItem);
257             contractItem.SelectionOperation(newWorkflowServiceOperationListItem);
258         }
259
260         private void okButton_Click(object sender, EventArgs e)
261         {
262             object selectedObject = operationsListBox.SelectedItem;
263             if (selectedObject == null)
264             {
265                 selectedOperation = null;
266             }
267             if (selectedObject is TypedServiceOperationListItem)
268             {
269                 selectedOperation = ((TypedServiceOperationListItem) selectedObject).Operation;
270             }
271             else if (selectedObject is WorkflowServiceOperationListItem)
272             {
273                 selectedOperation = ((WorkflowServiceOperationListItem) selectedObject).Operation;
274             }
275             else
276             {
277                 // dont close the dialog when contracts are selected
278                 return;
279             }
280             this.DialogResult = DialogResult.OK;
281             this.Close();
282         }
283
284         private void OperationPickerDialogLoad(object sender, EventArgs e)
285         {
286             if (this.serviceContracts.Count == 0)
287             {
288                 AddHelpListItem();
289             }
290             foreach (ServiceContractListItem serviceContractListItem in this.serviceContracts)
291             {
292                 if (!serviceContractListItem.IsCustomContract)
293                 {
294                     ImportContract(serviceContractListItem.ContractType);
295                 }
296             }
297             this.importContractButton.Click += new EventHandler(ImportContractButtonClicked);
298             this.operationsListBox.DoubleClick += new EventHandler(operationsListBox_DoubleClick);
299             this.operationsListBox.SelectedIndexChanged += new EventHandler(operationsListBox_SelectedIndexChanged);
300             this.addOperationButton.Click += new EventHandler(addOperationButton_Click);
301             this.toolStripButton1.Click += new EventHandler(NewContractButtonClicked);
302             this.okButton.Click += new EventHandler(okButton_Click);
303
304
305             // This is to make the selected operation the selected item in the operationsListBox.
306             // This needs to be done to work around the Microsoft bug causing selection events to not fire till form is loaded.
307             if (this.selectedOperation != null)
308             {
309                 SelectServiceOperation(this.selectedOperation);
310             }
311             else // select the first operation if no selectedoperation is set
312             {
313                 if (operationsListBox.Items.Count > 0)
314                 {
315                     operationsListBox.SetSelected(0, true);
316                 }
317             }
318         }
319
320
321         void operationsListBox_DoubleClick(object sender, EventArgs e)
322         {
323             okButton_Click(sender, e);
324         }
325
326         private void operationsListBox_SelectedIndexChanged(object sender, EventArgs e)
327         {
328             if (operationsListBox.SelectedItemViewControl != null)
329             {
330                 this.addOperationButton.Visible = false;
331                 detailsViewPanel.Visible = false;
332                 // Give the old details control a chance to valiadte its fields before tearing it down.
333                 foreach (Control control in detailsViewPanel.Controls)
334                 {
335                     UserControl userControl = control as UserControl;
336                     if (userControl != null)
337                     {
338                         userControl.ValidateChildren();
339                     }
340                 }
341                 detailsViewPanel.Controls.Clear();
342                 operationsListBox.SelectedItemViewControl.Dock = DockStyle.Fill;
343                 detailsViewPanel.Controls.Add(operationsListBox.SelectedItemViewControl);
344                 detailsViewPanel.Visible = true;
345                 if (operationsListBox.SelectedItem is ServiceOperationListItem)
346                 {
347                     this.okButton.Enabled = true;
348                 }
349                 else
350                 {
351                     this.okButton.Enabled = false;
352                     ServiceContractListItem serviceContractListItem = this.operationsListBox.SelectedItem as ServiceContractListItem;
353                     if ((serviceContractListItem != null) && (serviceContractListItem.IsCustomContract))
354                     {
355                         this.addOperationButton.Visible = true;
356                     }
357                 }
358             }
359
360         }
361
362         private void RemoveHelpListItem()
363         {
364             if (this.operationsListBox.Items.Count > 0 && this.operationsListBox.Items[0] is HelpListItem)
365             {
366                 this.operationsListBox.Items.Clear();
367             }
368         }
369
370         private void SelectServiceOperation(OperationInfoBase operationInfo)
371         {
372             Fx.Assert(operationInfo != null, "operationInfo cannot be null");
373             ServiceContractListItem serviceContract = this.serviceContracts.Find(operationInfo.GetContractFullName(null));
374             // Dont select operation if the contract cannot be found in the serviceContracts list
375             if (serviceContract == null)
376             {
377                 return;
378             }
379             ServiceOperationListItem operationItem = null;
380             if (operationInfo is OperationInfo)
381             {
382                 operationItem = new WorkflowServiceOperationListItem();
383                 operationItem.Validating += new CancelEventHandler(ServiceOperationValidating);
384
385                 operationItem.Name = operationInfo.Name;
386                 ((WorkflowServiceOperationListItem) operationItem).Operation = operationInfo as OperationInfo;
387
388             }
389             else if (operationInfo is TypedOperationInfo)
390             {
391                 operationItem = new TypedServiceOperationListItem();
392                 operationItem.Validating += new CancelEventHandler(ServiceOperationValidating);
393                 operationItem.Name = operationInfo.Name;
394                 ((TypedServiceOperationListItem) operationItem).Operation = operationInfo as TypedOperationInfo;
395             }
396
397             serviceContract.SelectionOperation(operationItem);
398         }
399
400         void ServiceContractValidating(object sender, CancelEventArgs e)
401         {
402             ServiceContractListItem serviceContractListItem = (ServiceContractListItem) sender;
403
404             if (string.IsNullOrEmpty(serviceContractListItem.Name))
405             {
406                 e.Cancel = true;
407                 string errorString = SR2.GetString(SR2.ContractNameCannotBeEmpty);
408                 DesignerHelpers.ShowMessage(this.serviceProvider, errorString, System.Workflow.ComponentModel.Design.DR.GetString(System.Workflow.ComponentModel.Design.DR.WorkflowDesignerTitle), MessageBoxButtons.OK,
409                     MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
410
411             }
412             bool duplicatesFound = false;
413             foreach (ServiceContractListItem foundContract in serviceContracts)
414             {
415                 if (foundContract == serviceContractListItem)
416                 {
417                     continue;
418                 }
419
420                 // allow reimport of existing imported contracts
421                 if (!serviceContractListItem.IsCustomContract && serviceContractListItem.ContractType.Equals(foundContract.ContractType))
422                 {
423                     continue;
424                 }
425
426                 if (foundContract.Name.Equals(serviceContractListItem.Name))
427                 {
428                     duplicatesFound = true;
429                     break;
430                 }
431
432             }
433             // contract names must be unique
434             if (duplicatesFound)
435             {
436
437                 e.Cancel = true;
438                 string errorString = SR2.GetString(SR2.ContractNameMustBeUnique);
439                 DesignerHelpers.ShowMessage(this.serviceProvider, errorString, System.Workflow.ComponentModel.Design.DR.GetString(System.Workflow.ComponentModel.Design.DR.WorkflowDesignerTitle), MessageBoxButtons.OK,
440                     MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
441
442             }
443         }
444
445
446
447
448         void ServiceOperationValidating(object sender, CancelEventArgs e)
449         {
450
451             ServiceOperationListItem serviceOperationListItem = (ServiceOperationListItem) sender;
452             string newOperationName = serviceOperationListItem.Name;
453             string contractName = serviceOperationListItem.ContractName;
454             if (string.IsNullOrEmpty(newOperationName))
455             {
456                 e.Cancel = true;
457                 string errorString = SR2.GetString(SR2.OperationNameCannotBeEmpty);
458                 DesignerHelpers.ShowMessage(this.serviceProvider, errorString, System.Workflow.ComponentModel.Design.DR.GetString(System.Workflow.ComponentModel.Design.DR.WorkflowDesignerTitle), MessageBoxButtons.OK,
459                     MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
460             }
461
462             Fx.Assert(!string.IsNullOrEmpty(contractName), "contract name should be valid to run this check");
463             ServiceContractListItem contractListItem = serviceContracts.Find(contractName);
464             Fx.Assert(contractListItem != null, "contract should be present in the list to run this check");
465
466             // operation names must be unique inside a contract
467             bool duplicatesFound = false;
468             foreach (ServiceOperationListItem foundOperation in contractListItem.Operations)
469             {
470                 if (foundOperation == serviceOperationListItem)
471                 {
472                     continue;
473                 }
474                 if (foundOperation.Name.Equals(newOperationName))
475                 {
476                     duplicatesFound = true;
477                     break;
478                 }
479
480             }
481             if (duplicatesFound)
482             {
483
484                 e.Cancel = true;
485                 string errorString = SR2.GetString(SR2.OperationNameMustBeUnique);
486                 DesignerHelpers.ShowMessage(this.serviceProvider, errorString, System.Workflow.ComponentModel.Design.DR.GetString(System.Workflow.ComponentModel.Design.DR.WorkflowDesignerTitle), MessageBoxButtons.OK,
487                     MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
488
489             }
490
491         }
492
493         [ListItemView(typeof(HelpListItemViewControl))]
494         [ListItemDetailView(typeof(ListItemViewControl))]
495         private class HelpListItem
496         {
497         }
498
499         private class HelpListItemViewControl : ListItemViewControl
500         {
501
502             protected override void OnLoad(EventArgs e)
503             {
504                 this.Width = this.Parent.Width - 10;
505                 Label label = new Label();
506                 label.ForeColor = System.Drawing.SystemColors.GrayText;
507                 label.Dock = DockStyle.Fill;
508                 this.Font = new Font(this.Font, FontStyle.Italic);
509                 label.Text = SR2.GetString(SR2.AddOperationsUsingImportAddButtons);
510                 this.Controls.Add(label);
511             }
512         }
513
514         private class ServiceContractsTypeFilterProvider : ITypeFilterProvider
515         {
516
517             string ITypeFilterProvider.FilterDescription
518             {
519                 get { return SR2.GetString(SR2.ChooseAServiceContractFromBelow); }
520             }
521             bool ITypeFilterProvider.CanFilterType(Type type, bool throwOnError)
522             {
523                 if (!type.IsInterface)
524                 {
525                     return false;
526                 }
527                 if (type.IsDefined(typeof(ServiceContractAttribute), true))
528                 {
529                     return true;
530                 }
531                 else
532                 {
533                     return false;
534                 }
535             }
536         }
537
538
539     }
540 }