File: System\Workflow\Activities\Design\OperationPickerDialog.cs
Project: ndp\cdf\src\NetFx35\System.WorkflowServices\System.WorkflowServices.csproj (System.WorkflowServices)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace System.Workflow.Activities.Design
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Reflection;
    using System.Runtime;
    using System.ServiceModel;
    using System.Windows.Forms;
    using System.Windows.Forms.Design;
    using System.Workflow.Activities;
    using System.Workflow.ComponentModel;
    using System.Workflow.ComponentModel.Design;
 
    partial class OperationPickerDialog : Form
    {
        private OperationInfoBase selectedOperation;
        private ServiceContractListItemList serviceContracts;
        private IServiceProvider serviceProvider = null;
 
        public OperationPickerDialog(IServiceProvider serviceProvider, bool allowNewContracts)
        {
            if (serviceProvider == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serviceProvider");
            }
            this.serviceProvider = serviceProvider;
            //Set dialog fonts
            IUIService uisvc = (IUIService) this.serviceProvider.GetService(typeof(IUIService));
            if (uisvc != null)
            {
                this.Font = (Font) uisvc.Styles["DialogFont"];
            }
            InitializeComponent();
            this.serviceContracts = new ServiceContractListItemList(this.operationsListBox);
            this.operationsListBox.ServiceProvider = this.serviceProvider;
            this.toolStripButton1.Visible = allowNewContracts;
        }
 
        public OperationInfoBase SelectedOperation
        {
            get
            {
                return selectedOperation;
            }
            internal set
            {
                if (value == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
                }
                selectedOperation = value;
                SelectServiceOperation(value);
            }
        }
 
        public void AddServiceOperation(OperationInfoBase operationInfo, Activity implementingActivity)
        {
            if (operationInfo == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operationInfo");
            }
 
            TypedOperationInfo typedOperationInfo = operationInfo as TypedOperationInfo;
            OperationInfo workflowOperationInfo = operationInfo as OperationInfo;
            string contractName = operationInfo.GetContractFullName(null);
            // Do not add operation if the contractName is not valid. Not throwing here gives the user to fix 
            // a broken contract/operation by selecting a different operation from the UI.
            if (String.IsNullOrEmpty(contractName))
            {
                return;
            }
            ServiceContractListItem serviceContract = this.serviceContracts.Find(contractName);
 
            if (typedOperationInfo != null)
            {
                if (serviceContract == null)
                {
                    serviceContract = new ServiceContractListItem(this.operationsListBox);
                    serviceContract.Validating += new CancelEventHandler(ServiceContractValidating);
                    serviceContract.Name = contractName;
                    serviceContract.ContractType = typedOperationInfo.ContractType;
                    serviceContract.IsCustomContract = false;
                    AddServiceContract(serviceContract);
                }
 
                TypedServiceOperationListItem operationItem = new TypedServiceOperationListItem();
                operationItem.Validating += new CancelEventHandler(ServiceOperationValidating);
                operationItem.Name = typedOperationInfo.Name;
                operationItem.Operation = typedOperationInfo;
 
                operationItem.ImplementingActivities.Add(implementingActivity);
                serviceContract.AddOperation(operationItem);
            }
            else if (workflowOperationInfo != null)
            {
                if (serviceContract == null)
                {
                    serviceContract = new ServiceContractListItem(this.operationsListBox);
                    serviceContract.Validating += new CancelEventHandler(ServiceContractValidating);
                    serviceContract.Name = workflowOperationInfo.ContractName;
                    serviceContract.IsCustomContract = true;
                    AddServiceContract(serviceContract);
                }
                WorkflowServiceOperationListItem workflowOperationItem = new WorkflowServiceOperationListItem();
                workflowOperationItem.Validating += new CancelEventHandler(ServiceOperationValidating);
                workflowOperationItem.Operation = workflowOperationInfo;
                workflowOperationItem.ImplementingActivities.Add(implementingActivity);
                serviceContract.AddOperation(workflowOperationItem);
            }
 
        }
 
        protected override void OnHelpButtonClicked(CancelEventArgs e)
        {
            e.Cancel = true;
            GetHelp();
        }
 
        protected override void OnHelpRequested(HelpEventArgs e)
        {
            e.Handled = true;
            GetHelp();
        }
 
        private void AddHelpListItem()
        {
            if (this.operationsListBox.Items.Count == 0)
            {
                this.operationsListBox.Items.Add(new HelpListItem());
            }
        }
 
        private void addOperationButton_Click(object sender, EventArgs e)
        {
            ServiceContractListItem serviceContractListItem = this.operationsListBox.SelectedItem as ServiceContractListItem;
            Fx.Assert(serviceContractListItem != null, "service contract list item cannot be null");
            Fx.Assert(serviceContractListItem.IsCustomContract, " this should work only on a custom contract item");
            WorkflowServiceOperationListItem newWorkflowServiceOperationListItem = serviceContractListItem.CreateOperation();
            newWorkflowServiceOperationListItem.Validating += new CancelEventHandler(ServiceOperationValidating);
            this.AddServiceOperation(newWorkflowServiceOperationListItem);
            serviceContractListItem.SelectionOperation(newWorkflowServiceOperationListItem);
        }
 
        private void AddServiceContract(ServiceContractListItem serviceContractListItem)
        {
            String key = serviceContractListItem.Name;
            if (this.serviceContracts.Find(key) == null)
            {
                RemoveHelpListItem();
                serviceContracts.Add(serviceContractListItem);
                operationsListBox.Items.Add(serviceContractListItem);
            }
        }
        private void AddServiceOperation(ServiceOperationListItem serviceOperation)
        {
            if (serviceOperation == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serviceOperation");
            }
            String key = serviceOperation.ContractName;
            ServiceContractListItem serviceContract = this.serviceContracts.Find(key);
            serviceContract.AddOperation(serviceOperation);
            serviceContract.SelectionOperation(serviceOperation);
        }
 
        private void cancelButton_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
            this.Close();
        }
 
        private void GetHelp()
        {
            DesignerHelpers.ShowHelpFromKeyword(this.serviceProvider, typeof(OperationPickerDialog).FullName + ".UI");
        }
        private List<MethodInfo> GetMethodsFromInterface(Type serviceContractInterfaceType)
        {
            List<MethodInfo> methodInfos = new List<MethodInfo>();
            Queue<Type> interfacesQueue = new Queue<Type>();
            List<Type> interfacesList = new List<Type>();
            interfacesQueue.Enqueue(serviceContractInterfaceType);
 
            while (interfacesQueue.Count > 0)
            {
                Type currentInterfaceType = interfacesQueue.Dequeue();
                interfacesList.Add(currentInterfaceType);
                foreach (Type baseInteface in currentInterfaceType.GetInterfaces())
                {
                    if (!interfacesList.Contains(baseInteface))
                    {
                        interfacesQueue.Enqueue(baseInteface);
                    }
                }
                methodInfos.AddRange(currentInterfaceType.GetMethods());
            }
            return methodInfos;
        }
 
        private void ImportContract(Type serviceContractType)
        {
 
            foreach (MethodInfo methodInfo in GetMethodsFromInterface(serviceContractType))
            {
                if (!ServiceOperationHelpers.IsValidServiceOperation(methodInfo))
                {
                    continue;
                }
                TypedServiceOperationListItem operationItem = new TypedServiceOperationListItem();
                operationItem.Validating += new CancelEventHandler(ServiceOperationValidating);
                operationItem.Name = ServiceOperationHelpers.GetOperationName(this.serviceProvider, methodInfo);
                operationItem.Operation.ContractType = serviceContractType;
                operationItem.Operation.Name = ServiceOperationHelpers.GetOperationName(this.serviceProvider, methodInfo);
                this.AddServiceOperation(operationItem);
            }
        }
 
        void ImportContractButtonClicked(object sender, EventArgs e)
        {
            using (TypeBrowserDialog typeBrowserDialog = new TypeBrowserDialog(serviceProvider as IServiceProvider, new ServiceContractsTypeFilterProvider(), "System.String"))
            {
                typeBrowserDialog.ShowDialog();
                if (typeBrowserDialog.SelectedType != null)
                {
                    ServiceContractListItem contractItem = new ServiceContractListItem(this.operationsListBox);
                    contractItem.Validating += new CancelEventHandler(ServiceContractValidating);
                    contractItem.Name = typeBrowserDialog.SelectedType.FullName;
                    contractItem.ContractType = typeBrowserDialog.SelectedType;
                    contractItem.IsCustomContract = false;
                    CancelEventArgs cancelEventArgs = new CancelEventArgs();
                    contractItem.Validating.Invoke(contractItem, cancelEventArgs);
                    if (cancelEventArgs.Cancel)
                    {
                        return;
                    }
                    AddServiceContract(contractItem);
 
                    ImportContract(typeBrowserDialog.SelectedType);
                }
            }
        }
 
        void NewContractButtonClicked(object sender, EventArgs e)
        {
            ServiceContractListItem contractItem = this.serviceContracts.CreateWithUniqueName();
            contractItem.Validating += new CancelEventHandler(ServiceContractValidating);
            contractItem.IsCustomContract = true;
            this.AddServiceContract(contractItem);
            WorkflowServiceOperationListItem newWorkflowServiceOperationListItem = contractItem.CreateOperation();
            newWorkflowServiceOperationListItem.Validating += new CancelEventHandler(ServiceOperationValidating);
            this.AddServiceOperation(newWorkflowServiceOperationListItem);
            contractItem.SelectionOperation(newWorkflowServiceOperationListItem);
        }
 
        private void okButton_Click(object sender, EventArgs e)
        {
            object selectedObject = operationsListBox.SelectedItem;
            if (selectedObject == null)
            {
                selectedOperation = null;
            }
            if (selectedObject is TypedServiceOperationListItem)
            {
                selectedOperation = ((TypedServiceOperationListItem) selectedObject).Operation;
            }
            else if (selectedObject is WorkflowServiceOperationListItem)
            {
                selectedOperation = ((WorkflowServiceOperationListItem) selectedObject).Operation;
            }
            else
            {
                // dont close the dialog when contracts are selected
                return;
            }
            this.DialogResult = DialogResult.OK;
            this.Close();
        }
 
        private void OperationPickerDialogLoad(object sender, EventArgs e)
        {
            if (this.serviceContracts.Count == 0)
            {
                AddHelpListItem();
            }
            foreach (ServiceContractListItem serviceContractListItem in this.serviceContracts)
            {
                if (!serviceContractListItem.IsCustomContract)
                {
                    ImportContract(serviceContractListItem.ContractType);
                }
            }
            this.importContractButton.Click += new EventHandler(ImportContractButtonClicked);
            this.operationsListBox.DoubleClick += new EventHandler(operationsListBox_DoubleClick);
            this.operationsListBox.SelectedIndexChanged += new EventHandler(operationsListBox_SelectedIndexChanged);
            this.addOperationButton.Click += new EventHandler(addOperationButton_Click);
            this.toolStripButton1.Click += new EventHandler(NewContractButtonClicked);
            this.okButton.Click += new EventHandler(okButton_Click);
 
 
            // This is to make the selected operation the selected item in the operationsListBox.
            // This needs to be done to work around the Microsoft bug causing selection events to not fire till form is loaded.
            if (this.selectedOperation != null)
            {
                SelectServiceOperation(this.selectedOperation);
            }
            else // select the first operation if no selectedoperation is set
            {
                if (operationsListBox.Items.Count > 0)
                {
                    operationsListBox.SetSelected(0, true);
                }
            }
        }
 
 
        void operationsListBox_DoubleClick(object sender, EventArgs e)
        {
            okButton_Click(sender, e);
        }
 
        private void operationsListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (operationsListBox.SelectedItemViewControl != null)
            {
                this.addOperationButton.Visible = false;
                detailsViewPanel.Visible = false;
                // Give the old details control a chance to valiadte its fields before tearing it down.
                foreach (Control control in detailsViewPanel.Controls)
                {
                    UserControl userControl = control as UserControl;
                    if (userControl != null)
                    {
                        userControl.ValidateChildren();
                    }
                }
                detailsViewPanel.Controls.Clear();
                operationsListBox.SelectedItemViewControl.Dock = DockStyle.Fill;
                detailsViewPanel.Controls.Add(operationsListBox.SelectedItemViewControl);
                detailsViewPanel.Visible = true;
                if (operationsListBox.SelectedItem is ServiceOperationListItem)
                {
                    this.okButton.Enabled = true;
                }
                else
                {
                    this.okButton.Enabled = false;
                    ServiceContractListItem serviceContractListItem = this.operationsListBox.SelectedItem as ServiceContractListItem;
                    if ((serviceContractListItem != null) && (serviceContractListItem.IsCustomContract))
                    {
                        this.addOperationButton.Visible = true;
                    }
                }
            }
 
        }
 
        private void RemoveHelpListItem()
        {
            if (this.operationsListBox.Items.Count > 0 && this.operationsListBox.Items[0] is HelpListItem)
            {
                this.operationsListBox.Items.Clear();
            }
        }
 
        private void SelectServiceOperation(OperationInfoBase operationInfo)
        {
            Fx.Assert(operationInfo != null, "operationInfo cannot be null");
            ServiceContractListItem serviceContract = this.serviceContracts.Find(operationInfo.GetContractFullName(null));
            // Dont select operation if the contract cannot be found in the serviceContracts list
            if (serviceContract == null)
            {
                return;
            }
            ServiceOperationListItem operationItem = null;
            if (operationInfo is OperationInfo)
            {
                operationItem = new WorkflowServiceOperationListItem();
                operationItem.Validating += new CancelEventHandler(ServiceOperationValidating);
 
                operationItem.Name = operationInfo.Name;
                ((WorkflowServiceOperationListItem) operationItem).Operation = operationInfo as OperationInfo;
 
            }
            else if (operationInfo is TypedOperationInfo)
            {
                operationItem = new TypedServiceOperationListItem();
                operationItem.Validating += new CancelEventHandler(ServiceOperationValidating);
                operationItem.Name = operationInfo.Name;
                ((TypedServiceOperationListItem) operationItem).Operation = operationInfo as TypedOperationInfo;
            }
 
            serviceContract.SelectionOperation(operationItem);
        }
 
        void ServiceContractValidating(object sender, CancelEventArgs e)
        {
            ServiceContractListItem serviceContractListItem = (ServiceContractListItem) sender;
 
            if (string.IsNullOrEmpty(serviceContractListItem.Name))
            {
                e.Cancel = true;
                string errorString = SR2.GetString(SR2.ContractNameCannotBeEmpty);
                DesignerHelpers.ShowMessage(this.serviceProvider, errorString, System.Workflow.ComponentModel.Design.DR.GetString(System.Workflow.ComponentModel.Design.DR.WorkflowDesignerTitle), MessageBoxButtons.OK,
                    MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
 
            }
            bool duplicatesFound = false;
            foreach (ServiceContractListItem foundContract in serviceContracts)
            {
                if (foundContract == serviceContractListItem)
                {
                    continue;
                }
 
                // allow reimport of existing imported contracts
                if (!serviceContractListItem.IsCustomContract && serviceContractListItem.ContractType.Equals(foundContract.ContractType))
                {
                    continue;
                }
 
                if (foundContract.Name.Equals(serviceContractListItem.Name))
                {
                    duplicatesFound = true;
                    break;
                }
 
            }
            // contract names must be unique
            if (duplicatesFound)
            {
 
                e.Cancel = true;
                string errorString = SR2.GetString(SR2.ContractNameMustBeUnique);
                DesignerHelpers.ShowMessage(this.serviceProvider, errorString, System.Workflow.ComponentModel.Design.DR.GetString(System.Workflow.ComponentModel.Design.DR.WorkflowDesignerTitle), MessageBoxButtons.OK,
                    MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
 
            }
        }
 
 
 
 
        void ServiceOperationValidating(object sender, CancelEventArgs e)
        {
 
            ServiceOperationListItem serviceOperationListItem = (ServiceOperationListItem) sender;
            string newOperationName = serviceOperationListItem.Name;
            string contractName = serviceOperationListItem.ContractName;
            if (string.IsNullOrEmpty(newOperationName))
            {
                e.Cancel = true;
                string errorString = SR2.GetString(SR2.OperationNameCannotBeEmpty);
                DesignerHelpers.ShowMessage(this.serviceProvider, errorString, System.Workflow.ComponentModel.Design.DR.GetString(System.Workflow.ComponentModel.Design.DR.WorkflowDesignerTitle), MessageBoxButtons.OK,
                    MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
            }
 
            Fx.Assert(!string.IsNullOrEmpty(contractName), "contract name should be valid to run this check");
            ServiceContractListItem contractListItem = serviceContracts.Find(contractName);
            Fx.Assert(contractListItem != null, "contract should be present in the list to run this check");
 
            // operation names must be unique inside a contract
            bool duplicatesFound = false;
            foreach (ServiceOperationListItem foundOperation in contractListItem.Operations)
            {
                if (foundOperation == serviceOperationListItem)
                {
                    continue;
                }
                if (foundOperation.Name.Equals(newOperationName))
                {
                    duplicatesFound = true;
                    break;
                }
 
            }
            if (duplicatesFound)
            {
 
                e.Cancel = true;
                string errorString = SR2.GetString(SR2.OperationNameMustBeUnique);
                DesignerHelpers.ShowMessage(this.serviceProvider, errorString, System.Workflow.ComponentModel.Design.DR.GetString(System.Workflow.ComponentModel.Design.DR.WorkflowDesignerTitle), MessageBoxButtons.OK,
                    MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
 
            }
 
        }
 
        [ListItemView(typeof(HelpListItemViewControl))]
        [ListItemDetailView(typeof(ListItemViewControl))]
        private class HelpListItem
        {
        }
 
        private class HelpListItemViewControl : ListItemViewControl
        {
 
            protected override void OnLoad(EventArgs e)
            {
                this.Width = this.Parent.Width - 10;
                Label label = new Label();
                label.ForeColor = System.Drawing.SystemColors.GrayText;
                label.Dock = DockStyle.Fill;
                this.Font = new Font(this.Font, FontStyle.Italic);
                label.Text = SR2.GetString(SR2.AddOperationsUsingImportAddButtons);
                this.Controls.Add(label);
            }
        }
 
        private class ServiceContractsTypeFilterProvider : ITypeFilterProvider
        {
 
            string ITypeFilterProvider.FilterDescription
            {
                get { return SR2.GetString(SR2.ChooseAServiceContractFromBelow); }
            }
            bool ITypeFilterProvider.CanFilterType(Type type, bool throwOnError)
            {
                if (!type.IsInterface)
                {
                    return false;
                }
                if (type.IsDefined(typeof(ServiceContractAttribute), true))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
 
 
    }
}