File: AuthoringOM\Design\CustomActivityDesigner.cs
Project: ndp\cdf\src\WF\Common\System.Workflow.ComponentModel.csproj (System.Workflow.ComponentModel)
namespace System.Workflow.ComponentModel.Design
{
    #region Using directives
 
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Text;
    using System.ComponentModel;
    using System.Drawing.Design;
    using System.ComponentModel.Design;
    using System.Workflow.ComponentModel;
    using System.Workflow.ComponentModel.Compiler;
    using System.Globalization;
    using System.Reflection;
    using System.Reflection.Emit;
    using System.ComponentModel.Design.Serialization;
    using System.Windows.Forms;
    using System.Windows.Forms.Design;
    using System.CodeDom;
 
    #endregion
 
    #region Class CustomActivityDesignerAdapter
 
    internal sealed class CustomActivityDesignerAdapter : IDisposable
    {
        private IServiceProvider serviceProvider = null;
        private EventHandler ensureChildHierarchyHandler = null;
 
        public CustomActivityDesignerAdapter(IServiceProvider serviceProvider)
        {
            this.serviceProvider = serviceProvider;
 
            IComponentChangeService componentChangeService = this.serviceProvider.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
            if (componentChangeService != null)
            {
                componentChangeService.ComponentAdding += new ComponentEventHandler(OnComponentAdding);
                componentChangeService.ComponentAdded += new ComponentEventHandler(OnComponentAdded);
            }
        }
 
        void IDisposable.Dispose()
        {
            if (this.ensureChildHierarchyHandler != null)
            {
                Application.Idle -= this.ensureChildHierarchyHandler;
                this.ensureChildHierarchyHandler = null;
            }
 
            IComponentChangeService componentChangeService = this.serviceProvider.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
            if (componentChangeService != null)
            {
                componentChangeService.ComponentAdding -= new ComponentEventHandler(OnComponentAdding);
                componentChangeService.ComponentAdded -= new ComponentEventHandler(OnComponentAdded);
            }
        }
 
        #region Helpers
        private void OnComponentAdding(object sender, ComponentEventArgs eventArgs)
        {
            //We are adding root component, while doing this make sure that we provide the root designer attribute
            IDesignerHost designerHost = (IDesignerHost)this.serviceProvider.GetService(typeof(IDesignerHost));
            if (designerHost != null)
            {
                if (designerHost.RootComponent == null)
                {
                    Activity rootActivity = eventArgs.Component as Activity;
                    if (rootActivity != null)
                    {
                        //Add root designer attribute
                        DesignerAttribute rootDesignerAttrib = GetDesignerAttribute(rootActivity, typeof(IRootDesigner));
                        if (rootDesignerAttrib.DesignerTypeName == typeof(ActivityDesigner).AssemblyQualifiedName)
                        {
                            DesignerAttribute designerAttrib = GetDesignerAttribute(rootActivity, typeof(IDesigner));
                            if (designerAttrib != null)
                                TypeDescriptor.AddAttributes(rootActivity, new Attribute[] { new DesignerAttribute(designerAttrib.DesignerTypeName, typeof(IRootDesigner)) });
                        }
                    }
                }
            }
        }
 
        private void OnComponentAdded(object sender, ComponentEventArgs eventArgs)
        {
            IDesignerHost designerHost = (IDesignerHost)this.serviceProvider.GetService(typeof(IDesignerHost));
            if (designerHost != null)
            {
                if (designerHost.RootComponent == eventArgs.Component)
                {
                    Activity rootActivity = designerHost.RootComponent as Activity;
                    if (rootActivity != null)
                    {
                        CompositeActivity compositeActivity = rootActivity as CompositeActivity;
                        if (compositeActivity != null)
                        {
                            if (this.ensureChildHierarchyHandler == null)
                            {
                                this.ensureChildHierarchyHandler = new EventHandler(OnEnsureChildHierarchy);
                                Application.Idle += this.ensureChildHierarchyHandler;
                            }
                        }
                        rootActivity.UserData[UserDataKeys.CustomActivity] = false;
                    }
                }
                else if (eventArgs.Component is Activity)
                {
                    if ((eventArgs.Component is CompositeActivity) && Helpers.IsCustomActivity(eventArgs.Component as CompositeActivity))
                        (eventArgs.Component as Activity).UserData[UserDataKeys.CustomActivity] = true;
                    else
                        (eventArgs.Component as Activity).UserData[UserDataKeys.CustomActivity] = false;
                }
            }
        }
 
        /// PLEASE NOTE: We have added this handler for a reason. When the user changes the base type of the Activity
        /// we reload the designer after flushing the changes to the buffer, we do that in the IDesignerHost.TransactionClosed event
        /// The reload of the designer is then done on Idle event; but during reload we add extra components in the composite activity
        /// which in short modifies the composite activity,but during loading process the BasicDesignerLoader ignores such modification and
        /// does not tag the buffer as modified. The problem which happens due to this is that we wont flush the changes caused by
        /// adding of additional components to the buffer there by not saving the child designers. Hence instead of adding components during reload
        /// we add them in the first idle event after reload.
        private void OnEnsureChildHierarchy(object sender, EventArgs e)
        {
            if (this.ensureChildHierarchyHandler != null)
            {
                Application.Idle -= this.ensureChildHierarchyHandler;
                this.ensureChildHierarchyHandler = null;
 
                IDesignerHost designerHost = (IDesignerHost)this.serviceProvider.GetService(typeof(IDesignerHost));
                if (designerHost != null)
                    EnsureDefaultChildHierarchy(designerHost);
            }
        }
 
        private static DesignerAttribute GetDesignerAttribute(object component, Type designerBaseType)
        {
            AttributeCollection attribs = TypeDescriptor.GetAttributes(component);
            foreach (Attribute attribute in attribs)
            {
                DesignerAttribute designerAttribute = attribute as DesignerAttribute;
                if (designerAttribute != null && designerAttribute.DesignerBaseTypeName == designerBaseType.AssemblyQualifiedName)
                    return designerAttribute;
            }
 
            return null;
        }
 
        private static void EnsureDefaultChildHierarchy(IDesignerHost designerHost)
        {
            //When we are adding the root activity we need to make sure that all the child activities which are required by the parent
            //activity are looked up in the toolboxitem and added appropriately
            //If the composite activity already has a some child activities but not all then it 
            //means that user has changed the InitializeComponent and hence we do nothing
            //This is the simple check to get the designer working in case of selecting composite
            //root activities
            CompositeActivity rootActivity = designerHost.RootComponent as CompositeActivity;
            if (rootActivity != null && rootActivity.Activities.Count == 0)
            {
                object[] attribs = rootActivity.GetType().GetCustomAttributes(typeof(ToolboxItemAttribute), false);
                ToolboxItemAttribute toolboxItemAttrib = (attribs != null && attribs.GetLength(0) > 0) ? attribs[0] as ToolboxItemAttribute : null;
                if (toolboxItemAttrib != null && toolboxItemAttrib.ToolboxItemType != null)
                {
                    ToolboxItem item = Activator.CreateInstance(toolboxItemAttrib.ToolboxItemType, new object[] { rootActivity.GetType() }) as ToolboxItem;
                    IComponent[] components = item.CreateComponents();
 
                    //I am assuming here that there will be always one top level component created.
                    //If there are multiple then there is a bigger problem as we dont know how
                    //to use those
                    CompositeActivity compositeActivity = null;
                    foreach (IComponent component in components)
                    {
                        if (component.GetType() == rootActivity.GetType())
                        {
                            compositeActivity = component as CompositeActivity;
                            break;
                        }
                    }
 
                    //Add the children
                    if (compositeActivity != null && compositeActivity.Activities.Count > 0)
                    {
                        IIdentifierCreationService identifierCreationService = designerHost.GetService(typeof(IIdentifierCreationService)) as IIdentifierCreationService;
                        if (identifierCreationService != null)
                        {
                            //We do not go thru the composite designer here as composite activity
                            //might have simple designer
                            Activity[] activities = compositeActivity.Activities.ToArray();
                            compositeActivity.Activities.Clear();
 
                            identifierCreationService.EnsureUniqueIdentifiers(rootActivity, activities);
                            // Work around : Don't called AddRange because it doesn't send the ListChange notifications
                            // to the activity collection.  Use multiple Add calls instaead
                            foreach (Activity newActivity in activities)
                                rootActivity.Activities.Add(newActivity);
 
                            foreach (Activity childActivity in activities)
                                WorkflowDesignerLoader.AddActivityToDesigner(designerHost, childActivity);
                        }
                    }
                }
            }
        }
        #endregion
    }
    #endregion
 
    #region Extenders
 
    #region Class CustomActivityPropertyExtender
    [ProvideProperty("BaseActivityType", typeof(Activity))]
    internal sealed class CustomActivityPropertyExtender : IExtenderProvider
    {
        public CustomActivityPropertyExtender()
        {
        }
 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [SRDisplayName(SR.BaseActivityType)]
        [SRCategory(SR.ActivityDesc)]
        [SRDescription(SR.CustomActivityBaseTypeDesc)]
        [Editor(typeof(TypeBrowserEditor), typeof(UITypeEditor))]
        [DesignOnly(true)]
        [TypeFilterProvider(typeof(BaseClassTypeFilterProvider))]
        [DefaultValue("System.Workflow.ComponentModel.Sequence")]
        public string GetBaseActivityType(Activity activity)
        {
            // The activity type will be the base type.  No need for more complicated logic here.
            return activity.GetType().FullName;
        }
 
        //Do not remove this function, it is being called indirectly
        public void SetBaseActivityType(Activity activity, string baseActivityTypeName)
        {
            CustomActivityDesignerHelper.SetBaseTypeName(baseActivityTypeName, activity.Site);
 
            // Once the base type is changed, cause each of the companion class properties
            // to set their value again, updating their base types appropriatly
        }
 
        bool IExtenderProvider.CanExtend(object extendee)
        {
            bool canExtend = false;
 
            Activity activity = extendee as Activity;
            if (activity != null && activity.Site != null && activity == Helpers.GetRootActivity(activity))
            {
                ActivityDesigner rootDesigner = ActivityDesigner.GetDesigner(activity);
                if (rootDesigner != null && rootDesigner.ParentDesigner == null)
                    canExtend = true;
            }
 
            return canExtend;
        }
    }
    #endregion
 
    #endregion
 
    #region Class CustomActivityDesignerHelper
    internal static class CustomActivityDesignerHelper
    {
        #region Base Type Helper Methods
        public static Type GetCustomActivityType(IServiceProvider serviceProvider)
        {
            IDesignerHost host = serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;
            if (host == null)
                throw new Exception(SR.GetString(SR.General_MissingService, typeof(IDesignerHost).FullName));
 
            string className = host.RootComponentClassName;
            if (string.IsNullOrEmpty(className))
                return null;
 
            ITypeProvider typeProvider = serviceProvider.GetService(typeof(ITypeProvider)) as ITypeProvider;
            if (typeProvider == null)
                throw new Exception(SR.GetString(SR.General_MissingService, typeof(ITypeProvider).FullName));
 
            return typeProvider.GetType(className, false);
        }
 
        public static void SetBaseTypeName(string typeName, IServiceProvider serviceProvider)
        {
            if (string.IsNullOrEmpty(typeName))
                throw new ArgumentNullException("typeName");
 
            IDesignerHost host = serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;
            if (host == null)
                throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(IDesignerHost).FullName));
 
            IMemberCreationService memberCreationService = serviceProvider.GetService(typeof(IMemberCreationService)) as IMemberCreationService;
            if (memberCreationService == null)
                throw new InvalidOperationException(SR.GetString("General_MissingService", typeof(IMemberCreationService).FullName));
 
            // Validate the base type (this will throw an exception if the type name isn't valid
            Type newBaseType = ValidateBaseType(typeName, serviceProvider);
 
            //Warn the user of the change
            Type oldBaseType = host.RootComponent.GetType();
            if (oldBaseType == newBaseType)
                return;
 
            // If we're switch to a base type that is not derived from CompositeActivity, make sure
            // we dont's support events or exceptions
            if (!TypeProvider.IsAssignable(typeof(CompositeActivity), newBaseType))
            {
                PropertyDescriptor supportsEventsPropDesc = TypeDescriptor.GetProperties(host.RootComponent)["SupportsEvents"];
                if (supportsEventsPropDesc != null && ((bool)supportsEventsPropDesc.GetValue(host.RootComponent)) == true)
                    supportsEventsPropDesc.SetValue(host.RootComponent, false);
 
                PropertyDescriptor supportsExceptionsPropDesc = TypeDescriptor.GetProperties(host.RootComponent)["SupportsExceptions"];
                if (supportsExceptionsPropDesc != null && ((bool)supportsExceptionsPropDesc.GetValue(host.RootComponent)) == true)
                    supportsExceptionsPropDesc.SetValue(host.RootComponent, false);
            }
 
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(host.RootComponent);
            if (host.RootComponent is CompositeActivity && ((CompositeActivity)host.RootComponent).Activities.Count > 0)
            {
                // Warn user first if there are any children that can not be re-parented to the new root.
                IUIService uiService = serviceProvider.GetService(typeof(IUIService)) as IUIService;
                if (uiService != null)
                {
                    if (DialogResult.OK != uiService.ShowMessage(SR.GetString(SR.NoChildActivities_Message),
                        SR.GetString(SR.NoChildActivities_Caption), MessageBoxButtons.OKCancel))
                        return;
                }
 
                // Remove the children first. This would cause the component removed event to be fired,
                // thus remove the generated field from the designer.cs file.
                List<Activity> activitiesToRemove = new List<Activity>(((CompositeActivity)host.RootComponent).Activities);
                CompositeActivityDesigner rootDesigner = host.GetDesigner(host.RootComponent) as CompositeActivityDesigner;
                if (rootDesigner != null)
                    rootDesigner.RemoveActivities(activitiesToRemove.AsReadOnly());
            }
 
            //Also, clear all properties of original base. That will allow undo to set old values back.
            foreach (PropertyDescriptor propertyDescriptor in properties)
            {
                if (!propertyDescriptor.Name.Equals("BaseActivityType", StringComparison.Ordinal) &&
                    !propertyDescriptor.Name.Equals("Name", StringComparison.Ordinal) &&
                    propertyDescriptor.CanResetValue(host.RootComponent))
                {
                    propertyDescriptor.ResetValue(host.RootComponent);
                }
            }
 
            PropertyDescriptor realBaseActivityTypePropertyDescriptor = properties["BaseActivityType"];
            PropertyDescriptor baseActivityTypePropertyDescriptor = TypeDescriptor.CreateProperty(realBaseActivityTypePropertyDescriptor.ComponentType, realBaseActivityTypePropertyDescriptor, DesignerSerializationVisibilityAttribute.Visible);
 
            IComponentChangeService changeService = serviceProvider.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
            if (changeService != null)
                changeService.OnComponentChanging(host.RootComponent, baseActivityTypePropertyDescriptor);
 
            ((Activity)host.RootComponent).UserData[UserDataKeys.NewBaseType] = newBaseType;
 
            memberCreationService.UpdateBaseType(host.RootComponentClassName, newBaseType);
 
            if (changeService != null)
                changeService.OnComponentChanged(host.RootComponent, baseActivityTypePropertyDescriptor, baseActivityTypePropertyDescriptor.GetValue(host.RootComponent), typeName);
 
            //Work around: Force update of the host by raising idle.This is to ensure undo events work on updated host.
            Application.RaiseIdle(new EventArgs());
        }
 
        private static Type ValidateBaseType(string typeName, IServiceProvider serviceProvider)
        {
            if (typeName != null && typeName.Length > 0)
            {
                ITypeProvider typeProvider = (ITypeProvider)serviceProvider.GetService(typeof(ITypeProvider));
                if (typeProvider == null)
                    throw new Exception(SR.GetString(SR.General_MissingService, typeof(ITypeProvider).FullName));
 
                Type type = typeProvider.GetType(typeName);
                if (type == null)
                    throw new Exception(SR.GetString(SR.Error_TypeNotResolved, typeName));
 
                IDesignerHost host = serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;
                if (host == null)
                    throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(IDesignerHost).FullName));
 
                Type rootComponentType = typeProvider.GetType(host.RootComponentClassName);
 
                if (type is DesignTimeType && rootComponentType != null && rootComponentType.Assembly == type.Assembly)
                    throw new InvalidOperationException(SR.GetString(SR.Error_CantUseCurrentProjectTypeAsBase));
 
                if (!TypeProvider.IsAssignable(typeof(Activity), type))
                    throw new InvalidOperationException(SR.GetString(SR.Error_BaseTypeMustBeActivity));
 
                return type;
            }
 
            return null;
        }
 
        #endregion
 
        #region Custom Properties Helper Methods
        internal static List<CustomProperty> GetCustomProperties(IServiceProvider serviceProvider)
        {
            // We need to perform a flush just before getting the custom properties so that we are sure that type system is updated
            // and we always get the updated properties
            WorkflowDesignerLoader loader = serviceProvider.GetService(typeof(IDesignerLoaderService)) as WorkflowDesignerLoader;
            if (loader != null)
                loader.Flush();
 
            Type customActivityType = GetCustomActivityType(serviceProvider);
            if (customActivityType == null)
                return null;
 
            List<CustomProperty> cpc = new List<CustomProperty>();
            PropertyInfo[] properties = customActivityType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
            foreach (PropertyInfo property in properties)
            {
                if (property.PropertyType != null)
                    cpc.Add(CreateCustomProperty(serviceProvider, customActivityType, property, property.PropertyType));
            }
 
            EventInfo[] events = customActivityType.GetEvents(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
            foreach (EventInfo evt in events)
            {
                if (evt.EventHandlerType == null)
                    continue;
                CustomProperty eventProperty = CreateCustomProperty(serviceProvider, customActivityType, evt, evt.EventHandlerType);
                eventProperty.IsEvent = true;
                cpc.Add(eventProperty);
            }
 
            return cpc;
        }
 
        private static CustomProperty CreateCustomProperty(IServiceProvider serviceProvider, Type customActivityType, MemberInfo member, Type propertyType)
        {
            CustomProperty customProperty = new CustomProperty(serviceProvider);
            customProperty.Name = member.Name;
            customProperty.IsEvent = (member is EventInfo);
 
            if (propertyType == typeof(ActivityBind))
            {
                customProperty.GenerateDependencyProperty = false;
                customProperty.Type = typeof(ActivityBind).FullName;
            }
            else
            {
                string fieldSuffix = (customProperty.IsEvent) ? "Event" : "Property";
                FieldInfo fieldInfo = customActivityType.GetField(member.Name + fieldSuffix, BindingFlags.Public | BindingFlags.Static);
                if ((fieldInfo != null && fieldInfo.FieldType == typeof(DependencyProperty)))
                    customProperty.GenerateDependencyProperty = true;
                else
                    customProperty.GenerateDependencyProperty = false;
 
                customProperty.Type = propertyType.FullName;
            }
 
            customProperty.oldPropertyName = member.Name;
            customProperty.oldPropertyType = propertyType.FullName;
 
            object[] hiddenCodeAttributes = member.GetCustomAttributes(typeof(FlagsAttribute), true);
            if (hiddenCodeAttributes != null && hiddenCodeAttributes.Length > 0)
                customProperty.Hidden = true;
 
            foreach (object attributeObj in member.GetCustomAttributes(false))
            {
                AttributeInfoAttribute attribute = attributeObj as AttributeInfoAttribute;
                AttributeInfo attributeInfo = (attribute != null) ? attribute.AttributeInfo : null;
                if (attributeInfo != null)
                {
                    try
                    {
                        if (attributeInfo.AttributeType == typeof(BrowsableAttribute) && attributeInfo.ArgumentValues.Count > 0)
                        {
                            customProperty.Browseable = (bool)attributeInfo.GetArgumentValueAs(serviceProvider, 0, typeof(bool));
                        }
                        else if (attributeInfo.AttributeType == typeof(CategoryAttribute) && attributeInfo.ArgumentValues.Count > 0)
                        {
                            customProperty.Category = attributeInfo.GetArgumentValueAs(serviceProvider, 0, typeof(string)) as string;
                        }
                        else if (attributeInfo.AttributeType == typeof(DescriptionAttribute) && attributeInfo.ArgumentValues.Count > 0)
                        {
                            customProperty.Description = attributeInfo.GetArgumentValueAs(serviceProvider, 0, typeof(string)) as string;
                        }
                        else if (attributeInfo.AttributeType == typeof(DesignerSerializationVisibilityAttribute) && attributeInfo.ArgumentValues.Count > 0)
                        {
                            customProperty.DesignerSerializationVisibility = (DesignerSerializationVisibility)attributeInfo.GetArgumentValueAs(serviceProvider, 0, typeof(DesignerSerializationVisibility));
                        }
                        else if (attributeInfo.AttributeType == typeof(EditorAttribute) && attributeInfo.ArgumentValues.Count > 1)
                        {
                            Type editorType = attributeInfo.GetArgumentValueAs(serviceProvider, 1, typeof(Type)) as Type;
                            if (editorType == typeof(UITypeEditor))
                            {
                                Type uiTypeEditorType = attributeInfo.GetArgumentValueAs(serviceProvider, 0, typeof(Type)) as Type;
                                if (uiTypeEditorType != null)
                                    customProperty.UITypeEditor = uiTypeEditorType.FullName;
 
                                if (String.IsNullOrEmpty(customProperty.UITypeEditor))
                                    customProperty.UITypeEditor = attributeInfo.GetArgumentValueAs(serviceProvider, 0, typeof(string)) as string;
                            }
                        }
                    }
                    catch
                    {
                        // Catch and ignore all attribute value conversion errors
                    }
                }
            }
 
            return customProperty;
        }
 
 
        internal static void SetCustomProperties(List<CustomProperty> customProperties, IServiceProvider serviceProvider)
        {
            if (customProperties == null)
                throw new ArgumentNullException("customProperties");
 
            Type customActivityType = GetCustomActivityType(serviceProvider);
            if (customActivityType == null)
                return;
 
            List<CustomProperty> existingCustomProperties = GetCustomProperties(serviceProvider);
 
            // Remove any deleted properties
            RemoveDeletedProperties(customProperties, customActivityType, serviceProvider);
 
            // Add any new properties
            AddNewProperties(customProperties, customActivityType, serviceProvider, existingCustomProperties);
        }
 
        private static void RemoveDeletedProperties(List<CustomProperty> propCollection, Type customActivityType, IServiceProvider serviceProvider)
        {
            // 
            IMemberCreationService memberCreationService = serviceProvider.GetService(typeof(IMemberCreationService)) as IMemberCreationService;
            if (memberCreationService == null)
                throw new Exception(SR.GetString(SR.General_MissingService, typeof(IMemberCreationService).FullName));
 
            PropertyInfo[] properties = customActivityType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
            foreach (PropertyInfo property in properties)
            {
                bool found = false;
                foreach (CustomProperty customProperty in propCollection)
                {
                    if (property.Name == customProperty.oldPropertyName &&
                        property.PropertyType.FullName == customProperty.oldPropertyType)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                    memberCreationService.RemoveProperty(customActivityType.FullName, property.Name, property.PropertyType);
            }
 
            EventInfo[] events = customActivityType.GetEvents(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
            foreach (EventInfo evtInfo in events)
            {
                bool found = false;
                foreach (CustomProperty customProperty in propCollection)
                {
                    if (evtInfo.Name == customProperty.oldPropertyName &&
                        evtInfo.EventHandlerType.FullName == customProperty.oldPropertyType)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found && evtInfo.Name != null && evtInfo.EventHandlerType != null)
                    memberCreationService.RemoveEvent(customActivityType.FullName, evtInfo.Name, evtInfo.EventHandlerType);
            }
        }
 
        private static void AddNewProperties(List<CustomProperty> propCollection, Type customActivityType, IServiceProvider serviceProvider, List<CustomProperty> existingProps)
        {
            IMemberCreationService memberCreationService = serviceProvider.GetService(typeof(IMemberCreationService)) as IMemberCreationService;
            if (memberCreationService == null)
                throw new Exception(SR.GetString(SR.General_MissingService, typeof(IMemberCreationService).FullName));
 
            ITypeProvider typeProvider = serviceProvider.GetService(typeof(ITypeProvider)) as ITypeProvider;
            if (typeProvider == null)
                throw new Exception(SR.GetString(SR.General_MissingService, typeof(ITypeProvider).FullName));
 
            try
            {
                //
 
 
 
                foreach (CustomProperty property in propCollection)
                {
                    bool createNew = (property.oldPropertyName == null || property.oldPropertyType == null);
                    if (!createNew)
                    {
                        if (!property.IsEvent)
                            createNew = (customActivityType.GetProperty(property.oldPropertyName, typeProvider.GetType(property.oldPropertyType)) == null);
                        else
                            createNew = (customActivityType.GetEvent(property.oldPropertyName) == null);
                    }
 
                    if (createNew)
                    {
                        AttributeInfo[] attributes = CreateCustomPropertyAttributeArray(property, serviceProvider);
                        if (property.IsEvent)
                            memberCreationService.CreateEvent(customActivityType.FullName, property.Name, typeProvider.GetType(property.Type), attributes, property.GenerateDependencyProperty);
                        else
                            memberCreationService.CreateProperty(customActivityType.FullName, property.Name, typeProvider.GetType(property.Type), attributes, property.GenerateDependencyProperty, false, false, null, false);
                    }
                    else
                    {
                        // 
 
                        CustomProperty oldProperty = null;
                        foreach (CustomProperty existingProperty in existingProps)
                        {
                            if (existingProperty.Name == property.oldPropertyName && existingProperty.Type == property.oldPropertyType)
                                oldProperty = existingProperty;
                        }
 
                        if (oldProperty == null || ArePropertiesDifferent(property, oldProperty))
                        {
                            AttributeInfo[] attributes = CreateCustomPropertyAttributeArray(property, serviceProvider);
                            AttributeInfo[] oldAttributes = CreateCustomPropertyAttributeArray(oldProperty, serviceProvider);
 
                            Type propertyType = typeProvider.GetType(property.Type, false);
                            Type oldPropertyType = typeProvider.GetType(property.oldPropertyType, false);
                            if (propertyType != null)
                            {
                                if (property.IsEvent)
                                    memberCreationService.UpdateEvent(customActivityType.FullName, property.oldPropertyName, oldPropertyType, property.Name, propertyType, attributes, property.GenerateDependencyProperty, false);
                                else
                                    memberCreationService.UpdateProperty(customActivityType.FullName, property.oldPropertyName, oldPropertyType, property.Name, propertyType, attributes, property.GenerateDependencyProperty, false);
                            }
                        }
                    }
                }
            }
            finally
            {
                //
 
 
            }
        }
 
        private static AttributeInfo[] CreateCustomPropertyAttributeArray(CustomProperty property, IServiceProvider serviceProvider)
        {
            // Don't generate these attributes for hidden properties, just let the
            // attributes that already exist on the property stay
            if (property == null || property.Hidden)
                return new AttributeInfo[0];
 
            List<AttributeInfo> attributeList = new List<AttributeInfo>();
 
            if (property.Category != null)
                attributeList.Add(new AttributeInfo(typeof(CategoryAttribute), new string[] { }, new object[] { new CodePrimitiveExpression(property.Category) }));
 
            if (property.Description != null)
                attributeList.Add(new AttributeInfo(typeof(DescriptionAttribute), new string[] { }, new object[] { new CodePrimitiveExpression(property.Description) }));
 
            if (!string.IsNullOrEmpty(property.UITypeEditor))
                attributeList.Add(new AttributeInfo(typeof(EditorAttribute), new string[] { }, new object[] { new CodeTypeOfExpression(property.UITypeEditor), new CodeTypeOfExpression(typeof(UITypeEditor)) }));
 
            attributeList.Add(new AttributeInfo(typeof(BrowsableAttribute), new string[] { }, new object[] { new CodePrimitiveExpression(property.Browseable) }));
            attributeList.Add(new AttributeInfo(typeof(DesignerSerializationVisibilityAttribute), new string[] { }, new object[] { new CodeSnippetExpression(typeof(DesignerSerializationVisibility).Name + "." + property.DesignerSerializationVisibility.ToString()) }));
 
            return attributeList.ToArray();
        }
 
        private static bool ArePropertiesDifferent(CustomProperty property, CustomProperty oldProperty)
        {
            if (property.Name == oldProperty.Name &&
                property.Type == oldProperty.Type &&
                property.Browseable == oldProperty.Browseable &&
                property.Category == oldProperty.Category &&
                property.Description == oldProperty.Description &&
                property.DesignerSerializationVisibility == oldProperty.DesignerSerializationVisibility &&
                property.Hidden == oldProperty.Hidden &&
                property.UITypeEditor == oldProperty.UITypeEditor)
            {
                return false;
            }
 
            return true;
        }
        #endregion
    }
    #endregion
 
    #region Class BaseClassTypeFilterProvider
    internal sealed class BaseClassTypeFilterProvider : ITypeFilterProvider
    {
        private IServiceProvider serviceProvider;
 
        public BaseClassTypeFilterProvider(IServiceProvider serviceProvider)
        {
            this.serviceProvider = serviceProvider;
        }
 
        #region ITypeFilterProvider Members
        bool ITypeFilterProvider.CanFilterType(Type type, bool throwOnError)
        {
            bool filterType = false;
            if (TypeProvider.IsAssignable(typeof(Activity), type) && type.IsPublic && !type.IsSealed && !type.IsAbstract && !(type is DesignTimeType))
            {
                filterType = true;
            }
 
            return filterType;
        }
 
        string ITypeFilterProvider.FilterDescription
        {
            get
            {
                return SR.GetString(SR.CustomActivityBaseClassTypeFilterProviderDesc);
            }
        }
        #endregion
    }
    #endregion
 
    #region CustomProperties
    internal sealed class CustomProperty
    {
        public string oldPropertyName;
        public string oldPropertyType;
        private string name;
        private string type;
        private string category;
        private string description;
        private DesignerSerializationVisibility designerSerializationVisibility = DesignerSerializationVisibility.Visible;
        // NOTE: we don't write the ValidationOption attribute anymore (WinOE Bug 17398). We have removed our property creation
        // dialog in beta1.  Now this code is only used for property promotion.  If the promoted property is a meta property,
        // it can not be bindable so no promotion is not allowed.  If the property is an instance property, this attribute is ignored.  
        // There is no reason for writing out this attribute anymore.We just remove it from property promotion all together.
        // NOTE II: for the same reason that this code is only used for promotion, we don't write out meta properties anymore.
        // We had customized the CodeDomSerializer.Deserialize to recognize meta properties by inspecting the field init expression,
        // which is no long needed.  If we were to bring this functionality back in the future, sample code can be found
        // from the file history in Source Depot.
        private bool isEvent = false;
        private bool browseable = true;
        private bool hidden = false;
        private string uiTypeEditor;
        private IServiceProvider serviceProvider = null;
        private bool generateDependencyProperty = true;
 
        public CustomProperty(IServiceProvider serviceProvider)
        {
            this.serviceProvider = serviceProvider;
        }
 
        public string Name
        {
            get
            {
                return this.name;
            }
            set
            {
                this.name = value;
            }
        }
 
        public string Type
        {
            get
            {
                return this.type;
            }
            set
            {
                this.type = value;
            }
        }
 
        public string Description
        {
            get
            {
                return this.description;
            }
            set
            {
                this.description = value;
            }
        }
 
        public string Category
        {
            get
            {
                return this.category;
            }
            set
            {
                this.category = value;
            }
        }
 
        public bool Browseable
        {
            get
            {
                return this.browseable;
            }
            set
            {
                this.browseable = value;
            }
        }
 
        public DesignerSerializationVisibility DesignerSerializationVisibility
        {
            get
            {
                return this.designerSerializationVisibility;
            }
            set
            {
                this.designerSerializationVisibility = value;
            }
        }
 
        public string UITypeEditor
        {
            get
            {
                return this.uiTypeEditor;
            }
            set
            {
                string typeName = value;
 
                // Try to make sure the type is specified witht he fullName;
                if (this.serviceProvider != null)
                {
                    ITypeProvider typeProvider = this.serviceProvider.GetService(typeof(ITypeProvider)) as ITypeProvider;
                    if (typeProvider == null)
                        throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(ITypeProvider).FullName));
 
                    Type type = typeProvider.GetType(typeName);
                    if (type != null)
                        typeName = type.FullName;
                }
 
                this.uiTypeEditor = typeName;
            }
        }
 
        public bool IsEvent
        {
            get
            {
                return this.isEvent;
            }
            set
            {
                this.isEvent = value;
            }
        }
 
        public bool Hidden
        {
            get
            {
                return this.hidden;
            }
            set
            {
                this.hidden = value;
            }
        }
 
        public bool GenerateDependencyProperty
        {
            get
            {
                return this.generateDependencyProperty;
            }
 
            set
            {
                this.generateDependencyProperty = value;
            }
        }
 
        #region Private Helpers
        public static CustomProperty CreateCustomProperty(IServiceProvider serviceProvider, string customPropertyName, PropertyDescriptor propertyDescriptor, object propertyOwner)
        {
            CustomProperty newCustomProperty = new CustomProperty(serviceProvider);
            newCustomProperty.Name = customPropertyName;
            if (TypeProvider.IsAssignable(typeof(ActivityBind), propertyDescriptor.PropertyType))
            {
                Type baseType = PropertyDescriptorUtils.GetBaseType(propertyDescriptor, propertyOwner, serviceProvider);
                if (baseType == null)
                    throw new InvalidOperationException(SR.GetString(SR.Error_CantDeterminePropertyBaseType, propertyDescriptor.Name));
                newCustomProperty.Type = baseType.FullName;
            }
            else
            {
                newCustomProperty.Type = propertyDescriptor.PropertyType.FullName;
            }
 
            if (propertyDescriptor is ActivityBindPropertyDescriptor)
            {
                DependencyProperty dependencyProperty = DependencyProperty.FromName(propertyDescriptor.Name, propertyDescriptor.ComponentType);
                newCustomProperty.IsEvent = (dependencyProperty != null && dependencyProperty.IsEvent);
            }
 
            newCustomProperty.Category = propertyDescriptor.Category;
            return newCustomProperty;
        }
        #endregion
    }
    #endregion
 
}