Merge pull request #1155 from steffen-kiess/json-string
[mono.git] / mcs / class / System.Design / System.ComponentModel.Design / CollectionEditor.cs
1 //
2 // System.ComponentModel.Design.CollectionEditor
3 //
4 // Authors:
5 //      Martin Willemoes Hansen (mwh@sysrq.dk)
6 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
7 //      Ivan N. Zlatev (contact@i-nz.net)
8 // 
9 // (C) 2003 Martin Willemoes Hansen
10 // (C) 2007 Andreas Nahr
11 // (C) 2007 Ivan N. Zlatev
12 // (C) 2008 Novell, Inc
13 //
14
15 //
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 // 
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 // 
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 //
35
36
37 using System;
38 using System.Reflection;
39 using System.Collections;
40 using System.ComponentModel;
41 using System.Drawing.Design;
42 using System.Windows.Forms;
43 using System.Windows.Forms.Design;
44
45 namespace System.ComponentModel.Design
46 {
47         public class CollectionEditor : UITypeEditor
48         {
49                 protected abstract class CollectionForm : Form
50                 {
51                         private CollectionEditor editor;
52                         private object editValue;
53
54                         public CollectionForm (CollectionEditor editor)
55                         {
56                                 this.editor = editor;
57                         }
58
59                         protected Type CollectionItemType
60                         {
61                                 get { return editor.CollectionItemType; }
62                         }
63
64                         protected Type CollectionType
65                         {
66                                 get { return editor.CollectionType; }
67                         }
68
69                         protected ITypeDescriptorContext Context
70                         {
71                                 get { return editor.Context; }
72                         }
73
74                         public object EditValue
75                         {
76                                 get { return editValue; }
77                                 set
78                                 {
79                                         editValue = value;
80                                         OnEditValueChanged ();
81                                 }
82                         }
83
84                         protected object[] Items
85                         {
86                                 get { return editor.GetItems (editValue); }
87                                 set {
88                                         if (editValue == null) {
89                                                 object newEmptyCollection = null;
90                                                 try {
91                                                         if (typeof (Array).IsAssignableFrom (CollectionType))
92                                                                 newEmptyCollection = Array.CreateInstance (CollectionItemType, 0);
93                                                         else
94                                                                 newEmptyCollection = Activator.CreateInstance (CollectionType);
95                                                 } catch {}
96
97                                                 object val = editor.SetItems (newEmptyCollection, value);
98                                                 if (val != newEmptyCollection)
99                                                         EditValue = val;
100                                         } else {
101                                                 object val = editor.SetItems (editValue, value);
102                                                 if (val != editValue)
103                                                         EditValue = val;
104                                         }
105                                 }
106                         }
107
108                         protected Type[] NewItemTypes
109                         {
110                                 get { return editor.NewItemTypes; }
111                         }
112
113                         protected bool CanRemoveInstance (object value)
114                         {
115                                 return editor.CanRemoveInstance (value);
116                         }
117
118                         protected virtual bool CanSelectMultipleInstances ()
119                         {
120                                 return editor.CanSelectMultipleInstances ();
121                         }
122
123                         protected object CreateInstance (Type itemType)
124                         {
125                                 return editor.CreateInstance (itemType);
126                         }
127
128                         protected void DestroyInstance (object instance)
129                         {
130                                 editor.DestroyInstance (instance);
131                         }
132
133                         protected virtual void DisplayError (Exception e)
134                         {
135                                 MessageBox.Show (e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Information);
136                         }
137
138                         protected override object GetService (Type serviceType)
139                         {
140                                 return editor.GetService (serviceType);
141                         }
142
143                         protected abstract void OnEditValueChanged ();
144
145                         protected internal virtual DialogResult ShowEditorDialog (IWindowsFormsEditorService edSvc)
146                         {
147                                 return edSvc.ShowDialog (this);
148                         }
149                 }
150
151                 private class ConcreteCollectionForm : CollectionForm
152                 {
153                         internal class ObjectContainerConverter : TypeConverter
154                         {
155                                 private class ObjectContainerPropertyDescriptor : TypeConverter.SimplePropertyDescriptor
156                                 {
157                                         private AttributeCollection attributes;
158
159                                         public ObjectContainerPropertyDescriptor (Type componentType, Type propertyType)
160                                                 : base (componentType, "Value", propertyType)
161                                         {
162                                                 CategoryAttribute cat = new CategoryAttribute (propertyType.Name);
163                                                 attributes = new AttributeCollection (new Attribute[] { cat });
164                                         }
165
166                                         public override object GetValue (object component)
167                                         {
168                                                 ObjectContainer container = (ObjectContainer)component;
169                                                 return container.Object;
170                                         }
171
172                                         public override void SetValue (object component, object value)
173                                         {
174                                                 ObjectContainer container = (ObjectContainer)component;
175                                                 container.Object = value;
176                                         }
177
178                                         public override AttributeCollection Attributes
179                                         {
180                                                 get { return attributes; }
181                                         }
182                                 }
183
184                                 public override PropertyDescriptorCollection GetProperties (ITypeDescriptorContext context, object value, Attribute[] attributes)
185                                 {
186                                         ObjectContainer container = (ObjectContainer)value;
187                                         ObjectContainerPropertyDescriptor desc = new ObjectContainerPropertyDescriptor (value.GetType (), container.editor.CollectionItemType);
188                                         PropertyDescriptor[] properties = new PropertyDescriptor[] { desc };
189                                         PropertyDescriptorCollection pc = new PropertyDescriptorCollection (properties);
190                                         return pc;
191                                 }
192
193                                 public override bool GetPropertiesSupported (ITypeDescriptorContext context)
194                                 {
195                                         return true;
196                                 }
197                         }
198
199                         [TypeConverter (typeof (ObjectContainerConverter))]
200                         private class ObjectContainer
201                         {
202                                 internal object Object;
203                                 internal CollectionEditor editor;
204
205                                 public ObjectContainer (object obj, CollectionEditor editor)
206                                 {
207                                         this.Object = obj;
208                                         this.editor = editor;
209                                 }
210
211                                 internal string Name {
212                                         get { return editor.GetDisplayText (Object); }
213                                 }
214
215                                 public override string ToString ()
216                                 {
217                                         return Name;
218                                 }
219                         }
220
221                         private class UpdateableListbox : ListBox
222                         {
223                                 public void DoRefreshItem (int index)
224                                 {
225                                         base.RefreshItem (index);
226                                 }
227                         }
228
229                         private CollectionEditor editor;
230
231                         private System.Windows.Forms.Label labelMember;
232                         private System.Windows.Forms.Label labelProperty;
233                         private UpdateableListbox itemsList;
234                         private System.Windows.Forms.PropertyGrid itemDisplay;
235                         private System.Windows.Forms.Button doClose;
236                         private System.Windows.Forms.Button moveUp;
237                         private System.Windows.Forms.Button moveDown;
238                         private System.Windows.Forms.Button doAdd;
239                         private System.Windows.Forms.Button doRemove;
240                         private System.Windows.Forms.Button doCancel;
241                         private System.Windows.Forms.ComboBox addType;
242
243                         public ConcreteCollectionForm (CollectionEditor editor)
244                                 : base (editor)
245                         {
246                                 this.editor = editor;
247
248                                 this.labelMember = new System.Windows.Forms.Label ();
249                                 this.labelProperty = new System.Windows.Forms.Label ();
250                                 this.itemsList = new UpdateableListbox ();
251                                 this.itemDisplay = new System.Windows.Forms.PropertyGrid ();
252                                 this.doClose = new System.Windows.Forms.Button ();
253                                 this.moveUp = new System.Windows.Forms.Button ();
254                                 this.moveDown = new System.Windows.Forms.Button ();
255                                 this.doAdd = new System.Windows.Forms.Button ();
256                                 this.doRemove = new System.Windows.Forms.Button ();
257                                 this.doCancel = new System.Windows.Forms.Button ();
258                                 this.addType = new System.Windows.Forms.ComboBox ();
259                                 this.SuspendLayout ();
260                                 // 
261                                 // labelMember
262                                 // 
263                                 this.labelMember.Location = new System.Drawing.Point (12, 9);
264                                 this.labelMember.Size = new System.Drawing.Size (55, 13);
265                                 this.labelMember.Text = "Members:";
266                                 // 
267                                 // labelProperty
268                                 // 
269                                 this.labelProperty.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
270                                                         | System.Windows.Forms.AnchorStyles.Right)));
271                                 this.labelProperty.Location = new System.Drawing.Point (172, 9);
272                                 this.labelProperty.Size = new System.Drawing.Size (347, 13);
273                                 this.labelProperty.Text = "Properties:";
274                                 // 
275                                 // itemsList
276                                 // 
277                                 this.itemsList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
278                                                         | System.Windows.Forms.AnchorStyles.Left)));
279                                 this.itemsList.HorizontalScrollbar = true;
280                                 this.itemsList.Location = new System.Drawing.Point (12, 25);
281                                 this.itemsList.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended;
282                                 this.itemsList.Size = new System.Drawing.Size (120, 290);
283                                 this.itemsList.TabIndex = 0;
284                                 this.itemsList.SelectedIndexChanged += new System.EventHandler (this.itemsList_SelectedIndexChanged);
285                                 // 
286                                 // itemDisplay
287                                 // 
288                                 this.itemDisplay.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
289                                                         | System.Windows.Forms.AnchorStyles.Left)
290                                                         | System.Windows.Forms.AnchorStyles.Right)));
291                                 this.itemDisplay.HelpVisible = false;
292                                 this.itemDisplay.Location = new System.Drawing.Point (175, 25);
293                                 this.itemDisplay.Size = new System.Drawing.Size (344, 314);
294                                 this.itemDisplay.TabIndex = 6;
295                                 this.itemDisplay.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler (this.itemDisplay_PropertyValueChanged);
296                                 // 
297                                 // doClose
298                                 // 
299                                 this.doClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
300                                 this.doClose.Location = new System.Drawing.Point (341, 345);
301                                 this.doClose.Size = new System.Drawing.Size (86, 26);
302                                 this.doClose.TabIndex = 7;
303                                 this.doClose.Text = "OK";
304                                 this.doClose.Click += new System.EventHandler (this.doClose_Click);
305                                 // 
306                                 // moveUp
307                                 // 
308                                 this.moveUp.Location = new System.Drawing.Point (138, 25);
309                                 this.moveUp.Size = new System.Drawing.Size (31, 28);
310                                 this.moveUp.TabIndex = 4;
311                                 this.moveUp.Enabled = false;
312                                 this.moveUp.Text = "Up";
313                                 this.moveUp.Click += new System.EventHandler (this.moveUp_Click);
314                                 // 
315                                 // moveDown
316                                 // 
317                                 this.moveDown.Location = new System.Drawing.Point (138, 59);
318                                 this.moveDown.Size = new System.Drawing.Size (31, 28);
319                                 this.moveDown.TabIndex = 5;
320                                 this.moveDown.Enabled = false;
321                                 this.moveDown.Text = "Dn";
322                                 this.moveDown.Click += new System.EventHandler (this.moveDown_Click);
323                                 // 
324                                 // doAdd
325                                 // 
326                                 this.doAdd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
327                                 this.doAdd.Location = new System.Drawing.Point (12, 346);
328                                 this.doAdd.Size = new System.Drawing.Size (59, 25);
329                                 this.doAdd.TabIndex = 1;
330                                 this.doAdd.Text = "Add";
331                                 this.doAdd.Click += new System.EventHandler (this.doAdd_Click);
332                                 // 
333                                 // doRemove
334                                 // 
335                                 this.doRemove.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
336                                 this.doRemove.Location = new System.Drawing.Point (77, 346);
337                                 this.doRemove.Size = new System.Drawing.Size (55, 25);
338                                 this.doRemove.TabIndex = 2;
339                                 this.doRemove.Text = "Remove";
340                                 this.doRemove.Click += new System.EventHandler (this.doRemove_Click);
341                                 // 
342                                 // doCancel
343                                 // 
344                                 this.doCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
345                                 this.doCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
346                                 this.doCancel.Location = new System.Drawing.Point (433, 345);
347                                 this.doCancel.Size = new System.Drawing.Size (86, 26);
348                                 this.doCancel.TabIndex = 8;
349                                 this.doCancel.Text = "Cancel";
350                                 this.doCancel.Click += new System.EventHandler (this.doCancel_Click);
351                                 // 
352                                 // addType
353                                 // 
354                                 this.addType.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
355                                 this.addType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
356                                 this.addType.Location = new System.Drawing.Point (12, 319);
357                                 this.addType.Size = new System.Drawing.Size (120, 21);
358                                 this.addType.TabIndex = 3;
359                                 // 
360                                 // DesignerForm
361                                 // 
362                                 this.AcceptButton = this.doClose;
363                                 this.CancelButton = this.doCancel;
364                                 this.ClientSize = new System.Drawing.Size (531, 381);
365                                 this.ControlBox = false;
366                                 this.Controls.Add (this.addType);
367                                 this.Controls.Add (this.doCancel);
368                                 this.Controls.Add (this.doRemove);
369                                 this.Controls.Add (this.doAdd);
370                                 this.Controls.Add (this.moveDown);
371                                 this.Controls.Add (this.moveUp);
372                                 this.Controls.Add (this.doClose);
373                                 this.Controls.Add (this.itemDisplay);
374                                 this.Controls.Add (this.itemsList);
375                                 this.Controls.Add (this.labelProperty);
376                                 this.Controls.Add (this.labelMember);
377                                 this.HelpButton = true;
378                                 this.MaximizeBox = false;
379                                 this.MinimizeBox = false;
380                                 this.MinimumSize = new System.Drawing.Size (400, 300);
381                                 this.ShowInTaskbar = false;
382                                 this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
383                                 this.ResumeLayout (false);
384
385                                 if (editor.CollectionType.IsGenericType)
386                                         this.Text = editor.CollectionItemType.Name + " Collection Editor";
387                                 else
388                                         this.Text = editor.CollectionType.Name + " Collection Editor";
389                                 foreach (Type type in editor.NewItemTypes)
390                                         addType.Items.Add (type.Name);
391                                 if (addType.Items.Count > 0)
392                                         addType.SelectedIndex = 0;
393                         }
394
395                         private void UpdateItems ()
396                         {
397                                 object[] items = editor.GetItems (EditValue);
398                                 if (items != null) {
399                                         itemsList.BeginUpdate ();
400                                         itemsList.Items.Clear ();
401                                         foreach (object o in items)
402                                                 this.itemsList.Items.Add (new ObjectContainer (o, editor));
403                                         if (itemsList.Items.Count > 0)
404                                                 itemsList.SelectedIndex = 0;
405                                         itemsList.EndUpdate ();
406                                 }
407                         }
408
409                         private void doClose_Click (object sender, EventArgs e)
410                         {
411                                 SetEditValue ();
412                                 this.Close ();
413                         }
414
415                         private void SetEditValue ()
416                         {
417                                 object[] items = new object[itemsList.Items.Count];
418                                 for (int i = 0; i < itemsList.Items.Count; i++)
419                                         items[i] = ((ObjectContainer)itemsList.Items[i]).Object;
420                                 this.Items = items;
421                         }
422
423                         private void doCancel_Click (object sender, EventArgs e)
424                         {
425                                 editor.CancelChanges ();
426                                 this.Close ();
427                         }
428
429                         private void itemsList_SelectedIndexChanged (object sender, EventArgs e)
430                         {
431                                 if (itemsList.SelectedIndex == -1) {
432                                         itemDisplay.SelectedObject = null;
433                                         return;
434                                 }
435
436                                 if (itemsList.SelectedIndex <= 0 || itemsList.SelectedItems.Count > 1)
437                                         moveUp.Enabled = false;
438                                 else
439                                         moveUp.Enabled = true;
440                                 if (itemsList.SelectedIndex > itemsList.Items.Count - 2 || itemsList.SelectedItems.Count > 1)
441                                         moveDown.Enabled = false;
442                                 else
443                                         moveDown.Enabled = true;
444
445                                 if (itemsList.SelectedItems.Count == 1)
446                                 {
447                                         ObjectContainer o = (ObjectContainer)itemsList.SelectedItem;
448                                         if (Type.GetTypeCode (o.Object.GetType ()) != TypeCode.Object)
449                                                 itemDisplay.SelectedObject = o;
450                                         else
451                                                 itemDisplay.SelectedObject = o.Object;
452                                 }
453                                 else
454                                 {
455                                         object[] items = new object[itemsList.SelectedItems.Count];
456                                         for (int i = 0; i < itemsList.SelectedItems.Count; i++)
457                                         {
458                                                 ObjectContainer o = (ObjectContainer)itemsList.SelectedItem;
459                                                 if (Type.GetTypeCode (o.Object.GetType ()) != TypeCode.Object)
460                                                         items[i] = ((ObjectContainer)itemsList.SelectedItems[i]);
461                                                 else
462                                                         items[i] = ((ObjectContainer)itemsList.SelectedItems[i]).Object;
463                                         }
464                                         itemDisplay.SelectedObjects = items;
465                                 }
466                                 labelProperty.Text = ((ObjectContainer)itemsList.SelectedItem).Name + " properties:";
467                         }
468
469                         private void itemDisplay_PropertyValueChanged (object sender, EventArgs e)
470                         {
471                                 int[] selected = new int[itemsList.SelectedItems.Count];
472                                 for (int i = 0; i < itemsList.SelectedItems.Count; i++)
473                                         selected[i] = itemsList.Items.IndexOf (itemsList.SelectedItems[i]);
474
475                                 // The list might be repopulated if a new instance of the collection edited
476                                 // is created during the update. This happen for example for Arrays.
477                                 SetEditValue ();
478
479                                 // Restore current selection in case the list gets repopulated.
480                                 // Refresh the item after that to reflect possible value change.
481                                 // 
482                                 itemsList.BeginUpdate ();
483                                 itemsList.ClearSelected ();
484                                 foreach (int index in selected) {
485                                         itemsList.DoRefreshItem (index);
486                                         itemsList.SetSelected (index, true);
487                                 }
488                                 itemsList.SelectedIndex = selected[0];
489                                 itemsList.EndUpdate ();
490                         }
491
492                         private void moveUp_Click (object sender, EventArgs e)
493                         {
494                                 if (itemsList.SelectedIndex <= 0)
495                                         return;
496
497                                 object selected = itemsList.SelectedItem;
498                                 int index = itemsList.SelectedIndex;
499                                 itemsList.Items.RemoveAt (index);
500                                 itemsList.Items.Insert (index - 1, selected);
501                                 itemsList.SelectedIndex = index - 1;
502                         }
503
504                         private void moveDown_Click (object sender, EventArgs e)
505                         {
506                                 if (itemsList.SelectedIndex > itemsList.Items.Count - 2)
507                                         return;
508
509                                 object selected = itemsList.SelectedItem;
510                                 int index = itemsList.SelectedIndex;
511                                 itemsList.Items.RemoveAt (index);
512                                 itemsList.Items.Insert (index + 1, selected);
513                                 itemsList.SelectedIndex = index + 1;
514                         }
515
516                         private void doAdd_Click (object sender, EventArgs e)
517                         {
518                                 object o;
519                                 try {
520                                         o = editor.CreateInstance (editor.NewItemTypes[addType.SelectedIndex]);
521                                 } catch (Exception ex) {
522                                         DisplayError (ex);
523                                         return;
524                                 }
525                                 itemsList.Items.Add (new ObjectContainer (o, editor));
526                                 itemsList.SelectedIndex = -1;
527                                 itemsList.SelectedIndex = itemsList.Items.Count - 1;
528                         }
529
530                         private void doRemove_Click (object sender, EventArgs e)
531                         {
532                                 if (itemsList.SelectedIndex != -1) {
533                                         int[] selected = new int[itemsList.SelectedItems.Count];
534                                         for (int i=0; i < itemsList.SelectedItems.Count; i++)
535                                                 selected[i] = itemsList.Items.IndexOf (itemsList.SelectedItems[i]);
536
537                                         for (int i = selected.Length - 1; i >= 0; i--)
538                                                 itemsList.Items.RemoveAt (selected[i]);
539
540                                         itemsList.SelectedIndex = Math.Min (selected[0], itemsList.Items.Count-1);
541                                 }
542                         }
543
544                         // OnEditValueChanged is called only if the  EditValue has changed,
545                         // which is only in the case when a new instance of the collection is 
546                         // required, e.g for arrays.
547                         // 
548                         protected override void OnEditValueChanged ()
549                         {
550                                 UpdateItems ();
551                         }
552                 }
553
554                 private Type type;
555                 private Type collectionItemType;
556                 private Type[] newItemTypes;
557                 private ITypeDescriptorContext context;
558                 private IServiceProvider provider;
559                 private IWindowsFormsEditorService editorService;
560
561                 public CollectionEditor (Type type)
562                 {
563                         this.type = type;
564                         this.collectionItemType = CreateCollectionItemType ();
565                         this.newItemTypes = CreateNewItemTypes ();
566                 }
567
568                 protected Type CollectionItemType
569                 {
570                         get { return collectionItemType; }
571                 }
572
573                 protected Type CollectionType
574                 {
575                         get { return type; }
576                 }
577
578                 protected ITypeDescriptorContext Context
579                 {
580                         get { return context; }
581                 }
582
583                 protected virtual string HelpTopic
584                 {
585                         get { return "CollectionEditor"; }
586                 }
587
588                 protected Type[] NewItemTypes
589                 {
590                         get { return newItemTypes; }
591                 }
592
593                 protected virtual void CancelChanges ()
594                 {
595                 }
596
597                 protected virtual bool CanRemoveInstance (object value)
598                 {
599                         return true;
600                 }
601
602                 protected virtual bool CanSelectMultipleInstances ()
603                 {
604                         return true;
605                 }
606
607                 protected virtual CollectionEditor.CollectionForm CreateCollectionForm ()
608                 {
609                         return new ConcreteCollectionForm (this);
610                 }
611
612                 protected virtual Type CreateCollectionItemType ()
613                 {
614                         PropertyInfo[] properties = type.GetProperties ();
615                         foreach (PropertyInfo property in properties)
616                                 if (property.Name == "Item")
617                                         return property.PropertyType;
618                         return typeof (object);
619                 }
620                 
621                 protected virtual object CreateInstance (Type itemType)
622                 {
623                         object instance = null;
624                         if (typeof (IComponent).IsAssignableFrom (itemType)) {
625                                 IDesignerHost host = GetService (typeof (IDesignerHost)) as IDesignerHost;
626                                 if (host != null)
627                                         instance = host.CreateComponent (itemType);
628                         }
629
630                         if (instance == null) {
631                                 instance = TypeDescriptor.CreateInstance (provider, itemType, null, null);
632                         }
633                         return instance;
634                 }
635                 
636                 protected virtual Type[] CreateNewItemTypes ()
637                 {
638                         return new Type[] { collectionItemType };
639                 }
640
641                 protected virtual void DestroyInstance (object instance)
642                 {
643                         IComponent component = instance as IComponent;
644                         if (component != null) {
645                                 IDesignerHost host = GetService (typeof (IDesignerHost)) as IDesignerHost;
646                                 if (host != null)
647                                         host.DestroyComponent (component);
648                         }
649                 }
650
651                 public override object EditValue (ITypeDescriptorContext context, IServiceProvider provider, object value)
652                 {
653                         this.context = context;
654                         this.provider = provider;
655
656                         if (context != null && provider != null)
657                         {
658                                 editorService = (IWindowsFormsEditorService)provider.GetService (typeof (IWindowsFormsEditorService));
659                                 if (editorService != null)
660                                 {
661                                         CollectionForm editorForm = CreateCollectionForm ();
662                                         editorForm.EditValue = value;
663                                         editorForm.ShowEditorDialog (editorService);
664                                         return editorForm.EditValue;
665                                 }
666                         }
667                         return base.EditValue (context, provider, value);
668                 }
669
670                 protected virtual string GetDisplayText (object value)
671                 {
672                         if (value == null)
673                                 return string.Empty;
674
675                         PropertyInfo nameProperty = value.GetType ().GetProperty ("Name");
676                         if (nameProperty != null)
677                         {
678                                 string data = (nameProperty.GetValue (value, null)) as string;
679                                 if (data != null)
680                                         if (data.Length != 0)
681                                                 return data;
682                         }
683
684                         if (Type.GetTypeCode (value.GetType ()) == TypeCode.Object)
685                                 return value.GetType ().Name;
686                         else
687                                 return value.ToString ();
688                 }
689
690                 public override UITypeEditorEditStyle GetEditStyle (ITypeDescriptorContext context)
691                 {
692                         return UITypeEditorEditStyle.Modal;
693                 }
694
695                 protected virtual object[] GetItems (object editValue)
696                 {
697                         if (editValue == null)
698                                 return new object[0];
699                         ICollection collection = editValue as ICollection;
700                         if (collection == null)
701                                 return new object[0];
702
703                         object[] result = new object[collection.Count];
704                         collection.CopyTo (result, 0);
705                         return result;
706                 }
707
708                 protected virtual IList GetObjectsFromInstance (object instance)
709                 {
710                         ArrayList list = new ArrayList ();
711                         list.Add (instance);
712                         return list;
713                 }
714
715                 protected object GetService (Type serviceType)
716                 {
717                         return context.GetService (serviceType);
718                 }
719
720                 protected virtual object SetItems (object editValue, object[] value)
721                 {
722                         IList list = (IList) editValue;
723                         if (list == null)
724                                 return null;
725
726                         list.Clear ();
727                         foreach (object o in value)
728                                 list.Add (o);
729
730                         return list;
731                 }
732
733                 protected virtual void ShowHelp ()
734                 {
735                         //TODO: Fixme Add parent and URL
736                         Help.ShowHelp (null, "", HelpTopic);
737                 }
738         }
739 }