2008-03-27 Carlos Alberto Cortez <calberto.cortez@gmail.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / PropertyGrid.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2004-2008 Novell, Inc.
21 //
22 // Authors:
23 //      Jonathan Chambers (jonathan.chambers@ansys.com)
24 //      Ivan N. Zlatev    (contact@i-nz.net)
25 //
26
27 // NOT COMPLETE
28
29 using System;
30 using System.IO;
31 using System.Drawing;
32 using System.Drawing.Design;
33 using System.ComponentModel;
34 using System.Collections;
35 using System.ComponentModel.Design;
36 using System.Reflection;
37 using System.Runtime.InteropServices;
38 using System.Windows.Forms.Design;
39 using System.Windows.Forms.PropertyGridInternal;
40
41 namespace System.Windows.Forms 
42 {
43         [Designer("System.Windows.Forms.Design.PropertyGridDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
44 #if NET_2_0
45         [ClassInterface (ClassInterfaceType.AutoDispatch)]
46         [ComVisible (true)]
47 #endif
48         public class PropertyGrid : System.Windows.Forms.ContainerControl, ComponentModel.Com2Interop.IComPropertyBrowser 
49         {
50                 #region Private Members
51                 
52                 
53                 private const string UNCATEGORIZED_CATEGORY_LABEL = "Misc";
54                 private AttributeCollection browsable_attributes = null;
55                 private bool can_show_commands = false;
56                 private Color commands_back_color;
57                 private Color commands_fore_color;
58                 private bool commands_visible;
59                 private bool commands_visible_if_available;
60                 private Point context_menu_default_location;
61                 private bool large_buttons;
62                 private Color line_color;
63                 private PropertySort property_sort;
64                 private PropertyTabCollection property_tabs;
65                 private GridEntry selected_grid_item;
66                 private GridEntry root_grid_item;
67                 private object[] selected_objects;
68                 private PropertyTab properties_tab;
69                 private PropertyTab selected_tab;
70
71                 private ImageList toolbar_imagelist;
72                 private Image categorized_image;
73                 private Image alphabetical_image;
74                 private Image propertypages_image;
75                 private PropertyToolBarButton categorized_toolbarbutton;
76                 private PropertyToolBarButton alphabetic_toolbarbutton;
77                 private PropertyToolBarButton propertypages_toolbarbutton;
78                 private PropertyToolBarSeparator separator_toolbarbutton;
79                 private PropertyToolBarButton properties_toolbarbutton;
80                 private PropertyToolBarButton events_toolbarbutton;
81                 private bool events_tab_visible;
82
83                 private PropertyToolBar toolbar;
84
85                 private PropertyGridView property_grid_view;
86                 private Splitter splitter;
87                 private Panel help_panel;
88                 private Label help_title_label;
89                 private Label help_description_label;
90                 private MenuItem reset_menuitem;
91                 private MenuItem description_menuitem;
92
93                 private Color category_fore_color;
94 #if NET_2_0
95                 private Color commands_active_link_color;
96                 private Color commands_disabled_link_color;
97                 private Color commands_link_color;
98 #endif
99                 #endregion      // Private Members
100                 
101                 #region Contructors
102                 public PropertyGrid ()
103                 {
104                         selected_objects = new object[0];
105                         property_tabs = new PropertyTabCollection(this);
106
107                         line_color = SystemColors.ScrollBar;
108                         category_fore_color = line_color;
109                         commands_visible_if_available = false;
110                         property_sort = PropertySort.CategorizedAlphabetical;
111                         property_grid_view = new PropertyGridView(this);
112
113                         splitter = new Splitter();
114                         splitter.Dock = DockStyle.Bottom;
115
116                         help_panel = new Panel();
117                         help_panel.Dock = DockStyle.Bottom;
118                         //help_panel.DockPadding.All = 3;
119                         help_panel.Height = 50;
120                         help_panel.BackColor = SystemColors.Control;
121
122
123                         help_title_label = new Label();
124                         help_title_label.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
125                         help_title_label.Name = "help_title_label";
126                         help_title_label.Font = new Font(this.Font,FontStyle.Bold);
127                         help_title_label.Location = new Point(2,2);
128                         help_title_label.Height = 17;
129                         help_title_label.Width = help_panel.Width - 4;
130
131                         
132                         help_description_label = new Label();
133                         help_description_label.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom;
134                         help_description_label.AutoEllipsis = true;
135                         help_description_label.AutoSize = false;
136                         help_description_label.Font = this.Font;
137                         help_description_label.Location = new Point(2,help_title_label.Top+help_title_label.Height);
138                         help_description_label.Width = help_panel.Width - 4;
139                         help_description_label.Height = help_panel.Height - help_description_label.Top - 2;
140
141                         help_panel.Controls.Add(help_description_label);
142                         help_panel.Controls.Add(help_title_label);
143                         help_panel.Paint+=new PaintEventHandler(help_panel_Paint);
144
145                         toolbar = new PropertyToolBar();
146                         toolbar.Dock = DockStyle.Top;
147                         categorized_toolbarbutton = new PropertyToolBarButton ();
148                         categorized_toolbarbutton.Pushed = true;
149                         alphabetic_toolbarbutton = new PropertyToolBarButton ();
150                         propertypages_toolbarbutton = new PropertyToolBarButton ();
151                         separator_toolbarbutton = new PropertyToolBarSeparator ();
152                         ContextMenu context_menu = new ContextMenu();
153
154                         categorized_image = new Bitmap (typeof (PropertyGrid), "propertygrid-categorized.png");
155                         alphabetical_image = new Bitmap (typeof (PropertyGrid), "propertygrid-alphabetical.png");
156                         propertypages_image = new Bitmap (typeof (PropertyGrid), "propertygrid-propertypages.png");
157
158                         toolbar_imagelist = new ImageList();
159                         toolbar_imagelist.ColorDepth = ColorDepth.Depth32Bit;
160                         toolbar_imagelist.ImageSize = new System.Drawing.Size(16, 16);
161                         toolbar_imagelist.TransparentColor = System.Drawing.Color.Transparent;
162
163                         toolbar.Appearance = ToolBarAppearance.Flat;
164                         toolbar.AutoSize = false;
165                         
166                         toolbar.ImageList = toolbar_imagelist;
167                         toolbar.Location = new System.Drawing.Point(0, 0);
168                         toolbar.ShowToolTips = true;
169                         toolbar.Size = new System.Drawing.Size(256, 27);
170                         toolbar.TabIndex = 0;
171 #if NET_2_0
172                         toolbar.Items.AddRange (new ToolStripItem [] {categorized_toolbarbutton,
173                                                                       alphabetic_toolbarbutton,
174                                                                       new PropertyToolBarSeparator (),
175                                                                       propertypages_toolbarbutton});
176                         //toolbar.ButtonSize = new System.Drawing.Size (20, 20);
177                         toolbar.ItemClicked += new ToolStripItemClickedEventHandler (toolbar_ButtonClick);
178 #else
179                         toolbar.Buttons.AddRange(new ToolBarButton [] {categorized_toolbarbutton,
180                                                                       alphabetic_toolbarbutton,
181                                                                       new PropertyToolBarSeparator (),
182                                                                       propertypages_toolbarbutton});
183                         toolbar.ButtonSize = new System.Drawing.Size(20, 20);
184                         toolbar.ButtonClick += new ToolBarButtonClickEventHandler(toolbar_ButtonClick);
185 #endif
186
187                         categorized_toolbarbutton.Style = ToolBarButtonStyle.ToggleButton;
188                         categorized_toolbarbutton.ToolTipText = Locale.GetText ("Categorized");
189
190                         alphabetic_toolbarbutton.Style = ToolBarButtonStyle.ToggleButton;
191                         alphabetic_toolbarbutton.ToolTipText = Locale.GetText ("Alphabetic");
192
193                         propertypages_toolbarbutton.Enabled = false;
194                         propertypages_toolbarbutton.Style = ToolBarButtonStyle.ToggleButton;
195                         propertypages_toolbarbutton.ToolTipText = "Property Pages";
196
197                         properties_tab = new PropertiesTab ();
198                         selected_tab = properties_tab;
199                         RefreshToolbar (property_tabs);
200                         
201                         reset_menuitem = context_menu.MenuItems.Add("Reset");
202                         reset_menuitem.Click +=new EventHandler(OnResetPropertyClick);
203                         context_menu.MenuItems.Add("-");
204                         description_menuitem = context_menu.MenuItems.Add("Description");
205                         description_menuitem.Click += new EventHandler(OnDescriptionClick);
206                         description_menuitem.Checked = this.HelpVisible;
207                         this.ContextMenu = context_menu;
208                         toolbar.ContextMenu = context_menu;
209                         
210                         BorderHelperControl helper = new BorderHelperControl ();
211                         helper.Dock = DockStyle.Fill;
212                         helper.Controls.Add (property_grid_view);
213                         
214                         this.Controls.Add(helper);
215                         this.Controls.Add(toolbar);
216                         this.Controls.Add(splitter);
217                         this.Controls.Add(help_panel);
218                         this.Name = "PropertyGrid";
219                         this.Size = new System.Drawing.Size(256, 400);
220                 }
221                 #endregion      // Constructors
222
223                 #region Public Instance Properties
224
225                 [BrowsableAttribute(false)]
226                 [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
227                 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
228                 public AttributeCollection BrowsableAttributes {
229                         get {
230                                 if (browsable_attributes == null) {
231                                         browsable_attributes = new AttributeCollection (new Attribute[] { 
232                                                 BrowsableAttribute.Yes });
233                                 }
234                                 return browsable_attributes;
235                         }
236                         set {
237                                 if (browsable_attributes == value)
238                                         return;
239
240                                 if (browsable_attributes == null || browsable_attributes.Count == 0)
241                                         browsable_attributes = null;
242                                 else
243                                         browsable_attributes = value;
244                         }
245                 }
246                 
247                 [Browsable(false)]
248                 [EditorBrowsable(EditorBrowsableState.Never)]
249                 public override bool AutoScroll {
250                         get {
251                                 return base.AutoScroll;
252                         }
253                         set {
254                                 base.AutoScroll = value;
255                         }
256                 }
257
258                 public override Color BackColor {
259                         get {
260                                 return base.BackColor;
261                         }
262
263                         set {
264                                 base.BackColor = value;
265                                 toolbar.BackColor = value;
266                                 Refresh ();
267                         }
268                 }
269                 
270                 [Browsable(false)]
271                 [EditorBrowsable(EditorBrowsableState.Never)]
272                 public override Image BackgroundImage {
273                         get {
274                                 return base.BackgroundImage;
275                         }               
276                         set {
277                                 base.BackgroundImage = value;
278                         }
279                 }
280
281 #if NET_2_0
282                 [EditorBrowsable(EditorBrowsableState.Never)]
283                 [Browsable(false)]
284                 public override ImageLayout BackgroundImageLayout {
285                         get { return base.BackgroundImageLayout; }
286                         set { base.BackgroundImageLayout = value; }
287                 }
288 #endif
289
290                 [BrowsableAttribute(false)]
291                 [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
292                 public virtual bool CanShowCommands {
293                         get {
294                                 return can_show_commands;
295                         }
296                 }
297 #if NET_2_0
298                 [DefaultValue(typeof(Color), "ControlText")]
299                 public
300 #else
301                 internal
302 #endif
303                 Color CategoryForeColor {
304                         get {
305                                 return category_fore_color;
306                         }
307                         set {
308                                 if (category_fore_color != value) {
309                                         category_fore_color = value;
310                                         Invalidate ();
311                                 }
312                         }
313                 }
314
315                 public Color CommandsBackColor {
316                         get {
317                                 return commands_back_color;
318                         }
319
320                         set {
321                                 if (commands_back_color == value) {
322                                         return;
323                                 }
324                                 commands_back_color = value;
325                         }
326                 }
327
328                 public Color CommandsForeColor {
329                         get {
330                                 return commands_fore_color;
331                         }
332
333                         set {
334                                 if (commands_fore_color == value) {
335                                         return;
336                                 }
337                                 commands_fore_color = value;
338                         }
339                 }
340 #if NET_2_0
341                 public Color CommandsActiveLinkColor {
342                         get {
343                                 return commands_active_link_color;
344                         }
345                         set {
346                                 commands_active_link_color = value;
347                         }
348                 }
349                 
350                 public Color CommandsDisabledLinkColor {
351                         get {
352                                 return commands_disabled_link_color;
353                         }
354                         set {
355                                 commands_disabled_link_color = value;
356                         }
357                 }
358
359                 public Color CommandsLinkColor {
360                         get {
361                                 return commands_link_color;
362                         }
363                         set {
364                                 commands_link_color = value;
365                         }
366                 }
367 #endif
368
369                 [BrowsableAttribute (false)]
370                 [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
371                 [MonoTODO ("Commands are not implemented yet.")]
372                 public virtual bool CommandsVisible {
373                         get {
374                                 return commands_visible;
375                         }
376                 }
377
378 #if NET_2_0
379                 [DefaultValue (true)]
380 #else
381                 [DefaultValue (false)]
382 #endif
383                 public virtual bool CommandsVisibleIfAvailable {
384                         get {
385                                 return commands_visible_if_available;
386                         }
387
388                         set {
389                                 if (commands_visible_if_available == value) {
390                                         return;
391                                 }
392                                 commands_visible_if_available = value;
393                         }
394                 }
395
396                 [BrowsableAttribute(false)]
397                 [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
398                 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
399                 public Point ContextMenuDefaultLocation {
400                         get {
401                                 return context_menu_default_location;
402                         }
403                 }
404                 
405                 [Browsable(false)]
406                 [EditorBrowsable(EditorBrowsableState.Never)]
407                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
408                 public new Control.ControlCollection Controls {
409                         get {
410                                 return base.Controls;
411                         }
412                 }
413                 
414                 [Browsable(false)]
415                 [EditorBrowsable(EditorBrowsableState.Never)]
416                 public override Color ForeColor {
417                         get {
418                                 return base.ForeColor;
419                         }
420                         set {
421                                 base.ForeColor = value;
422                         }
423                 }
424
425 #if NET_2_0
426                 [DefaultValue ("Color [Control]")]
427 #endif
428                 public Color HelpBackColor {
429                         get {
430                                 return help_panel.BackColor;
431                         }
432                         set {
433                                 if (help_panel.BackColor == value) {
434                                         return;
435                                 }
436
437                                 help_panel.BackColor = value;
438                         }
439                 }
440
441 #if NET_2_0
442                 [DefaultValue ("Color [ControlText]")]
443 #endif
444                 public Color HelpForeColor {
445                         get {
446                                 return help_panel.ForeColor;
447                         }
448
449                         set {
450                                 if (help_panel.ForeColor == value) {
451                                         return;
452                                 }
453
454                                 help_panel.ForeColor = value;
455                         }
456                 }
457
458                 [DefaultValue(true)]
459                 [Localizable(true)]
460                 public virtual bool HelpVisible {
461                         get {
462                                 return help_panel.Visible;
463                         }
464
465                         set {
466                                 if (help_panel.Visible == value) {
467                                         return;
468                                 }
469
470                                 help_panel.Visible = value;
471                         }
472                 }
473
474 #if NET_2_0
475                 [DefaultValue (false)]
476 #endif
477                 public bool LargeButtons {
478                         get {
479                                 return large_buttons;
480                         }
481
482                         set {
483                                 if (large_buttons == value) {
484                                         return;
485                                 }
486
487                                 large_buttons = value;
488                         }
489                 }
490
491 #if NET_2_0
492                 [DefaultValue ("Color [InactiveBorder]")]
493 #endif
494                 public Color LineColor {
495                         get {
496                                 return line_color;
497                         }
498
499                         set {
500                                 if (line_color == value) {
501                                         return;
502                                 }
503
504                                 line_color = value;
505                         }
506                 }
507
508 #if NET_2_0
509                 [EditorBrowsable(EditorBrowsableState.Never)]
510                 [Browsable(false)]
511                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
512                 public new Padding Padding {
513                         get { return base.Padding; }
514                         set { base.Padding = value; }
515                 }
516 #endif
517                 
518                 [DefaultValue(PropertySort.CategorizedAlphabetical)]
519                 public PropertySort PropertySort {
520                         get {
521                                 return property_sort;
522                         }
523
524                         set {
525 #if NET_2_0
526                                 if (!Enum.IsDefined (typeof (PropertySort), value))
527                                         throw new InvalidEnumArgumentException ("value", (int) value, typeof (PropertySort));
528 #endif
529                                 if (property_sort == value)
530                                         return;
531
532                                 // we do not need to update the the grid items and fire
533                                 // a PropertySortChanged event when switching between
534                                 // Categorized and CateogizedAlphabetical
535                                 bool needUpdate = (property_sort & PropertySort.Categorized) == 0 ||
536                                         (value & PropertySort.Categorized) == 0;
537                                 property_sort = value;
538                                 if (needUpdate) {
539                                         UpdateSortLayout (root_grid_item);
540                                         // update selection
541                                         if (selected_grid_item != null) {
542                                                 if (selected_grid_item.GridItemType == GridItemType.Category && 
543                                                     (value == PropertySort.Alphabetical || value == PropertySort.NoSort))
544                                                         SelectItemCore (null, null);
545                                                 else
546                                                         SelectItemCore (null, selected_grid_item);
547                                         }
548                                         property_grid_view.UpdateView ();
549
550 #if NET_2_0
551                                         EventHandler eh = (EventHandler)(Events [PropertySortChangedEvent]);
552                                         if (eh != null)
553                                                 eh (this, EventArgs.Empty);
554 #endif
555                                 }
556                         }
557                 }
558
559                 [BrowsableAttribute(false)]
560                 [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
561                 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
562                 public PropertyTabCollection PropertyTabs {
563                         get { return property_tabs; }
564                 }
565
566                 [BrowsableAttribute(false)]
567                 [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
568                 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
569                 public GridItem SelectedGridItem {
570                         get { return selected_grid_item; }
571                         set {
572                                 if (value == null)
573                                         throw new ArgumentException ("GridItem specified to PropertyGrid.SelectedGridItem must be a valid GridItem.");
574                                 if (value != selected_grid_item) {
575                                         GridEntry oldItem = selected_grid_item;
576                                         SelectItemCore (oldItem, (GridEntry)value);
577                                         OnSelectedGridItemChanged (new SelectedGridItemChangedEventArgs (oldItem, value));
578                                 }
579                         }
580                 }
581
582                 internal GridItem RootGridItem {
583                         get { return root_grid_item; }
584                 }
585
586                 private void UpdateHelp (GridItem item)
587                 {
588                         if (item == null) {
589                                 help_title_label.Text = string.Empty;
590                                 help_description_label.Text = string.Empty;
591                         } else {
592                                 help_title_label.Text = item.Label;
593                                 if (item.PropertyDescriptor != null)
594                                         this.help_description_label.Text = item.PropertyDescriptor.Description;
595                         }
596                 }
597
598                 private void SelectItemCore (GridEntry oldItem, GridEntry item)
599                 {
600                         UpdateHelp (item);
601                         selected_grid_item = item;
602                         property_grid_view.SelectItem (oldItem, item);
603                 }
604
605                 internal void OnPropertyValueChangedInternal (GridItem item, object property_value) 
606                 {
607                         PopulateSubGridItems (selected_grid_item);
608                         property_grid_view.UpdateView ();
609                         OnPropertyValueChanged (new PropertyValueChangedEventArgs (item, property_value));
610                 }
611
612                 internal void OnExpandItem (GridEntry item)
613                 {
614                         property_grid_view.ExpandItem (item);
615                 }
616
617                 internal void OnCollapseItem (GridEntry item)
618                 {
619                         property_grid_view.CollapseItem (item);
620                 }
621
622                 internal DialogResult ShowError (string text)
623                 {
624                         return this.ShowError (text, MessageBoxButtons.OK);
625                 }
626
627                 internal DialogResult ShowError (string text, MessageBoxButtons buttons)
628                 {
629                         if (text == null)
630                                 throw new ArgumentNullException ("text");
631                         return MessageBox.Show (this, text, "Properties Window", buttons, MessageBoxIcon.Exclamation);
632                 }
633
634                 [DefaultValue(null)]
635                 [TypeConverter("System.Windows.Forms.PropertyGrid+SelectedObjectConverter, " + Consts.AssemblySystem_Windows_Forms)]
636                 public object SelectedObject {
637                         get {
638                                 if (selected_objects.Length > 0)
639                                         return selected_objects[0];
640                                 return null;
641                         }
642
643                         set {
644                                 if (selected_objects != null && selected_objects.Length == 1 && selected_objects[0] == value)
645                                         return;
646                                 if (value == null)
647                                         SelectedObjects = new object[0];
648                                 else
649                                         SelectedObjects = new object[] {value};
650
651                         }
652                 }
653
654                 [BrowsableAttribute(false)]
655                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
656                 public object[] SelectedObjects {
657                         get {
658                                 return selected_objects;
659                         }
660
661                         set {
662                                 SelectItemCore (null, null); // unselect current item in the view
663                                 if (value != null) {
664                                         for (int i = 0; i < value.Length; i++) {
665                                                 if (value [i] == null)
666                                                         throw new ArgumentException (String.Format ("Item {0} in the objs array is null.", i));
667                                         }
668                                         selected_objects = value;
669                                 } else {
670                                         selected_objects = new object [0];
671                                 }
672
673                                 ShowEventsButton (false);
674                                 PopulateGrid (selected_objects);
675                                 RefreshTabs(PropertyTabScope.Component);
676                                 if (root_grid_item != null)
677                                         SelectItemCore (null, GetDefaultPropertyItem (root_grid_item, selected_tab));
678                                 property_grid_view.UpdateView ();
679                                 OnSelectedObjectsChanged (EventArgs.Empty);
680                         }
681                 }
682
683                 [BrowsableAttribute(false)]
684                 [EditorBrowsable(EditorBrowsableState.Advanced)]
685                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
686                 public PropertyTab SelectedTab {
687                         get { return selected_tab; }
688                 }
689
690                 public override ISite Site {
691                         get { return base.Site; }
692                         set { base.Site = value; }
693                 }
694
695 #if NET_2_0
696                 [Browsable (false)]
697                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
698                 public override string Text {
699                         get { return base.Text; }
700                         set { base.Text = value; }
701                 }
702  #endif
703
704                 [DefaultValue(true)]
705                 public virtual bool ToolbarVisible {
706                         get { return toolbar.Visible; }
707                         set {
708                                 if (toolbar.Visible == value) {
709                                         return;
710                                 }
711
712                                 toolbar.Visible = value;
713                         }
714                 }
715                 
716 #if NET_2_0
717                 protected ToolStripRenderer ToolStripRenderer {
718                         get {
719                                 if (toolbar != null) {
720                                         return toolbar.Renderer;
721                                 }
722                                 return null;
723                         }
724                         set {
725                                 if (toolbar != null) {
726                                         toolbar.Renderer = value;
727                                 }
728                         }
729                 }
730  
731 #endif
732
733 #if NET_2_0
734                 [DefaultValue ("Color [Window]")]
735 #endif
736                 public Color ViewBackColor {
737                         get { return property_grid_view.BackColor; }
738                         set {
739                                 if (property_grid_view.BackColor == value) {
740                                         return;
741                                 }
742
743                                 property_grid_view.BackColor = value;
744                         }
745                 }
746
747 #if NET_2_0
748                 [DefaultValue ("Color [WindowText]")]
749 #endif
750                 public Color ViewForeColor {
751                         get { return property_grid_view.ForeColor; }
752                         set {
753                                 if (property_grid_view.ForeColor == value) {
754                                         return;
755                                 }
756
757                                 property_grid_view.ForeColor = value;
758                         }
759                 }
760 #if NET_2_0
761
762                 [DefaultValue (false)]
763                 public bool UseCompatibleTextRendering {
764                         get { return use_compatible_text_rendering; }
765                         set { use_compatible_text_rendering = value; }
766                 }
767 #endif
768
769                 #endregion      // Public Instance Properties
770
771                 #region Protected Instance Properties
772
773                 protected override Size DefaultSize {
774                         get { return base.DefaultSize; }
775                 }
776
777
778                 [Browsable(false)]
779                 [EditorBrowsable(EditorBrowsableState.Advanced)]
780                 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
781                 protected virtual Type DefaultTabType {
782                         get { return typeof(PropertiesTab); }
783                 }
784                 
785                 protected bool DrawFlatToolbar {
786                         get { return (toolbar.Appearance == ToolBarAppearance.Flat); }                  
787                         set {
788                                 if (value) 
789                                         toolbar.Appearance = ToolBarAppearance.Flat;
790                                 else
791                                         toolbar.Appearance = ToolBarAppearance.Normal;
792                         }
793                 }
794
795                 protected internal override bool ShowFocusCues {
796                         get { return base.ShowFocusCues; }
797                 }
798
799                 #endregion      // Protected Instance Properties
800
801                 #region Public Instance Methods
802                 
803                 protected override void Dispose(bool disposing) {
804                         base.Dispose(disposing);
805                 }
806
807                 public void CollapseAllGridItems () 
808                 {
809                         GridEntry category = FindCategoryItem (selected_grid_item);
810                         if (category != null)
811                                 SelectedGridItem = category;
812                         CollapseItemRecursive (root_grid_item);
813                         property_grid_view.UpdateView ();
814                 }
815
816                 private void CollapseItemRecursive (GridItem item)
817                 {
818                         if (item == null)
819                                 return;
820
821                         foreach (GridItem child in item.GridItems) {
822                                 CollapseItemRecursive (child);
823                                 if (child.Expandable)
824                                         child.Expanded = false;
825                         }
826                 }
827
828                 private GridEntry FindCategoryItem (GridEntry entry)
829                 {
830                         if (entry == null || (property_sort != PropertySort.Categorized && 
831                             property_sort != PropertySort.CategorizedAlphabetical))
832                                 return null;
833
834                         if (entry.GridItemType == GridItemType.Category)
835                                 return entry;
836
837                         GridEntry category = null;
838                         GridItem current = (GridItem)entry;
839                         while (category == null) {
840                                 if (current.Parent != null && current.Parent.GridItemType == GridItemType.Category)
841                                         category = (GridEntry) current.Parent;
842                                 current = current.Parent;
843                                 if (current == null)
844                                         break;
845                         }
846                         return (GridEntry) category;
847                 }
848
849                 public void ExpandAllGridItems () 
850                 {
851                         ExpandItemRecursive (root_grid_item);
852                         property_grid_view.UpdateView ();
853                 }
854
855                 private void ExpandItemRecursive (GridItem item)
856                 {
857                         if (item == null)
858                                 return;
859
860                         foreach (GridItem child in item.GridItems) {
861                                 ExpandItemRecursive (child);
862                                 if (child.Expandable)
863                                         child.Expanded = true;
864                         }
865                 }
866
867                 public override void Refresh () 
868                 {
869                         base.Refresh ();
870                         property_grid_view.UpdateView ();
871                 }
872
873                 private void toolbar_Clicked (PropertyToolBarButton button)
874                 {
875                         if (button == null) 
876                                 return;
877
878                         if (button == alphabetic_toolbarbutton) {
879                                 this.PropertySort = PropertySort.Alphabetical;
880                                 alphabetic_toolbarbutton.Pushed = true;
881                                 categorized_toolbarbutton.Pushed = false;
882                         } else if (button == categorized_toolbarbutton) {
883                                 this.PropertySort = PropertySort.CategorizedAlphabetical;
884                                 categorized_toolbarbutton.Pushed = true;
885                                 alphabetic_toolbarbutton.Pushed = false;
886                         } else {
887                                 if (button.Enabled)
888                                         SelectPropertyTab (button.PropertyTab);
889                         }
890                 }
891
892                 private void SelectPropertyTab (PropertyTab propertyTab)
893                 {
894                         if (propertyTab != null && selected_tab != propertyTab) {
895                                 foreach (object toolbarItem in toolbar.Items) {
896                                         PropertyToolBarButton button = toolbarItem as PropertyToolBarButton;
897                                         if (button != null && button.PropertyTab != null) {
898                                                 if (button.PropertyTab == selected_tab)
899                                                         button.Pushed = false;
900                                                 else if (button.PropertyTab == propertyTab)
901                                                         button.Pushed = true;
902                                         }
903                                 }
904                                 selected_tab = propertyTab;
905                                 PopulateGrid (selected_objects);
906                                 SelectItemCore (null, GetDefaultPropertyItem (root_grid_item, selected_tab));
907                         }
908                 }
909                 
910                 protected void ShowEventsButton (bool value) 
911                 {
912                         if (value && property_tabs.Contains (typeof (EventsTab)))
913                                 events_tab_visible = true;
914                         else
915                                 events_tab_visible = false;
916                         RefreshTabs (PropertyTabScope.Component);
917                 }
918
919                 public void RefreshTabs (PropertyTabScope tabScope) 
920                 {
921                         property_tabs.Clear (tabScope);
922                         if (selected_objects != null) {
923                                 Type[] tabTypes = null;
924                                 PropertyTabScope[] tabScopes = null;
925
926                                 if (events_tab_visible && property_tabs.Contains (typeof (EventsTab)))
927                                         property_tabs.InsertTab (0, properties_tab, PropertyTabScope.Component);
928
929                                 GetMergedPropertyTabs (selected_objects, out tabTypes, out tabScopes);
930                                 if (tabTypes != null && tabScopes != null && tabTypes.Length > 0) {
931                                         bool selectedTabPreserved = false;
932                                         for (int i=0; i < tabTypes.Length; i++) {
933                                                 property_tabs.AddTabType (tabTypes[i], tabScopes[i]);
934                                                 if (tabTypes[i] == selected_tab.GetType ())
935                                                         selectedTabPreserved = true;
936                                         }
937                                         if (!selectedTabPreserved)
938                                                 SelectPropertyTab (properties_tab);
939                                 }
940                         } else {
941                                 SelectPropertyTab (properties_tab);
942                         }
943                         RefreshToolbar (property_tabs);
944                 }
945
946                 private void RefreshToolbar (PropertyTabCollection tabs)
947                 {
948                         EnsurePropertiesTab ();
949
950                         toolbar.SuspendLayout ();
951                         toolbar.Items.Clear ();
952                         toolbar_imagelist.Images.Clear ();
953
954                         int imageIndex = 0;
955                         toolbar.Items.Add (categorized_toolbarbutton);
956                         toolbar_imagelist.Images.Add (categorized_image);
957                         categorized_toolbarbutton.ImageIndex = imageIndex;
958                         imageIndex++;
959                         toolbar.Items.Add (alphabetic_toolbarbutton);
960                         toolbar_imagelist.Images.Add (alphabetical_image);
961                         alphabetic_toolbarbutton.ImageIndex = imageIndex;
962                         imageIndex++;
963                         toolbar.Items.Add (separator_toolbarbutton);
964                         if (tabs != null && tabs.Count > 0) {
965                                 foreach (PropertyTab tab in tabs) {
966                                         PropertyToolBarButton button = new PropertyToolBarButton (tab);
967                                         toolbar.Items.Add (button);
968                                         if (tab.Bitmap != null) {
969                                                 tab.Bitmap.MakeTransparent ();
970                                                 toolbar_imagelist.Images.Add (tab.Bitmap);
971                                                 button.ImageIndex = imageIndex;
972                                                 imageIndex++;
973                                         }
974                                         if (tab == selected_tab)
975                                                 button.Pushed = true;
976                                 }
977                                 toolbar.Items.Add (new PropertyToolBarSeparator ());
978                         }
979
980                         toolbar.Items.Add (propertypages_toolbarbutton);
981                         toolbar_imagelist.Images.Add (propertypages_image);
982                         propertypages_toolbarbutton.ImageIndex = imageIndex;
983                         
984                         toolbar.ResumeLayout ();
985                 }
986
987                 private void EnsurePropertiesTab ()
988                 {
989                         if (property_tabs == null)
990                                 return;
991
992                         if (property_tabs.Count > 0 && !property_tabs.Contains (typeof (PropertiesTab)))
993                                 property_tabs.InsertTab (0, properties_tab, PropertyTabScope.Component);
994                 }
995
996                 private void GetMergedPropertyTabs (object[] objects, out Type[] tabTypes, out PropertyTabScope[] tabScopes)
997                 {
998                         tabTypes = null;
999                         tabScopes = null;
1000                         if (objects == null || objects.Length == 0)
1001                                 return;
1002
1003                         ArrayList intersection = null;
1004                         ArrayList scopes = new ArrayList ();
1005                         for (int i=0; i < objects.Length; i++) {
1006                                 if (objects[i] == null)
1007                                         continue;
1008                                 PropertyTabAttribute tabAttribute = (PropertyTabAttribute)TypeDescriptor.GetAttributes (objects[i])[typeof (PropertyTabAttribute)];
1009                                 if (tabAttribute == null || tabAttribute.TabClasses == null || tabAttribute.TabClasses.Length == 0)
1010                                         return;
1011
1012                                 ArrayList new_intersection = new ArrayList ();
1013                                 scopes.Clear ();
1014                                 IList currentIntersection = (i == 0 ? (IList)tabAttribute.TabClasses : (IList)intersection);
1015                                 for (int j=0; j < currentIntersection.Count; j++) {
1016                                         if ((Type)intersection[j] == tabAttribute.TabClasses[j]) {
1017                                                 new_intersection.Add (tabAttribute.TabClasses[j]);
1018                                                 scopes.Add (tabAttribute.TabScopes[j]);
1019                                         }
1020                                 }
1021                                 intersection = new_intersection;
1022                         }
1023
1024                         tabTypes = new Type[intersection.Count];
1025                         intersection.CopyTo (tabTypes);
1026                         tabScopes = new PropertyTabScope[tabTypes.Length];
1027                         scopes.CopyTo (tabScopes);
1028                 }
1029
1030                 public void ResetSelectedProperty() 
1031                 {
1032                         if (selected_grid_item == null)
1033                                 return;
1034                         selected_grid_item.ResetValue ();
1035                 }
1036                 #endregion      // Public Instance Methods
1037
1038                 #region Protected Instance Methods
1039
1040                 protected virtual PropertyTab CreatePropertyTab (Type tabType) 
1041                 {
1042                         if (!typeof(PropertyTab).IsAssignableFrom (tabType))
1043                                 return null;
1044
1045                         PropertyTab tab = null;
1046
1047                         ConstructorInfo ctor = tabType.GetConstructor (new Type[] { typeof (IServiceProvider) });
1048                         if (ctor != null)
1049                                 tab = (PropertyTab)ctor.Invoke (new object[] { this.Site });
1050                         else
1051                                 tab = (PropertyTab)Activator.CreateInstance (tabType);
1052                         return tab;
1053                 }
1054                 
1055                 [MonoTODO]
1056                 protected void OnComComponentNameChanged(ComponentRenameEventArgs e)
1057                 {
1058                         ComponentRenameEventHandler eh = (ComponentRenameEventHandler)(Events [ComComponentNameChangedEvent]);
1059                         if (eh != null)
1060                                 eh (this, e);
1061                 }
1062
1063 #if NET_2_0
1064                 protected override void OnEnabledChanged (EventArgs e) {
1065                         base.OnEnabledChanged (e);
1066                 }
1067
1068 #endif
1069                 
1070                 protected override void OnFontChanged(EventArgs e) {
1071                         base.OnFontChanged (e);
1072                 }
1073
1074                 protected override void OnGotFocus(EventArgs e) {
1075                         base.OnGotFocus(e);
1076                 }
1077
1078                 protected override void OnHandleCreated (EventArgs e) {
1079                         base.OnHandleCreated (e);
1080                 }
1081
1082                 protected override void OnHandleDestroyed (EventArgs e) {
1083                         base.OnHandleDestroyed (e);
1084                 }
1085
1086                 protected override void OnMouseDown (MouseEventArgs me) {
1087                         base.OnMouseDown (me);
1088                 }
1089
1090                 protected override void OnMouseMove (MouseEventArgs me) {
1091                         base.OnMouseMove (me);
1092                 }
1093
1094                 protected override void OnMouseUp (MouseEventArgs me) {
1095                         base.OnMouseUp (me);
1096                 }
1097                 
1098                 protected void OnNotifyPropertyValueUIItemsChanged(object sender, EventArgs e) 
1099                 {
1100                         property_grid_view.UpdateView ();
1101                 }
1102
1103                 protected override void OnPaint (PaintEventArgs pevent) {
1104                         pevent.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(BackColor), pevent.ClipRectangle);
1105                         base.OnPaint (pevent);
1106                 }
1107
1108 #if NET_2_0
1109                 protected virtual void OnPropertySortChanged(EventArgs e) {
1110                         EventHandler eh = (EventHandler) Events [PropertySortChangedEvent];
1111                         if (eh != null)
1112                                 eh (this, e);
1113                 }               
1114 #endif
1115                 
1116                 protected virtual void OnPropertyTabChanged (PropertyTabChangedEventArgs e) 
1117                 {
1118                         PropertyTabChangedEventHandler eh = (PropertyTabChangedEventHandler)(Events [PropertyTabChangedEvent]);
1119                         if (eh != null)
1120                                 eh (this, e);
1121                 }
1122
1123                 protected virtual void OnPropertyValueChanged (PropertyValueChangedEventArgs e) {
1124                         PropertyValueChangedEventHandler eh = (PropertyValueChangedEventHandler)(Events [PropertyValueChangedEvent]);
1125                         if (eh != null)
1126                                 eh (this, e);
1127                 }
1128
1129                 protected override void OnResize (EventArgs e) {
1130                         base.OnResize (e);
1131                 }
1132
1133                 protected virtual void OnSelectedGridItemChanged (SelectedGridItemChangedEventArgs e) {
1134                         SelectedGridItemChangedEventHandler eh = (SelectedGridItemChangedEventHandler)(Events [SelectedGridItemChangedEvent]);
1135                         if (eh != null)
1136                                 eh (this, e);
1137                 }
1138
1139                 protected virtual void OnSelectedObjectsChanged (EventArgs e) {
1140                         EventHandler eh = (EventHandler)(Events [SelectedObjectsChangedEvent]);
1141                         if (eh != null)
1142                                 eh (this, e);
1143                 }
1144
1145                 protected override void OnSystemColorsChanged (EventArgs e) {
1146                         base.OnSystemColorsChanged (e);
1147                 }
1148
1149                 protected override void OnVisibleChanged (EventArgs e) {
1150                         base.OnVisibleChanged (e);
1151                 }
1152
1153                 protected override bool ProcessDialogKey (Keys keyData) {
1154                         return base.ProcessDialogKey (keyData);
1155                 }
1156
1157 #if NET_2_0
1158                 [EditorBrowsable (EditorBrowsableState.Never)]
1159 #endif
1160                 protected override void ScaleCore (float dx, float dy) {
1161                         base.ScaleCore (dx, dy);
1162                 }
1163                 
1164                 protected override void WndProc (ref Message m) 
1165                 {
1166                         base.WndProc (ref m);
1167                 }
1168                 #endregion
1169
1170                 #region Events
1171                 static object PropertySortChangedEvent = new object ();
1172                 static object PropertyTabChangedEvent = new object ();
1173                 static object PropertyValueChangedEvent = new object ();
1174                 static object SelectedGridItemChangedEvent = new object ();
1175                 static object SelectedObjectsChangedEvent = new object ();
1176
1177                 public event EventHandler PropertySortChanged {
1178                         add { Events.AddHandler (PropertySortChangedEvent, value); }
1179                         remove { Events.RemoveHandler (PropertySortChangedEvent, value); }
1180                 }
1181
1182                 public event PropertyTabChangedEventHandler PropertyTabChanged {
1183                         add { Events.AddHandler (PropertyTabChangedEvent, value); }
1184                         remove { Events.RemoveHandler (PropertyTabChangedEvent, value); }
1185                 }
1186
1187                 public event PropertyValueChangedEventHandler PropertyValueChanged {
1188                         add { Events.AddHandler (PropertyValueChangedEvent, value); }
1189                         remove { Events.RemoveHandler (PropertyValueChangedEvent, value); }
1190                 }
1191
1192                 public event SelectedGridItemChangedEventHandler SelectedGridItemChanged {
1193                         add { Events.AddHandler (SelectedGridItemChangedEvent, value); }
1194                         remove { Events.RemoveHandler (SelectedGridItemChangedEvent, value); }
1195                 }
1196
1197                 public event EventHandler SelectedObjectsChanged {
1198                         add { Events.AddHandler (SelectedObjectsChangedEvent, value); }
1199                         remove { Events.RemoveHandler (SelectedObjectsChangedEvent, value); }
1200                 }
1201                 
1202                 [Browsable(false)]
1203                 [EditorBrowsable(EditorBrowsableState.Never)]
1204                 public new event EventHandler BackgroundImageChanged {
1205                         add { base.BackgroundImageChanged += value; }
1206                         remove { base.BackgroundImageChanged -= value; }
1207                 }
1208
1209 #if NET_2_0
1210                 [Browsable(false)]
1211                 [EditorBrowsable(EditorBrowsableState.Never)]
1212                 public new event EventHandler BackgroundImageLayoutChanged {
1213                         add { base.BackgroundImageLayoutChanged += value; }
1214                         remove { base.BackgroundImageLayoutChanged -= value; }
1215                 }
1216 #endif
1217                 
1218                 [Browsable(false)]
1219                 [EditorBrowsable(EditorBrowsableState.Never)]
1220                 public new event EventHandler ForeColorChanged {
1221                         add { base.ForeColorChanged += value; }
1222                         remove { base.ForeColorChanged -= value; }
1223                 }
1224 #if NET_2_0
1225                 [EditorBrowsable(EditorBrowsableState.Advanced)]
1226                 [Browsable(false)]
1227                 public new event KeyEventHandler KeyDown {
1228                         add { base.KeyDown += value; }
1229                         remove { base.KeyDown -= value; }
1230                 }
1231                 
1232                 [Browsable(false)]
1233                 [EditorBrowsable(EditorBrowsableState.Advanced)]
1234                 public new event KeyPressEventHandler KeyPress {
1235                         add { base.KeyPress += value; }
1236                         remove { base.KeyPress -= value; }
1237                 }
1238                 
1239                 [EditorBrowsable(EditorBrowsableState.Advanced)]
1240                 [Browsable(false)]
1241                 public new event KeyEventHandler KeyUp {
1242                         add { base.KeyUp += value; }
1243                         remove { base.KeyUp -= value; }
1244                 }
1245
1246                 [Browsable(false)]
1247                 [EditorBrowsable(EditorBrowsableState.Advanced)]
1248                 public new event MouseEventHandler MouseDown {
1249                         add { base.MouseDown += value; }
1250                         remove { base.MouseDown -= value; }
1251                 }
1252                 
1253                 [EditorBrowsable(EditorBrowsableState.Advanced)]
1254                 [Browsable(false)]
1255                 public new event EventHandler MouseEnter {
1256                         add { base.MouseEnter += value; }
1257                         remove { base.MouseEnter -= value; }
1258                 }
1259
1260                 [EditorBrowsable(EditorBrowsableState.Advanced)]
1261                 [Browsable(false)]
1262                 public new event EventHandler MouseLeave {
1263                         add { base.MouseLeave += value; }
1264                         remove { base.MouseLeave -= value; }
1265                 }
1266
1267                 [EditorBrowsable(EditorBrowsableState.Advanced)]
1268                 [Browsable(false)]
1269                 public new event MouseEventHandler MouseMove {
1270                         add { base.MouseMove += value; }
1271                         remove { base.MouseMove -= value; }
1272                 }
1273                 
1274                 [EditorBrowsable(EditorBrowsableState.Advanced)]
1275                 [Browsable(false)]
1276                 public new event MouseEventHandler MouseUp {
1277                         add { base.MouseUp += value; }
1278                         remove { base.MouseUp -= value; }
1279                 }
1280                 
1281                 [Browsable(false)]
1282                 [EditorBrowsable(EditorBrowsableState.Never)]
1283                 public new event EventHandler PaddingChanged {
1284                         add { base.PaddingChanged += value; }
1285                         remove { base.PaddingChanged -= value; }
1286                 }
1287                 
1288                 [Browsable(false)]
1289                 public new event EventHandler TextChanged {
1290                         add { base.TextChanged += value; }
1291                         remove { base.TextChanged -= value; }
1292                 }
1293 #endif
1294                 #endregion
1295
1296                 #region Com2Interop.IComPropertyBrowser Interface
1297                 [MonoTODO]
1298                 bool ComponentModel.Com2Interop.IComPropertyBrowser.InPropertySet {
1299                         get  {
1300                                 throw new NotImplementedException();
1301                         }
1302                 }
1303
1304                 [MonoTODO]
1305                 void ComponentModel.Com2Interop.IComPropertyBrowser.DropDownDone() {
1306                         throw new NotImplementedException();
1307                 }
1308
1309                 [MonoTODO]
1310                 bool ComponentModel.Com2Interop.IComPropertyBrowser.EnsurePendingChangesCommitted() {
1311                         throw new NotImplementedException();
1312                 }
1313
1314                 [MonoTODO]
1315                 void ComponentModel.Com2Interop.IComPropertyBrowser.HandleF4() {
1316                         throw new NotImplementedException();
1317                 }
1318
1319                 [MonoTODO]
1320                 void ComponentModel.Com2Interop.IComPropertyBrowser.LoadState(Microsoft.Win32.RegistryKey key) {
1321                         throw new NotImplementedException();
1322                 }
1323
1324                 [MonoTODO]
1325                 void ComponentModel.Com2Interop.IComPropertyBrowser.SaveState(Microsoft.Win32.RegistryKey key) {
1326                         throw new NotImplementedException();
1327                 }
1328
1329                 static object ComComponentNameChangedEvent = new object ();
1330                 event ComponentRenameEventHandler ComponentModel.Com2Interop.IComPropertyBrowser.ComComponentNameChanged {
1331                         add { Events.AddHandler (ComComponentNameChangedEvent, value); }
1332                         remove { Events.RemoveHandler (ComComponentNameChangedEvent, value); }
1333                 }
1334                 #endregion      // Com2Interop.IComPropertyBrowser Interface
1335
1336                 #region PropertyTabCollection Class
1337                 public class PropertyTabCollection : ICollection, IEnumerable 
1338                 {
1339                         ArrayList property_tabs;
1340                         ArrayList property_tabs_scopes;
1341                         PropertyGrid property_grid;
1342
1343                         internal PropertyTabCollection (PropertyGrid propertyGrid) 
1344                         {
1345                                 property_grid = propertyGrid;
1346                                 property_tabs = new ArrayList ();
1347                                 property_tabs_scopes = new ArrayList ();
1348                         }
1349
1350                         public PropertyTab this[int index] {
1351                                 get { return (PropertyTab)property_tabs[index]; }
1352                         }
1353                 
1354                         bool ICollection.IsSynchronized {
1355                                 get { return property_tabs.IsSynchronized; }
1356                         }
1357
1358                         void ICollection.CopyTo (Array array, int index) 
1359                         {
1360                                 property_tabs.CopyTo (array, index);
1361                         }
1362
1363                         object ICollection.SyncRoot {
1364                                 get { return property_tabs.SyncRoot; }
1365                         }
1366
1367                         public IEnumerator GetEnumerator ()
1368                         {
1369                                 return property_tabs.GetEnumerator ();
1370                         }
1371
1372                         public int Count {
1373                                 get { return property_tabs.Count; }
1374                         }
1375
1376                         public void AddTabType (Type propertyTabType)
1377                         {
1378                                 AddTabType (propertyTabType, PropertyTabScope.Global);
1379                         }
1380
1381                         public void AddTabType (Type propertyTabType, PropertyTabScope tabScope)
1382                         {
1383                                 if (propertyTabType == null)
1384                                         throw new ArgumentNullException ("propertyTabType");
1385
1386                                 // Avoid duplicates
1387                                 if (this.Contains (propertyTabType))
1388                                         return;
1389                                 PropertyTab tab = property_grid.CreatePropertyTab (propertyTabType);
1390                                 if (tab != null) {
1391                                         property_tabs.Add (tab);
1392                                         property_tabs_scopes.Add (tabScope);
1393                                 }
1394                                 property_grid.RefreshToolbar (this);
1395                         }
1396
1397                         internal PropertyTabScope GetTabScope (PropertyTab tab)
1398                         {
1399                                 if (tab == null)
1400                                         throw new ArgumentNullException ("tab");
1401
1402                                 int index = property_tabs.IndexOf (tab);
1403                                 if (index != -1)
1404                                         return (PropertyTabScope)property_tabs_scopes[index];
1405                                 return PropertyTabScope.Global;
1406                         }
1407
1408                         internal void InsertTab (int index, PropertyTab propertyTab, PropertyTabScope tabScope)
1409                         {
1410                                 if (propertyTab == null)
1411                                         throw new ArgumentNullException ("propertyTab");
1412                                 
1413                                 if (!this.Contains (propertyTab.GetType ())) {
1414                                         property_tabs.Insert (index, propertyTab);
1415                                         property_tabs_scopes.Insert (index, tabScope);
1416                                 }
1417                         }
1418
1419                         internal bool Contains (Type propertyType)
1420                         {
1421                                 if (propertyType == null)
1422                                         throw new ArgumentNullException ("propertyType");
1423
1424                                 foreach (PropertyTab t in property_tabs) {
1425                                         if (t.GetType () == propertyType)
1426                                                 return true;
1427                                 }
1428                                 return false;
1429                         }
1430
1431                         internal PropertyTab this[Type tabType] {
1432                                 get {
1433                                         foreach (PropertyTab tab in property_tabs) {
1434                                                 if (tabType == tab.GetType ())
1435                                                         return tab;
1436                                         }
1437                                         return null;
1438                                 }
1439                         }
1440
1441                         public void Clear (PropertyTabScope tabScope)
1442                         {
1443                                 ArrayList toRemove = new ArrayList ();
1444                                 for (int i=0; i < property_tabs_scopes.Count; i++) {
1445                                         if ((PropertyTabScope)property_tabs_scopes[i] == tabScope)
1446                                                 toRemove.Add (i);
1447                                 }
1448                                 foreach (int indexToRemove in toRemove) {
1449                                         property_tabs.RemoveAt (indexToRemove);
1450                                         property_tabs_scopes.RemoveAt (indexToRemove);
1451                                 }
1452                                 property_grid.RefreshToolbar (this);
1453                         }
1454
1455                         public void RemoveTabType (Type propertyTabType)
1456                         {
1457                                 if (propertyTabType == null)
1458                                         throw new ArgumentNullException ("propertyTabType");
1459
1460                                 ArrayList toRemove = new ArrayList ();
1461                                 for (int i=0; i < property_tabs.Count; i++) {
1462                                         if (property_tabs[i].GetType () == propertyTabType)
1463                                                 toRemove.Add (i);
1464                                 }
1465                                 foreach (int indexToRemove in toRemove) {
1466                                         property_tabs.RemoveAt (indexToRemove);
1467                                         property_tabs_scopes.RemoveAt (indexToRemove);
1468                                 }
1469                                 property_grid.RefreshToolbar (this);
1470                         }
1471                 }
1472                 #endregion      // PropertyTabCollection Class
1473
1474                 #region Private Helper Methods
1475
1476                 private GridItem FindFirstPropertyItem (GridItem root)
1477                 {
1478                         if (root.GridItemType == GridItemType.Property)
1479                                 return root;
1480
1481                         foreach (GridItem item in root.GridItems) {
1482                                 GridItem subitem = FindFirstPropertyItem (item);
1483                                 if (subitem != null)
1484                                         return subitem;
1485                         }
1486
1487                         return null;
1488                 }
1489
1490                 private GridEntry GetDefaultPropertyItem (GridEntry rootItem, PropertyTab propertyTab)
1491                 {
1492                         if (rootItem == null || rootItem.GridItems.Count == 0 || propertyTab == null)
1493                                 return null;
1494                         object[] propertyOwners = rootItem.Values;
1495                         if (propertyOwners == null || propertyOwners.Length == 0 || propertyOwners[0] == null)
1496                                 return null;
1497
1498                         GridItem defaultSelected = null;
1499                         if (propertyOwners.Length > 1)
1500                                 defaultSelected = rootItem.GridItems[0];
1501                         else {
1502                                 PropertyDescriptor defaultProperty = propertyTab.GetDefaultProperty (propertyOwners[0]);
1503                                 if (defaultProperty != null)
1504                                         defaultSelected = FindItem (defaultProperty.Name, rootItem);
1505                                 if (defaultSelected == null)
1506                                         defaultSelected = FindFirstPropertyItem (rootItem);
1507                         }
1508
1509                         return defaultSelected as GridEntry;
1510                 }
1511
1512                 private GridEntry FindItem (string name, GridEntry rootItem)
1513                 {
1514                         if (rootItem == null || name == null)
1515                                 return null;
1516
1517                         if (property_sort == PropertySort.Alphabetical || property_sort == PropertySort.NoSort) {
1518                                 foreach (GridItem item in rootItem.GridItems) {
1519                                         if (item.Label == name) {
1520                                                 return (GridEntry)item;
1521                                         }
1522                                 }
1523                         } else if (property_sort == PropertySort.Categorized || 
1524                                    property_sort == PropertySort.CategorizedAlphabetical) {
1525                                 foreach (GridItem categoryItem in rootItem.GridItems) {
1526                                         foreach (GridItem item in categoryItem.GridItems) {
1527                                                 if (item.Label == name) {
1528                                                         return (GridEntry)item;
1529                                                 }
1530                                         }
1531                                 }
1532                         }
1533
1534                         return null;
1535                 }
1536
1537 #if NET_2_0
1538                 private void toolbar_ButtonClick (object sender, ToolStripItemClickedEventArgs e)
1539                 {
1540                         toolbar_Clicked (e.ClickedItem as PropertyToolBarButton);
1541                 }
1542 #else
1543                 private void toolbar_ButtonClick (object sender, ToolBarButtonClickEventArgs e)
1544                 {
1545                         toolbar_Clicked (e.Button as PropertyToolBarButton);
1546                 }
1547 #endif
1548
1549                 private void OnResetPropertyClick (object sender, EventArgs e)
1550                 {
1551                         ResetSelectedProperty();
1552                 }
1553
1554                 private void OnDescriptionClick (object sender, EventArgs e)
1555                 {
1556                         this.HelpVisible = !this.HelpVisible;
1557                         description_menuitem.Checked = this.HelpVisible;
1558                 }
1559
1560                 private void PopulateGrid (object[] objects) 
1561                 {
1562                         if (objects.Length > 0) {
1563                                 root_grid_item = new RootGridEntry (this, objects);
1564                                 PopulateRootGridItems (root_grid_item, objects, GetMergedPropertyNames (objects));
1565                         } else {
1566                                 root_grid_item = null;
1567                         }
1568                 }
1569
1570                 private bool IsPropertyVisible (PropertyDescriptor property, bool merging)
1571                 {
1572                         if (property == null)
1573                                 return false;
1574                                 
1575                         if (merging) {
1576                                 MergablePropertyAttribute attrib = property.Attributes [typeof (MergablePropertyAttribute)] as MergablePropertyAttribute;
1577                                 if (attrib != null && !attrib.AllowMerge)
1578                                         return false;
1579                         }
1580
1581                         return true;
1582                 }
1583
1584                 private string[] GetMergedPropertyNames (object [] objects)
1585                 {
1586                         ArrayList intersection = null;
1587                         for (int i = 0; i < objects.Length; i ++) {
1588                                 if (objects [i] == null)
1589                                         continue;
1590
1591                                 PropertyDescriptorCollection properties = GetProperties (objects[i], BrowsableAttributes);
1592                                 ArrayList new_intersection = new ArrayList ();
1593
1594                                 foreach (PropertyDescriptor currentProperty in (i == 0 ? (ICollection)properties : (ICollection)intersection)) {
1595                                         PropertyDescriptor matchingProperty = (i == 0 ? currentProperty : properties [currentProperty.Name]);
1596
1597                                         if (!IsPropertyVisible (matchingProperty, objects.Length > 1))
1598                                                 continue;
1599                                         if (matchingProperty.PropertyType == currentProperty.PropertyType)
1600                                                 new_intersection.Add (matchingProperty);
1601                                 }
1602
1603                                 intersection = new_intersection;
1604                         }
1605
1606                         string[] propertyNames = new string [intersection.Count];
1607                         for (int i=0; i < intersection.Count; i++)
1608                                 propertyNames[i] = ((PropertyDescriptor)intersection[i]).Name;
1609                                 
1610                         return propertyNames;
1611                 }
1612
1613                 private PropertyDescriptor GetPropertyDescriptor (object propertyOwner, string propertyName)
1614                 {
1615                         if (propertyOwner == null || propertyName == null)
1616                                 return null;
1617
1618                         PropertyDescriptorCollection properties = GetProperties (propertyOwner, BrowsableAttributes);
1619                         if (properties != null)
1620                                 return properties[propertyName];
1621                         return null;
1622                 }
1623
1624                 private PropertyDescriptorCollection GetProperties (object propertyOwner, AttributeCollection attributes)
1625                 {
1626                         if (propertyOwner == null || selected_tab == null)
1627                                 return new PropertyDescriptorCollection (null);
1628
1629                         Attribute[] atts = new Attribute[attributes.Count];
1630                         attributes.CopyTo (atts, 0);
1631                         return selected_tab.GetProperties (propertyOwner, atts);
1632                 }
1633
1634                 private void PopulateRootGridItems (GridEntry rootItem, object[] propertyOwners, string[] propertyNames)
1635                 {
1636                         if (propertyOwners == null || propertyNames == null)
1637                                 return;
1638
1639                         bool categorized = property_sort == PropertySort.Categorized || 
1640                                 property_sort == PropertySort.CategorizedAlphabetical;
1641                         rootItem.GridItems.Clear ();
1642
1643                         foreach (string propertyName in propertyNames) {
1644                                 GridEntry item = null;
1645                                 PropertyDescriptor[] properties = new PropertyDescriptor[propertyOwners.Length];
1646                                 for (int i=0; i < propertyOwners.Length; i++)
1647                                         properties[i] = GetPropertyDescriptor (propertyOwners[i], propertyName);
1648
1649                                 if (categorized) {
1650                                         string categoryName = null;
1651                                         foreach (PropertyDescriptor property in properties) {
1652                                                 categoryName = property.Category;
1653                                                 if (categoryName != null)
1654                                                         break;
1655                                         }
1656                                         if (categoryName == null)
1657                                                 categoryName = UNCATEGORIZED_CATEGORY_LABEL;
1658                                         GridEntry category = (GridEntry)root_grid_item.GridItems[categoryName];
1659                                         if (category == null) {
1660                                                 category = new CategoryGridEntry (this, categoryName, rootItem);
1661                                                 category.Expanded = true;
1662                                                 rootItem.GridItems.Add (category);
1663                                         }
1664                                         item = new GridEntry (this, properties, category);
1665                                         category.GridItems.Add (item);
1666                                 } else {
1667                                         item = new GridEntry (this, properties, rootItem);
1668                                         rootItem.GridItems.Add (item);
1669                                 }
1670
1671                                 PopulateSubGridItems (item);
1672                         }
1673                 }
1674
1675                 private void PopulateSubGridItems (GridEntry parentItem)
1676                 {
1677                         parentItem.GridItems.Clear ();
1678                         if (!IsExpandable (parentItem))
1679                                 return;
1680
1681                         object[] propertyOwners = parentItem.Values;
1682                         if (propertyOwners == null)
1683                                 return;
1684
1685                         PropertyDescriptorCollection propertiesCollection = GetProperties (propertyOwners[0], BrowsableAttributes);
1686                         if (propertiesCollection == null)
1687                                 return;
1688
1689                         foreach (PropertyDescriptor property in propertiesCollection) {
1690                                 string propertyName = property.Name;
1691
1692                                 PropertyDescriptor[] properties = new PropertyDescriptor[propertyOwners.Length];
1693                                 for (int i=0; i < propertyOwners.Length; i++)
1694                                         properties[i] = GetPropertyDescriptor (propertyOwners[i], propertyName);
1695
1696                                 GridEntry item = new GridEntry (this, properties, parentItem);
1697                                 parentItem.GridItems.Add (item);
1698                                 if (IsExpandable (item))
1699                                         PopulateSubGridItems (item);
1700                         }
1701                 }
1702
1703                 private bool IsExpandable (GridEntry item)
1704                 {
1705                         if (item == null || item.PropertyDescriptor == null || 
1706                             item.PropertyDescriptor.Converter == null)
1707                                 return false;
1708                         else if (!item.PropertyDescriptor.Converter.GetPropertiesSupported () &&
1709                                  !item.PropertyDescriptor.Attributes.Contains (
1710                                          DesignerSerializationVisibilityAttribute.Content))
1711                                 return false;
1712                         return true;
1713                 }
1714
1715                 private void UpdateSortLayout (GridEntry rootItem)
1716                 {
1717                         if (rootItem == null)
1718                                 return;
1719
1720                         GridItemCollection reordered = new GridItemCollection ();
1721
1722                         if (property_sort == PropertySort.Alphabetical || property_sort == PropertySort.NoSort) {
1723                                 alphabetic_toolbarbutton.Pushed = true;
1724                                 categorized_toolbarbutton.Pushed = false;
1725                                 foreach (GridItem item in rootItem.GridItems) {
1726                                         if (item.GridItemType == GridItemType.Category) {
1727                                                 foreach (GridItem categoryChild in item.GridItems) {
1728                                                         reordered.Add (categoryChild);
1729                                                         ((GridEntry)categoryChild).SetParent (rootItem);
1730                                                 }
1731                                         } else {
1732                                                 reordered.Add (item);
1733                                         }
1734                                 }
1735                         } else if (property_sort == PropertySort.Categorized || 
1736                                    property_sort == PropertySort.CategorizedAlphabetical) {
1737                                 alphabetic_toolbarbutton.Pushed = false;
1738                                 categorized_toolbarbutton.Pushed = true;
1739                                 GridItemCollection categories = new GridItemCollection ();
1740
1741                                 foreach (GridItem item in rootItem.GridItems) {
1742                                         if (item.GridItemType == GridItemType.Category) {
1743                                                 categories.Add (item);
1744                                                 continue;
1745                                         }
1746
1747                                         string categoryName = item.PropertyDescriptor.Category;
1748                                         if (categoryName == null)
1749                                                 categoryName = UNCATEGORIZED_CATEGORY_LABEL;
1750                                         GridItem category_item = rootItem.GridItems [categoryName];
1751                                         if (category_item == null)
1752                                                 category_item = categories [categoryName];
1753
1754                                         if (category_item == null) {
1755                                                 // Create category grid items if they already don't
1756                                                 category_item = new CategoryGridEntry (this, categoryName, rootItem);
1757                                                 category_item.Expanded = true;
1758                                                 categories.Add (category_item);
1759                                         }
1760
1761                                         category_item.GridItems.Add (item);
1762                                         ((GridEntry)item).SetParent (category_item);
1763                                 }
1764
1765                                 reordered.AddRange (categories);
1766                         }
1767
1768                         rootItem.GridItems.Clear ();
1769                         rootItem.GridItems.AddRange (reordered);
1770                 }
1771
1772                 private void help_panel_Paint(object sender, PaintEventArgs e) {
1773                         e.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(help_panel.BackColor), help_panel.ClientRectangle );
1774                         e.Graphics.DrawRectangle(SystemPens.ControlDark, 0,0,help_panel.Width-1,help_panel.Height-1 );
1775                 }
1776
1777                 #endregion      // Private Helper Methods
1778
1779 #region Internal helper classes
1780                 // as we can not change the color for BorderStyle.FixedSingle and we need the correct
1781                 // ClientRectangle so that the ScrollBar doesn't draw over the border we need this class
1782                 internal class BorderHelperControl : Control {
1783
1784                         public BorderHelperControl ()
1785                         {
1786                                 BackColor = ThemeEngine.Current.ColorWindow;
1787                         }
1788
1789                         protected override void OnPaint (PaintEventArgs e)
1790                         {
1791                                 e.Graphics.DrawRectangle (SystemPens.ControlDark, 0 , 0 , Width - 1, Height - 1);
1792                                 base.OnPaint (e);
1793                         }
1794                         
1795                         protected override void OnSizeChanged (EventArgs e)
1796                         {
1797                                 if (Controls.Count == 1) {
1798                                         Control control = Controls [0];
1799                                         
1800                                         if (control.Location.X != 1 || control.Location.Y != 1)
1801                                                 control.Location = new Point (1, 1);
1802                                         
1803                                         control.Width = ClientRectangle.Width - 2;
1804                                         control.Height = ClientRectangle.Height - 2;
1805                                 }
1806                                 base.OnSizeChanged (e);
1807                         }
1808                 }
1809
1810                 private class PropertyToolBarSeparator : 
1811 #if NET_2_0
1812                 ToolStripSeparator
1813 #else
1814                 ToolBarButton
1815 #endif
1816                 {
1817                         public PropertyToolBarSeparator ()
1818                         {
1819 #if !NET_2_0
1820                                 this.Style = ToolBarButtonStyle.Separator;
1821 #endif
1822                         }
1823                 }
1824
1825                 private class PropertyToolBarButton :
1826 #if NET_2_0
1827                 ToolStripButton
1828 #else
1829                 ToolBarButton
1830 #endif
1831                 {
1832                         private PropertyTab property_tab;
1833
1834                         public PropertyToolBarButton ()
1835                         {
1836                         }
1837
1838                         public PropertyToolBarButton (PropertyTab propertyTab)
1839                         {
1840                                 if (propertyTab == null)
1841                                         throw new ArgumentNullException ("propertyTab");
1842                                 property_tab = propertyTab;
1843                         }
1844
1845                         public PropertyTab PropertyTab {
1846                                 get { return property_tab; }
1847                         }
1848
1849 #if NET_2_0
1850                         public bool Pushed {
1851                                 get { return base.Checked; }
1852                                 set { base.Checked = value; }
1853                         }
1854                         
1855                         public ToolBarButtonStyle Style {
1856                                 get { return ToolBarButtonStyle.PushButton; }
1857                                 set { }
1858                         }
1859 #endif
1860                 }
1861                 
1862                 // needed! this little helper makes it possible to draw a different toolbar border
1863                 // and toolbar backcolor in ThemeWin32Classic
1864                 internal class PropertyToolBar : 
1865 #if NET_2_0
1866                 ToolStrip
1867 #else
1868                 ToolBar 
1869 #endif
1870                 {
1871                 
1872 #if NET_2_0
1873                         bool flat;
1874 #endif
1875                         public PropertyToolBar ()
1876                         {
1877                                 SetStyle (ControlStyles.ResizeRedraw, true);
1878 #if NET_2_0
1879                                 GripStyle = ToolStripGripStyle.Hidden;
1880 #endif
1881                         }
1882
1883 #if !NET_2_0
1884                         public IList Items {
1885                                 get { return base.Buttons; }
1886                         }
1887 #endif
1888
1889 #if NET_2_0
1890                         public bool ShowToolTips {
1891                                 get { return base.ShowItemToolTips; }
1892                                 set { base.ShowItemToolTips = value; }
1893                         }
1894                         
1895                         public ToolBarAppearance Appearance {
1896                                 get { return flat ? ToolBarAppearance.Flat : ToolBarAppearance.Normal; }
1897                                 set { 
1898                                         if (value == Appearance)
1899                                                 return;
1900                                                 
1901                                         switch (value) {
1902                                         case ToolBarAppearance.Flat:
1903                                                 Renderer = new ToolStripSystemRenderer ();
1904                                                 break;
1905                                         case ToolBarAppearance.Normal:
1906                                                 ProfessionalColorTable table = new ProfessionalColorTable ();
1907                                                 table.UseSystemColors = true;
1908                                                 Renderer = new ToolStripProfessionalRenderer (table);
1909                                                 break;
1910                                         }
1911                                 }
1912                         }
1913 #endif
1914                 }
1915
1916
1917                 [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")]
1918                 private class SelectedObjectConverter : TypeConverter
1919                 {
1920                 }
1921 #endregion
1922         }
1923 }