diff options
Diffstat (limited to 'source/ShiftUI/Widgets/CollectionEditor.cs')
| -rw-r--r-- | source/ShiftUI/Widgets/CollectionEditor.cs | 738 |
1 files changed, 738 insertions, 0 deletions
diff --git a/source/ShiftUI/Widgets/CollectionEditor.cs b/source/ShiftUI/Widgets/CollectionEditor.cs new file mode 100644 index 0000000..07bbc51 --- /dev/null +++ b/source/ShiftUI/Widgets/CollectionEditor.cs @@ -0,0 +1,738 @@ +// +// System.ComponentModel.Design.CollectionEditor +// +// Authors: +// Martin Willemoes Hansen ([email protected]) +// Andreas Nahr ([email protected]) +// Ivan N. Zlatev ([email protected]) +// +// (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 ShiftUI; +using ShiftUI.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"); + } + + 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 ShiftUI.Label labelMember; + private ShiftUI.Label labelProperty; + private UpdateableListbox itemsList; + private ShiftUI.PropertyGrid itemDisplay; + private ShiftUI.Button doClose; + private ShiftUI.Button moveUp; + private ShiftUI.Button moveDown; + private ShiftUI.Button doAdd; + private ShiftUI.Button doRemove; + private ShiftUI.Button doCancel; + private ShiftUI.ComboBox addType; + + public ConcreteCollectionForm (CollectionEditor editor) + : base (editor) + { + this.editor = editor; + + this.labelMember = new ShiftUI.Label (); + this.labelProperty = new ShiftUI.Label (); + this.itemsList = new UpdateableListbox (); + this.itemDisplay = new ShiftUI.PropertyGrid (); + this.doClose = new ShiftUI.Button (); + this.moveUp = new ShiftUI.Button (); + this.moveDown = new ShiftUI.Button (); + this.doAdd = new ShiftUI.Button (); + this.doRemove = new ShiftUI.Button (); + this.doCancel = new ShiftUI.Button (); + this.addType = new ShiftUI.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 = ((ShiftUI.AnchorStyles)(((ShiftUI.AnchorStyles.Top | ShiftUI.AnchorStyles.Left) + | ShiftUI.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 = ((ShiftUI.AnchorStyles)(((ShiftUI.AnchorStyles.Top | ShiftUI.AnchorStyles.Bottom) + | ShiftUI.AnchorStyles.Left))); + this.itemsList.HorizontalScrollbar = true; + this.itemsList.Location = new System.Drawing.Point (12, 25); + this.itemsList.SelectionMode = ShiftUI.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 = ((ShiftUI.AnchorStyles)((((ShiftUI.AnchorStyles.Top | ShiftUI.AnchorStyles.Bottom) + | ShiftUI.AnchorStyles.Left) + | ShiftUI.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 ShiftUI.PropertyValueChangedEventHandler (this.itemDisplay_PropertyValueChanged); + // + // doClose + // + this.doClose.Anchor = ((ShiftUI.AnchorStyles)((ShiftUI.AnchorStyles.Bottom | ShiftUI.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 = ((ShiftUI.AnchorStyles)((ShiftUI.AnchorStyles.Bottom | ShiftUI.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 = ((ShiftUI.AnchorStyles)((ShiftUI.AnchorStyles.Bottom | ShiftUI.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 = ((ShiftUI.AnchorStyles)((ShiftUI.AnchorStyles.Bottom | ShiftUI.AnchorStyles.Right))); + this.doCancel.DialogResult = ShiftUI.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 = ((ShiftUI.AnchorStyles)((ShiftUI.AnchorStyles.Bottom | ShiftUI.AnchorStyles.Left))); + this.addType.DropDownStyle = ShiftUI.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.WidgetBox = false; + this.Widgets.Add (this.addType); + this.Widgets.Add (this.doCancel); + this.Widgets.Add (this.doRemove); + this.Widgets.Add (this.doAdd); + this.Widgets.Add (this.moveDown); + this.Widgets.Add (this.moveUp); + this.Widgets.Add (this.doClose); + this.Widgets.Add (this.itemDisplay); + this.Widgets.Add (this.itemsList); + this.Widgets.Add (this.labelProperty); + this.Widgets.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 = ShiftUI.FormStartPosition.CenterScreen; + this.ResumeLayout (false); + + if (editor.CollectionType.IsGenericType) + this.Text = editor.CollectionItemType.Name + " Collection Editor"; + else + this.Text = editor.CollectionType.Name + " Collection Editor"; + 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) { + instance = TypeDescriptor.CreateInstance (provider, itemType, null, null); + } + 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 No help provider. + } + } +} |
