File: winforms\Managed\System\WinForms\PropertyGridInternal\CategoryGridEntry.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="CategoryGridEntry.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
//#define PAINT_CATEGORY_TRIANGLE
/*
 */
namespace System.Windows.Forms.PropertyGridInternal {
 
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
 
     using System;
     using System.Collections;
     using System.Reflection;
     
     using System.ComponentModel;
     using System.ComponentModel.Design;
     using System.Windows.Forms;
     using System.Drawing;
     using Microsoft.Win32;
 
     internal class CategoryGridEntry : GridEntry {
 
        internal string name;
        private Brush backBrush = null;
        private static Hashtable categoryStates = null;
 
        [
            SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")  // GridEntry classes are internal so we have complete
                                                                                                    // control over who does what in the constructor.
        ]
        public CategoryGridEntry(PropertyGrid ownerGrid, GridEntry peParent,string name, GridEntry[] childGridEntries)
        : base(ownerGrid, peParent) {
            this.name = name;
 
#if DEBUG
            for (int n = 0;n < childGridEntries.Length; n++) {
                Debug.Assert(childGridEntries[n] != null, "Null item in category subproperty list");
            }
#endif
            if (categoryStates == null) {
                categoryStates = new Hashtable();
            }
 
            lock (categoryStates) {
                if (!categoryStates.ContainsKey(name)) {
                    categoryStates.Add(name, true);
                }
            }
 
            this.IsExpandable = true;
            
            for (int i = 0; i < childGridEntries.Length; i++) {
                childGridEntries[i].ParentGridEntry = this;
            }
            
            this.ChildCollection = new GridEntryCollection(this, childGridEntries);
 
            lock (categoryStates) {
                this.InternalExpanded = (bool)categoryStates[name];
            }
 
            this.SetFlag(GridEntry.FLAG_LABEL_BOLD,true);
        }
        
          
        /// <include file='doc\CategoryGridEntry.uex' path='docs/doc[@for="CategoryGridEntry.HasValue"]/*' />
        /// <devdoc>
        /// Returns true if this GridEntry has a value field in the right hand column.
        /// </devdoc>
        internal override bool HasValue {
            get {
               return false;
            }
        }
 
        protected override void Dispose(bool disposing) {
            if (disposing) {
                if (backBrush != null) {
                    backBrush.Dispose();
                    backBrush = null;
                }
 
                if (ChildCollection != null) {
                    ChildCollection = null;
                }
            }
            base.Dispose(disposing);
        }
 
        public override void DisposeChildren() {
 
            // categories should never dispose
            //
            return;
        }
        
        
        // we don't want this guy participating in property depth.
        public override int PropertyDepth {
            get {
                return base.PropertyDepth - 1;
            }
        }
 
        /// <summary>
        /// Gets the accessibility object for the current category grid entry.
        /// </summary>
        /// <returns></returns>
        protected override GridEntryAccessibleObject GetAccessibilityObject() {
            if (AccessibilityImprovements.Level3) {
                return new CategoryGridEntryAccessibleObject(this);
            }
 
            return base.GetAccessibilityObject();
        }
 
 
        protected override Brush GetBackgroundBrush(Graphics g) {
            return this.GridEntryHost.GetLineBrush(g);
        }
 
        protected override Color LabelTextColor {
            get {
                return ownerGrid.CategoryForeColor;
            }
        }
 
        public override bool Expandable {
            get {
                return !GetFlagSet(FL_EXPANDABLE_FAILED);
            }
        }
        
        internal override bool InternalExpanded {
            set {
                base.InternalExpanded = value;
                lock (categoryStates) {
                    categoryStates[this.name] = value;
                }
            }
        }
        
        public override GridItemType GridItemType {
            get {
                return GridItemType.Category;
            }
        }
        public override string HelpKeyword {
            get {
               return null;
            }
        }
 
        public override string PropertyLabel {
            get {
                return name;
            }
        }
        
        internal override int PropertyLabelIndent {
            get {
                // we give an extra pixel for breathing room
                // we want to make sure that we return 0 for property depth here instead of
                PropertyGridView gridHost = this.GridEntryHost;
                
                // we call base.PropertyDepth here because we don't want the subratction to happen.
                return 1+gridHost.GetOutlineIconSize()+OUTLINE_ICON_PADDING + (base.PropertyDepth * gridHost.GetDefaultOutlineIndent());
            }
        }
 
        public override string GetPropertyTextValue(object o) {
            return "";
        }
 
        public override Type PropertyType {
            get {
                return typeof(void);
            }
        }
 
        /// <include file='doc\CategoryGridEntry.uex' path='docs/doc[@for="CategoryGridEntry.GetChildValueOwner"]/*' />
        /// <devdoc>
        /// Gets the owner of the current value.  This is usually the value of the
        /// root entry, which is the object being browsed
        /// </devdoc>
        public override object GetChildValueOwner(GridEntry childEntry) {
            return ParentGridEntry.GetChildValueOwner(childEntry);
        }
 
        protected override bool CreateChildren(bool diffOldChildren) {
            return true;
        }
 
        public override string GetTestingInfo() {
            string str = "object = (";
            str += FullLabel;
            str += "), Category = (" + this.PropertyLabel + ")";
            return str;
        }
 
        public override void PaintLabel(System.Drawing.Graphics g, Rectangle rect, Rectangle clipRect, bool selected, bool paintFullLabel) {
 
            base.PaintLabel(g, rect, clipRect, false, true);
 
            // now draw the focus rect
            if (selected && hasFocus) {
                bool bold = ((this.Flags & GridEntry.FLAG_LABEL_BOLD) != 0);
                Font font = GetFont(bold);
                int labelWidth = GetLabelTextWidth(this.PropertyLabel, g, font);
 
                int indent = PropertyLabelIndent-2;
                Rectangle focusRect = new Rectangle(indent, rect.Y, labelWidth+3, rect.Height-1);
                if (SystemInformation.HighContrast && !OwnerGrid.developerOverride && AccessibilityImprovements.Level1) {
                    // we changed line color to SystemColors.ControlDarkDark in high contrast mode
                    ControlPaint.DrawFocusRectangle(g, focusRect, SystemColors.ControlText, OwnerGrid.LineColor);
                }
                else {
                    ControlPaint.DrawFocusRectangle(g, focusRect);
                }
            }
 
            // draw the line along the top
            if (parentPE.GetChildIndex(this) > 0) {
                using (Pen topLinePen = new System.Drawing.Pen(ownerGrid.CategorySplitterColor, 1)) {
                    g.DrawLine(topLinePen, rect.X - 1, rect.Y - 1, rect.Width + 2, rect.Y - 1);
                }
            }
        }
 
        public override void PaintValue(object val, System.Drawing.Graphics g, Rectangle rect, Rectangle clipRect, PaintValueFlags paintFlags) {
            base.PaintValue(val, g, rect, clipRect, paintFlags & ~PaintValueFlags.DrawSelected);
 
            // draw the line along the top
            if (parentPE.GetChildIndex(this) > 0) {
                using (Pen topLinePen = new System.Drawing.Pen(ownerGrid.CategorySplitterColor, 1)) {
                    g.DrawLine(topLinePen, rect.X - 2, rect.Y - 1, rect.Width + 1, rect.Y - 1);
                }
            }
        }
 
        internal override bool NotifyChildValue(GridEntry pe, int type) {
            return parentPE.NotifyChildValue(pe, type);
        }
 
        /// <summary>
        /// Defines the Category Grid Entry accessible object that is derived from Grid Entry accessible object.
        /// </summary>
        [Runtime.InteropServices.ComVisible(true)]
        internal class CategoryGridEntryAccessibleObject : GridEntryAccessibleObject {
 
            private CategoryGridEntry _owningCategoryGridEntry;
 
            /// <summary>
            /// Initializes new instance of CategoryGridEntryAccessibleObject.
            /// </summary>
            /// <param name="owningCategoryGridEntry">The owning Category Grid Entry object.</param>
            public CategoryGridEntryAccessibleObject(CategoryGridEntry owningCategoryGridEntry) : base(owningCategoryGridEntry) {
                _owningCategoryGridEntry = owningCategoryGridEntry;
            }
 
            /// <summary>
            /// Returns the element in the specified direction.
            /// </summary>
            /// <param name="direction">Indicates the direction in which to navigate.</param>
            /// <returns>Returns the element in the specified direction.</returns>
            internal override UnsafeNativeMethods.IRawElementProviderFragment FragmentNavigate(UnsafeNativeMethods.NavigateDirection direction) {
                PropertyGridView.PropertyGridViewAccessibleObject parent = (PropertyGridView.PropertyGridViewAccessibleObject)Parent;
 
                switch (direction) {
                    case UnsafeNativeMethods.NavigateDirection.Parent:
                        return Parent;
                    case UnsafeNativeMethods.NavigateDirection.NextSibling:
                        return parent.GetNextCategory(_owningCategoryGridEntry);
                    case UnsafeNativeMethods.NavigateDirection.PreviousSibling:
                        return parent.GetPreviousCategory(_owningCategoryGridEntry);
                    case UnsafeNativeMethods.NavigateDirection.FirstChild:
                        return parent.GetFirstChildProperty(_owningCategoryGridEntry);
                    case UnsafeNativeMethods.NavigateDirection.LastChild:
                        return parent.GetLastChildProperty(_owningCategoryGridEntry);
                }
 
                return base.FragmentNavigate(direction);
            }
 
            public override AccessibleRole Role {
                get {
                    return AccessibleRole.ButtonDropDownGrid;
                }
            }
        }
    }
}