// Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // Copyright (c) 2004-2008 Novell, Inc. // // Authors: // Jonathan Chambers (jonathan.chambers@ansys.com) // Ivan N. Zlatev (contact@i-nz.net) // // NOT COMPLETE using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; using System.Reflection; using System.Windows.Forms.Design; using System.Windows.Forms.PropertyGridInternal; using System.Xml.Linq; namespace System.Windows.Forms { public class PropertyGrid : UserControl { #region Private Members private const string UNCATEGORIZED_CATEGORY_LABEL = "Misc"; private AttributeCollection browsable_attributes = null; private Color line_color; private PropertySort property_sort; private PropertyTabCollection property_tabs; private GridEntry selected_grid_item; private GridEntry root_grid_item; private object[] selected_objects; private Hashtable collapsed_categories; private PropertyTab properties_tab; private PropertyTab selected_tab; private ImageList toolbar_imagelist; private Image categorized_image; private Image alphabetical_image; private PropertyToolBarButton categorized_toolbarbutton; private PropertyToolBarButton alphabetic_toolbarbutton; private PropertyToolBarSeparator separator_toolbarbutton; private bool events_tab_visible; private PropertyToolBar toolbar; private PropertyGridView property_grid_view; private Splitter splitter; private Panel help_panel; private Label help_title_label; private Label help_description_label; private Color category_fore_color; #endregion // Private Members #region Contructors public PropertyGrid() { selected_objects = new object[0]; collapsed_categories = new Hashtable(); property_tabs = new PropertyTabCollection(this); line_color = Drawing.SystemColors.ControlLight; category_fore_color = Drawing.SystemColors.ControlText; property_sort = PropertySort.CategorizedAlphabetical; property_grid_view = new PropertyGridView(this); property_grid_view.BackColor = System.Drawing.SystemColors.Window; property_grid_view.Padding = new Padding(1); property_grid_view.Dock = DockStyle.Fill; splitter = new Splitter(); splitter.Dock = DockStyle.Bottom; splitter.Height = _dpi(3); help_panel = new Panel(); help_panel.Dock = DockStyle.Bottom; help_panel.Height = _dpi(50); help_panel.BackColor = Drawing.SystemColors.Control; help_title_label = new Label(); help_title_label.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; help_title_label.Name = "help_title_label"; help_title_label.Font = new Font(this.Font, Drawing.FontStyle.Bold); help_title_label.Location = new Drawing.Point(2, 2); help_title_label.Height = 17; help_title_label.Width = help_panel.Width - 4; help_description_label = new Label(); help_description_label.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom; help_description_label.AutoSize = false; help_description_label.Font = this.Font; help_description_label.Location = new Drawing.Point(2, help_title_label.Top + help_title_label.Height); help_description_label.Width = help_panel.Width - 4; help_description_label.Height = help_panel.Height - help_description_label.Top - 2; help_panel.Controls.Add(help_description_label); help_panel.Controls.Add(help_title_label); help_panel.Paint += new PaintEventHandler(help_panel_Paint); toolbar = new PropertyToolBar(); categorized_toolbarbutton = new PropertyToolBarButton(); categorized_toolbarbutton.Pushed = true; alphabetic_toolbarbutton = new PropertyToolBarButton(); separator_toolbarbutton = new PropertyToolBarSeparator(); categorized_image = ResourceLoader.GetBitmap("categorized.png"); alphabetical_image = ResourceLoader.GetBitmap("alphabetical.png"); toolbar_imagelist = new ImageList(); toolbar_imagelist.ColorDepth = ColorDepth.Depth32Bit; toolbar_imagelist.ImageSize = new System.Drawing.Size(16, 16); toolbar.Dock = DockStyle.Top; toolbar.AutoSize = false; toolbar.ImageList = toolbar_imagelist; toolbar.Size = new System.Drawing.Size(256, 27); toolbar.TabIndex = 0; toolbar.Items.AddRange(new ToolStripItem[] {categorized_toolbarbutton, alphabetic_toolbarbutton}); categorized_toolbarbutton.Click += new EventHandler(toolbarbutton_clicked); alphabetic_toolbarbutton.Click += new EventHandler(toolbarbutton_clicked); categorized_toolbarbutton.ToolTipText = "Categorized"; alphabetic_toolbarbutton.ToolTipText = "Alphabetic"; properties_tab = CreatePropertyTab(this.DefaultTabType); selected_tab = properties_tab; RefreshToolbar(property_tabs); this.Controls.Add(property_grid_view);// helper); this.Controls.Add(toolbar); this.Controls.Add(splitter); this.Controls.Add(help_panel); this.Name = "PropertyGrid"; this.Size = new System.Drawing.Size(256, 400); this.BorderStyle = BorderStyle.FixedSingle; } #endregion // Constructors #region Public Instance Properties [Browsable(false)] [EditorBrowsableAttribute(EditorBrowsableState.Advanced)] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] public AttributeCollection BrowsableAttributes { get { if (browsable_attributes == null) { browsable_attributes = new AttributeCollection(new Attribute[] { BrowsableAttribute.Yes }); } return browsable_attributes; } set { if (browsable_attributes == value) return; if (browsable_attributes == null || browsable_attributes.Count == 0) browsable_attributes = null; else browsable_attributes = value; } } public override Color BackColor { get { return base.BackColor; } set { base.BackColor = value; toolbar.BackColor = value; Refresh(); } } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] public override Image BackgroundImage { get { return base.BackgroundImage; } set { base.BackgroundImage = value; } } [EditorBrowsable(EditorBrowsableState.Never)] [Browsable(false)] public override ImageLayout BackgroundImageLayout { get { return base.BackgroundImageLayout; } set { base.BackgroundImageLayout = value; } } [DefaultValue(typeof(Color), "ControlText")] public Color CategoryForeColor { get { return category_fore_color; } set { if (category_fore_color != value) { category_fore_color = value; Invalidate(); } } } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new Control.ControlCollection Controls { get { return base.Controls; } } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] public override Color ForeColor { get { return base.ForeColor; } set { base.ForeColor = value; } } public Color SplitterBackColor { get => splitter.BackColor; set => splitter.BackColor = value; } [DefaultValue("Color [Control]")] public Color HelpBackColor { get { return help_panel.BackColor; } set { help_panel.BackColor = value; splitter.BackColor = value; } } [DefaultValue("Color [ControlText]")] public Color HelpForeColor { get { return help_panel.ForeColor; } set { help_panel.ForeColor = value; } } [DefaultValue(true)] [Localizable(true)] public virtual bool HelpVisible { get { return help_panel.Visible; } set { splitter.Visible = value; help_panel.Visible = value; } } [DefaultValue("Color [InactiveBorder]")] public Color LineColor { get { return line_color; } set { if (line_color == value) { return; } line_color = value; } } [EditorBrowsable(EditorBrowsableState.Never)] [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new Padding Padding { get { return base.Padding; } set { base.Padding = value; } } [DefaultValue(PropertySort.CategorizedAlphabetical)] public PropertySort PropertySort { get { return property_sort; } set { if (!Enum.IsDefined(typeof(PropertySort), value)) throw new InvalidEnumArgumentException("value", (int)value, typeof(PropertySort)); if (property_sort == value) return; // we do not need to update the the grid items and fire // a PropertySortChanged event when switching between // Categorized and CateogizedAlphabetical bool needUpdate = (property_sort & PropertySort.Categorized) == 0 || (value & PropertySort.Categorized) == 0; property_sort = value; if (needUpdate) { UpdateSortLayout(root_grid_item); // update selection if (selected_grid_item != null) { if (selected_grid_item.GridItemType == GridItemType.Category && (value == PropertySort.Alphabetical || value == PropertySort.NoSort)) SelectItemCore(null, null); else SelectItemCore(null, selected_grid_item); } property_grid_view.UpdateView(); OnPropertySortChanged(EventArgs.Empty); } UpdatePropertySortButtonsState(); } } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Advanced)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public PropertyTabCollection PropertyTabs { get { return property_tabs; } } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Advanced)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public GridItem SelectedGridItem { get { return selected_grid_item; } set { if (value == null) throw new ArgumentException("GridItem specified to PropertyGrid.SelectedGridItem must be a valid GridItem."); if (value != selected_grid_item) { GridEntry oldItem = selected_grid_item; SelectItemCore(oldItem, (GridEntry)value); OnSelectedGridItemChanged(new SelectedGridItemChangedEventArgs(oldItem, value)); } } } internal GridItem RootGridItem { get { return root_grid_item; } } private void UpdateHelp(GridItem item) { if (item == null) { help_title_label.Text = string.Empty; help_description_label.Text = string.Empty; } else { help_title_label.Text = item.Label; if (item.PropertyDescriptor != null) this.help_description_label.Text = item.PropertyDescriptor.Description; } } private void SelectItemCore(GridEntry oldItem, GridEntry item) { UpdateHelp(item); selected_grid_item = item; property_grid_view.SelectItem(oldItem, item); } internal void OnPropertyValueChangedInternal(GridItem item, object property_value) { property_grid_view.UpdateView(); OnPropertyValueChanged(new PropertyValueChangedEventArgs(item, property_value)); } internal void OnExpandItem(GridEntry item) { property_grid_view.ExpandItem(item); OnExpandedItemChanged(EventArgs.Empty); } internal void OnCollapseItem(GridEntry item) { property_grid_view.CollapseItem(item); OnExpandedItemChanged(EventArgs.Empty); } internal DialogResult ShowError(string text) { return this.ShowError(text, MessageBoxButtons.OK); } internal DialogResult ShowError(string text, MessageBoxButtons buttons) { if (text == null) throw new ArgumentNullException("text"); return MessageBox.Show(text, "Properties Window", buttons, MessageBoxIcon.Exclamation); } public object SelectedObject { get { if (selected_objects.Length > 0) return selected_objects[0]; return null; } set { if (selected_objects != null && selected_objects.Length == 1 && selected_objects[0] == value) return; if (value == null) SelectedObjects = new object[0]; else SelectedObjects = new object[] { value }; } } [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public object[] SelectedObjects { get { return selected_objects; } set { var old_item = GetItemPath(selected_grid_item); GetCollapsedCategories(root_grid_item); root_grid_item = null; SelectItemCore(null, null); // unselect current item in the view if (value != null) { for (int i = 0; i < value.Length; i++) { if (value[i] == null) throw new ArgumentException(String.Format("Item {0} in the objs array is null.", i)); } selected_objects = value; } else { selected_objects = new object[0]; } ShowEventsButton(false); PopulateGrid(selected_objects); RefreshTabs(PropertyTabScope.Component); if (root_grid_item != null) { CollapseCategories(root_grid_item); var new_item = FindItem(old_item); SelectItemCore(null, new_item ?? GetDefaultPropertyItem(root_grid_item, selected_tab)); } property_grid_view.UpdateView(); OnSelectedObjectsChanged(EventArgs.Empty); } } [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Advanced)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public PropertyTab SelectedTab { get { return selected_tab; } } [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override string Text { get { return base.Text; } set { base.Text = value; } } [DefaultValue(true)] public virtual bool ToolbarVisible { get { return toolbar.Visible; } set { if (toolbar.Visible == value) { return; } toolbar.Visible = value; } } protected ToolStripRenderer ToolStripRenderer { get { if (toolbar != null) { return toolbar.Renderer; } return null; } set { if (toolbar != null) { toolbar.Renderer = value; } } } [DefaultValue("Color [Window]")] public Color ViewBackColor { get { return property_grid_view.BackColor; } set { if (property_grid_view.BackColor == value) { return; } property_grid_view.BackColor = value; } } [DefaultValue("Color [WindowText]")] public Color ViewForeColor { get { return property_grid_view.ForeColor; } set { if (property_grid_view.ForeColor == value) { return; } property_grid_view.ForeColor = value; } } public bool UseCompatibleTextRendering { get; set; } public Drawing.Color CommandsActiveLinkColor { get; set; } public Drawing.Color CommandsDisabledLinkColor { get; set; } public Drawing.Color CommandsLinkColor { get; set; } #endregion // Public Instance Properties #region Protected Instance Properties [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Advanced)] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] protected virtual Type DefaultTabType { get { return typeof(PropertiesTab); } } #endregion // Protected Instance Properties #region Public Instance Methods protected override void Dispose(bool disposing) { base.Dispose(disposing); } public void CollapseAllGridItems() { GridEntry category = FindCategoryItem(selected_grid_item); if (category != null) SelectedGridItem = category; CollapseItemRecursive(root_grid_item); property_grid_view.UpdateView(); } private void CollapseItemRecursive(GridItem item) { if (item == null) return; foreach (GridItem child in item.GridItems) { CollapseItemRecursive(child); if (child.Expandable) child.Expanded = false; } } private GridEntry FindCategoryItem(GridEntry entry) { if (entry == null || (property_sort != PropertySort.Categorized && property_sort != PropertySort.CategorizedAlphabetical)) return null; if (entry.GridItemType == GridItemType.Category) return entry; GridEntry category = null; GridItem current = entry; while (category == null) { if (current.Parent != null && current.Parent.GridItemType == GridItemType.Category) category = (GridEntry)current.Parent; current = current.Parent; if (current == null) break; } return category; } public void ExpandAllGridItems() { ExpandItemRecursive(root_grid_item); property_grid_view.UpdateView(); } private void ExpandItemRecursive(GridItem item) { if (item == null) return; foreach (GridItem child in item.GridItems) { ExpandItemRecursive(child); if (child.Expandable) child.Expanded = true; } } public override void Refresh() { base.Refresh(); // force a full reload here SelectedObjects = SelectedObjects; } private void toolbar_Clicked(PropertyToolBarButton button) { if (button == null) return; if (button == alphabetic_toolbarbutton) { this.PropertySort = PropertySort.Alphabetical; alphabetic_toolbarbutton.Pushed = true; categorized_toolbarbutton.Pushed = false; } else if (button == categorized_toolbarbutton) { this.PropertySort = PropertySort.CategorizedAlphabetical; categorized_toolbarbutton.Pushed = true; alphabetic_toolbarbutton.Pushed = false; } else { if (button.Enabled) SelectPropertyTab(button.PropertyTab); } } private void toolbarbutton_clicked(object o, EventArgs args) { toolbar_Clicked(o as PropertyToolBarButton); } private void SelectPropertyTab(PropertyTab propertyTab) { if (propertyTab != null && selected_tab != propertyTab) { foreach (object toolbarItem in toolbar.Items) { PropertyToolBarButton button = toolbarItem as PropertyToolBarButton; if (button != null && button.PropertyTab != null) { if (button.PropertyTab == selected_tab) button.Pushed = false; else if (button.PropertyTab == propertyTab) button.Pushed = true; } } selected_tab = propertyTab; PopulateGrid(selected_objects); SelectItemCore(null, GetDefaultPropertyItem(root_grid_item, selected_tab)); property_grid_view.UpdateView(); } } private void UpdatePropertySortButtonsState() { if (property_sort == PropertySort.NoSort) { alphabetic_toolbarbutton.Pushed = false; categorized_toolbarbutton.Pushed = false; } else if (property_sort == PropertySort.Alphabetical) { alphabetic_toolbarbutton.Pushed = true; categorized_toolbarbutton.Pushed = false; } else if (property_sort == PropertySort.Categorized || property_sort == PropertySort.CategorizedAlphabetical) { alphabetic_toolbarbutton.Pushed = false; categorized_toolbarbutton.Pushed = true; } } protected void ShowEventsButton(bool value) { value = value && property_tabs.Contains(typeof(EventsTab)); if (events_tab_visible != value) { events_tab_visible = value; RefreshTabs(PropertyTabScope.Component); } } public void RefreshTabs(PropertyTabScope tabScope) { property_tabs.Clear(tabScope); if (selected_objects != null) { Type[] tabTypes = null; PropertyTabScope[] tabScopes = null; if (events_tab_visible && property_tabs.Contains(typeof(EventsTab))) property_tabs.InsertTab(0, properties_tab, PropertyTabScope.Component); GetMergedPropertyTabs(selected_objects, out tabTypes, out tabScopes); if (tabTypes != null && tabScopes != null && tabTypes.Length > 0) { bool selectedTabPreserved = false; for (int i = 0; i < tabTypes.Length; i++) { property_tabs.AddTabType(tabTypes[i], tabScopes[i]); if (tabTypes[i] == selected_tab.GetType()) selectedTabPreserved = true; } if (!selectedTabPreserved) SelectPropertyTab(properties_tab); } } else { SelectPropertyTab(properties_tab); } //RefreshToolbar(property_tabs); } private void RefreshToolbar(PropertyTabCollection tabs) { EnsurePropertiesTab(); toolbar.SuspendLayout(); toolbar.Items.Clear(); toolbar_imagelist.Images.Clear(); int imageIndex = 0; toolbar.Items.Add(categorized_toolbarbutton); toolbar_imagelist.Images.Add(categorized_image); categorized_toolbarbutton.ImageIndex = imageIndex; imageIndex++; toolbar.Items.Add(alphabetic_toolbarbutton); toolbar_imagelist.Images.Add(alphabetical_image); alphabetic_toolbarbutton.ImageIndex = imageIndex; imageIndex++; toolbar.Items.Add(separator_toolbarbutton); if (tabs != null && tabs.Count > 0) { foreach (PropertyTab tab in tabs) { PropertyToolBarButton button = new PropertyToolBarButton(tab); button.ToolTipText = tab.TabName; button.Click += new EventHandler(toolbarbutton_clicked); toolbar.Items.Add(button); if (tab.Bitmap != null) { tab.Bitmap.MakeTransparent(); toolbar_imagelist.Images.Add(tab.Bitmap); button.ImageIndex = imageIndex; imageIndex++; } if (tab == selected_tab) button.Pushed = true; } toolbar.Items.Add(new PropertyToolBarSeparator()); } toolbar.ResumeLayout(); } private void EnsurePropertiesTab() { if (property_tabs == null) return; if (property_tabs.Count > 0 && !property_tabs.Contains(this.DefaultTabType)) property_tabs.InsertTab(0, properties_tab, PropertyTabScope.Component); } private void GetMergedPropertyTabs(object[] objects, out Type[] tabTypes, out PropertyTabScope[] tabScopes) { tabTypes = null; tabScopes = null; if (objects == null || objects.Length == 0) return; ArrayList intersection = null; ArrayList scopes = new ArrayList(); for (int i = 0; i < objects.Length; i++) { if (objects[i] == null) continue; PropertyTabAttribute tabAttribute = (PropertyTabAttribute)TypeDescriptor.GetAttributes(objects[i])[typeof(PropertyTabAttribute)]; if (tabAttribute == null || tabAttribute.TabClasses == null || tabAttribute.TabClasses.Length == 0) return; ArrayList new_intersection = new ArrayList(); scopes.Clear(); IList currentIntersection = (i == 0 ? (IList)tabAttribute.TabClasses : (IList)intersection); for (int j = 0; j < currentIntersection.Count; j++) { if ((Type)currentIntersection[j] == tabAttribute.TabClasses[j]) { new_intersection.Add(tabAttribute.TabClasses[j]); scopes.Add(tabAttribute.TabScopes[j]); } } intersection = new_intersection; } tabTypes = new Type[intersection.Count]; intersection.CopyTo(tabTypes); tabScopes = new PropertyTabScope[tabTypes.Length]; scopes.CopyTo(tabScopes); } public void ResetSelectedProperty() { if (selected_grid_item == null) return; selected_grid_item.ResetValue(); } #endregion // Public Instance Methods #region Protected Instance Methods protected virtual PropertyTab CreatePropertyTab(Type tabType) { if (!typeof(PropertyTab).IsAssignableFrom(tabType)) return null; PropertyTab tab = null; ConstructorInfo ctor = tabType.GetConstructor(new Type[] { typeof(IServiceProvider) }); if (ctor != null) tab = (PropertyTab)ctor.Invoke(new object[] { this.Site }); else tab = (PropertyTab)Activator.CreateInstance(tabType); return tab; } protected override void OnEnabledChanged(EventArgs e) { base.OnEnabledChanged(e); } protected override void OnFontChanged(EventArgs e) { base.OnFontChanged(e); help_title_label.Font = new Font(this.Font, Drawing.FontStyle.Bold); help_title_label.Height = help_title_label.Font.Height; help_description_label.Font = this.Font; help_description_label.Location = new Drawing.Point(2, help_title_label.Top + help_title_label.Height); property_grid_view.Font = this.Font; } protected override void OnGotFocus(EventArgs e) { base.OnGotFocus(e); } protected override void OnMouseDown(MouseEventArgs me) { base.OnMouseDown(me); } protected override void OnMouseMove(MouseEventArgs me) { base.OnMouseMove(me); } protected override void OnMouseUp(MouseEventArgs me) { base.OnMouseUp(me); } protected void OnNotifyPropertyValueUIItemsChanged(object sender, EventArgs e) { property_grid_view.UpdateView(); } protected override void OnPaint(PaintEventArgs pevent) { pevent.Graphics.FillRectangle(ResPool.GetSolidBrush(BackColor), pevent.ClipRectangle); base.OnPaint(pevent); } protected virtual void OnPropertySortChanged(EventArgs e) => PropertySortChanged?.Invoke(this, e); protected virtual void OnPropertyTabChanged(PropertyTabChangedEventArgs e) => PropertyTabChanged?.Invoke(this, e); protected virtual void OnPropertyValueChanged(PropertyValueChangedEventArgs e) => PropertyValueChanged?.Invoke(this, e); protected virtual void OnSelectedGridItemChanged(SelectedGridItemChangedEventArgs e) => SelectedGridItemChanged?.Invoke(this, e); protected virtual void OnSelectedObjectsChanged(EventArgs e) => SelectedObjectsChanged?.Invoke(this, e); protected void OnExpandedItemChanged(EventArgs e) => ExpandedItemChanged?.Invoke(this, e); #endregion #region Events public event EventHandler PropertySortChanged; public event PropertyTabChangedEventHandler PropertyTabChanged; public event PropertyValueChangedEventHandler PropertyValueChanged; public event SelectedGridItemChangedEventHandler SelectedGridItemChanged; public event EventHandler SelectedObjectsChanged; internal event EventHandler ExpandedItemChanged; #endregion #region PropertyTabCollection Class public class PropertyTabCollection : ICollection, IEnumerable { ArrayList property_tabs; ArrayList property_tabs_scopes; PropertyGrid property_grid; internal PropertyTabCollection(PropertyGrid propertyGrid) { property_grid = propertyGrid; property_tabs = new ArrayList(); property_tabs_scopes = new ArrayList(); } public PropertyTab this[int index] { get { return (PropertyTab)property_tabs[index]; } } bool ICollection.IsSynchronized { get { return property_tabs.IsSynchronized; } } void ICollection.CopyTo(Array dest, int index) { property_tabs.CopyTo(dest, index); } object ICollection.SyncRoot { get { return property_tabs.SyncRoot; } } public IEnumerator GetEnumerator() { return property_tabs.GetEnumerator(); } public int Count { get { return property_tabs.Count; } } public void AddTabType(Type propertyTabType) { AddTabType(propertyTabType, PropertyTabScope.Global); } public void AddTabType(Type propertyTabType, PropertyTabScope tabScope) { if (propertyTabType == null) throw new ArgumentNullException("propertyTabType"); // Avoid duplicates if (this.Contains(propertyTabType)) return; PropertyTab tab = property_grid.CreatePropertyTab(propertyTabType); if (tab != null) { property_tabs.Add(tab); property_tabs_scopes.Add(tabScope); } property_grid.RefreshToolbar(this); } internal PropertyTabScope GetTabScope(PropertyTab tab) { if (tab == null) throw new ArgumentNullException("tab"); int index = property_tabs.IndexOf(tab); if (index != -1) return (PropertyTabScope)property_tabs_scopes[index]; return PropertyTabScope.Global; } internal void InsertTab(int index, PropertyTab propertyTab, PropertyTabScope tabScope) { if (propertyTab == null) throw new ArgumentNullException("propertyTab"); if (!this.Contains(propertyTab.GetType())) { property_tabs.Insert(index, propertyTab); property_tabs_scopes.Insert(index, tabScope); } } internal bool Contains(Type propertyType) { if (propertyType == null) throw new ArgumentNullException("propertyType"); foreach (PropertyTab t in property_tabs) { if (t.GetType() == propertyType) return true; } return false; } internal PropertyTab this[Type tabType] { get { foreach (PropertyTab tab in property_tabs) { if (tabType == tab.GetType()) return tab; } return null; } } public void Clear(PropertyTabScope tabScope) { ArrayList toRemove = new ArrayList(); for (int i = 0; i < property_tabs_scopes.Count; i++) { if ((PropertyTabScope)property_tabs_scopes[i] == tabScope) toRemove.Add(i); } foreach (int indexToRemove in toRemove) { if (property_tabs.Count > indexToRemove) property_tabs.RemoveAt(indexToRemove); if (property_tabs_scopes.Count > indexToRemove) property_tabs_scopes.RemoveAt(indexToRemove); } property_grid.RefreshToolbar(this); } public void RemoveTabType(Type propertyTabType) { if (propertyTabType == null) throw new ArgumentNullException("propertyTabType"); ArrayList toRemove = new ArrayList(); for (int i = 0; i < property_tabs.Count; i++) { if (property_tabs[i].GetType() == propertyTabType) toRemove.Add(i); } foreach (int indexToRemove in toRemove) { property_tabs.RemoveAt(indexToRemove); property_tabs_scopes.RemoveAt(indexToRemove); } property_grid.RefreshToolbar(this); } } #endregion // PropertyTabCollection Class #region Private Helper Methods private GridItem FindFirstPropertyItem(GridItem root) { if (root.GridItemType == GridItemType.Property) return root; foreach (GridItem item in root.GridItems) { GridItem subitem = FindFirstPropertyItem(item); if (subitem != null) return subitem; } return null; } private GridEntry GetDefaultPropertyItem(GridEntry rootItem, PropertyTab propertyTab) { if (rootItem == null || rootItem.GridItems.Count == 0 || propertyTab == null) return null; object[] propertyOwners = rootItem.Values; if (propertyOwners == null || propertyOwners.Length == 0 || propertyOwners[0] == null) return null; GridItem defaultSelected = null; if (propertyOwners.Length > 1) defaultSelected = rootItem.GridItems[0]; else { PropertyDescriptor defaultProperty = propertyTab.GetDefaultProperty(propertyOwners[0]); if (defaultProperty != null) defaultSelected = FindItem(defaultProperty.Name, rootItem); if (defaultSelected == null) defaultSelected = FindFirstPropertyItem(rootItem); } return defaultSelected as GridEntry; } private GridEntry FindItem(string path) { string[] names = path.Split(new char[] { '.' }); GridEntry item = root_grid_item; for (int i = 0; i < names.Length; i++) { item = FindItem(names[i], item); if (item == null) return null; if (i != names.Length - 1 && item.Expandable) item.Expanded = true; } return item; } private string GetItemPath(GridItem item) { string path = ""; while (item != null && item != root_grid_item) { if (item is not CategoryGridEntry) path = item.Label + (path == "" ? "" : "." + path); item = item.Parent; } return path; } private GridEntry FindItem(string name, GridEntry rootItem) { if (rootItem == null || name == null) return null; if (property_sort == PropertySort.Alphabetical || property_sort == PropertySort.NoSort || rootItem != root_grid_item) { foreach (GridItem item in rootItem.GridItems) { if (item.Label == name) { return (GridEntry)item; } } } else if (property_sort == PropertySort.Categorized || property_sort == PropertySort.CategorizedAlphabetical) { foreach (GridItem categoryItem in rootItem.GridItems) { foreach (GridItem item in categoryItem.GridItems) { if (item.Label == name) { return (GridEntry)item; } } } } return null; } private void GetCollapsedCategories(GridEntry rootItem) { if ((property_sort == PropertySort.Categorized || property_sort == PropertySort.CategorizedAlphabetical) && rootItem != null) { foreach (GridItem categoryItem in rootItem.GridItems) { if (categoryItem.Expanded) collapsed_categories.Remove(categoryItem.Label); else collapsed_categories[categoryItem.Label] = null; } } } private void CollapseCategories(GridEntry rootItem) { if (property_sort == PropertySort.Categorized || property_sort == PropertySort.CategorizedAlphabetical && rootItem != null) { foreach (GridItem categoryItem in rootItem.GridItems) { if (collapsed_categories.Contains(categoryItem.Label)) categoryItem.Expanded = false; } } } private void PopulateGrid(object[] objects) { if (objects.Length > 0) { root_grid_item = new RootGridEntry(this, objects); root_grid_item.Expanded = true; UpdateSortLayout(root_grid_item); } else { root_grid_item = null; } } private void UpdateSortLayout(GridEntry rootItem) { if (rootItem == null) return; GridItemCollection reordered = new GridItemCollection(); if (property_sort == PropertySort.Alphabetical || property_sort == PropertySort.NoSort) { alphabetic_toolbarbutton.Pushed = true; categorized_toolbarbutton.Pushed = false; foreach (GridItem item in rootItem.GridItems) { if (item.GridItemType == GridItemType.Category) { foreach (GridItem categoryChild in item.GridItems) { reordered.Add(categoryChild); ((GridEntry)categoryChild).SetParent(rootItem); } } else { reordered.Add(item); } } } else if (property_sort == PropertySort.Categorized || property_sort == PropertySort.CategorizedAlphabetical) { alphabetic_toolbarbutton.Pushed = false; categorized_toolbarbutton.Pushed = true; GridItemCollection categories = new GridItemCollection(); foreach (GridItem item in rootItem.GridItems) { if (item.GridItemType == GridItemType.Category) { categories.Add(item); continue; } string categoryName = item.PropertyDescriptor.Category; if (categoryName == null) categoryName = UNCATEGORIZED_CATEGORY_LABEL; GridItem category_item = rootItem.GridItems[categoryName]; if (category_item == null || !(category_item is CategoryGridEntry)) category_item = categories[categoryName]; if (category_item == null) { // Create category grid items if they already don't category_item = new CategoryGridEntry(this, categoryName, rootItem); category_item.Expanded = true; categories.Add(category_item); } category_item.GridItems.Add(item); ((GridEntry)item).SetParent(category_item); } reordered.AddRange(categories); } rootItem.GridItems.Clear(); rootItem.GridItems.AddRange(reordered); } private void help_panel_Paint(object sender, PaintEventArgs e) { e.Graphics.FillRectangle(ResPool.GetSolidBrush(help_panel.BackColor), help_panel.ClientRectangle); if (BorderStyle != BorderStyle.None) this.DrawVisualStyleBorder(e.Graphics, new Rectangle(0, 0, help_panel.Width - 1, help_panel.Height - 1)); } #endregion // Private Helper Methods #region Internal helper classes private class PropertyToolBarSeparator : ToolStripSeparator { public PropertyToolBarSeparator() { } } private class PropertyToolBarButton : ToolStripButton { private PropertyTab property_tab; public PropertyToolBarButton() { CheckOnClick = true; } public PropertyToolBarButton(PropertyTab propertyTab) : this() { if (propertyTab == null) throw new ArgumentNullException("propertyTab"); property_tab = propertyTab; } public PropertyTab PropertyTab { get { return property_tab; } } public bool Pushed { get { return base.Checked; } set { base.Checked = value; } } } internal class PropertyToolBar : ToolStrip { public PropertyToolBar() { SetStyle(ControlStyles.ResizeRedraw, true); GripStyle = ToolStripGripStyle.Hidden; } } #endregion } }