/mcs/class/System.Design/System.ComponentModel.Design/CollectionEditor.cs
C# | 747 lines | 582 code | 86 blank | 79 comment | 67 complexity | d2138ef92e2bdbd57fdb0c191fcf3c27 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
- //
- // System.ComponentModel.Design.CollectionEditor
- //
- // Authors:
- // Martin Willemoes Hansen (mwh@sysrq.dk)
- // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
- // Ivan N. Zlatev (contact@i-nz.net)
- //
- // (C) 2003 Martin Willemoes Hansen
- // (C) 2007 Andreas Nahr
- // (C) 2007 Ivan N. Zlatev
- // (C) 2008 Novell, Inc
- //
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- using System;
- using System.Reflection;
- using System.Collections;
- using System.ComponentModel;
- using System.Drawing.Design;
- using System.Windows.Forms;
- using System.Windows.Forms.Design;
- namespace System.ComponentModel.Design
- {
- public class CollectionEditor : UITypeEditor
- {
- protected abstract class CollectionForm : Form
- {
- private CollectionEditor editor;
- private object editValue;
- public CollectionForm (CollectionEditor editor)
- {
- this.editor = editor;
- }
- protected Type CollectionItemType
- {
- get { return editor.CollectionItemType; }
- }
- protected Type CollectionType
- {
- get { return editor.CollectionType; }
- }
- protected ITypeDescriptorContext Context
- {
- get { return editor.Context; }
- }
- public object EditValue
- {
- get { return editValue; }
- set
- {
- editValue = value;
- OnEditValueChanged ();
- }
- }
- protected object[] Items
- {
- get { return editor.GetItems (editValue); }
- set {
- if (editValue == null) {
- object newEmptyCollection = null;
- try {
- if (typeof (Array).IsAssignableFrom (CollectionType))
- newEmptyCollection = Array.CreateInstance (CollectionItemType, 0);
- else
- newEmptyCollection = Activator.CreateInstance (CollectionType);
- } catch {}
- object val = editor.SetItems (newEmptyCollection, value);
- if (val != newEmptyCollection)
- EditValue = val;
- } else {
- object val = editor.SetItems (editValue, value);
- if (val != editValue)
- EditValue = val;
- }
- }
- }
- protected Type[] NewItemTypes
- {
- get { return editor.NewItemTypes; }
- }
- protected bool CanRemoveInstance (object value)
- {
- return editor.CanRemoveInstance (value);
- }
- protected virtual bool CanSelectMultipleInstances ()
- {
- return editor.CanSelectMultipleInstances ();
- }
- protected object CreateInstance (Type itemType)
- {
- return editor.CreateInstance (itemType);
- }
- protected void DestroyInstance (object instance)
- {
- editor.DestroyInstance (instance);
- }
- protected virtual void DisplayError (Exception e)
- {
- MessageBox.Show (e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Information);
- }
- protected override object GetService (Type serviceType)
- {
- return editor.GetService (serviceType);
- }
- protected abstract void OnEditValueChanged ();
- protected internal virtual DialogResult ShowEditorDialog (IWindowsFormsEditorService edSvc)
- {
- return edSvc.ShowDialog (this);
- }
- }
- private class ConcreteCollectionForm : CollectionForm
- {
- internal class ObjectContainerConverter : TypeConverter
- {
- private class ObjectContainerPropertyDescriptor : TypeConverter.SimplePropertyDescriptor
- {
- private AttributeCollection attributes;
- public ObjectContainerPropertyDescriptor (Type componentType, Type propertyType)
- : base (componentType, "Value", propertyType)
- {
- CategoryAttribute cat = new CategoryAttribute (propertyType.Name);
- attributes = new AttributeCollection (new Attribute[] { cat });
- }
- public override object GetValue (object component)
- {
- ObjectContainer container = (ObjectContainer)component;
- return container.Object;
- }
- public override void SetValue (object component, object value)
- {
- ObjectContainer container = (ObjectContainer)component;
- container.Object = value;
- }
- public override AttributeCollection Attributes
- {
- get { return attributes; }
- }
- }
- public override PropertyDescriptorCollection GetProperties (ITypeDescriptorContext context, object value, Attribute[] attributes)
- {
- ObjectContainer container = (ObjectContainer)value;
- ObjectContainerPropertyDescriptor desc = new ObjectContainerPropertyDescriptor (value.GetType (), container.editor.CollectionItemType);
- PropertyDescriptor[] properties = new PropertyDescriptor[] { desc };
- PropertyDescriptorCollection pc = new PropertyDescriptorCollection (properties);
- return pc;
- }
- public override bool GetPropertiesSupported (ITypeDescriptorContext context)
- {
- return true;
- }
- }
- [TypeConverter (typeof (ObjectContainerConverter))]
- private class ObjectContainer
- {
- internal object Object;
- internal CollectionEditor editor;
- public ObjectContainer (object obj, CollectionEditor editor)
- {
- this.Object = obj;
- this.editor = editor;
- }
- internal string Name {
- get { return editor.GetDisplayText (Object); }
- }
- public override string ToString ()
- {
- return Name;
- }
- }
- private class UpdateableListbox : ListBox
- {
- public void DoRefreshItem (int index)
- {
- base.RefreshItem (index);
- }
- }
- private CollectionEditor editor;
- private System.Windows.Forms.Label labelMember;
- private System.Windows.Forms.Label labelProperty;
- private UpdateableListbox itemsList;
- private System.Windows.Forms.PropertyGrid itemDisplay;
- private System.Windows.Forms.Button doClose;
- private System.Windows.Forms.Button moveUp;
- private System.Windows.Forms.Button moveDown;
- private System.Windows.Forms.Button doAdd;
- private System.Windows.Forms.Button doRemove;
- private System.Windows.Forms.Button doCancel;
- private System.Windows.Forms.ComboBox addType;
- public ConcreteCollectionForm (CollectionEditor editor)
- : base (editor)
- {
- this.editor = editor;
- this.labelMember = new System.Windows.Forms.Label ();
- this.labelProperty = new System.Windows.Forms.Label ();
- this.itemsList = new UpdateableListbox ();
- this.itemDisplay = new System.Windows.Forms.PropertyGrid ();
- this.doClose = new System.Windows.Forms.Button ();
- this.moveUp = new System.Windows.Forms.Button ();
- this.moveDown = new System.Windows.Forms.Button ();
- this.doAdd = new System.Windows.Forms.Button ();
- this.doRemove = new System.Windows.Forms.Button ();
- this.doCancel = new System.Windows.Forms.Button ();
- this.addType = new System.Windows.Forms.ComboBox ();
- this.SuspendLayout ();
- //
- // labelMember
- //
- this.labelMember.Location = new System.Drawing.Point (12, 9);
- this.labelMember.Size = new System.Drawing.Size (55, 13);
- this.labelMember.Text = "Members:";
- //
- // labelProperty
- //
- this.labelProperty.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.labelProperty.Location = new System.Drawing.Point (172, 9);
- this.labelProperty.Size = new System.Drawing.Size (347, 13);
- this.labelProperty.Text = "Properties:";
- //
- // itemsList
- //
- this.itemsList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
- | System.Windows.Forms.AnchorStyles.Left)));
- this.itemsList.HorizontalScrollbar = true;
- this.itemsList.Location = new System.Drawing.Point (12, 25);
- this.itemsList.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended;
- this.itemsList.Size = new System.Drawing.Size (120, 290);
- this.itemsList.TabIndex = 0;
- this.itemsList.SelectedIndexChanged += new System.EventHandler (this.itemsList_SelectedIndexChanged);
- //
- // itemDisplay
- //
- this.itemDisplay.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
- | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.itemDisplay.HelpVisible = false;
- this.itemDisplay.Location = new System.Drawing.Point (175, 25);
- this.itemDisplay.Size = new System.Drawing.Size (344, 314);
- this.itemDisplay.TabIndex = 6;
- this.itemDisplay.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler (this.itemDisplay_PropertyValueChanged);
- //
- // doClose
- //
- this.doClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
- this.doClose.Location = new System.Drawing.Point (341, 345);
- this.doClose.Size = new System.Drawing.Size (86, 26);
- this.doClose.TabIndex = 7;
- this.doClose.Text = "OK";
- this.doClose.Click += new System.EventHandler (this.doClose_Click);
- //
- // moveUp
- //
- this.moveUp.Location = new System.Drawing.Point (138, 25);
- this.moveUp.Size = new System.Drawing.Size (31, 28);
- this.moveUp.TabIndex = 4;
- this.moveUp.Enabled = false;
- this.moveUp.Text = "Up";
- this.moveUp.Click += new System.EventHandler (this.moveUp_Click);
- //
- // moveDown
- //
- this.moveDown.Location = new System.Drawing.Point (138, 59);
- this.moveDown.Size = new System.Drawing.Size (31, 28);
- this.moveDown.TabIndex = 5;
- this.moveDown.Enabled = false;
- this.moveDown.Text = "Dn";
- this.moveDown.Click += new System.EventHandler (this.moveDown_Click);
- //
- // doAdd
- //
- this.doAdd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
- this.doAdd.Location = new System.Drawing.Point (12, 346);
- this.doAdd.Size = new System.Drawing.Size (59, 25);
- this.doAdd.TabIndex = 1;
- this.doAdd.Text = "Add";
- this.doAdd.Click += new System.EventHandler (this.doAdd_Click);
- //
- // doRemove
- //
- this.doRemove.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
- this.doRemove.Location = new System.Drawing.Point (77, 346);
- this.doRemove.Size = new System.Drawing.Size (55, 25);
- this.doRemove.TabIndex = 2;
- this.doRemove.Text = "Remove";
- this.doRemove.Click += new System.EventHandler (this.doRemove_Click);
- //
- // doCancel
- //
- this.doCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
- this.doCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
- this.doCancel.Location = new System.Drawing.Point (433, 345);
- this.doCancel.Size = new System.Drawing.Size (86, 26);
- this.doCancel.TabIndex = 8;
- this.doCancel.Text = "Cancel";
- this.doCancel.Click += new System.EventHandler (this.doCancel_Click);
- //
- // addType
- //
- this.addType.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
- this.addType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
- this.addType.Location = new System.Drawing.Point (12, 319);
- this.addType.Size = new System.Drawing.Size (120, 21);
- this.addType.TabIndex = 3;
- //
- // DesignerForm
- //
- this.AcceptButton = this.doClose;
- this.CancelButton = this.doCancel;
- this.ClientSize = new System.Drawing.Size (531, 381);
- this.ControlBox = false;
- this.Controls.Add (this.addType);
- this.Controls.Add (this.doCancel);
- this.Controls.Add (this.doRemove);
- this.Controls.Add (this.doAdd);
- this.Controls.Add (this.moveDown);
- this.Controls.Add (this.moveUp);
- this.Controls.Add (this.doClose);
- this.Controls.Add (this.itemDisplay);
- this.Controls.Add (this.itemsList);
- this.Controls.Add (this.labelProperty);
- this.Controls.Add (this.labelMember);
- this.HelpButton = true;
- this.MaximizeBox = false;
- this.MinimizeBox = false;
- this.MinimumSize = new System.Drawing.Size (400, 300);
- this.ShowInTaskbar = false;
- this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
- this.ResumeLayout (false);
- #if NET_2_0
- if (editor.CollectionType.IsGenericType)
- this.Text = editor.CollectionItemType.Name + " Collection Editor";
- else
- this.Text = editor.CollectionType.Name + " Collection Editor";
- #else
- this.Text = editor.CollectionType.Name + " Collection Editor";
- #endif
- foreach (Type type in editor.NewItemTypes)
- addType.Items.Add (type.Name);
- if (addType.Items.Count > 0)
- addType.SelectedIndex = 0;
- }
- private void UpdateItems ()
- {
- object[] items = editor.GetItems (EditValue);
- if (items != null) {
- itemsList.BeginUpdate ();
- itemsList.Items.Clear ();
- foreach (object o in items)
- this.itemsList.Items.Add (new ObjectContainer (o, editor));
- if (itemsList.Items.Count > 0)
- itemsList.SelectedIndex = 0;
- itemsList.EndUpdate ();
- }
- }
- private void doClose_Click (object sender, EventArgs e)
- {
- SetEditValue ();
- this.Close ();
- }
- private void SetEditValue ()
- {
- object[] items = new object[itemsList.Items.Count];
- for (int i = 0; i < itemsList.Items.Count; i++)
- items[i] = ((ObjectContainer)itemsList.Items[i]).Object;
- this.Items = items;
- }
- private void doCancel_Click (object sender, EventArgs e)
- {
- editor.CancelChanges ();
- this.Close ();
- }
- private void itemsList_SelectedIndexChanged (object sender, EventArgs e)
- {
- if (itemsList.SelectedIndex == -1) {
- itemDisplay.SelectedObject = null;
- return;
- }
- if (itemsList.SelectedIndex <= 0 || itemsList.SelectedItems.Count > 1)
- moveUp.Enabled = false;
- else
- moveUp.Enabled = true;
- if (itemsList.SelectedIndex > itemsList.Items.Count - 2 || itemsList.SelectedItems.Count > 1)
- moveDown.Enabled = false;
- else
- moveDown.Enabled = true;
- if (itemsList.SelectedItems.Count == 1)
- {
- ObjectContainer o = (ObjectContainer)itemsList.SelectedItem;
- if (Type.GetTypeCode (o.Object.GetType ()) != TypeCode.Object)
- itemDisplay.SelectedObject = o;
- else
- itemDisplay.SelectedObject = o.Object;
- }
- else
- {
- object[] items = new object[itemsList.SelectedItems.Count];
- for (int i = 0; i < itemsList.SelectedItems.Count; i++)
- {
- ObjectContainer o = (ObjectContainer)itemsList.SelectedItem;
- if (Type.GetTypeCode (o.Object.GetType ()) != TypeCode.Object)
- items[i] = ((ObjectContainer)itemsList.SelectedItems[i]);
- else
- items[i] = ((ObjectContainer)itemsList.SelectedItems[i]).Object;
- }
- itemDisplay.SelectedObjects = items;
- }
- labelProperty.Text = ((ObjectContainer)itemsList.SelectedItem).Name + " properties:";
- }
- private void itemDisplay_PropertyValueChanged (object sender, EventArgs e)
- {
- int[] selected = new int[itemsList.SelectedItems.Count];
- for (int i = 0; i < itemsList.SelectedItems.Count; i++)
- selected[i] = itemsList.Items.IndexOf (itemsList.SelectedItems[i]);
- // The list might be repopulated if a new instance of the collection edited
- // is created during the update. This happen for example for Arrays.
- SetEditValue ();
- // Restore current selection in case the list gets repopulated.
- // Refresh the item after that to reflect possible value change.
- //
- itemsList.BeginUpdate ();
- itemsList.ClearSelected ();
- foreach (int index in selected) {
- itemsList.DoRefreshItem (index);
- itemsList.SetSelected (index, true);
- }
- itemsList.SelectedIndex = selected[0];
- itemsList.EndUpdate ();
- }
- private void moveUp_Click (object sender, EventArgs e)
- {
- if (itemsList.SelectedIndex <= 0)
- return;
- object selected = itemsList.SelectedItem;
- int index = itemsList.SelectedIndex;
- itemsList.Items.RemoveAt (index);
- itemsList.Items.Insert (index - 1, selected);
- itemsList.SelectedIndex = index - 1;
- }
- private void moveDown_Click (object sender, EventArgs e)
- {
- if (itemsList.SelectedIndex > itemsList.Items.Count - 2)
- return;
- object selected = itemsList.SelectedItem;
- int index = itemsList.SelectedIndex;
- itemsList.Items.RemoveAt (index);
- itemsList.Items.Insert (index + 1, selected);
- itemsList.SelectedIndex = index + 1;
- }
- private void doAdd_Click (object sender, EventArgs e)
- {
- object o;
- try {
- o = editor.CreateInstance (editor.NewItemTypes[addType.SelectedIndex]);
- } catch (Exception ex) {
- DisplayError (ex);
- return;
- }
- itemsList.Items.Add (new ObjectContainer (o, editor));
- itemsList.SelectedIndex = -1;
- itemsList.SelectedIndex = itemsList.Items.Count - 1;
- }
- private void doRemove_Click (object sender, EventArgs e)
- {
- if (itemsList.SelectedIndex != -1) {
- int[] selected = new int[itemsList.SelectedItems.Count];
- for (int i=0; i < itemsList.SelectedItems.Count; i++)
- selected[i] = itemsList.Items.IndexOf (itemsList.SelectedItems[i]);
- for (int i = selected.Length - 1; i >= 0; i--)
- itemsList.Items.RemoveAt (selected[i]);
- itemsList.SelectedIndex = Math.Min (selected[0], itemsList.Items.Count-1);
- }
- }
- // OnEditValueChanged is called only if the EditValue has changed,
- // which is only in the case when a new instance of the collection is
- // required, e.g for arrays.
- //
- protected override void OnEditValueChanged ()
- {
- UpdateItems ();
- }
- }
- private Type type;
- private Type collectionItemType;
- private Type[] newItemTypes;
- private ITypeDescriptorContext context;
- private IServiceProvider provider;
- private IWindowsFormsEditorService editorService;
- public CollectionEditor (Type type)
- {
- this.type = type;
- this.collectionItemType = CreateCollectionItemType ();
- this.newItemTypes = CreateNewItemTypes ();
- }
- protected Type CollectionItemType
- {
- get { return collectionItemType; }
- }
- protected Type CollectionType
- {
- get { return type; }
- }
- protected ITypeDescriptorContext Context
- {
- get { return context; }
- }
- protected virtual string HelpTopic
- {
- get { return "CollectionEditor"; }
- }
- protected Type[] NewItemTypes
- {
- get { return newItemTypes; }
- }
- protected virtual void CancelChanges ()
- {
- }
- protected virtual bool CanRemoveInstance (object value)
- {
- return true;
- }
- protected virtual bool CanSelectMultipleInstances ()
- {
- return true;
- }
- protected virtual CollectionEditor.CollectionForm CreateCollectionForm ()
- {
- return new ConcreteCollectionForm (this);
- }
- protected virtual Type CreateCollectionItemType ()
- {
- PropertyInfo[] properties = type.GetProperties ();
- foreach (PropertyInfo property in properties)
- if (property.Name == "Item")
- return property.PropertyType;
- return typeof (object);
- }
-
- protected virtual object CreateInstance (Type itemType)
- {
- object instance = null;
- if (typeof (IComponent).IsAssignableFrom (itemType)) {
- IDesignerHost host = GetService (typeof (IDesignerHost)) as IDesignerHost;
- if (host != null)
- instance = host.CreateComponent (itemType);
- }
- if (instance == null) {
- #if NET_2_0
- instance = TypeDescriptor.CreateInstance (provider, itemType, null, null);
- #else
- instance = Activator.CreateInstance (itemType);
- #endif
- }
- return instance;
- }
-
- protected virtual Type[] CreateNewItemTypes ()
- {
- return new Type[] { collectionItemType };
- }
- protected virtual void DestroyInstance (object instance)
- {
- IComponent component = instance as IComponent;
- if (component != null) {
- IDesignerHost host = GetService (typeof (IDesignerHost)) as IDesignerHost;
- if (host != null)
- host.DestroyComponent (component);
- }
- }
- public override object EditValue (ITypeDescriptorContext context, IServiceProvider provider, object value)
- {
- this.context = context;
- this.provider = provider;
- if (context != null && provider != null)
- {
- editorService = (IWindowsFormsEditorService)provider.GetService (typeof (IWindowsFormsEditorService));
- if (editorService != null)
- {
- CollectionForm editorForm = CreateCollectionForm ();
- editorForm.EditValue = value;
- editorForm.ShowEditorDialog (editorService);
- return editorForm.EditValue;
- }
- }
- return base.EditValue (context, provider, value);
- }
- protected virtual string GetDisplayText (object value)
- {
- if (value == null)
- return string.Empty;
- PropertyInfo nameProperty = value.GetType ().GetProperty ("Name");
- if (nameProperty != null)
- {
- string data = (nameProperty.GetValue (value, null)) as string;
- if (data != null)
- if (data.Length != 0)
- return data;
- }
- if (Type.GetTypeCode (value.GetType ()) == TypeCode.Object)
- return value.GetType ().Name;
- else
- return value.ToString ();
- }
- public override UITypeEditorEditStyle GetEditStyle (ITypeDescriptorContext context)
- {
- return UITypeEditorEditStyle.Modal;
- }
- protected virtual object[] GetItems (object editValue)
- {
- if (editValue == null)
- return new object[0];
- ICollection collection = editValue as ICollection;
- if (collection == null)
- return new object[0];
- object[] result = new object[collection.Count];
- collection.CopyTo (result, 0);
- return result;
- }
- protected virtual IList GetObjectsFromInstance (object instance)
- {
- ArrayList list = new ArrayList ();
- list.Add (instance);
- return list;
- }
- protected object GetService (Type serviceType)
- {
- return context.GetService (serviceType);
- }
- protected virtual object SetItems (object editValue, object[] value)
- {
- IList list = (IList) editValue;
- if (list == null)
- return null;
- list.Clear ();
- foreach (object o in value)
- list.Add (o);
- return list;
- }
- protected virtual void ShowHelp ()
- {
- //TODO: Fixme Add parent and URL
- Help.ShowHelp (null, "", HelpTopic);
- }
- }
- }