2007-01-03 Jonathan Pobst <monkey@jpobst.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / PropertyGrid.cs
index 6a76006fe6510a4bb1a73ed2b8360edd18818f8f..5646d06d53211f45fddbab352f632bce1a76938c 100644 (file)
@@ -32,11 +32,16 @@ using System.ComponentModel;
 using System.Collections;
 using System.ComponentModel.Design;
 using System.Reflection;
+using System.Runtime.InteropServices;
 using System.Windows.Forms.Design;
 using System.Windows.Forms.PropertyGridInternal;
 
 namespace System.Windows.Forms {
        [Designer("System.Windows.Forms.Design.PropertyGridDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
+#if NET_2_0
+       [ClassInterface (ClassInterfaceType.AutoDispatch)]
+       [ComVisible (true)]
+#endif
        public class PropertyGrid : System.Windows.Forms.ContainerControl, ComponentModel.Com2Interop.IComPropertyBrowser {
                #region Private Members
                
@@ -57,7 +62,7 @@ namespace System.Windows.Forms {
                private PropertySort property_sort;
                private PropertyTabCollection property_tabs;
                private GridItem selected_grid_item;
-               internal GridItemCollection grid_items;
+               internal GridItem root_grid_item;
                private object[] selected_objects;
                private PropertyTab selected_tab;
 
@@ -73,7 +78,6 @@ namespace System.Windows.Forms {
                internal Panel help_panel;
                internal Label help_title_label;
                internal Label help_description_label;
-               private ContextMenu context_menu;
                private MenuItem reset_menuitem;
                private MenuItem description_menuitem;
                private object current_property_value;
@@ -83,7 +87,6 @@ namespace System.Windows.Forms {
                #region Contructors
                public PropertyGrid() {
                        selected_objects = new object[0];
-                       grid_items = new GridItemCollection();
                        property_tabs = new PropertyTabCollection();
 
                        line_color = SystemColors.ScrollBar;
@@ -108,7 +111,6 @@ namespace System.Windows.Forms {
                        help_title_label.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
                        help_title_label.Name = "help_title_label";
                        help_title_label.Font = new Font(this.Font,FontStyle.Bold);
-                       help_title_label.Text = "Title";
                        help_title_label.Location = new Point(2,2);
                        help_title_label.Height = 17;
                        help_title_label.Width = help_panel.Width - 4;
@@ -118,10 +120,9 @@ namespace System.Windows.Forms {
                        help_description_label.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
                        help_description_label.Name = "help_description_label";
                        help_description_label.Font = this.Font;
-                       help_description_label.Text = "The long important Description";
                        help_description_label.Location = new Point(2,help_title_label.Top+help_title_label.Height);
                        help_description_label.Width = help_panel.Width - 4;
-                       help_description_label.Height = 17;
+                       help_description_label.Height = help_panel.Height - help_description_label.Top - 2;
 
                        help_panel.Controls.Add(help_description_label);
                        help_panel.Controls.Add(help_title_label);
@@ -133,7 +134,7 @@ namespace System.Windows.Forms {
                        alphabetic_toolbarbutton = new ToolBarButton();
                        separator_toolbarbutton = new ToolBarButton();
                        propertypages_toolbarbutton = new ToolBarButton();
-                       context_menu = new ContextMenu();
+                       ContextMenu context_menu = new ContextMenu();
 
                        toolbar_imagelist = new ImageList();
                        toolbar_imagelist.ColorDepth = ColorDepth.Depth32Bit;
@@ -145,12 +146,11 @@ namespace System.Windows.Forms {
 
                        toolbar.Appearance = ToolBarAppearance.Flat;
                        toolbar.AutoSize = false;
-                       toolbar.Buttons.AddRange(new ToolBarButton[] {
-                                                                                                                        categorized_toolbarbutton,
-                                                                                                                        alphabetic_toolbarbutton,
-                                                                                                                        separator_toolbarbutton,
-                                                                                                                        propertypages_toolbarbutton});
-
+                       toolbar.Buttons.AddRange(new ToolBarButton[] {categorized_toolbarbutton,
+                                                                     alphabetic_toolbarbutton,
+                                                                     separator_toolbarbutton,
+                                                                     propertypages_toolbarbutton});
+                       
                        toolbar.ButtonSize = new System.Drawing.Size(20, 20);
                        toolbar.ImageList = toolbar_imagelist;
                        toolbar.Location = new System.Drawing.Point(0, 0);
@@ -161,11 +161,11 @@ namespace System.Windows.Forms {
 
                        categorized_toolbarbutton.ImageIndex = 0;
                        categorized_toolbarbutton.Style = ToolBarButtonStyle.ToggleButton;
-                       categorized_toolbarbutton.ToolTipText = (string)Locale.GetResource( "Categorized");
+                       categorized_toolbarbutton.ToolTipText = Locale.GetText ("Categorized");
 
                        alphabetic_toolbarbutton.ImageIndex = 1;
                        alphabetic_toolbarbutton.Style = ToolBarButtonStyle.ToggleButton;
-                       alphabetic_toolbarbutton.ToolTipText = (string)Locale.GetResource( "Alphabetic");
+                       alphabetic_toolbarbutton.ToolTipText = Locale.GetText ("Alphabetic");
 
                        separator_toolbarbutton.Style = ToolBarButtonStyle.Separator;
 
@@ -287,7 +287,7 @@ namespace System.Windows.Forms {
                        }
                }
 
-               [BrowsableAttribute(false)]
+               [BrowsableAttribute (false)]
                [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
                public virtual bool CommandsVisible {
                        get {
@@ -295,7 +295,11 @@ namespace System.Windows.Forms {
                        }
                }
 
-               [DefaultValue(false)]
+#if NET_2_0
+               [DefaultValue (true)]
+#else
+               [DefaultValue (false)]
+#endif
                public virtual bool CommandsVisibleIfAvailable {
                        get {
                                return commands_visible_if_available;
@@ -338,6 +342,9 @@ namespace System.Windows.Forms {
                        }
                }
 
+#if NET_2_0
+               [DefaultValue ("Color [Control]")]
+#endif
                public Color HelpBackColor {
                        get {
                                return help_panel.BackColor;
@@ -351,6 +358,9 @@ namespace System.Windows.Forms {
                        }
                }
 
+#if NET_2_0
+               [DefaultValue ("Color [ControlText]")]
+#endif
                public Color HelpForeColor {
                        get {
                                return help_panel.ForeColor;
@@ -381,6 +391,9 @@ namespace System.Windows.Forms {
                        }
                }
 
+#if NET_2_0
+               [DefaultValue (false)]
+#endif
                public bool LargeButtons {
                        get {
                                return large_buttons;
@@ -395,6 +408,9 @@ namespace System.Windows.Forms {
                        }
                }
 
+#if NET_2_0
+               [DefaultValue ("Color [InactiveBorder]")]
+#endif
                public Color LineColor {
                        get {
                                return line_color;
@@ -429,10 +445,10 @@ namespace System.Windows.Forms {
                                UpdateToolBarButtons();
                                ReflectObjects();
                                property_grid_view.Refresh();
-                               
-                               if (PropertySortChanged != null) {
-                                       PropertySortChanged(this, EventArgs.Empty);
-                               }
+
+                               EventHandler eh = (EventHandler)(Events [PropertySortChangedEvent]);
+                               if (eh != null)
+                                       eh (this, EventArgs.Empty);
                        }
                }
 
@@ -496,22 +512,10 @@ namespace System.Windows.Forms {
 
                        set {
                                if (value == null)
-                                       selected_objects = new object[0];
+                                       SelectedObjects = new object[0];
                                else
-                                       selected_objects = new object[] {value};
+                                       SelectedObjects = new object[] {value};
 
-                               if (value != null) {
-                                       PropertyTabAttribute[] propTabs = (PropertyTabAttribute[])this.SelectedObject.GetType().GetCustomAttributes(typeof(PropertyTabAttribute),true);
-                                       if (propTabs.Length > 0) {
-                                               foreach (Type tabType in propTabs[0].TabClasses) {
-                                                       this.PropertyTabs.AddTabType(tabType);
-                                               }
-                                       }
-                               }
-
-                               RefreshTabs(PropertyTabScope.Component);
-                               ReflectObjects();
-                               property_grid_view.Refresh();
                        }
                }
 
@@ -532,7 +536,24 @@ namespace System.Windows.Forms {
                                } else {
                                        selected_objects = new object [0];
                                }
+
+                               if (selected_objects.Length > 0) {
+                                       PropertyTabAttribute[] propTabs = (PropertyTabAttribute[])this.SelectedObject.GetType().GetCustomAttributes(typeof(PropertyTabAttribute),true);
+                                       if (propTabs.Length > 0) {
+                                               foreach (Type tabType in propTabs[0].TabClasses) {
+                                                       this.PropertyTabs.AddTabType(tabType);
+                                               }
+                                       }
+                               }
+
+                               RefreshTabs(PropertyTabScope.Component);
                                ReflectObjects();
+                               if (root_grid_item != null) {
+                                       /* find the first non category grid item and select it */
+                                       SelectedGridItem = FindFirstItem (root_grid_item);
+                               }
+                               property_grid_view.Refresh();
+                               OnSelectedObjectsChanged (EventArgs.Empty);
                        }
                }
 
@@ -571,6 +592,9 @@ namespace System.Windows.Forms {
                        }
                }
 
+#if NET_2_0
+               [DefaultValue ("Color [Window]")]
+#endif
                public Color ViewBackColor {
                        get {
                                return property_grid_view.BackColor;
@@ -585,6 +609,9 @@ namespace System.Windows.Forms {
                        }
                }
 
+#if NET_2_0
+               [DefaultValue ("Color [WindowText]")]
+#endif
                public Color ViewForeColor {
                        get {
                                return property_grid_view.ForeColor;
@@ -644,16 +671,22 @@ namespace System.Windows.Forms {
                protected override void Dispose(bool val) {
                        base.Dispose(val);
                }
-               
+
+               [MonoTODO ("should this be recursive?  or just the toplevel items?")]
                public void CollapseAllGridItems () {
-                       foreach (GridItem item in this.grid_items) {
-                               item.Expanded = false;
+                       if (root_grid_item != null) {
+                               foreach (GridItem item in root_grid_item.GridItems) {
+                                       item.Expanded = false;
+                               }
                        }
                }
 
+               [MonoTODO ("should this be recursive?  or just the toplevel items?")]
                public void ExpandAllGridItems () {
-                       foreach (GridItem item in this.grid_items) {
-                               item.Expanded = true;
+                       if (root_grid_item != null) {
+                               foreach (GridItem item in root_grid_item.GridItems) {
+                                       item.Expanded = true;
+                               }
                        }
                }
 
@@ -697,8 +730,11 @@ namespace System.Windows.Forms {
                }
                
                [MonoTODO]
-               protected void OnComComponentNameChanged(ComponentRenameEventArgs e) {
-                       throw new NotImplementedException();
+               protected void OnComComponentNameChanged(ComponentRenameEventArgs e)
+               {
+                       ComponentRenameEventHandler eh = (ComponentRenameEventHandler)(Events [ComComponentNameChangedEvent]);
+                       if (eh != null)
+                               eh (this, e);
                }
 
                protected override void OnFontChanged(EventArgs e) {
@@ -744,8 +780,9 @@ namespace System.Windows.Forms {
                }
 
                protected virtual void OnPropertyValueChanged (PropertyValueChangedEventArgs e) {
-                       if (PropertyValueChanged != null) {
-                               PropertyValueChanged(this, e);
+                       PropertyValueChangedEventHandler eh = (PropertyValueChangedEventHandler)(Events [PropertyValueChangedEvent]);
+                       if (eh != null) {
+                               eh (this, e);
                                current_property_value = selected_grid_item.Value;
                        }
                }
@@ -755,15 +792,15 @@ namespace System.Windows.Forms {
                }
 
                protected virtual void OnSelectedGridItemChanged (SelectedGridItemChangedEventArgs e) {
-                       if (SelectedGridItemChanged != null) {
-                               SelectedGridItemChanged(this, e);
-                       }
+                       SelectedGridItemChangedEventHandler eh = (SelectedGridItemChangedEventHandler)(Events [SelectedGridItemChangedEvent]);
+                       if (eh != null)
+                               eh (this, e);
                }
 
                protected virtual void OnSelectedObjectsChanged (EventArgs e) {
-                       if (SelectedObjectsChanged != null) {
-                               SelectedObjectsChanged(this, e);
-                       }
+                       EventHandler eh = (EventHandler)(Events [SelectedObjectsChangedEvent]);
+                       if (eh != null)
+                               eh (this, e);
                }
 
                protected override void OnSystemColorsChanged (EventArgs e) {
@@ -778,6 +815,7 @@ namespace System.Windows.Forms {
                        return base.ProcessDialogKey (keyData);
                }
 
+               [EditorBrowsable (EditorBrowsableState.Never)]
                protected override void ScaleCore (float dx, float dy) {
                        base.ScaleCore (dx, dy);
                }
@@ -793,11 +831,36 @@ namespace System.Windows.Forms {
                #endregion
 
                #region Events
-               public event EventHandler PropertySortChanged;
-               public event PropertyTabChangedEventHandler PropertyTabChanged;
-               public event PropertyValueChangedEventHandler PropertyValueChanged;
-               public event SelectedGridItemChangedEventHandler SelectedGridItemChanged;
-               public event EventHandler SelectedObjectsChanged;
+               static object PropertySortChangedEvent = new object ();
+               static object PropertyTabChangedEvent = new object ();
+               static object PropertyValueChangedEvent = new object ();
+               static object SelectedGridItemChangedEvent = new object ();
+               static object SelectedObjectsChangedEvent = new object ();
+
+               public event EventHandler PropertySortChanged {
+                       add { Events.AddHandler (PropertySortChangedEvent, value); }
+                       remove { Events.RemoveHandler (PropertySortChangedEvent, value); }
+               }
+
+               public event PropertyTabChangedEventHandler PropertyTabChanged {
+                       add { Events.AddHandler (PropertyTabChangedEvent, value); }
+                       remove { Events.RemoveHandler (PropertyTabChangedEvent, value); }
+               }
+
+               public event PropertyValueChangedEventHandler PropertyValueChanged {
+                       add { Events.AddHandler (PropertyValueChangedEvent, value); }
+                       remove { Events.RemoveHandler (PropertyValueChangedEvent, value); }
+               }
+
+               public event SelectedGridItemChangedEventHandler SelectedGridItemChanged {
+                       add { Events.AddHandler (SelectedGridItemChangedEvent, value); }
+                       remove { Events.RemoveHandler (SelectedGridItemChangedEvent, value); }
+               }
+
+               public event EventHandler SelectedObjectsChanged {
+                       add { Events.AddHandler (SelectedObjectsChangedEvent, value); }
+                       remove { Events.RemoveHandler (SelectedObjectsChangedEvent, value); }
+               }
                
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
@@ -847,11 +910,10 @@ namespace System.Windows.Forms {
                        throw new NotImplementedException();
                }
 
-               [MonoTODO]
-               private event ComponentRenameEventHandler com_component_name_changed;
+               static object ComComponentNameChangedEvent = new object ();
                event ComponentRenameEventHandler ComponentModel.Com2Interop.IComPropertyBrowser.ComComponentNameChanged {
-                       add { com_component_name_changed += value; }
-                       remove { com_component_name_changed -= value; }
+                       add { Events.AddHandler (ComComponentNameChangedEvent, value); }
+                       remove { Events.RemoveHandler (ComComponentNameChangedEvent, value); }
                }
                #endregion      // Com2Interop.IComPropertyBrowser Interface
 
@@ -929,6 +991,21 @@ namespace System.Windows.Forms {
 
                #region Private Helper Methods
 
+               private GridItem FindFirstItem (GridItem root)
+               {
+                       if (root.GridItemType == GridItemType.Property)
+                               return root;
+
+                       foreach (GridItem item in root.GridItems) {
+                               GridItem subitem = FindFirstItem (item);
+                               if (subitem != null)
+                                       return subitem;
+                       }
+
+                       return null;
+               }
+
+
                private void toolbar_ButtonClick (object sender, ToolBarButtonClickEventArgs e) {
                        if (e.Button == alphabetic_toolbarbutton) {
                                this.PropertySort = PropertySort.Alphabetical;
@@ -964,10 +1041,12 @@ namespace System.Windows.Forms {
                }
 
                private void ReflectObjects () {
-                       grid_items = new GridItemCollection();
-
-                       if (selected_objects.Length > 0)
-                               PopulateMergedGridItems (selected_objects, grid_items, true, null);
+                       if (selected_objects.Length > 0) {
+                               root_grid_item = new RootGridEntry (property_grid_view,
+                                                                   selected_objects.Length > 1 ? selected_objects : selected_objects[0]);
+                                                                          
+                               PopulateMergedGridItems (selected_objects, root_grid_item.GridItems, true, root_grid_item);
+                       }
                }
 
                private void PopulateMergedGridItems (object[] objs, GridItemCollection grid_item_coll, bool recurse, GridItem parent_grid_item)
@@ -984,7 +1063,18 @@ namespace System.Windows.Forms {
                                /* i tried using filter attributes, but there's no way to do it for EditorBrowsableAttributes,
                                   since that type lacks an override for IsDefaultAttribute, and for some reason the
                                   BrowsableAttribute.Yes filter wasn't working */
-                               PropertyDescriptorCollection properties = TypeDescriptor.GetProperties (type);
+                               PropertyDescriptorCollection properties = null;
+
+                               if (typeof (ICustomTypeDescriptor).IsAssignableFrom (type)) {
+                                       properties = ((ICustomTypeDescriptor)objs[i]).GetProperties ();
+                               }
+                               if (properties == null) {
+                                       TypeConverter cvt = TypeDescriptor.GetConverter (objs[i]);
+                                       properties = cvt.GetProperties (objs[i]);
+                               }
+                               if (properties == null) {
+                                       properties = TypeDescriptor.GetProperties (objs[i]);
+                               }
 
                                foreach (PropertyDescriptor p in (i == 0 ? (ICollection)properties : (ICollection)intersection)) {
                                        PropertyDescriptor property = (i == 0 ? p : properties [p.Name]);
@@ -993,7 +1083,7 @@ namespace System.Windows.Forms {
                                                   exclude it */
                                        }
                                        else if (!property.IsBrowsable
-                                           || (objs.Length > 0 && property.Attributes.Contains (MergablePropertyAttribute.No))
+                                           || (objs.Length > 1 && property.Attributes.Contains (MergablePropertyAttribute.No))
                                            || property.Attributes.Contains (new EditorBrowsableAttribute (EditorBrowsableState.Never))
                                            || property.Attributes.Contains (new EditorBrowsableAttribute (EditorBrowsableState.Advanced))) {
                                                /* if the property isn't supposed to be displayed in the merged view,
@@ -1021,12 +1111,12 @@ namespace System.Windows.Forms {
                                                              GridItemCollection grid_item_coll, bool recurse, GridItem parent_grid_item) {
                        foreach (PropertyDescriptor property in properties) {
 
-                               GridEntry grid_entry = new GridEntry (objs, property);
+                               GridEntry grid_entry = new GridEntry (property_grid_view, objs, property);
                                grid_entry.SetParent (parent_grid_item);
-                               if (property_sort == PropertySort.Alphabetical || !recurse) {
+                               if (property_sort == PropertySort.Alphabetical || /* XXX */property_sort == PropertySort.NoSort || !recurse) {
                                        if (grid_item_coll[property.Name] == null) {
                                                grid_item_coll.Add(property.Name,grid_entry);
-                                               grid_entry.SetUIParent ((GridEntry)parent_grid_item);
+                                               grid_entry.SetParent ((GridEntry)parent_grid_item);
                                        }
                                }
                                else if (property_sort == PropertySort.Categorized || property_sort == PropertySort.CategorizedAlphabetical) {
@@ -1034,18 +1124,17 @@ namespace System.Windows.Forms {
                                        string category = property.Category;
                                        CategoryGridEntry cat_item = grid_item_coll[category] as CategoryGridEntry;
                                        if (cat_item == null) {
-                                               cat_item = new CategoryGridEntry(category);
+                                               cat_item = new CategoryGridEntry (property_grid_view, category);
                                                cat_item.SetParent (parent_grid_item);
-                                               cat_item.SetUIParent ((GridEntry)parent_grid_item);
-                                               grid_item_coll.Add(category,cat_item);
+                                               grid_item_coll.Add (category, cat_item);
                                        }
                                        if (cat_item.GridItems[property.Name] == null) {
                                                cat_item.GridItems.Add(property.Name,grid_entry);
-                                               grid_entry.SetUIParent (cat_item);
+                                               grid_entry.SetParent (cat_item);
                                        }
                                }
 
-                               if (recurse && TypeDescriptor.GetConverter(property.PropertyType).GetPropertiesSupported()) {
+                               if (recurse && property.Converter != null && property.Converter.GetPropertiesSupported()) {
                                        object[] subobjs = new object[objs.Length];
                                        for (int i = 0; i < objs.Length; i ++)
                                                subobjs[i] = property.GetValue (objs[i]);
@@ -1064,7 +1153,10 @@ namespace System.Windows.Forms {
                {
                        object target = ((GridEntry)item).SelectedObjects[selected_index];
 
-                       if (item.Parent != null)
+                       while (item.Parent != null && item.Parent.GridItemType != GridItemType.Property)
+                               item = item.Parent;
+
+                       if (item.Parent != null && item.Parent.PropertyDescriptor != null)
                                target = item.Parent.PropertyDescriptor.GetValue (((GridEntry)item.Parent).SelectedObjects[selected_index]);
 
                        return target;
@@ -1074,6 +1166,7 @@ namespace System.Windows.Forms {
 
 #if NET_2_0
 
+               [DefaultValue (false)]
                public bool UseCompatibleTextRendering {
                        get {
                                return use_compatible_text_rendering;
@@ -1118,5 +1211,11 @@ namespace System.Windows.Forms {
                // needed! this little helper makes it possible to draw a different toolbar border
                // and toolbar backcolor in ThemeWin32Classic
                internal class PropertyToolBar : ToolBar {}
+
+
+               [MonoTODO ("not sure what this class does, but it's listed as a type converter for a property in this class, and this causes problems if it's not present")]
+               internal class SelectedObjectConverter : TypeConverter
+               {
+               }
        }
 }