// This is a part of the Smart PropertyGrid Library
// Copyright (C) 2001-2006 VisualHint
// All rights reserved.
//
// This source code can be used, distributed or modified
// only under terms and conditions 
// of the accompanying license agreement.

using System;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Globalization;
using System.Security.Permissions;
using System.Collections.Generic;
using System.Drawing.Design;

namespace VisualHint.SmartPropertyGrid
{
    /// <summary>
    /// Summary description for InternalGrid.
	/// </summary>
    [
        ToolboxItem(false)
    ]
#if _XHEOSOURCECODE
    [System.ComponentModel.LicenseProvider(typeof(Xheo.Licensing.ExtendedLicenseProvider))]
#endif
    internal class InternalGrid : Control, IMouseHookClient
	{
#if _XHEOSOURCECODE
        System.ComponentModel.License _license = null;
#endif
        public class DisplayNameSortComparer : IComparer
        {
            public int Compare(object left, object right)
            {
                return string.Compare(((Property)left).DisplayName, ((Property)right).DisplayName, true, CultureInfo.CurrentCulture);
            }
        }

        internal MouseHook _mouseHook;

        private long _lastTimeClickedFromParent = 0;

        private long _lastTimeClicked = 0;

        private Point _lastPosClickedInParent;

        private Point _lastPosClicked;

        private bool _doubleClickDone = false;

        private bool _columnsLock = false;

        private bool _displayModeChangeInProgress = false;

//        private bool _updateParentChildrenAntiRecursion = false;

        private bool _dontShowInPlaceCtrlInGotFocus = false;

        private const int MinimumLabelColumnWidth = 20;

        private int _propertyVerticalMargin = 4;

        public int PropertyVerticalMargin
        {
            set
            {
                _propertyVerticalMargin = value;
                RecalcPropertyItemHeight();
            }

            get { return _propertyVerticalMargin; }
        }

        private Point _toolTipLocation = Point.Empty;

        private bool _lockRefresh = false;

        private bool _visibleItemCountValid = false;

        private bool _clickWithControl = false;

//        private bool _antiRecursion = false;

        private PropertyGrid _parentCtrl;

        private PropertyTree _categorizedPropertyCollection = new PropertyTree();

        private PropertyTree _flatPropertyCollection = new PropertyTree();

        private PropertyTree _activePropertyCollection;

        private int _firstDisplayedLine = 1;

        private int _basicPropertyHeight = -1;

        private bool _resizingColumns = false;

		private int _visibleItemCount = 0;

		private int _visibleLineCount = 0;

        private ArrayList _multiSelectedItems = new ArrayList();

        private Color _disabledForeColor = SystemColors.GrayText;

        private Color _readOnlyForeColor = SystemColors.WindowText;

        private int _labelColumnWidth = 100;

        public int LabelColumnWidth
        {
            set
            {
                Rectangle clientRect = ClientRectangle;

                int oldWidth = _labelColumnWidth;
                _labelColumnWidth = value;

                if (oldWidth > LabelColumnWidth)
                {
                    Invalidate(new Rectangle(LeftColumnWidth + 1, 0, clientRect.Width - LeftColumnWidth, clientRect.Height), false);
                    Update();
                }

                if (_currentInPlaceControl != null)
                {
                    Property property = SelectedPropertyEnumerator.Property;
                    Rectangle valueRect = GetItemRect(SelectedPropertyEnumerator);
                    valueRect = property.GetValueRect(valueRect);

                    PropertyFeel feel = property.Feel;
                    feel.MoveControl(valueRect, SelectedPropertyEnumerator, false);
                }

                if (oldWidth < LabelColumnWidth)
                {
                    Invalidate(new Rectangle(LeftColumnWidth + 1, 0, clientRect.Width - LeftColumnWidth, clientRect.Height), false);
                    Update();
                }

#if _SPGEVAL
                Parent.Refresh();
#endif
            }

            get
            {
                Rectangle clientRect = ClientRectangle;
                int labelColumnWidth;

                if (clientRect.Width > 0)
                {
                    if (LeftColumnWidth + _labelColumnWidth + MinimumLabelColumnWidth > clientRect.Width)
                        labelColumnWidth = clientRect.Width - LeftColumnWidth - MinimumLabelColumnWidth;
                    else
                        labelColumnWidth = _labelColumnWidth;
                }
                else
                {
                    labelColumnWidth = _labelColumnWidth;
                }

                if (labelColumnWidth < MinimumLabelColumnWidth)
                    labelColumnWidth = MinimumLabelColumnWidth;

                return labelColumnWidth;
            }
        }

        private Size _prevSize = Size.Empty;

        private bool _labelColumnFollowsResize = false;

        public bool LabelColumnFollowsResize
        {
            set
            {
                _prevSize = Size;
                _labelColumnFollowsResize = value;
            }
        }

        private PropertyGrid.DisableModes _disableMode = PropertyGrid.DisableModes.Simple | PropertyGrid.DisableModes.EverythingGrayedOut;

        public PropertyGrid.DisableModes DisableMode
        {
            set
            {
                if (_disableMode != value)
                {
                    _disableMode = value;
                    Invalidate();

                    if (_enabled == false)
                        ProcessDisable();
                }
            }

            get { return _disableMode; }
        }

        private bool _enabled = true;

        public new bool Enabled
        {
            set
            {
                _enabled = value;
                Invalidate();

                if (_enabled == false)
                    ProcessDisable();
            }

            get
            {
                if ((_disableMode == PropertyGrid.DisableModes.None) || (_disableMode == PropertyGrid.DisableModes.EverythingGrayedOut))
                    return true;

                return _enabled;
            }
        }

        private bool CanSelectProperties
        {
            get
            {
                if (Enabled)
                    return true;

                if ((_disableMode & PropertyGrid.DisableModes.NoPropertySelection) != 0)
                    return false;

                return true;
            }
        }

        private ImageList _imageList = null;

        public ImageList ImageList
        {
            set { _imageList = value; }
            get { return _imageList; }
        }

        private ToolTipCtrl _tooltipCtrl;

        private PropertyGrid.ToolTipModes _toolTipMode = PropertyGrid.ToolTipModes.None;

        public PropertyGrid.ToolTipModes ToolTipMode
        {
            set
            {
                _toolTipMode = value;

                if (_toolTipMode == PropertyGrid.ToolTipModes.None)
	            {
                    if (_tooltipCtrl != null)
                    {
                        _tooltipCtrl.Dispose();
                        _tooltipCtrl = null;
                    }
	            }
            }

            get { return _toolTipMode; }
        }

        private PropertyGrid.ReadOnlyVisuals _readOnlyVisual = PropertyGrid.ReadOnlyVisuals.Disabled;

        public PropertyGrid.ReadOnlyVisuals ReadOnlyVisual
        {
            set { _readOnlyVisual = value; }
            get { return _readOnlyVisual; }
        }

        private CustomDrawManager _drawManager;

        public CustomDrawManager DrawManager
		{
			get { return _drawManager; }
            set { _drawManager = value; _drawManager.Grid = _parentCtrl; }
        }

        private PropertyEnumerator CloneHierarchyUnder(PropertyEnumerator oldParentEnum, PropertyEnumerator newParentEnum, Property selectedProperty, ref PropertyEnumerator newSelectedEnum)
        {
            PropertyEnumerator siblingEnum = oldParentEnum.Children.GetSiblingEnumerator();
            PropertyEnumerator lastEnum = oldParentEnum;
            while (siblingEnum != siblingEnum.RightBound)
            {
                PropertyEnumerator newEnum = AddPropertyUnder(newParentEnum, siblingEnum.Property);

                if (siblingEnum.Property == selectedProperty)
                    newSelectedEnum = newEnum;

                lastEnum = CloneHierarchyUnder(siblingEnum, newEnum, selectedProperty, ref newSelectedEnum).GetDeepEnumerator();

                siblingEnum.MoveNext();
            }

            return lastEnum;
        }

        private PropertyGrid.DisplayModes _displayMode = PropertyGrid.DisplayModes.Categorized;

        public PropertyGrid.DisplayModes DisplayMode
        {
            set
            {
	            if (_displayMode == value)
		            return;

	            _displayMode = value;

	            HideInPlaceControl();

	            if (_displayMode == PropertyGrid.DisplayModes.Categorized)
	            {
		            InvalidateVisibleItemCount();

                    _activePropertyCollection = _categorizedPropertyCollection;

                    // Init the selected property
                    PropertyEnumerator propEnum = _activePropertyCollection.GetDeepEnumerator().MoveFirst();
                    while (propEnum != propEnum.RightBound)
                    {
                        Property property = propEnum.Property;
                        if (property != null)
                        {
                            if (property.Selected)
                            {
                                _selectedPropertyEnum = propEnum.GetVisibleDeepEnumerator();
                                break;
                            }
                        }

                        propEnum.MoveNext();
                    }

		            // Reset the first displayed item
                    _firstDisplayedPropertyEnumerator = _activePropertyCollection.GetVisibleDeepEnumerator();
                    _firstDisplayedPropertyEnumerator.MoveFirst();

		            // Cleanup the flat list
		            _flatPropertyCollection.Clear();

//		            HideInPlaceControl();

		            CheckScrollbar();

		            EnsureVisible(_selectedPropertyEnum);

                    Invalidate();

                    _parentCtrl.OnDisplayModeChanged(new EventArgs());
	            }
	            else if ((_displayMode == PropertyGrid.DisplayModes.Flat) || (_displayMode == PropertyGrid.DisplayModes.FlatSorted))
	            {
                    _displayModeChangeInProgress = true;

                    _parentCtrl.BeginUpdate();
                    
                    // Store the currently selected property
                    Property selectedProperty = null;
                    if (_selectedPropertyEnum.Property != null)
		            {
			            selectedProperty = _selectedPropertyEnum.Property;
                        // Unselect the selected item in the current collection
                        SelectProperty(_categorizedPropertyCollection.GetVisibleDeepEnumerator().RightBound.GetVisibleDeepEnumerator());
                    }

		            // Cleanup the flat list
		            _flatPropertyCollection.Clear();

		            _activePropertyCollection = _flatPropertyCollection;
                    _firstDisplayedPropertyEnumerator = _activePropertyCollection.GetVisibleDeepEnumerator().RightBound.GetVisibleDeepEnumerator();
		            _selectedPropertyEnum = _firstDisplayedPropertyEnumerator;

                    // Collect all properties except those child of grouped properties
                    PropertyEnumerator propEnum = _categorizedPropertyCollection.GetDeepEnumerator().MoveFirst();
                    PropertyEnumerator selectedEnum = null;
                    while (propEnum != propEnum.RightBound)
                    {
                        Property property = propEnum.Property;

                        if ((property.Value != null) || (property is PropertyHyperLink))    // Something that is not a (sub)category
                        {
                            if (propEnum.Parent.Property.Value == null)   // and that is under a (sub)category
                            {
                                PropertyEnumerator newEnum = AddPropertyBefore(_flatPropertyCollection.GetDeepEnumerator().RightBound, property);
                                propEnum = CloneHierarchyUnder(propEnum, newEnum, selectedProperty, ref selectedEnum);

                                if (property == selectedProperty)
                                    selectedEnum = newEnum;
                            }
                        }
                        propEnum.MoveNext();
                    }

		            // Sort the properties
                    if (_displayMode == PropertyGrid.DisplayModes.FlatSorted)
                        _flatPropertyCollection.Sort(new DisplayNameSortComparer());

                    _firstDisplayedPropertyEnumerator = _flatPropertyCollection.GetVisibleDeepEnumerator();
                    _firstDisplayedLine = 1;
                    _firstDisplayedPropertyEnumerator.MoveFirst();

                    if (selectedEnum != null)
                        SelectProperty(selectedEnum);
		            else
                        SelectProperty(_firstDisplayedPropertyEnumerator);

                    _displayModeChangeInProgress = false;

                    ResetScrollPosToFirstDisplayedProperty();

                    EnsureVisible(_selectedPropertyEnum);

                    _parentCtrl.EndUpdate();
                    CheckScrollbar();
                    Refresh();

                    _parentCtrl.OnDisplayModeChanged(new EventArgs());
                }

                ProcessDisable();

                Focus();
            }

            get { return _displayMode; }
        }

        private PropertyGrid.MultiSelectModes _multiSelectMode = PropertyGrid.MultiSelectModes.None;

        public PropertyGrid.MultiSelectModes MultiSelectMode
        {
            set { _multiSelectMode = value; }
            get { return _multiSelectMode; }
        }

        private PropertyVisibleDeepEnumerator _selectedPropertyEnum;

        public PropertyVisibleDeepEnumerator SelectedPropertyEnumerator
		{
			get { return _selectedPropertyEnum; }
		}

        private Control _currentInPlaceControl;

        public Control InPlaceControl
        {
            get { return _currentInPlaceControl; }
        }

        public InternalGrid(PropertyGrid parentCtrl)
        {
#if _XHEOSOURCECODE
            _license = System.ComponentModel.LicenseManager.Validate(typeof(InternalGrid), this);
#endif
            _parentCtrl = parentCtrl;

            SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint |
                ControlStyles.OptimizedDoubleBuffer | ControlStyles.Opaque, true);

            UpdateStyles();

            LeftColumnWidth = 16;

            GridColor = SystemColors.ActiveBorder;

            _activePropertyCollection = _categorizedPropertyCollection;

            _firstDisplayedPropertyEnumerator = _activePropertyCollection.GetVisibleDeepEnumerator().RightBound.GetVisibleDeepEnumerator();
            _selectedPropertyEnum = _activePropertyCollection.GetVisibleDeepEnumerator().RightBound.GetVisibleDeepEnumerator();

            TabStop = true;

            BackColor = SystemColors.Window;

            _mouseHook = new MouseHook(this, this);
        }

        protected override CreateParams CreateParams
        {
            [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
            get
            {
                CreateParams cp = base.CreateParams;
                cp.Style |= Win32Calls.WS_VSCROLL;

                return cp;
            }
        }

        private PropertyVisibleDeepEnumerator _firstDisplayedPropertyEnumerator;

        public PropertyVisibleDeepEnumerator FirstDisplayedProperty
        {
            set
            {
                _firstDisplayedPropertyEnumerator = new PropertyVisibleDeepEnumerator(value.Node);
                ResetScrollPosToFirstDisplayedProperty();
            }

            get { return (PropertyVisibleDeepEnumerator)_firstDisplayedPropertyEnumerator.Clone(); }
        }

//		private bool _showCategoryLine = true;

/*		public bool ShowCategoryLine
		{
			set { _showCategoryLine = value; }	
			get { return _showCategoryLine; }
		}
*/		
		protected override void OnPaint(PaintEventArgs e)
        {
            Rectangle clientRect = ClientRectangle;

            DrawManager.DrawGridBackground(e.Graphics, clientRect);

	        // Draw the vertical separation between the first column and the properties labels
	        Rectangle leftRect = clientRect;
	        leftRect.Width = LeftColumnWidth + 1;

            // The first property to be displayed is maybe a multiline property partially displayed.
            // In this case the starting position (Y) must be shifted upward.
            Rectangle propertyRect = ClientRectangle;
            propertyRect.Y -= (_firstDisplayedLine - 1) * _basicPropertyHeight;

            PropertyVisibleDeepEnumerator vdEnumerator = FirstDisplayedProperty;
            while (vdEnumerator != vdEnumerator.RightBound)
            {
                Property property = vdEnumerator.Property;
                int itemHeight = _basicPropertyHeight * property.HeightMultiplier;
                propertyRect.Height = itemHeight;

                if (propertyRect.Top > e.ClipRectangle.Bottom)
                    break;

                leftRect.Y = propertyRect.Y;
                leftRect.Height = propertyRect.Height;
                DrawManager.DrawLeftColumnBackground(e.Graphics, leftRect, vdEnumerator);

                if (Rectangle.Intersect(propertyRect, e.ClipRectangle).IsEmpty == false)
                    property.Draw(e.Graphics, propertyRect, vdEnumerator);

                propertyRect.Offset(0, itemHeight);

                if (propertyRect.Top > clientRect.Bottom)
                    break;

                vdEnumerator.MoveNext();
            }

#if _SPGEVAL
            Pen pen = new Pen(Color.LightGray, 2.0f);
	        Rectangle evalRect = clientRect;
            evalRect.Width = LeftColumnWidth + LabelColumnWidth;
            e.Graphics.DrawLine(pen, evalRect.Left, evalRect.Top, evalRect.Right, evalRect.Bottom);
            e.Graphics.DrawLine(pen, evalRect.Right, evalRect.Top, evalRect.Left, evalRect.Bottom);
            pen.Dispose();
#endif

            base.OnPaint(e);
        }

        private int _leftColumnWidth;

        public int LeftColumnWidth
        {
            set { _leftColumnWidth = value; Invalidate(); }
            get { return _leftColumnWidth; }
        }

        // TODO : will be used when implementing RTL
        private Rectangle _rootGlyphsRect = Rectangle.Empty;
        public Rectangle RootGlyphsRect
        {
            get { return _rootGlyphsRect; }
        }

        private Color _refColor;

        public Color GridColor
        {
            get { return _refColor; }
            set
            {
                _refColor = value;
/*	            if (force)
		            m_refColor = color;
	            else
	            {
		            double H,S,L;
		            RGBtoHSL(color,&H,&S,&L);

		            m_refColor = HSLtoRGB(H,S,192./255.);
	            }*/

                Invalidate();
            }
        }

		private Color _selectedBkgColor = SystemColors.Highlight;

		public Color SelectedBackColor
		{
			set { _selectedBkgColor = value; }
			get { return _selectedBkgColor; }
		}

        private Color _selectedNotFocusedBkgColor = Color.Empty;
        
        public Color SelectedNotFocusedBackColor
		{
            set { _selectedNotFocusedBkgColor = value; }
            get
            {
                if (_selectedNotFocusedBkgColor == Color.Empty)
                    return GridColor;

                return _selectedNotFocusedBkgColor;
            }
		}

        private Color _highlightedTextColor = SystemColors.HighlightText;

        public Color HighlightedTextColor
        {
            set { _highlightedTextColor = value; }
            get { return _highlightedTextColor; }
        }

        private void RecalcPropertyItemHeight()
        {
            Graphics graphics = CreateGraphics();

            Size size = Win32Calls.GetTextExtent(graphics, "A0j", Font);
            _basicPropertyHeight = size.Height + _propertyVerticalMargin;				// Make it a little bigger

            // Recalculate the height of all the inplace controls
            foreach (PropertyFeel feel in _parentCtrl._registeredFeels.Values)
            {
                if (feel != null)
                    feel.UpdateFont();
            }

            graphics.Dispose();
            Invalidate();
        }

        public int BasicPropertyHeight
        {
            get { return _basicPropertyHeight; }
        }

        public override Color BackColor
        {
            get { return base.BackColor; }
            set
            {
                base.BackColor = value;
                if ((_currentInPlaceControl != null) && _currentInPlaceControl.Visible)
                    _currentInPlaceControl.BackColor = value;
            }
        }

        public override Color ForeColor
        {
            get { return base.ForeColor; }
            set
            {
                base.ForeColor = value;
                if ((_currentInPlaceControl != null) && _currentInPlaceControl.Visible)
                    _currentInPlaceControl.ForeColor = value;
            }
        }

        public Color DisabledForeColor
        {
            get { return _disabledForeColor; }
            set
            {
                _disabledForeColor = value;
                Refresh();
            }
        }

        public Color ReadOnlyForeColor
        {
            get { return _readOnlyForeColor; }
            set
            {
                _readOnlyForeColor = value;
                Refresh();
            }
        }

        public bool ColumnsLock
        {
            set { _columnsLock = value; }
        }

        public override Font Font
        {
            get { return base.Font; }
            set
            {
                base.Font = value;

                // A visible inplace control must be hidden because if the row height changes
                // the inplace control will be resized
                bool showInPlaceCtrlAfterSet = false;
                if ((_currentInPlaceControl != null) && _currentInPlaceControl.Visible)
                {
                    showInPlaceCtrlAfterSet = true;
                    HideInPlaceControl();
                }

                // Assign the font to the tooltip
                if (ToolTip != null)
                    ToolTip.Font = Font;

                // Calculate item height
                RecalcPropertyItemHeight();

		        // Recalculate the margin of editboxes
                TextBox tb = new TextBox();
                tb.Font = Font;
                Win32Calls.SendMessage(tb.Handle, Win32Calls.EM_SETMARGINS, 0x0003, Win32Calls.MakeLong(0xffff, 0xffff));
                PropertyGrid.GlobalTextMargin = 2 + Win32Calls.LoWord(Win32Calls.SendMessage(tb.Handle, Win32Calls.EM_GETMARGINS, 0, 0));
                tb.Dispose();

                // If an inplace control has been hidden, show it again
		        if (showInPlaceCtrlAfterSet)
			        ShowInPlaceControl(SelectedPropertyEnumerator);

		        CheckScrollbar();
            }
        }

        private bool IsScrollbarVisible()
        {
            return ((Win32Calls.GetWindowLong(Handle, Win32Calls.GWL_STYLE) & Win32Calls.WS_VSCROLL) != 0);
        }

        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == Win32Calls.WM_MOUSEACTIVATE)
            {
                if (Focused == false)
                {
                    Rectangle itemRect;
                    Point pt = PointToClient(MousePosition);
                    if (ClientRectangle.Contains(pt))
                    {
                        PropertyEnumerator propEnum = PropertyItemFromPoint(pt, out itemRect);
                        if (SelectedPropertyEnumerator != propEnum)
                        {
                            _dontShowInPlaceCtrlInGotFocus = true;

                            // When we are in the dropdown part of a UITypeEditor, we want to forward the click
                            // to the control (internalgrid or another inplace control). If Focus() is not called,
                            // it behaves like the MSPG
                            if (Form.ActiveForm is PropInPlaceUITypeEditor.DropDownForm)
                                Focus();
                        }
                    }
                }
            }
            else if (m.Msg == Win32Calls.WM_LBUTTONDOWN)
            {
                // If we don't do all this stuff here, a shift + double-click is not correctly detected
                // (this is used when double-clicking a property label to cycle values)
                _doubleClickDone = false;

                long now = DateTime.Now.Ticks;
                int x = Win32Calls.LoWord((int)m.LParam);
                int y = Win32Calls.HiWord((int)m.LParam);

                if ((_lastTimeClicked != 0) && ((int)((now - _lastTimeClicked) / 0x2710) < SystemInformation.DoubleClickTime))
                {
                    if ((Math.Abs(x - _lastPosClicked.X) < SystemInformation.DoubleClickSize.Width) &&
                        (Math.Abs(y - _lastPosClicked.Y) < SystemInformation.DoubleClickSize.Height))
                        _doubleClickDone = true;

                    _lastTimeClicked = 0;
                    _lastPosClicked = Point.Empty;
                }

                if (_doubleClickDone == false)
                {
                    _lastTimeClicked = now;
                    _lastPosClicked = new Point(x, y);
                }
            }
            else if (m.Msg == Win32Calls.WM_LBUTTONDBLCLK)
            {
                _lastTimeClicked = 0;
            }
            else if (m.Msg == Win32Calls.WM_NCCALCSIZE)
            {
                //                if (m.WParam != IntPtr.Zero)
                {
                    Win32Calls.NCCALCSIZE_PARAMS csp;

                    csp = (Win32Calls.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(Win32Calls.NCCALCSIZE_PARAMS));
                    Rectangle rect = new Rectangle(csp.rgrc0.Left, csp.rgrc0.Top,
                        csp.rgrc0.Right - csp.rgrc0.Left, csp.rgrc0.Bottom - csp.rgrc0.Top);
                    DrawManager.NcCalcSize(ref rect);
                    csp.rgrc0.Left = rect.X;
                    csp.rgrc0.Right = rect.X + rect.Width;
                    csp.rgrc0.Top = rect.Y;
                    csp.rgrc0.Bottom = rect.Y + rect.Height;
                    Marshal.StructureToPtr(csp, m.LParam, false);
                }
            }
            else if (m.Msg == Win32Calls.WM_NOTIFY)
            {
                if (m.LParam != IntPtr.Zero)
                {
                    Win32Calls.NMHDR nmhdr = (Win32Calls.NMHDR)m.GetLParam(typeof(Win32Calls.NMHDR));
                    if (nmhdr.code == Win32Calls.TTN_SHOW)
                    {
                        if ((ToolTip != null) && (nmhdr.hwndFrom == ToolTip.Handle))
                        {
                            ToolTip.Location = _toolTipLocation;
                            m.Result = (IntPtr)1;
                            return;
                        }
                    }
                }
            }
            else if (m.Msg == Win32Calls.WM_NCPAINT)
            {
                IntPtr hDC = Win32Calls.GetWindowDC(m.HWnd);
                Graphics graphics = Graphics.FromHdc(hDC);

                Win32Calls.RECT rc = new Win32Calls.RECT();
                Win32Calls.GetWindowRect(m.HWnd, ref rc);
                Rectangle rect = new Rectangle(0, 0, rc.Right - rc.Left, rc.Bottom - rc.Top);
                DrawManager.DrawGridNonClientArea(graphics, rect);

                Win32Calls.ReleaseDC(m.HWnd, hDC);
            }
            else if (m.Msg == Win32Calls.WM_VSCROLL)
            {
                int nSBCode = Win32Calls.LoWord((int)m.WParam);

                if (nSBCode == Win32Calls.SB_ENDSCROLL)
                    return;

                Rectangle clientRect = ClientRectangle;
                int itemsPerPage = clientRect.Height / _basicPropertyHeight;

                // Get some info about the old state of the scroll
                Win32Calls.SCROLLINFO si = new Win32Calls.SCROLLINFO();
                si.cbSize = Marshal.SizeOf(si);
                si.fMask = Win32Calls.SIF_PAGE | Win32Calls.SIF_RANGE;
                Win32Calls.GetScrollInfo(Handle, Win32Calls.SB_VERT, ref si);

                switch (nSBCode)
                {
                    case Win32Calls.SB_LINEDOWN:
                        {
                            if ((si.nPage > 0) && (Win32Calls.GetScrollPos(Handle, Win32Calls.SB_VERT) < si.nMax - (si.nPage - 1)))
                            {
                                if (_firstDisplayedLine == FirstDisplayedProperty.Property.HeightMultiplier)
                                {
                                    _firstDisplayedPropertyEnumerator.MoveNext();
                                    _firstDisplayedLine = 1;
                                }
                                else
                                    _firstDisplayedLine++;

                                Win32Calls.SetScrollPos(Handle, Win32Calls.SB_VERT, Win32Calls.GetScrollPos(Handle, Win32Calls.SB_VERT) + 1, true);
                                Invalidate();
                            }
                            break;
                        }
                    case Win32Calls.SB_LINEUP:
                        {
                            if (Win32Calls.GetScrollPos(Handle, Win32Calls.SB_VERT) > 0)
                            {
                                if (_firstDisplayedLine > 1)
                                    _firstDisplayedLine--;
                                else
                                {
                                    _firstDisplayedPropertyEnumerator.MovePrev();
                                    _firstDisplayedLine = FirstDisplayedProperty.Property.HeightMultiplier;
                                }

                                Win32Calls.SetScrollPos(Handle, Win32Calls.SB_VERT, Win32Calls.GetScrollPos(Handle, Win32Calls.SB_VERT) - 1, true);
                                Invalidate();
                            }
                            break;
                        }
                    case Win32Calls.SB_PAGEDOWN:
                        {
                            int counter = 0;
                            PropertyVisibleDeepEnumerator enumerator = FirstDisplayedProperty.GetVisibleDeepEnumerator();
                            while (enumerator != enumerator.RightBound)
                            {
                                Rectangle itemRect = GetAbsoluteItemRect(enumerator);
                                if (itemRect.Bottom > clientRect.Bottom)
                                {
                                    // We have found the last displayed property pointed by iter
                                    PropertyVisibleDeepEnumerator currentLastDisplayedPropertyEnum = enumerator.GetVisibleDeepEnumerator();
                                    int lastItemDisplayLine = (clientRect.Bottom - itemRect.Top) / _basicPropertyHeight + 1;

                                    // We loop to make it scroll up without creating blank space at the bottom
                                    do
                                    {
                                        // Scroll one line at the top
                                        if (_firstDisplayedLine == FirstDisplayedProperty.Property.HeightMultiplier)
                                        {
                                            _firstDisplayedPropertyEnumerator.MoveNext();
                                            _firstDisplayedLine = 1;
                                        }
                                        else
                                            _firstDisplayedLine++;

                                        // Determine the new bottom item
                                        if (lastItemDisplayLine == currentLastDisplayedPropertyEnum.Property.HeightMultiplier)
                                        {
                                            currentLastDisplayedPropertyEnum.MoveNext();
                                            lastItemDisplayLine = 1;
                                        }
                                        else
                                            lastItemDisplayLine++;

                                        counter++;
                                    }
                                    while ((counter < itemsPerPage - 1) && (currentLastDisplayedPropertyEnum != currentLastDisplayedPropertyEnum.RightBound));

                                    break;
                                }

                                enumerator.MoveNext();
                            }

                            Win32Calls.SetScrollPos(Handle, Win32Calls.SB_VERT, Win32Calls.GetScrollPos(Handle, Win32Calls.SB_VERT) + counter, true);
                            Invalidate();

                            break;
                        }
                    case Win32Calls.SB_PAGEUP:
                        {
                            int newPos = Win32Calls.GetScrollPos(Handle, Win32Calls.SB_VERT) - itemsPerPage + 1;

                            // Provide a limit for the maximum position
                            if (newPos < 0)
                                newPos = 0;

                            // Scroll the first displayed element
                            for (int i = 0; i < Win32Calls.GetScrollPos(Handle, Win32Calls.SB_VERT) - newPos; i++)
                            {
                                if (_firstDisplayedLine > 1)
                                    _firstDisplayedLine--;
                                else
                                {
                                    _firstDisplayedPropertyEnumerator.MovePrev();
                                    _firstDisplayedLine = FirstDisplayedProperty.Property.HeightMultiplier;
                                }
                            }

                            Win32Calls.SetScrollPos(Handle, Win32Calls.SB_VERT, newPos, true);
                            Invalidate();
                            break;
                        }
                    case Win32Calls.SB_THUMBTRACK:
                    case Win32Calls.SB_THUMBPOSITION:
                        {
                            int nPos = Win32Calls.HiWord((int)m.WParam);

                            // Scroll the first displayed element
                            for (int i = 0; i < Math.Abs((nPos - Win32Calls.GetScrollPos(Handle, Win32Calls.SB_VERT))); i++)
                            {
                                if (nPos > Win32Calls.GetScrollPos(Handle, Win32Calls.SB_VERT))
                                {
                                    if (FirstDisplayedProperty.Property.HeightMultiplier == _firstDisplayedLine)
                                    {
                                        _firstDisplayedPropertyEnumerator.MoveNext();
                                        _firstDisplayedLine = 1;
                                    }
                                    else
                                        _firstDisplayedLine++;
                                }
                                else
                                {
                                    if (_firstDisplayedLine > 1)
                                        _firstDisplayedLine--;
                                    else
                                    {
                                        _firstDisplayedPropertyEnumerator.MovePrev();
                                        _firstDisplayedLine = FirstDisplayedProperty.Property.HeightMultiplier;
                                    }
                                }
                            }

                            Win32Calls.SetScrollPos(Handle, Win32Calls.SB_VERT, nPos, true);
                            Invalidate();
                            break;
                        }
                }

                if (Focused == false)
                    Focus();

                CheckScrollbar();
            }

            base.WndProc(ref m);
        }

        internal PropertyFeel FindFeel(PropertyEnumerator parentEnum, PropertyEnumerator propEnum)
        {
            PropertyFeel feel = null;

            // Try to find if the user specified a PropertyFeelAttribute for the property
            List<Attribute> feelAttrs = propEnum.Property.Value.GetAttributes(typeof(PropertyFeelAttribute));
            foreach (PropertyFeelAttribute attr in feelAttrs)
            {
                if (attr.ChildPropertyName.Length == 0)
                {
                    if (attr.PropertyFeelName == null)
                        return null;

                    feel = _parentCtrl.GetRegisteredFeel(attr.PropertyFeelName);

                    if (feel == PropertyFeel.Empty)
                        return null;
                    else if (feel != null)
                        break;
                }
            }

            if (feel == null)
            {
                // Is there a PropertyFeelAttribute set on the parent and defined for this property ?
                if (parentEnum.Property.Value != null)
                {
                    feelAttrs = parentEnum.Property.Value.GetAttributes(typeof(PropertyFeelAttribute));
                    foreach (PropertyFeelAttribute attr in feelAttrs)
                    {
                        if (attr.ChildPropertyName == propEnum.Property.Value.DisplayName)
                        {
                            if (attr.PropertyFeelName == null)
                                return null;

                            feel = _parentCtrl.GetRegisteredFeel(attr.PropertyFeelName);
                            break;
                        }
                    }
                }
            }

            if (feel == null)
            {
                PasswordPropertyTextAttribute attr = (PasswordPropertyTextAttribute)propEnum.Property.Value.GetAttribute(typeof(PasswordPropertyTextAttribute));
                if ((attr != null) && attr.Password)
                    feel = _parentCtrl.GetRegisteredFeel(PropertyGrid.FeelEditPassword);
            }

            if (feel == null)
                // Is there a default PropertyFeel that has been registered for the Property type ?
                feel = _parentCtrl.GetRegisteredFeelAttachment(propEnum.Property.Value.UnderlyingType);

            if (feel == null)
            {
                // Try to find a UITypeEditor attached to the PropertyDescriptor
                UITypeEditor editor = (UITypeEditor)propEnum.Property.Value.PropertyDescriptor.GetEditor(typeof(UITypeEditor));
                if (editor == null)
                {
                    NullableConverter nc = propEnum.Property.Value.TypeConverter as NullableConverter;
                    if (nc != null)
                        editor = (UITypeEditor)TypeDescriptor.GetEditor(nc.UnderlyingType, typeof(UITypeEditor));
                }

                if (editor == null)
                {
                    // Try to find a UITypeEditor attached to the property with an attribute
                    EditorAttribute eAttr = (EditorAttribute)propEnum.Property.Value.GetAttribute(typeof(EditorAttribute));
                    if (eAttr == null)
                    {
                        foreach(object obj in propEnum.Property.Value.UnderlyingType.GetCustomAttributes(typeof(EditorAttribute), true))
                        {
                            if (obj is EditorAttribute)
                            {
                                eAttr = (EditorAttribute)obj;
                                break;
                            }
                        }
                    }

                    if (eAttr != null)
                    {
                        Type[] typeArray = new Type[] { typeof(Type) };
                        Type editorType = Utilities.GetTypeFromName(eAttr.EditorTypeName, propEnum.Property.Value.UnderlyingType);
                        if (editorType == typeof(UITypeEditor))
                        {
                            if (editorType.GetConstructor(typeArray) != null)
                                editor = (UITypeEditor)TypeDescriptor.CreateInstance(null, editorType, typeArray, new object[] { propEnum.Property.Value.UnderlyingType });
                            else
                                editor = (UITypeEditor)TypeDescriptor.CreateInstance(null, editorType, null, null);
                        }
                    }
                }

                // Try to find a UITypeEditor attached to the Type
                if (editor == null)
                    editor = (UITypeEditor)TypeDescriptor.GetEditor(propEnum.Property.Value.UnderlyingType, typeof(UITypeEditor));

                if ((editor != null) && !editor.GetType().Equals(typeof(UITypeEditor)))
                {
                    PropertyTypeDescriptorContext context = propEnum.Property.Value.GetTypeDescriptorContext(propEnum);
                    if ((editor.GetEditStyle() == UITypeEditorEditStyle.None) &&
                        propEnum.Property.Value.TypeConverter.GetStandardValuesSupported(context))
                        feel = _parentCtrl.GetRegisteredFeel(PropertyGrid.FeelEditList);
                    else
                        feel = new PropertyUITypeEditorFeel(editor, _parentCtrl);
                }
            }

            // If the underlying type supports a list of allowed values, let's associate a list feel with it
            if (feel == null)
            {
                PropertyTypeDescriptorContext context = propEnum.Property.Value.GetTypeDescriptorContext(propEnum);
                if (propEnum.Property.Value.TypeConverter.GetStandardValuesSupported(context))
                    feel = _parentCtrl.GetRegisteredFeel(PropertyGrid.FeelEditList);
            }

            // If it was not found, assign the global default feel
            if (feel == null)
                feel = _parentCtrl.DefaultFeel;

            return feel;
        }

        PropertyLook FindLook(PropertyEnumerator parentEnum, PropertyEnumerator propEnum)
        {
            PropertyLook look = null;

            List<Attribute> plAttrs = propEnum.Property.Value.GetAttributes(typeof(PropertyLookAttribute));
            foreach (PropertyLookAttribute attr in plAttrs)
            {
                if (attr.ChildPropertyName.Length == 0)
                {
                    if (attr.LookType == null)
                        return null;

                    return (PropertyLook)Activator.CreateInstance(attr.LookType, attr.Parameters);
                }
            }

            if (look == null)
            {
                // Is there a look attribute set on the parent ?
                if (parentEnum.Property != null) // (In sorted mode you may have no parent...)
                {
                    if (parentEnum.Property.Value != null)
                    {
                        plAttrs = parentEnum.Property.Value.GetAttributes(typeof(PropertyLookAttribute));
                        foreach (PropertyLookAttribute attr in plAttrs)
                        {
                            if (attr.ChildPropertyName.CompareTo(propEnum.Property.Value.DisplayName) == 0)
                                return (PropertyLook)Activator.CreateInstance(attr.LookType);
                        }
                    }
                }
            }

            if (look == null)
            {
                PasswordPropertyTextAttribute attr = (PasswordPropertyTextAttribute)propEnum.Property.Value.GetAttribute(typeof(PasswordPropertyTextAttribute));
                if ((attr != null) && attr.Password)
                    look = new PropertyPasswordLook();
            }

            if (look == null)
                look = _parentCtrl.GetRegisteredLookAttachment(propEnum.Property.Value.UnderlyingType);

            return look;
        }

        public PropertyEnumerator AppendRootCategory(int id, string catName)
        {
            System.Diagnostics.Debug.Assert(_parentCtrl.DisplayMode == PropertyGrid.DisplayModes.Categorized, "Properties can only be inserted in categorized mode.");

            RootCategory category = new RootCategory(id, catName);
            category.ParentGrid = _parentCtrl;

            category.TreeLevel = 0;

            PropertyEnumerator propEnum = _activePropertyCollection.Append(_activePropertyCollection.GetDeepEnumerator(), category);

            if (FirstDisplayedProperty == _activePropertyCollection.GetVisibleDeepEnumerator().RightBound)
                FirstDisplayedProperty = propEnum.GetVisibleDeepEnumerator();

            InvalidateVisibleItemCount();

	        if (Handle != IntPtr.Zero)    // necessary test ?
                Invalidate();

            if (FirstProperty.Count == 1)
                SelectProperty(FirstProperty);

            _parentCtrl.OnPropertyCreated(new PropertyCreatedEventArgs(propEnum));

            return propEnum;
        }

        public PropertyEnumerator InsertRootCategory(PropertyEnumerator beforeCategory, int id, string catName)
        {
            if (beforeCategory == _activePropertyCollection.GetDeepEnumerator().RightBound)
                return AppendRootCategory(id, catName);

            System.Diagnostics.Debug.Assert(_parentCtrl.DisplayMode == PropertyGrid.DisplayModes.Categorized, "Properties can only be inserted in categorized mode.");

            System.Diagnostics.Debug.Assert(beforeCategory.HasParent == false, "Root categories can only be inserted at the root.");

            RootCategory category = new RootCategory(id, catName);
            category.ParentGrid = _parentCtrl;

            category.TreeLevel = 0;

            PropertyEnumerator propEnum = _activePropertyCollection.InsertBefore(beforeCategory, category);

            if (FirstDisplayedProperty == _activePropertyCollection.GetVisibleDeepEnumerator().RightBound)
                FirstDisplayedProperty = propEnum.GetVisibleDeepEnumerator();

            InvalidateVisibleItemCount();

            if (Handle != IntPtr.Zero)    // necessary test ?
                Invalidate();

            _parentCtrl.OnPropertyCreated(new PropertyCreatedEventArgs(propEnum));

            return propEnum;
        }
        /*
        public void RecreateChildProperties(PropertyEnumerator parentEnum)
        {
            PropertyValue propValue = parentEnum.Property.Value;

            // TODO: Trouver le bon test
//            if (propValue.TypeConverter.GetPropertiesSupported() && !propValue.TypeConverter.GetCreateInstanceSupported())
            {
                if (parentEnum.Count > 0)
                {
                    _parentCtrl.BeginUpdate();

                    bool expanded = parentEnum.Property.Expanded;

                    PropertyEnumerator propEnum = parentEnum.Children;
                    int index = 1;
                    int selectedIndex = 0;
                    while (propEnum != propEnum.RightBound)
                    {
                        PropertyEnumerator nextEnum = ((PropertyEnumerator)propEnum.Clone()).MoveNext();
                        if ((propEnum == SelectedPropertyEnumerator) && (selectedIndex == 0))
                        {
                            selectedIndex = index;
                        }

                        DeletePropertyInternal(propEnum);
                        propEnum = nextEnum;
                        index++;
                    }

                    AddChildProperties(parentEnum);

                    if (selectedIndex != 0)
                    {
                        propEnum = parentEnum.Children;
                        index = 1;
                        while (propEnum != propEnum.RightBound)
                        {
                            if (index++ == selectedIndex)
                            {
                                SelectProperty(propEnum);
                                break;
                            }
                            propEnum = propEnum.MoveNext();
                        }
                    }

                    CloseEmptySpace();
                    CheckScrollbar();

                    _parentCtrl.EndUpdate();
                }
            }
        }
*/
        internal bool AddChildProperties(PropertyEnumerator underParent)
        {
            PropertyValue parentValue = underParent.Property.Value;
            if (parentValue == null)
                return false;

            if (parentValue.TypeConverter.GetPropertiesSupported(parentValue.GetTypeDescriptorContext(underParent)) == false)
            {
                ShowChildPropertiesAttribute showChildrenAttr = (ShowChildPropertiesAttribute)underParent.Property.Value.GetAttribute(typeof(ShowChildPropertiesAttribute));
                if ((showChildrenAttr == null) || !showChildrenAttr.ShowChildProperties)
                    return false;
            }
            else
            {
                ShowChildPropertiesAttribute showChildrenAttr = (ShowChildPropertiesAttribute)underParent.Property.Value.GetAttribute(typeof(ShowChildPropertiesAttribute));
                if ((showChildrenAttr != null) && !showChildrenAttr.ShowChildProperties)
                    return false;
            }

            PropertyValue[] childValues = underParent.Property.Value.GetChildValues();

            if ((childValues != null) && (childValues.Length > 0))
            {
                List<Attribute> hideAttrs = underParent.Property.Value.GetAttributes(typeof(PropertyHideAttribute));
                List<Attribute> disableAttrs = underParent.Property.Value.GetAttributes(typeof(PropertyDisableAttribute));
                foreach (PropertyValue propValue in childValues)
                {
                    bool isHidden = false;
                    foreach (PropertyHideAttribute hideAttr in hideAttrs)
                    {
                        if (hideAttr.ChildPropertyName.CompareTo(propValue.DisplayName) == 0)
                        {
                            isHidden = true;
                            break;
                        }
                    }
                    if (isHidden)
                        continue;

                    Property property = new Property(propValue.Id, propValue.DisplayName);
                    property.ParentGrid = _parentCtrl;
                    property.Value = propValue;
                    property.Value.Grid = _parentCtrl;
                    if (property.Value.PropertyDescriptor != null)
                        property.Comment = property.Value.PropertyDescriptor.Description;

                    PropertyEnumerator propEnum = AddPropertyUnder(underParent, property);

                    foreach (PropertyDisableAttribute disableAttr in disableAttrs)
                    {
                        if (disableAttr.ChildPropertyName.CompareTo(propValue.DisplayName) == 0)
                        {
                            EnableProperty(propEnum, false);
                            break;
                        }
                    }

                    // If this category is disabled, force the state of the new property to disabled
                    if (IsAncestorDisabled(propEnum))
                        property.Enable(propEnum, false, true, true);

                    _parentCtrl.OnPropertyCreated(new PropertyCreatedEventArgs(propEnum));
                }
            }

            return HasOneVisibleChild(underParent);
        }

        PropertyEnumerator AddPropertyBefore(PropertyEnumerator beforeEnum, Property property)
        {
            if (_displayMode == PropertyGrid.DisplayModes.Categorized)
                property.TreeLevel = beforeEnum.Depth;

            Invalidate();

            PropertyEnumerator propEnum = _activePropertyCollection.InsertBefore(beforeEnum, property);

            if (FirstDisplayedProperty == _activePropertyCollection.GetVisibleDeepEnumerator().RightBound)
                FirstDisplayedProperty = propEnum.GetVisibleDeepEnumerator();

            if (_activePropertyCollection == _categorizedPropertyCollection)
            {
                if (AddChildProperties(propEnum))
                    ExpandProperty(propEnum, false);
            }

            InvalidateVisibleItemCount();

            if (property.Value != null)
            {
                property.Value.OwnerEnumerator = propEnum;

                bool readOnly = property.Value.IsReadOnly(propEnum);
                if (readOnly)
                {
                    if (ReadOnlyVisual == PropertyGrid.ReadOnlyVisuals.Disabled)
                        EnableProperty(propEnum, false);
//                    else
  //                      property.ForeColor = property.Value.DisabledForeColor;
                }

                if (property.Look == null)
                {
                    property.Value.Look = FindLook(beforeEnum.Parent, propEnum);
                    if (propEnum.Property.Look != null)
                        propEnum.Property.Look.ControlHeightMultiplier();
                }

                if ((property.Feel == null) && (_displayMode == PropertyGrid.DisplayModes.Categorized))
                    property.Value.Feel = FindFeel(beforeEnum.Parent, propEnum);

                AssignValidator(propEnum);

                HandleAttributes(propEnum);
            }

            InvalidateVisibleItemCount();

            return propEnum;
        }

        private PropertyEnumerator AddPropertyUnder(PropertyEnumerator underParent, Property property)
        {
	        Invalidate();

            if (_parentCtrl.DisplayMode == PropertyGrid.DisplayModes.Categorized)	// We don't modify the tree level of items in sorted mode
                property.TreeLevel = underParent.Depth + 1;

            PropertyEnumerator propEnum = _activePropertyCollection.Append(underParent.Children, property);

            if (FirstDisplayedProperty == _activePropertyCollection.GetVisibleDeepEnumerator().RightBound)
                FirstDisplayedProperty = propEnum.GetVisibleDeepEnumerator();

            if (property.Value != null)
            {
                property.Value.OwnerEnumerator = propEnum;

                if (_activePropertyCollection == _categorizedPropertyCollection)
                {
                    if (AddChildProperties(propEnum))
                        ExpandProperty(propEnum, false);
                }
            }

            InvalidateVisibleItemCount();

            if (property.Value != null)
            {
                bool readOnly = property.Value.IsReadOnly(propEnum);
                if (readOnly)
                {
                    if (ReadOnlyVisual == PropertyGrid.ReadOnlyVisuals.Disabled)
                        EnableProperty(propEnum, false);
//                    else
  //                      property.ForeColor = property.Value.DisabledForeColor;
                }

                if (propEnum.Property.Value.Look == null)
                {
                    propEnum.Property.Value.Look = FindLook(underParent, propEnum);
                    if (propEnum.Property.Value.Look != null)
                        propEnum.Property.Value.Look.ControlHeightMultiplier();
                }

                if (propEnum.Property.Feel == null)
                    property.Value.Feel = FindFeel(underParent, propEnum);

                AssignValidator(propEnum);

                HandleAttributes(propEnum);
            }

            return propEnum;
        }

        private void HandleAttributes(PropertyEnumerator propEnum)
        {
            List<Attribute> disableAttrs = propEnum.Property.Value.GetAttributes(typeof(PropertyDisableAttribute));
            foreach (PropertyDisableAttribute disableAttr in disableAttrs)
            {
                if (disableAttr.ChildPropertyName.Length == 0)
                {
                    EnableProperty(propEnum, false);
                    break;
                }
            }

            PropertyHeightMultiplierAttribute heightMultiplierAttr = propEnum.Property.Value.GetAttribute(
                typeof(PropertyHeightMultiplierAttribute)) as PropertyHeightMultiplierAttribute;
            if (heightMultiplierAttr != null)
                propEnum.Property.HeightMultiplier = heightMultiplierAttr.HeightMultiplier;

            PropertyManuallyDisabledAttribute manuallyDisableAttr = propEnum.Property.Value.GetAttribute(
                typeof(PropertyManuallyDisabledAttribute)) as PropertyManuallyDisabledAttribute;
            if (manuallyDisableAttr != null)
                propEnum.Property.SetManuallyDisabled(propEnum, true);

            List<Attribute> hideAttrs = propEnum.Property.Value.GetAttributes(typeof(PropertyHideAttribute));
            foreach (PropertyHideAttribute hideAttr in hideAttrs)
            {
                if (hideAttr.ChildPropertyName.Length == 0)
                {
                    ShowProperty(propEnum, false);
                    break;
                }
            }
        }

        public PropertyEnumerator AppendProperty(PropertyEnumerator underCategory, int id, string propName, object container, PropertyDescriptor propertyDescriptor, string comment, Attribute[] attributes)
        {
            System.Diagnostics.Debug.Assert(_parentCtrl.DisplayMode == PropertyGrid.DisplayModes.Categorized, "Properties can only be inserted in categorized mode.");

            // If a BrowsableAttribute(false) has been put at design-time, then don't create the property
            BrowsableAttribute attr = propertyDescriptor.Attributes[typeof(BrowsableAttribute)] as BrowsableAttribute;
            if ((attr != null) && (attr.Browsable == false))
                return RightBound;

            Property property = new Property(id, propName);
            property.Comment = comment;
            property.ParentGrid = _parentCtrl;

            property.Value = new PropertyValueIndirect(_parentCtrl, container, propertyDescriptor, attributes);

            // If a BrowsableAttribute(false) has been put at run-time, then don't create the property
            attr = (BrowsableAttribute)property.Value.GetAttribute(typeof(BrowsableAttribute));
            if ((attr != null) && (attr.Browsable == false))
                return RightBound;

//            property.Value.Grid = _parentCtrl;

            PropertyEnumerator propEnum = AddPropertyUnder(underCategory, property);

            _parentCtrl.AddTargetInstanceHook(propEnum);

            // Initial check of the validity of the value assigned to the property
            PropertyValidatorBase validator = propEnum.Property.Value.Validator;
            if (validator != null)
                validator.Check(propEnum.Property.Value.GetValue(), true);

            // If this category is disabled, force the state of the new property to disabled
            if (IsAncestorDisabled(propEnum))
                property.Enable(propEnum, false, true, true);

            CheckScrollbar();

            _parentCtrl.OnPropertyCreated(new PropertyCreatedEventArgs(propEnum));

            return propEnum;
        }

        public PropertyEnumerator AppendProperty(PropertyEnumerator underCategory, int id, string propName, object container, string memberName, string comment, Attribute[] attributes)
        {
            PropertyDescriptor propertyDescriptor = TypeDescriptor.GetProperties(container)[memberName];
            if (propertyDescriptor == null)
                throw new MemberAccessException("The property " + memberName + " doesn't exist in type " + container.GetType());

            return AppendProperty(underCategory, id, propName, container, propertyDescriptor, comment, attributes);
        }

        public PropertyEnumerator InsertProperty(PropertyEnumerator beforeProperty, int id, string propName, object container, PropertyDescriptor propertyDescriptor, string comment, Attribute[] attributes)
        {
            System.Diagnostics.Debug.Assert(_parentCtrl.DisplayMode == PropertyGrid.DisplayModes.Categorized, "Properties can only be inserted in categorized mode.");

            // If a BrowsableAttribute(false) has been put at design-time, then don't create the property
            BrowsableAttribute attr = propertyDescriptor.Attributes[typeof(BrowsableAttribute)] as BrowsableAttribute;
            if ((attr != null) && (attr.Browsable == false))
                return RightBound;

            Property property = new Property(id, propName);
            property.Comment = comment;
            property.ParentGrid = _parentCtrl;
            property.Value = new PropertyValueIndirect(_parentCtrl, container, propertyDescriptor, attributes);

            // If a BrowsableAttribute(false) has been put at run-time, then don't create the property
            attr = (BrowsableAttribute)property.Value.GetAttribute(typeof(BrowsableAttribute));
            if ((attr != null) && (attr.Browsable == false))
                return RightBound;

//            property.Value.Grid = _parentCtrl;

            PropertyEnumerator propEnum = AddPropertyBefore(beforeProperty, property);

            _parentCtrl.AddTargetInstanceHook(propEnum);

            // Initial check of the validity of the value assigned to the property
            PropertyValidatorBase validator = propEnum.Property.Value.Validator;
            if (validator != null)
                validator.Check(propEnum.Property.Value.GetValue(), true);

            // Simulate a string value change in case we are in a grouped property
            //            if (underCategory.Property.Value != null)
            //                property.Value.SetValue(property.Value.GetStringValue());

            // If this category is disabled, force the state of the new property to disabled
            if (IsAncestorDisabled(propEnum))
                property.Enable(propEnum, false, true, true);

            CheckScrollbar();

            _parentCtrl.OnPropertyCreated(new PropertyCreatedEventArgs(propEnum));

            return propEnum;
        }

        public PropertyEnumerator InsertProperty(PropertyEnumerator beforeProperty, int id, string propName, object container, string memberName, string comment, Attribute[] attributes)
        {
            PropertyDescriptor propertyDescriptor = TypeDescriptor.GetProperties(container)[memberName];
            if (propertyDescriptor == null)
                throw new MemberAccessException("The property " + memberName + " doesn't exist in type " + container.GetType());

            return InsertProperty(beforeProperty, id, propName, container, propertyDescriptor, comment, attributes);
        }

        public void AddTargetInstance(PropertyEnumerator propEnum, object targetInstance, string memberName)
        {
            if (propEnum.Property.Value is PropertyValueIndirect == false)
                throw new ArgumentException("The property must already have a target instance.", "propEnum");

            ((PropertyValueIndirect)propEnum.Property.Value).AddTargetInstance(targetInstance, memberName);
        }

        public PropertyEnumerator AppendManagedProperty(PropertyEnumerator underCategory, int id, string propName, Type valueType, object initialValue, string comment, params Attribute[] attributes)
        {
            System.Diagnostics.Debug.Assert(_parentCtrl.DisplayMode == PropertyGrid.DisplayModes.Categorized, "Properties can only be inserted in categorized mode.");

            Property property = new Property(id, propName);
            property.Comment = comment;
            property.ParentGrid = _parentCtrl;
            property.Value = new PropertyValueManaged(id, valueType, initialValue, attributes);
            property.Value.Grid = _parentCtrl;

            PropertyEnumerator propEnum = AddPropertyUnder(underCategory, property);

            // Initial check of the validity of the value assigned to the property
            PropertyValidatorBase validator = propEnum.Property.Value.Validator;
            if (validator != null)
                validator.Check(propEnum.Property.Value.GetValue(), true);

            // Simulate a string value change in case we are in a grouped property
//            if (underCategory.Property.Value != null)
//                property.Value.SetValue(initialValue);

            // If this category is disabled, force the state of the new property to disabled
            if (IsAncestorDisabled(propEnum))
                property.Enable(propEnum, false, true, true);

            CheckScrollbar();

            _parentCtrl.OnPropertyCreated(new PropertyCreatedEventArgs(propEnum));

            return propEnum;
        }

        public PropertyEnumerator InsertManagedProperty(PropertyEnumerator beforeProperty, int id, string propName, Type valueType, object initialValue, string comment, Attribute[] attributes)
        {
            System.Diagnostics.Debug.Assert(_parentCtrl.DisplayMode == PropertyGrid.DisplayModes.Categorized, "Properties can only be inserted in categorized mode.");

            Property property = new Property(id, propName);
            property.Comment = comment;
            property.ParentGrid = _parentCtrl;
            property.Value = new PropertyValueManaged(id, valueType, initialValue, attributes);
            property.Value.Grid = _parentCtrl;

            PropertyEnumerator propEnum = AddPropertyBefore(beforeProperty, property);

            // Initial check of the validity of the value assigned to the property
            PropertyValidatorBase validator = propEnum.Property.Value.Validator;
            if (validator != null)
                validator.Check(propEnum.Property.Value.GetValue(), true);

            // Simulate a string value change in case we are in a grouped property
            //            if (underCategory.Property.Value != null)
            //                property.Value.SetValue(initialValue);

            // If this category is disabled, force the state of the new property to disabled
            if (IsAncestorDisabled(propEnum))
                property.Enable(propEnum, false, true, true);

            CheckScrollbar();

            _parentCtrl.OnPropertyCreated(new PropertyCreatedEventArgs(propEnum));

            return propEnum;
        }

        public PropertyEnumerator AppendHyperLinkProperty(PropertyEnumerator underCategory, int id, string propName, string comment)
        {
            System.Diagnostics.Debug.Assert(_parentCtrl.DisplayMode == PropertyGrid.DisplayModes.Categorized, "Properties can only be inserted in categorized mode.");

            Property property = new PropertyHyperLink(id);
            property.DisplayName = propName;
            property.Comment = comment;
            property.ParentGrid = _parentCtrl;

            PropertyEnumerator propEnum = AddPropertyUnder(underCategory, property);

            if (IsAncestorDisabled(propEnum))
                property.Enable(propEnum, false, true, true);

            CheckScrollbar();

            _parentCtrl.OnPropertyCreated(new PropertyCreatedEventArgs(propEnum));

            return propEnum;
        }

        public PropertyEnumerator InsertHyperLinkProperty(PropertyEnumerator beforeProperty, int id, string propName, string comment)
        {
            System.Diagnostics.Debug.Assert(_parentCtrl.DisplayMode == PropertyGrid.DisplayModes.Categorized, "Properties can only be inserted in categorized mode.");

            Property property = new PropertyHyperLink(id);
            property.DisplayName = propName;
            property.Comment = comment;
            property.ParentGrid = _parentCtrl;

            PropertyEnumerator propEnum = AddPropertyBefore(beforeProperty, property);

            if (IsAncestorDisabled(propEnum))
                property.Enable(propEnum, false, true, true);

            CheckScrollbar();

            _parentCtrl.OnPropertyCreated(new PropertyCreatedEventArgs(propEnum));

            return propEnum;
        }

        public PropertyEnumerator AppendSubCategory(PropertyEnumerator underCategory, int id, string catName)
        {
            System.Diagnostics.Debug.Assert(_parentCtrl.DisplayMode == PropertyGrid.DisplayModes.Categorized, "Properties can only be inserted in categorized mode.");

            SubCategory subCategory = new SubCategory(id, catName);

            // The new property item must be attached to the same properties control
            subCategory.ParentGrid = _parentCtrl;

            PropertyEnumerator propEnum = AddPropertyUnder(underCategory, subCategory);

            // If this category is disabled, force the state of the new property to disabled
            if (IsAncestorDisabled(propEnum))
                subCategory.Enable(propEnum, false, true, true);

            CheckScrollbar();

            _parentCtrl.OnPropertyCreated(new PropertyCreatedEventArgs(propEnum));

            return propEnum;
        }

        public PropertyEnumerator InsertSubCategory(PropertyEnumerator beforeProperty, int id, string catName)
        {
            System.Diagnostics.Debug.Assert(_parentCtrl.DisplayMode == PropertyGrid.DisplayModes.Categorized, "Properties can only be inserted in categorized mode.");

            SubCategory subCategory = new SubCategory(id, catName);

            // The new property item must be attached to the same properties control
            subCategory.ParentGrid = _parentCtrl;

            PropertyEnumerator propEnum = AddPropertyBefore(beforeProperty, subCategory);

            // If this category is disabled, force the state of the new property to disabled
            if (IsAncestorDisabled(propEnum))
                subCategory.Enable(propEnum, false, true, true);

            CheckScrollbar();

            _parentCtrl.OnPropertyCreated(new PropertyCreatedEventArgs(propEnum));

            return propEnum;
        }

        internal bool IsAncestorDisabled(PropertyEnumerator propEnum)
        {
            PropertyEnumerator currentEnum = propEnum.Parent;
            while (currentEnum != currentEnum.RightBound)
            {
                if (currentEnum.Property.GetManuallyDisabledVariable() == false)
                    return true;

                currentEnum = currentEnum.Parent;
            }

	        return false;
        }

        public bool HasOneVisibleChild(PropertyEnumerator propEnum)
        {
            PropertyEnumerator childrenEnumerator = propEnum.Children;
            while (childrenEnumerator != childrenEnumerator.RightBound)
            {
                if (childrenEnumerator.Property.Visible)
                    return true;

                childrenEnumerator.MoveNext();
            }

            return false;
        }

        public bool DrawImage(int imageIndex, Graphics graphics, int x, int y)
        {
            try
            {
                Image img = _imageList.Images[imageIndex];
                Rectangle rect = new Rectangle(x, y, img.Width, img.Height);
                graphics.DrawImage(img, rect);
            }
            catch(Exception)
            {
                return false;
            }

            return true;
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            // Find the location of the mouse cursor
            PropertyGrid.HitTests hitTest = HitTest(e.Location);

            if (((e.Clicks == 2) || _doubleClickDone) && (hitTest != PropertyGrid.HitTests.TreeGlyph) && (hitTest != PropertyGrid.HitTests.ManualDisable))
            {
                if (e.Button == MouseButtons.Left)
                {
                    Rectangle itemRect;
                    PropertyEnumerator propEnum = PropertyItemFromPoint(e.Location, out itemRect);
                    Property property = propEnum.Property;

                    if (property != null)
                    {
                        if (hitTest == PropertyGrid.HitTests.ColumnSplit)
                        {
                            AdjustLabelColumn();
                        }
                        else if ((hitTest == PropertyGrid.HitTests.Label) && (InPlaceControl != null) && ((HasOneVisibleChild(propEnum) == false) || property.Value.NoLinkWithChildren))
                        {
                            bool valueChanged = ((IInPlaceControl)InPlaceControl).ScrollValueOnDoubleClick(!(ModifierKeys == Keys.Shift), true);
                            if (!valueChanged)
                                _parentCtrl.ActiveControl = _currentInPlaceControl;
                            //InPlaceControl.Focus();
                        }
                        else
                        {
                            if (propEnum.Children.Count > 0)
                                ExpandProperty(propEnum, !property.Expanded);
                            else if (property.Enabled && (property is RootCategory == false) && (property is PropertyHyperLink == false))
                                Win32Calls.keybd_event(Win32Calls.VK_RETURN, 0, 0, UIntPtr.Zero);
                        }
                    }
                }
            }
            else
            {
	            bool hasFocus = true;

                Rectangle itemRect = Rectangle.Empty;
                PropertyEnumerator propEnum = null;
                
                // Focus must be regained if lost
                if ((Focused == false) && CanSelectProperties)
                {
                    if (ContainsFocus == false)    // No child has focus ?
			            hasFocus = false;

                    // Here I use a trick to avoid calling ShowInPlaceControl when we set the Focus and then
                    // HideInPlaceControl and ShowInPlaceControl again when selecting the property later in this
                    // method. By setting _dontShowInPlaceCtrlInGotFocus to true it will prevent ShowInPlaceControl to be called.
                    // But it must be called when we click on the property that is already selected because
                    // SelectProperty won't.
                    propEnum = PropertyItemFromPoint(e.Location, out itemRect);
                    if (SelectedPropertyEnumerator != propEnum)
                        _dontShowInPlaceCtrlInGotFocus = true;

/*                    if (((_parentCtrl.NavigationKeyMode & PropertyGrid.NavigationKeyModes.TabKey) != 0) &&
                        ((_parentCtrl.NavigationKeyMode & PropertyGrid.NavigationKeyModes.TabKeyWithAutoFocus) != 0))
                    {
                        if ((hasFocus == false) || (propEnum.Property is RootCategory) ||
                            (propEnum.Property.Feel == null) || !propEnum.Property.Enabled)
                            Focus();
                    }
                    else*/
                        Focus();

		            Invalidate();
	            }

                if (hitTest == PropertyGrid.HitTests.ColumnSplit)
                {
                    if (e.Button == MouseButtons.Left)
                    {
                        Cursor = Cursors.VSplit;
                        Capture = true;
                        _resizingColumns = true;
                    }
                }
                else
                {
                    if (propEnum == null)
		                propEnum = PropertyItemFromPoint(e.Location, out itemRect);
                    Property property = propEnum.Property;

		            if (property != null)
		            {
                        if ((hitTest == PropertyGrid.HitTests.ManualDisable) && Enabled && (e.Button == MouseButtons.Left))
                        {
                            if (propEnum.HasParent == false)
                                EnableProperty(propEnum, !property.Enabled);
                            else
                            {
                                // The user can press on the checkbox only if its parent category is enabled
                                if (propEnum.Parent.Property.Enabled)
                                    EnableProperty(propEnum, !property.Enabled);
                            }
                        }

                        if (hitTest == PropertyGrid.HitTests.TreeGlyph)						// No selection when clicking +/-
			            {
                            if (e.Button == MouseButtons.Left)
                                ExpandProperty(propEnum, !property.Expanded);
			            }
                        else if (CanSelectProperties)
			            {
                            if ((ModifierKeys == Keys.Shift) && (_multiSelectMode != PropertyGrid.MultiSelectModes.None))
                            {
					            PropertyEnumerator ancestorEnum = null;
                                if (_multiSelectMode == PropertyGrid.MultiSelectModes.SameLevel)
                                {
                                    if (SelectedPropertyEnumerator.Children.Count == 0)
							            ancestorEnum = SelectedPropertyEnumerator.Parent;
						            else
							            ancestorEnum = SelectedPropertyEnumerator;
					            }

					            // Clear previous multi selection
                                foreach(PropertyVisibleDeepEnumerator currentEnum in _multiSelectedItems)
					            {
                                    currentEnum.Property.Selected = false;
					            }
					            _multiSelectedItems.Clear();

					            Rectangle r = GetAbsoluteItemRect(SelectedPropertyEnumerator);
					            PropertyVisibleDeepEnumerator selectEnum = SelectedPropertyEnumerator.GetVisibleDeepEnumerator();
					            do
					            {
						            if (r.Bottom < e.Location.Y)
							            selectEnum.MoveNext();
						            else if (r.Top > e.Location.Y)
							            selectEnum.MovePrev();

						            // In SAMELEVEL mode, we must test if we are not outside the correct level
                                    if (_multiSelectMode == PropertyGrid.MultiSelectModes.SameLevel)
                                    {
							            if (IsDescendantOf(selectEnum, ancestorEnum.GetDeepEnumerator()) == false)
								            break;
						            }

						            if (selectEnum.Children.Count == 0)
						            {
							            if (_parentCtrl.OnValidateMultiSelection(SelectedPropertyEnumerator, selectEnum))
							            {
                                            selectEnum.Property.Selected = true;
								            _multiSelectedItems.Add(selectEnum);
							            }
						            }
					            }
					            while(selectEnum != propEnum);
					            Invalidate();
				            }
                            else if ((ModifierKeys == Keys.Control) && (_multiSelectMode != PropertyGrid.MultiSelectModes.None))
                            {
					            bool selectImpossible = false;
                                if (_multiSelectMode == PropertyGrid.MultiSelectModes.SameLevel)
                                {
    					            PropertyEnumerator ancestorEnum;
                                    if (SelectedPropertyEnumerator.Children.Count == 0)
							            ancestorEnum = SelectedPropertyEnumerator.Parent;
						            else
							            ancestorEnum = SelectedPropertyEnumerator;

						            if (IsDescendantOf(propEnum, ancestorEnum.GetDeepEnumerator()) == false)
							            selectImpossible = true;
					            }

					            _clickWithControl = true;

					            if (selectImpossible == false)
					            {
						            // If the main selected property is clicked to be unselected
						            if ((propEnum == SelectedPropertyEnumerator) && (_multiSelectedItems.Count > 0))
						            {
							            // Assign the main selected property to the first property of the multiselected set
                                        SelectProperty((PropertyEnumerator)_multiSelectedItems[0], e.Location);

							            // Remove the newly selected property from the multiselected set
                                        _multiSelectedItems.RemoveAt(0);
						            }
						            else if (propEnum.Children.Count == 0)
						            {
							            // If the clicked item must be unselected
							            if (propEnum.Property.Selected)
							            {
								            if (propEnum != SelectedPropertyEnumerator)
								            {
									            // Unselect the clicked property
                                                propEnum.Property.Selected = false;

									            // And remove it from the multiselected set
                                                _multiSelectedItems.Remove(propEnum);
								            }
							            }
							            // Else if the clicked item must be selected
							            else
							            {
								            if (_parentCtrl.OnValidateMultiSelection(SelectedPropertyEnumerator, propEnum.GetVisibleDeepEnumerator()))
								            {
                                                propEnum.Property.Selected = true;
									            _multiSelectedItems.Add(propEnum);
								            }
							            }
						            }

						            Invalidate();
					            }

					            _clickWithControl = false;
				            }
				            else
				            {
                                if ((_multiSelectedItems.Count > 0) && ((propEnum.Property.Selected && (hitTest == PropertyGrid.HitTests.Value)) || (hasFocus == false)))
                                {
                                    _clickWithControl = true;

                                    _multiSelectedItems.Add(SelectedPropertyEnumerator);
                                    PropertyVisibleDeepEnumerator oldSelectedEnum = SelectedPropertyEnumerator.GetVisibleDeepEnumerator();

                                    SelectProperty(propEnum, e.Location);

                                    oldSelectedEnum.Property.Selected = true;

                                    // Remove the new main selected property from the multiselected set
                                    _multiSelectedItems.Remove(propEnum);

                                    _clickWithControl = false;
                                }
                                else
                                {
                                    SelectProperty(propEnum, e.Location);
                                }
                            }

                            // We forward the click to the inplace control.
                            // We don't do it if Ctrl is pressed and a hyperlink has been defined for the property
				            if ((_currentInPlaceControl != null) &&
                                ((ModifierKeys != Keys.Control) || (property.HyperLinkFormat.Length == 0)) &&
                                (e.Button == MouseButtons.Left))
				            {
                                Rectangle rect = _currentInPlaceControl.Bounds;
                                Point pt = PointToScreen(e.Location);
                                pt = _currentInPlaceControl.PointToClient(pt);
                                if (rect.Contains(e.Location) && !TryOnForbidClickThrough(pt))
                                {
                                    // Obsolete comment:
                                    // I release the capture because I discovered that the .NET framework takes the Capture while
                                    // handling the left mouse button. It releases it in the MouseUp handler.
                                    // Without releasing the Capture, my mouse_event call would not work as expected.
//                                    Capture = false;
//                                    _currentInPlaceControl.Focus();

                                    // Mouse position in the inplace control
                                    Point mousePos = PointToScreen(e.Location);
                                    mousePos = _currentInPlaceControl.PointToClient(mousePos);
                                    // Let's find if the inplace control has a child that would receive the mouse click
                                    IntPtr handle = IntPtr.Zero;
                                    if (_currentInPlaceControl.HasChildren)
                                    {
                                        Control child = _currentInPlaceControl.GetChildAtPoint(mousePos);
                                        if (child != null)
                                        {
                                            handle = child.Handle;
                                            mousePos = PointToScreen(e.Location);
                                            mousePos = child.PointToClient(mousePos);
                                        }
                                    }
                                    if (handle == IntPtr.Zero)
                                        handle = _currentInPlaceControl.Handle;
                                    // Send to the inplace control (or its child) a button down event
                                    _parentCtrl.ClickThroughInProgress = true;
                                    Win32Calls.SendMessage(handle, Win32Calls.WM_LBUTTONDOWN, 0, Win32Calls.MakeLong(mousePos.X, mousePos.Y));
                                    _parentCtrl.ClickThroughInProgress = false;
                                    _mouseHook.HookMessages = true;
                                    _lastTimeClickedFromParent = DateTime.Now.Ticks;
                                    _lastPosClickedInParent = PointToScreen(new Point(e.X, e.Y));
                                }
                            }

                            if ((hitTest != PropertyGrid.HitTests.ManualDisable) && (property.Enabled) &&
                                (e.Clicks == 1) && (e.Button == MouseButtons.Left))
                                property.OnPropertyClicked(propEnum, e.Location, itemRect);
                        }
		            }
                }
            }

            base.OnMouseDown(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (_resizingColumns)
                LabelColumnWidth = (e.Location.X - LeftColumnWidth);
            else
            {
                Rectangle itemRect = Rectangle.Empty;
                PropertyEnumerator enumerator = null;
                if (ToolTipMode != PropertyGrid.ToolTipModes.None)
                    enumerator = PropertyItemFromPoint(e.Location, out itemRect);

                _toolTipLocation = Point.Empty;

                if ((ToolTipMode & PropertyGrid.ToolTipModes.ToolTipsOnValues) != 0)
		        {
                    Property property = enumerator.Property;
			        if ((property != null) && !(property is RootCategory) && !property.Selected)
			        {
                        Rectangle valueRect = property.GetValueRect(itemRect);

				        if (valueRect.Contains(e.Location) && (property.Value != null))
				        {
        					// Get the bounding rectangle for the string displayed in the control
                            Graphics graphics = CreateGraphics();
                            Rectangle strRect = property.Value.GetStringValueRect(graphics, valueRect, e.Location);

					        strRect.Height--;
					        if (strRect.Contains(e.Location))
        					{
    					        strRect.Height++;
                                Rectangle screenRect = Screen.GetWorkingArea(this);
						        Rectangle strScreenRect = strRect;
						        strScreenRect = RectangleToScreen(strScreenRect);

						        if ((strRect.Right > valueRect.Right) || (strScreenRect.Right > screenRect.Right) ||
							        (strRect.Bottom > valueRect.Bottom))
						        {
                                    ToolTip.Font = property.Value.Font;

                                    Point pt = new Point(strRect.Left - 1, strRect.Top);
                                    pt = PointToScreen(pt);
                                    if ((PropertyVerticalMargin == 0) || (PropertyVerticalMargin == 2))
                                        pt.Y++;

                                    int line = (e.Location.Y - valueRect.Top) / _basicPropertyHeight;
                                    
                                    // We also need the actual height of the text to set the tooltip margin
                                    Size size = property.Value.GetTooltipStringSize(graphics, valueRect, e.Location, line);
							        int diff = (strRect.Height+1 - size.Height - 4);
							        int topMargin = diff % 2 + diff / 2;
							        int bottomMargin = diff / 2;
                                    ToolTip.SetMargins(PropertyGrid.GlobalTextMargin - 2, topMargin, PropertyGrid.GlobalTextMargin - 2, bottomMargin);
                                    Win32Calls.SendMessage(ToolTip.Handle, Win32Calls.TTM_SETMAXTIPWIDTH, 0, size.Width);

							        if (strScreenRect.Right > screenRect.Right)
                                        pt.X = screenRect.Right - size.Width - PropertyGrid.GlobalTextMargin;
							        pt.X -= PropertyGrid.GlobalTextMargin;
                                    _toolTipLocation = new Point(pt.X, pt.Y - 1);

                                    ToolTip.SetText(property.Value.GetTooltipString(line), enumerator);

//                                    int bk = System.Drawing.ColorTranslator.ToWin32(Color.White);
//                                    Win32Calls.SendMessage(ToolTip.Handle, 0x0400 + 19, bk, ToolTip.GetTOOLINFO());
                                }
					        }

                            graphics.Dispose();
				        }
			        }
                }

                if ((ToolTipMode & PropertyGrid.ToolTipModes.ToolTipsOnLabels) != 0)
                {
                    Property property = enumerator.Property;
                    if ((property != null) && !(property is RootCategory) && (property.Value != null))
                    {
                        Rectangle labelRect = property.GetLabelRect(itemRect, enumerator.GetVisibleDeepEnumerator());
                        labelRect.Inflate(-PropertyGrid.GlobalTextMargin, 0);

                        // Get the bounding rectangle for the string displayed in the control
                        Graphics graphics = CreateGraphics();
                        Size size = Win32Calls.GetTextExtent(graphics, property.DisplayName, property.Font);
                        Rectangle strRect = labelRect;
                        strRect.Width = size.Width;
                        strRect.Height = _basicPropertyHeight;
                        graphics.Dispose();

                        if (strRect.Right > LeftColumnWidth + 1 + LabelColumnWidth)
                            strRect.Width = LeftColumnWidth + 1 + LabelColumnWidth - strRect.Left;

                        if (strRect.Contains(e.Location))
                        {
                            Rectangle screenRect = Screen.GetWorkingArea(this);
                            Rectangle strScreenRect = labelRect;
                            strScreenRect = RectangleToScreen(strScreenRect);

                            int rightLimit = LeftColumnWidth + 1 + LabelColumnWidth;
                            if ((_parentCtrl.EllipsisMode & PropertyGrid.EllipsisModes.EllipsisOnLabels) != 0)
                                rightLimit -= PropertyGrid.GlobalTextMargin;

                            if ((strRect.Left + size.Width > rightLimit) || (strScreenRect.Right > screenRect.Right))
                            {
                                ToolTip.Font = property.Font;

                                Point pt = new Point(strRect.Left - 1, strRect.Top);
                                pt = PointToScreen(pt);
                                if ((PropertyVerticalMargin == 0) || (PropertyVerticalMargin == 2))
                                    pt.Y++;

                                // We also need the actual height of the text to set the tooltip margin
                                int diff = (_basicPropertyHeight + 1 - size.Height - 4);
                                int topMargin = diff % 2 + diff / 2;
                                int bottomMargin = diff / 2;
                                ToolTip.SetMargins(PropertyGrid.GlobalTextMargin - 2, topMargin, PropertyGrid.GlobalTextMargin - 2, bottomMargin);
                                Win32Calls.SendMessage(ToolTip.Handle, Win32Calls.TTM_SETMAXTIPWIDTH, 0, size.Width);

                                if (strScreenRect.Right > screenRect.Right)
                                    pt.X = screenRect.Right - size.Width - PropertyGrid.GlobalTextMargin;
                                pt.X -= PropertyGrid.GlobalTextMargin;
                                _toolTipLocation = new Point(pt.X, pt.Y - 1);

                                ToolTip.SetText(property.DisplayName, enumerator);
                            }
                        }
                    }
                }

                if ((ToolTip != null) && (_toolTipLocation == Point.Empty))
                    ToolTip.SetText("", enumerator);
            }

            // OnSetCursor
            //------------

            PropertyGrid.HitTests hitTest = HitTest(e.Location);
            if (_resizingColumns == false)
            {
                if (hitTest == PropertyGrid.HitTests.ColumnSplit)
                {
                    Cursor = Cursors.VSplit;
                }
                else
                {
                    bool cursorSet = false;

                    if (Enabled || (DisableMode == PropertyGrid.DisableModes.None))
                    {
                        Rectangle itemRect;
                        PropertyEnumerator propEnum = PropertyItemFromPoint(e.Location, out itemRect);
                        if (propEnum.Property != null)
                        {
                            if (propEnum.Property.OverrideCursor(e.Location, itemRect, propEnum))
                                cursorSet = true;
                        }
                    }

                    if (cursorSet == false)
                        Cursor = Cursors.Arrow;
                }
            }

            base.OnMouseMove(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (_resizingColumns)
            {
                _resizingColumns = false;
                Capture = false;
            }

            base.OnMouseUp(e);
        }
        
        protected override void OnMouseWheel(MouseEventArgs e)
        {
            if (IsScrollbarVisible())
            {
                int nb = e.Delta / 120;

                if (e.Delta > 0)
                {
                    for (int i = 0; i < nb; i++)
                        Win32Calls.SendMessage(Handle, Win32Calls.WM_VSCROLL, Win32Calls.MakeLong(Win32Calls.SB_LINEUP, 0), 0);
                }
                else if (e.Delta < 0)
                {
                    for (int i = 0; i < -nb; i++)
                        Win32Calls.SendMessage(Handle, Win32Calls.WM_VSCROLL, Win32Calls.MakeLong(Win32Calls.SB_LINEDOWN, 0), 0);
                }
            }

            // Simulate a mouse move so that the tooltip can be updated if any
            Point point = PointToClient(e.Location);
            Win32Calls.PostMessage(Handle, Win32Calls.WM_MOUSEMOVE, 0, Win32Calls.MakeLong(point.X, point.Y));

            base.OnMouseWheel(e);
        }
        
        public PropertyGrid.HitTests HitTest(Point point)
        {
            Rectangle itemRect;
            PropertyEnumerator propEnum = PropertyItemFromPoint(point, out itemRect);

            if (propEnum.Property != null)	// On an item row ?
            {
                if ((point.X >= LeftColumnWidth + 1 + LabelColumnWidth - 1) &&
                    (point.X <= LeftColumnWidth + 1 + LabelColumnWidth + 1))
                {
                    if ((_parentCtrl.DrawManager.ShowCategoryVerticalLine || (propEnum.Property is RootCategory == false)) &&
                        (propEnum.Property is PropertyHyperLink == false) && (_columnsLock == false))
                        return PropertyGrid.HitTests.ColumnSplit;
                }

                Rectangle signRect = Rectangle.Empty;
                if (HasOneVisibleChild(propEnum))
                    signRect = propEnum.Property.GetSignRect(itemRect);
                if (signRect.Contains(point) && HasOneVisibleChild(propEnum))
                    return PropertyGrid.HitTests.TreeGlyph;

                if ((DisplayMode == PropertyGrid.DisplayModes.Categorized) &&
                    (point.X <= LeftColumnWidth))
                    return PropertyGrid.HitTests.LeftColumn;

                if (propEnum.Property.CanBeDisabledManually)
                {
                    Rectangle checkRect = propEnum.Property.GetManuallyDisableRect(itemRect, propEnum);
                    if (checkRect.Contains(point))
                        return PropertyGrid.HitTests.ManualDisable;
                }

                if (point.X > LeftColumnWidth + 1 + LabelColumnWidth + 1)
                {
                    if (propEnum.Property is RootCategory == false)
                        return PropertyGrid.HitTests.Value;
                }

                Rectangle labelRect = propEnum.Property.GetLabelRect(itemRect, propEnum.GetVisibleDeepEnumerator());
                if (labelRect.Contains(point))
                    return PropertyGrid.HitTests.Label;
            }

            return PropertyGrid.HitTests.Client;
        }

        public PropertyEnumerator PropertyItemFromPoint(Point point, out Rectangle itemRect)
        {
            // Restrict the search to the list area
            Rectangle clientRect = ClientRectangle;
            itemRect = new Rectangle(-1, -1, -1, -1);

            // If above or below the list, return NULL
            if ((point.Y > clientRect.Bottom) || (point.Y < clientRect.Top))
                return _activePropertyCollection.GetDeepEnumerator().RightBound;

            // Scan the items from top to bottom
            PropertyEnumerator currentEnum = FirstDisplayedProperty;
            while (currentEnum != currentEnum.RightBound)
            {
                Rectangle rect = GetItemRect(currentEnum);

                if (rect.Contains(point))	// Success
                {
                    itemRect = rect;
                    break;
                }

                currentEnum.MoveNext();
            }

            return currentEnum;
        }

        public Rectangle GetItemRect(PropertyEnumerator propEnum)
        {
            if (propEnum == propEnum.RightBound)
                return new Rectangle(-1, -1, -1, -1);

            Property property = propEnum.Property;

            // Calculate the rect of the first displayed item

            Rectangle clientRect = ClientRectangle;

            Rectangle itemRect = clientRect;
            itemRect.Y -= (_firstDisplayedLine - 1) * _basicPropertyHeight;
            itemRect.Height += (_firstDisplayedLine - 1) * _basicPropertyHeight;

            PropertyEnumerator currentEnum = FirstDisplayedProperty;
            while(currentEnum.Property != null)
            {
                int itemHeight = _basicPropertyHeight * currentEnum.Property.HeightMultiplier;
                itemRect.Height = itemHeight;

                if ((property == currentEnum.Property) && (itemRect.Top < clientRect.Bottom))
                    break;

                if (itemRect.Top >= clientRect.Bottom)	// out of the window
                {
                    itemRect = new Rectangle(-1, -1, -1, -1);
                    break;
                }

                itemRect.Offset(0, itemHeight);

                currentEnum.MoveNext();
            }

            if (currentEnum.Property == null)
                itemRect = new Rectangle(-1, -1, -1, -1);

            return itemRect;
        }

        Rectangle GetAbsoluteItemRect(PropertyEnumerator propEnum)
        {
            Property rectProperty = propEnum.Property;
            PropertyVisibleDeepEnumerator currentEnum = FirstDisplayedProperty;
            Property currentProperty = currentEnum.Property;

            if (currentProperty == null)
                return new Rectangle(-1, -1, -1, -1);

            // Calculate the rect of the first displayed item

            Rectangle clientRect = ClientRectangle;

            Rectangle itemRect = clientRect;
            itemRect.Y -= (_firstDisplayedLine - 1) *_basicPropertyHeight;
            itemRect.Height = currentProperty.HeightMultiplier * _basicPropertyHeight;

            // Find our item above the first displayed item
            while(currentProperty != null)
            {
                int itemHeight = _basicPropertyHeight * currentProperty.HeightMultiplier;
                itemRect.Y = itemRect.Bottom - itemHeight;
                itemRect.Height = itemHeight;

                if (currentProperty == rectProperty)
                    break;

                currentEnum.MovePrev();
                currentProperty = currentEnum.Property;

                itemRect.Height = 0;
	        }

            if (currentProperty != null)
                return itemRect;

	        // Find our item below the first displayed item

	        itemRect = clientRect;
	        itemRect.Y -= (_firstDisplayedLine - 1) * _basicPropertyHeight;

            currentEnum = FirstDisplayedProperty;
            currentProperty = currentEnum.Property;
            while (currentProperty != null)
            {
                int itemHeight = _basicPropertyHeight * currentProperty.HeightMultiplier;
                itemRect.Height = itemHeight;

                if (currentProperty == rectProperty)
                    break;

                itemRect.Offset(0,itemHeight);

                currentEnum.MoveNext();
                currentProperty = currentEnum.Property;
            }

            if (currentProperty != null)
                return itemRect;

	        return new Rectangle(-1,-1,-1,-1);
        }

        private void _EnableCategoryItem(PropertyEnumerator propEnum, bool enable, bool ancestorDisabled, bool direct)
        {
	        // Change the state of the item
            Property property = propEnum.Property;
            property.Enable(propEnum, enable, ancestorDisabled, direct);

            PropertyEnumerator childEnumerator = propEnum.Children.GetSiblingEnumerator();
            while (childEnumerator != childEnumerator.RightBound)
            {
                Property childProperty = childEnumerator.Property;

                if (childEnumerator.Children.Count > 0)
                {
                    _EnableCategoryItem(childEnumerator, enable, !property.GetManuallyDisabledVariable() || ancestorDisabled, false);
                }
		        else
		        {
                    childProperty.Enable(childEnumerator, enable, !property.GetManuallyDisabledVariable() || ancestorDisabled, false);
                }

                childEnumerator.MoveNext();
            }
        }

        public void EnableProperty(PropertyEnumerator propEnum, bool enable)
        {
            if (propEnum == propEnum.RightBound)
		        return;

            Property property = propEnum.Property;
            if (property.Enabled != enable)
            {
                if (HasOneVisibleChild(propEnum))
                {
                    _EnableCategoryItem(propEnum, enable, IsAncestorDisabled(propEnum), true);
                }
                else
                {
                    property.Enable(propEnum, enable, IsAncestorDisabled(propEnum), true);
                }

                if ((SelectedPropertyEnumerator.Property == property) && !enable && (_currentInPlaceControl != null))
                    HideInPlaceControl();
                else if (enable && (SelectedPropertyEnumerator.Property == property) && (_currentInPlaceControl == null))
                    ShowInPlaceControl(SelectedPropertyEnumerator);

                Invalidate();
            }
        }

        public void SelectProperty(PropertyEnumerator enumerator)
        {
            SelectProperty(enumerator, Point.Empty);
        }

        private void SelectProperty(PropertyEnumerator enumerator, Point mousePos)
        {
            if ((enumerator.Property != null) && (CheckPropertyVisibility(enumerator) == false))
                throw new ArgumentException("The property enumerator passed to SelectProperty must point to a visible property.", "enumerator");

	        // Clear multi selected items
	        bool multiSelectionCleared = false;
	        if (!_clickWithControl && (_multiSelectedItems.Count > 0))
	        {
                foreach(PropertyVisibleDeepEnumerator currentEnum in _multiSelectedItems)
		        {
                    if (currentEnum != _selectedPropertyEnum)
                        currentEnum.Property.Selected = false;
                }

		        _multiSelectedItems.Clear();
		        multiSelectionCleared = true;
	        }

            bool selectedPropertyChanged = ((_selectedPropertyEnum != enumerator) || multiSelectionCleared);

            if ((enumerator != enumerator.RightBound) && (enumerator.RightBound != null))
            {
                if (selectedPropertyChanged)
                {
                    if (_selectedPropertyEnum != _selectedPropertyEnum.RightBound)
                        _selectedPropertyEnum.Property.Selected = false;

                    _selectedPropertyEnum = enumerator.GetVisibleDeepEnumerator();

                    if (IsHandleCreated)
                    {
                        Rectangle clientRect = ClientRectangle;
                        Rectangle rect = GetItemRect(enumerator);

                        // Show the inplace control, even if partially visible
                        if ((rect.Top < clientRect.Bottom) && (rect.Bottom > clientRect.Top))
                            ShowInPlaceControl(enumerator, mousePos);
                    }
                }

                if (selectedPropertyChanged)
                    _selectedPropertyEnum.Property.Selected = true;
            }
		    else if (selectedPropertyChanged)	// No item selected
		    {
                if (IsHandleCreated)
                {
				    // We hide the in-place control
    			    HideInPlaceControl();
			    }

                if (_selectedPropertyEnum.Property != null)
                    _selectedPropertyEnum.Property.Selected = false;

                _selectedPropertyEnum = enumerator.GetVisibleDeepEnumerator();
            }

            if (selectedPropertyChanged)
            {
                if (IsHandleCreated)
                {
                    if (_parentCtrl.CommentsVisibility)
                        _parentCtrl.Refresh();
                    else
                        Refresh();
                }

                // Notify the derived class
                if (_selectedPropertyEnum != RightBound)
                    _parentCtrl.OnPropertySelected(new PropertySelectedEventArgs(_selectedPropertyEnum));
            }
        }

        private bool _hideInPlaceControlInProgress = false;

        public void HideInPlaceControl()
        {
            if (_hideInPlaceControlInProgress == false)
            {
                _hideInPlaceControlInProgress = true;

                if (_currentInPlaceControl != null)
                {
                    if (_currentInPlaceControl.IsHandleCreated)
                    {
                        _currentInPlaceControl.Hide();

                        _currentInPlaceControl.LostFocus -= OnChildLostFocus;
                        _currentInPlaceControl.GotFocus -= OnChildGotFocus;

                        _parentCtrl.OnInPlaceCtrlHidden(new InPlaceCtrlVisibleEventArgs(_selectedPropertyEnum, _currentInPlaceControl));

                        if (_currentInPlaceControl.ContainsFocus)
                            Focus();

                        _currentInPlaceControl = null;
                        _mouseHook.HookMessages = false;
                    }
                }

                _hideInPlaceControlInProgress = false;
            }
        }
        
        public void ShowInPlaceControl(PropertyEnumerator enumerator)
        {
            ShowInPlaceControl(enumerator, Point.Empty);
        }
        
        public void ShowInPlaceControl(PropertyEnumerator enumerator, Point mousePos)
        {
            if (!ContainsFocus)
                return;

            if (!Enabled && ((DisableMode & PropertyGrid.DisableModes.NoValueSelection) != 0))
                return;

            if (enumerator.Property.Enabled && (Parent.ContainsFocus || Parent.Focused))
            {
                Rectangle rect = GetItemRect(enumerator);
                rect.X += LeftColumnWidth + 1 + LabelColumnWidth + 1;
                rect.Width -= LeftColumnWidth + 1 + LabelColumnWidth + 1;

                // We must hide the preceding inplace control if any
		        HideInPlaceControl();

                if ((enumerator.Property.Feel != PropertyFeel.Empty) && (enumerator.Property.Feel != null))
                {
                    _currentInPlaceControl = enumerator.Property.Feel.ShowControl(rect, enumerator);

                    if (_currentInPlaceControl != null)
                    {
                        _currentInPlaceControl.LostFocus += new EventHandler(OnChildLostFocus);
                        _currentInPlaceControl.GotFocus += new EventHandler(OnChildGotFocus);
                    }

                    if ((InPlaceControl != null) &&
                        ((_parentCtrl.NavigationKeyMode & PropertyGrid.NavigationKeyModes.TabKey) != 0) &&
                        ((_parentCtrl.NavigationKeyMode & PropertyGrid.NavigationKeyModes.TabKeyWithAutoFocus) != 0))
                    {
                        rect = _currentInPlaceControl.Bounds;
                        Point pt = PointToScreen(mousePos);
                        pt = _currentInPlaceControl.PointToClient(pt);
                        if (rect.Contains(mousePos) && !TryOnForbidClickThrough(pt))
                            _parentCtrl.ClickThroughInProgress = true;

                        _parentCtrl.ActiveControl = InPlaceControl;

                        if (_parentCtrl.ClickThroughInProgress)
                            _parentCtrl.ClickThroughInProgress = false;
                    }
                }
            }
	        else
		        HideInPlaceControl();
        }

        protected override bool IsInputKey(Keys keyData)
        {
            if (keyData == Keys.Down)
                return true;

            if (keyData == Keys.Up)
                return true;

            if (keyData == Keys.Right)
                return true;

            if (keyData == Keys.Left)
                return true;

            return base.IsInputKey(keyData);
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            // If only Control is clicked we simulate a mouse move so that the cursor could be updated on
            // a hyperlink property.
            if (e.KeyCode == Keys.ControlKey)
            {
                if (_currentInPlaceControl != null)
                {
                    Win32Calls.RECT rect = new Win32Calls.RECT();
                    Win32Calls.GetWindowRect(_currentInPlaceControl.Handle, ref rect);
                    Rectangle bounds = Rectangle.FromLTRB(rect.Left, rect.Top, rect.Right, rect.Bottom);

                    if (bounds.Contains(MousePosition))
                    {
                        base.OnKeyDown(e);
                        return;
                    }
                }

                Rectangle itemRect;
                Point pt = PointToClient(MousePosition);
                PropertyEnumerator propEnum = PropertyItemFromPoint(pt, out itemRect);

                if (propEnum.Property != null)
                    propEnum.Property.OverrideCursor(pt, itemRect, propEnum);
                
                base.OnKeyDown(e);
                return;
            }

            Property selectedProperty = _selectedPropertyEnum.Property;

            if (selectedProperty != null)
            {
                // Hide the tooltip if it is visible
//                if (ToolTip != null)
  //                  ToolTip.SetText("", null);

                if (_currentInPlaceControl != null)
                {
                    IInPlaceControl c = (_currentInPlaceControl as IInPlaceControl);
                    if ((c != null) && c.OnParentKeyDown(e))
                        return;
                }

                switch (e.KeyCode)
                {
                    case Keys.F4:
                    {
                        if ((_currentInPlaceControl != null) && (e.Modifiers == 0))
                        {
                            IInPlaceControl c = (_currentInPlaceControl as IInPlaceControl);
                            if (c != null)
                                c.OnF4();
                        }
                        break;
                    }
                    case Keys.Space:
                    case Keys.Return:
                    {
                        if ((SelectedPropertyEnumerator.Property.CanBeDisabledManually) && (e.KeyCode == Keys.Space))
                        {
                            if (SelectedPropertyEnumerator.HasParent == false)
                            {
                                EnableProperty(SelectedPropertyEnumerator, !SelectedPropertyEnumerator.Property.Enabled);
                                e.SuppressKeyPress = true;
                            }
                            else
                            {
                                // The user can press on the checkbox only if its parent category is enabled
                                if (SelectedPropertyEnumerator.Parent.Property.Enabled)
                                {
                                    EnableProperty(SelectedPropertyEnumerator, !SelectedPropertyEnumerator.Property.Enabled);
                                    e.SuppressKeyPress = true;
                                }
                            }
                        }
                        // TODO : the following code should not be in this class.
                        else if (SelectedPropertyEnumerator.Property is PropertyHyperLink)
                        {
                            if (SelectedPropertyEnumerator.Property.Enabled)
                            {
                                PropertyHyperLinkClickedEventArgs ev = new PropertyHyperLinkClickedEventArgs(SelectedPropertyEnumerator, SelectedPropertyEnumerator.Property.HyperLink);
                                _parentCtrl.OnHyperLinkPropertyClicked(ev);
                                if (SelectedPropertyEnumerator.Property.HyperLinkPropertyClickedInternal != null)
                                    SelectedPropertyEnumerator.Property.HyperLinkPropertyClickedInternal(this, ev);
                            }
                        }
                        else if (HasOneVisibleChild(SelectedPropertyEnumerator))
                        {
                            Property property = SelectedPropertyEnumerator.Property;
                            ExpandProperty(SelectedPropertyEnumerator, !property.Expanded);
                        }

                        break;
                    }
                    case Keys.Right:		// Opens the item if it is a closed category
                    case Keys.Add:
                    {
                        if ((e.KeyCode == Keys.Right) && (ModifierKeys == Keys.Control))
                        {
                            LabelColumnWidth += 3;
                            break;
                        }

                        if (SelectedPropertyEnumerator.Children.Count > 0)
                        {
                            Property property = SelectedPropertyEnumerator.Property;
                            if (!property.Expanded && HasOneVisibleChild(SelectedPropertyEnumerator))
                            {
                                ExpandProperty(SelectedPropertyEnumerator, true);
                                break;
                            }
                        }

                        if (e.KeyCode == Keys.Add)
                            break;

                        goto case Keys.Down;
                    }
                    case Keys.Down:		// Moves the selected item down
                    {
                        if (e.Modifiers == Keys.Alt)
                        {
                            if (_currentInPlaceControl != null)
                            {
                                IInPlaceControl c = (_currentInPlaceControl as IInPlaceControl);
                                if ((c != null) && !SelectedPropertyEnumerator.Property.Value.IsReadOnly(SelectedPropertyEnumerator))
                                {
                                    c.OnF4();
                                    break;
                                }
                            }
                        }

                        PropertyVisibleDeepEnumerator nextEnum = new PropertyVisibleDeepEnumerator(_selectedPropertyEnum.Node);
                        nextEnum.MoveNext();

                        Property nextProperty = nextEnum.Property;
                        if (nextProperty != null)
                        {
                            Rectangle clientRect = ClientRectangle;
                            Rectangle itemRect = GetAbsoluteItemRect(nextEnum);

                            if (itemRect.Top < clientRect.Top)	// Test if the item is above the top of the grid
                            {
                                while (true)
                                {
                                    Win32Calls.SendMessage(Handle, Win32Calls.WM_VSCROLL, Win32Calls.MakeLong(Win32Calls.SB_LINEUP, 0), 0);
                                    itemRect = GetAbsoluteItemRect(nextEnum);
                                    if (itemRect.Top == clientRect.Top)
                                        break;
                                }
                            }
                            else if (itemRect.Bottom > clientRect.Bottom)		// Test if the item is below the bottom of the grid
                            {
                                // We scroll in a loop because the item may have a row height greater than the base row height
                                // if the current selected item is the last one displayed
                                do
                                {
                                    Win32Calls.SendMessage(Handle, Win32Calls.WM_VSCROLL, Win32Calls.MakeLong(Win32Calls.SB_LINEDOWN, 0), 0);
                                    itemRect = GetAbsoluteItemRect(nextEnum);
                                }
                                while ((itemRect.Bottom > clientRect.Bottom) && (itemRect.Top > clientRect.Top));
                            }

                            SelectProperty(nextEnum);
/*
                            if ((InPlaceControl != null) &&
                                ((_parentCtrl.NavigationKeyMode & PropertyGrid.NavigationKeyModes.TabKey) != 0) &&
                                ((_parentCtrl.NavigationKeyMode & PropertyGrid.NavigationKeyModes.TabKeyWithAutoFocus) != 0))
                            {
                                _parentCtrl.ActiveControl = InPlaceControl;
                            }*/

                        }

                        break;
                    }
                    case Keys.Left:		// Closes the item if it is an expanded category
                    case Keys.Subtract:
                    {
                        if ((e.KeyCode == Keys.Left) && (ModifierKeys == Keys.Control))
                        {
                            LabelColumnWidth -= 3;
                            break;
                        }

                        if (SelectedPropertyEnumerator.Children.Count > 0)
                        {
                            Property property = SelectedPropertyEnumerator.Property;
                            if (property.Expanded && HasOneVisibleChild(SelectedPropertyEnumerator))
                            {
                                ExpandProperty(SelectedPropertyEnumerator, false);
                                break;
                            }
                        }

                        if (e.KeyCode == Keys.Subtract)
                            break;

                        goto case Keys.Up;
                    }
                    case Keys.Up:		// Moves the selected item up
                    {
                        PropertyVisibleDeepEnumerator prevEnum = new PropertyVisibleDeepEnumerator(_selectedPropertyEnum.Node);
                        prevEnum.MovePrev();

                        Property prevProperty = prevEnum.Property;
                        if (prevProperty != null)
                        {
                            Rectangle clientRect = ClientRectangle;
                            Rectangle itemRect = GetAbsoluteItemRect(prevEnum);

                            if (itemRect.Top < clientRect.Top)
                            {
                                _firstDisplayedLine = 1;
                                FirstDisplayedProperty = prevEnum;
                            }
                            else if (itemRect.Bottom > clientRect.Bottom)
                            {
                                while(true)
                                {
                                    Win32Calls.SendMessage(Handle, Win32Calls.WM_VSCROLL, Win32Calls.MakeLong(Win32Calls.SB_LINEDOWN, 0), 0);
                                    itemRect = GetAbsoluteItemRect(prevEnum);
                                    if (itemRect.Bottom < clientRect.Bottom)
                                        break;
                                }
                            }

                            SelectProperty(prevEnum);
/*
                            if ((InPlaceControl != null) &&
                                ((_parentCtrl.NavigationKeyMode & PropertyGrid.NavigationKeyModes.TabKey) != 0) &&
                                ((_parentCtrl.NavigationKeyMode & PropertyGrid.NavigationKeyModes.TabKeyWithAutoFocus) != 0))
                            {
                                _parentCtrl.ActiveControl = InPlaceControl;
                            }*/
                        }
                        break;
                    }
                    case Keys.Next:
                    {
                        Rectangle clientRect = ClientRectangle;
                        int itemsPerPage = clientRect.Height / _basicPropertyHeight - 1;
                        Rectangle itemRect = GetAbsoluteItemRect(SelectedPropertyEnumerator);

                        // Find the item one page down
                        int count = 0;
                        PropertyEnumerator propEnum = SelectedPropertyEnumerator.GetVisibleDeepEnumerator();
                        int lineCount = (propEnum == FirstDisplayedProperty ? _firstDisplayedLine : 1);
                        while ((count < itemsPerPage) && (propEnum != propEnum.RightBound))
                        {
                            if (lineCount == propEnum.Property.HeightMultiplier)
                            {
                                propEnum.MoveNext();
                                lineCount = 1;
                            }
                            else
                                lineCount++;

                            count++;
                        }

                        // Selected item is above the grid ?
                        if (itemRect.Bottom < clientRect.Top)
                        {
                            if (propEnum == propEnum.RightBound)
                            {
                                propEnum.MovePrev();
                                _firstDisplayedLine = propEnum.Property.HeightMultiplier;
                            }
                            else
                                _firstDisplayedLine = lineCount;

                            SelectProperty(propEnum);
                            EnsureVisible(propEnum);
                        }
                        // Selected item is in or below the grid ?
                        else
                        {
                            if (propEnum == propEnum.RightBound)	// Not a complete page down because at the far bottom ?
                            {
                                propEnum.MovePrev();
                                lineCount = propEnum.Property.HeightMultiplier;
                                PropertyVisibleDeepEnumerator propertyToSelectEnum = propEnum.GetVisibleDeepEnumerator();

                                count = itemsPerPage;
                                while ((propEnum != _activePropertyCollection.GetVisibleDeepEnumerator().MoveFirst()) && (count > 0))
                                {
                                    if (lineCount > 1)
                                        lineCount--;
                                    else
                                    {
                                        propEnum.MovePrev();
                                        lineCount = propEnum.Property.HeightMultiplier;
                                    }

                                    count--;
                                }

                                _firstDisplayedLine = lineCount;
                                FirstDisplayedProperty = propEnum as PropertyVisibleDeepEnumerator;
                                SelectProperty(propertyToSelectEnum);
                            }
                            else
                            {
                                // The grid height is to small to properly page down ?
                                if (itemsPerPage < propEnum.Property.HeightMultiplier)
                                {
                                    // Advance one item
                                    if (propEnum != _activePropertyCollection.GetVisibleDeepEnumerator().MoveLast())
                                    {
                                        if (propEnum == SelectedPropertyEnumerator)
                                            propEnum.MoveNext();

                                        _firstDisplayedLine = 1;
                                        FirstDisplayedProperty = propEnum as PropertyVisibleDeepEnumerator;
                                        SelectProperty(propEnum);
                                    }
                                }
                                else
                                {
                                    FirstDisplayedProperty = SelectedPropertyEnumerator;
                                    SelectProperty(propEnum);
                                }
                            }
                        }

                        Invalidate();

                        break;
                    }
                    case Keys.Prior:
                    {
                        Rectangle clientRect = ClientRectangle;
                        int itemsPerPage = clientRect.Height / _basicPropertyHeight - 1;

                        // Find the item one page up
                        int count = 0;
                        PropertyVisibleDeepEnumerator enumerator = SelectedPropertyEnumerator.GetVisibleDeepEnumerator();
                        int lineCount = enumerator.Property.HeightMultiplier;
                        while ((count < itemsPerPage) && (enumerator != _activePropertyCollection.GetVisibleDeepEnumerator().MoveFirst()))
                        {
                            if (lineCount == 1)
                            {
                                enumerator.MovePrev();
                                lineCount = enumerator.Property.HeightMultiplier;
                            }
                            else
                                lineCount--;

                            count++;
                        }

                        if ((count == 0) && (enumerator != _activePropertyCollection.GetVisibleDeepEnumerator().MoveFirst()))
                        {
                            enumerator.MovePrev();
                            count = 1;
                        }

                        Rectangle itemRect = GetAbsoluteItemRect(enumerator);

                        // Is the new selected item in the grid ?
                        if ((itemRect.Top >= clientRect.Top) && (itemRect.Bottom < clientRect.Bottom))
                            SelectProperty(enumerator);

                        // Is the new selected item below the grid ?
                        else if (itemRect.Bottom > clientRect.Bottom)
                        {
                            PropertyEnumerator currentEnum = enumerator.GetVisibleDeepEnumerator();
                            lineCount = 1;
                            while((count > 0) && (currentEnum != _activePropertyCollection.GetVisibleDeepEnumerator().MoveFirst()))
                            {
                                if (lineCount == 1)
                                {
                                    currentEnum.MovePrev();
                                    lineCount = currentEnum.Property.HeightMultiplier;
                                }
                                else
                                    lineCount--;

                                count--;
                            }

                            FirstDisplayedProperty = currentEnum as PropertyVisibleDeepEnumerator;
                            SelectProperty(enumerator);
                        }

                        // Is the new selected item above the grid ?
                        else if (itemRect.Top < clientRect.Top)
                        {
                            _firstDisplayedLine = 1;
                            FirstDisplayedProperty = enumerator;
                            SelectProperty(FirstDisplayedProperty);
                        }

                        Refresh();

                        break;
                    }
                    case Keys.Home:
                    {
                        Win32Calls.SetScrollPos(Handle, Win32Calls.SB_VERT, 0, true);
                        _firstDisplayedPropertyEnumerator = _activePropertyCollection.GetVisibleDeepEnumerator();
                        _firstDisplayedPropertyEnumerator.MoveFirst();
                        _firstDisplayedLine = 1;
                        SelectProperty(FirstDisplayedProperty);

                        break;
                    }
                    case Keys.End:
                    {
                        Rectangle clientRect = ClientRectangle;

                        _firstDisplayedPropertyEnumerator = _activePropertyCollection.GetVisibleDeepEnumerator();
                        _firstDisplayedPropertyEnumerator.MoveLast();

                        _firstDisplayedLine = 1;
                        PropertyVisibleDeepEnumerator currentEnum = _firstDisplayedPropertyEnumerator.GetVisibleDeepEnumerator();
                        Rectangle itemRect = GetItemRect(currentEnum);
                        while ((_firstDisplayedPropertyEnumerator != _activePropertyCollection.GetVisibleDeepEnumerator().MoveFirst()) && (clientRect.Bottom - itemRect.Bottom > _basicPropertyHeight))
                        {
                            if (_firstDisplayedLine > 1)
                                _firstDisplayedLine--;
                            else
                            {
                                _firstDisplayedPropertyEnumerator.MovePrev();
                                _firstDisplayedLine = _firstDisplayedPropertyEnumerator.Property.HeightMultiplier;
                            }

                            itemRect = GetItemRect(currentEnum);
                        }

                        Win32Calls.SCROLLINFO si = new Win32Calls.SCROLLINFO();
                        si.cbSize = Marshal.SizeOf(si);
                        si.fMask = Win32Calls.SIF_PAGE | Win32Calls.SIF_RANGE;
                        Win32Calls.GetScrollInfo(Handle, Win32Calls.SB_VERT, ref si);
                        Win32Calls.SetScrollPos(Handle, Win32Calls.SB_VERT, si.nMax - (si.nPage - 1), true);

                        PropertyVisibleDeepEnumerator lastEnum = _activePropertyCollection.GetVisibleDeepEnumerator();
                        lastEnum.MoveLast();
                        SelectProperty(lastEnum);

                        break;
                    }
			        case Keys.A:
			        {
				        if (e.Control)
				        {
					        if (_multiSelectMode == PropertyGrid.MultiSelectModes.SameLevel)
					        {
						        // Find the parent of the concerned level
						        PropertyEnumerator ancestorEnum;
                                if (SelectedPropertyEnumerator.Children.Count == 0)
                                    ancestorEnum = SelectedPropertyEnumerator.Parent;
                                else
                                    ancestorEnum = SelectedPropertyEnumerator;

                                // And browse all properties at this level and under
                                PropertyEnumerator propEnum = ancestorEnum.Children.GetVisibleDeepEnumerator();
                                propEnum.RestrictedToThisLevelAndUnder = true;
                                while(propEnum != ancestorEnum.Children.RightBound)
						        {
                                    if (_parentCtrl.OnValidateMultiSelection(SelectedPropertyEnumerator, propEnum as PropertyVisibleDeepEnumerator))
							        {
                                        propEnum.Property.Selected = true;
								        _multiSelectedItems.Add(propEnum);
							        }

                                    propEnum.MoveNext();
                                }

						        Invalidate();
					        }
					        else if (_multiSelectMode == PropertyGrid.MultiSelectModes.Global)
					        {
                                PropertyEnumerator propEnum = _activePropertyCollection.GetVisibleDeepEnumerator();
                                propEnum.MoveFirst();
                                while (propEnum != propEnum.RightBound)
                                {
                                    if ((propEnum != SelectedPropertyEnumerator) && (propEnum.Children.Count == 0))
                                    {
                                        if (_parentCtrl.OnValidateMultiSelection(SelectedPropertyEnumerator, propEnum as PropertyVisibleDeepEnumerator))
                                        {
                                            propEnum.Property.Selected = true;
                                            _multiSelectedItems.Add(propEnum);
                                        }
                                    }

                                    propEnum.MoveNext();
                                }

						        Invalidate();
					        }
				        }

				        break;
			        }
                }
            }

            base.OnKeyDown(e);
        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            // If the Control key is released the cursor is restored to default in case we were on a hyperlinked property
            // a hyperlink property.
            if (e.KeyCode == Keys.ControlKey)
            {
                if (_currentInPlaceControl != null)
                {
                    Win32Calls.RECT rect = new Win32Calls.RECT();
                    Win32Calls.GetWindowRect(_currentInPlaceControl.Handle, ref rect);
                    Rectangle bounds = Rectangle.FromLTRB(rect.Left, rect.Top, rect.Right, rect.Bottom);

                    if (bounds.Contains(MousePosition))
                    {
                        base.OnKeyUp(e);
                        return;
                    }
                }

                Rectangle itemRect;
                Point pt = PointToClient(MousePosition);
                PropertyEnumerator propEnum = PropertyItemFromPoint(pt, out itemRect);

                if (!(propEnum.Property is PropertyHyperLink))
                    Cursor = Cursors.Arrow;
            }

            base.OnKeyUp(e);
        }

        protected override bool ProcessDialogChar(char charCode)
        {
            if ((charCode == '+') || (charCode == '-'))
            {
                if (SelectedPropertyEnumerator.Children.Count > 0)
                {
                    if (HasOneVisibleChild(SelectedPropertyEnumerator))
                        return true;
                }
            }

            return base.ProcessDialogChar(charCode);
        }

        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            if (_currentInPlaceControl != null)
            {
                _parentCtrl.ActiveControl = _currentInPlaceControl;
//                _currentInPlaceControl.Focus();
                Win32Calls.PostMessage(_currentInPlaceControl.Handle, Win32Calls.WM_CHAR, e.KeyChar, 0);
            }

            base.OnKeyPress(e);
        }

        protected override void OnGotFocus(EventArgs e)
        {
            base.OnGotFocus(e);

            // The selected property must be repainted
            Invalidate();
//            Refresh();

            // Sometimes, when we hide the inplace control, the properties control
            // regains the focus and tries to show the inplace control again. We must
            // prevent this by testing if m_currentInPlaceControl already has a value.
            if (_dontShowInPlaceCtrlInGotFocus)
            {
                _dontShowInPlaceCtrlInGotFocus = false;
                return;
            }

            Property property = SelectedPropertyEnumerator.Property;
            if ((property != null) && (property.InPlaceCtrlInAction == null))
            {
                ShowInPlaceControl(SelectedPropertyEnumerator);
            }
        }

        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);

            // The inplace control must be hidden when another application gains the focus (becomes the foreground window)
            if ((_currentInPlaceControl != null) && (_currentInPlaceControl.ContainsFocus == false))
                HideInPlaceControl();

            Invalidate();
        }

        public bool IsDescendantOf(PropertyEnumerator enumDescendantTested, PropertyEnumerator enumAncestor)
        {
	        // This is an agreement that a property is not a descendant of itself
            if (enumDescendantTested == enumAncestor)
                return false;

            PropertyDeepEnumerator currentEnum = enumDescendantTested.GetDeepEnumerator();
            while (currentEnum.HasParent && (enumAncestor != currentEnum))
                currentEnum.MoveParent();

            return (enumAncestor == currentEnum);
        }

        public void ExpandProperty(PropertyEnumerator propEnum, bool expand)
        {
            if (propEnum == propEnum.RightBound)
                return;

            Property property = propEnum.Property;

            // Do nothing if the expand state won't change
            if (expand == property.Expanded)
                return;

            InvalidateVisibleItemCount();

            // Hide the inplace control if it is a child of the closed category
            if (property.Expanded && !expand)
            {
                if (IsDescendantOf(SelectedPropertyEnumerator, propEnum))
                    SelectProperty(propEnum);

                if (IsDescendantOf(FirstDisplayedProperty, propEnum))
                    FirstDisplayedProperty = propEnum.GetVisibleDeepEnumerator();
            }

            property.Expanded = expand;

            _parentCtrl.OnPropertyExpanded(new PropertyExpandedEventArgs(propEnum, expand));

            if (IsHandleCreated)
            {
                // We call OnSizeChanged here because this method checks to see if there
                // is some space left at the bottom of the grid and scrolls it accordingly.
                // It also calls CheckScrollbar()
                Rectangle rect = ClientRectangle;
                OnSizeChanged(rect.Width, rect.Height);

                Invalidate();
            }
        }

        public void ExpandAllProperties(bool expand)
        {
            PropertyEnumerator propEnum = FirstProperty;
            while (propEnum != RightBound)
            {
                ExpandProperty(propEnum, expand);
                propEnum.MoveNext();
            }
        }

        private void InvalidateVisibleItemCount()
        {
            _visibleItemCountValid = false;
        }

        private int GetVisibleItemCount()
        {
	        if (_visibleItemCountValid)
		        return _visibleItemCount;
	        else
	        {
		        _visibleItemCountValid = true;
		        _visibleItemCount = 0;
		        _visibleLineCount = 0;

                PropertyVisibleDeepEnumerator enumerator = _activePropertyCollection.GetVisibleDeepEnumerator();
                enumerator.MoveFirst();
                while(enumerator != enumerator.RightBound)
                {
                    _visibleLineCount += enumerator.Property.HeightMultiplier;
                    _visibleItemCount++;

                    enumerator.MoveNext();
                }

		        return _visibleItemCount;
	        }
        }

        private int GetVisibleLineCount()
        {
	        if (_visibleItemCountValid == false)
		        GetVisibleItemCount();

	        return _visibleLineCount;
        }

        private bool TryOnForbidClickThrough(Point pt)
        {
            MethodInfo methodInfo = _currentInPlaceControl.GetType().GetMethod("OnForbidClickThrough");
            if (methodInfo != null)
            {
                return (bool)methodInfo.Invoke(_currentInPlaceControl, new object[] { pt });
            }

            return false;
        }

        internal void CloseEmptySpace()
        {
            // Test for empty space at the bottom and scroll up accordingly
            PropertyVisibleDeepEnumerator lastVisiblePropertyEnum = _activePropertyCollection.GetVisibleDeepEnumerator();
            lastVisiblePropertyEnum.MoveLast();
            if (lastVisiblePropertyEnum.Property != null)
            {
                Rectangle clientRect = ClientRectangle;

                Rectangle itemRect = GetAbsoluteItemRect(lastVisiblePropertyEnum);
                while ((clientRect.Bottom - itemRect.Bottom >= _basicPropertyHeight) && (Win32Calls.GetScrollPos(Handle, Win32Calls.SB_VERT) > 0))
                {
                    Win32Calls.SendMessage(Handle, Win32Calls.WM_VSCROLL, Win32Calls.MakeLong(Win32Calls.SB_LINEUP, 0), 0);
                    itemRect = GetAbsoluteItemRect(lastVisiblePropertyEnum);
                }
            }
        }

        private void OnSizeChanged(int width, int height)
        {
            // Test for empty space at the bottom and scroll up accordingly
            CloseEmptySpace();

            CheckScrollbar();
        }

        internal void HeightMultiplierChanged()
        {
            InvalidateVisibleItemCount();
            CheckScrollbar();
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);

            if (Size.Height == 0)
                return;

            // In case the vertical separation between the second and third column
            // is not visible anymore, move it in the middle of the visible area.
            if ((Size.Width > 0) && (Size.Height > 0) && (LabelColumnWidth + LeftColumnWidth > Size.Width))
            {
                int width = (Size.Width - LeftColumnWidth) / 2;
                if (IsScrollbarVisible())
                    width -= SystemInformation.VerticalScrollBarWidth;

                LabelColumnWidth = width;
            }
            else if (_labelColumnFollowsResize)
            {
                double ratio = (double)LabelColumnWidth / _prevSize.Width;
                LabelColumnWidth = (int)Math.Round(ratio * Size.Width);
                _prevSize = Size;
            }

            _rootGlyphsRect = new Rectangle(0, 0, LeftColumnWidth, Size.Height);

            // Check scrollbars and avoid empty space at the bottom of the list
            OnSizeChanged(Size.Width, Size.Height);

            // Redraw the control
            //	        Invalidate(false);
        }

        internal void CheckScrollbar()
        {
            if (_displayModeChangeInProgress)
                return;

            if (IsHandleCreated == false)
                return;

            Rectangle clientRect = ClientRectangle;
            if (clientRect.Height == 0)
                return;

            Win32Calls.SCROLLINFO si = new Win32Calls.SCROLLINFO();
            si.cbSize = Marshal.SizeOf(si);

            // Determine if the number of properties to display can fit in the grid.
            int lineCount = GetVisibleLineCount();
            if (lineCount * _basicPropertyHeight > clientRect.Height)
            {
                // If it can't, the scrollbar must be visible and its parameters checked

                if (!IsScrollbarVisible())
                {
                    Win32Calls.ShowScrollBar(Handle, Win32Calls.SB_VERT, true);

                    // Redraw only the value column
                    Invalidate(new Rectangle(LeftColumnWidth + LabelColumnWidth, 0, clientRect.Width - (LeftColumnWidth + LabelColumnWidth), clientRect.Height), false);
                    Invalidate(false);

                    // Invalidate the inplace control
                    if (_currentInPlaceControl != null)
                        _currentInPlaceControl.Refresh();
                }

                // Set the scrollbar parameters
                si.nMin = 0;
                si.nMax = lineCount - 1;
                si.nPage = clientRect.Height / _basicPropertyHeight;
                si.fMask = Win32Calls.SIF_PAGE | Win32Calls.SIF_RANGE;
                Win32Calls.SetScrollInfo(Handle, Win32Calls.SB_VERT, ref si, true);

                // Enable both ends of the scrollbar
                Win32Calls.EnableScrollBar(Handle, Win32Calls.SB_VERT, Win32Calls.ESB_ENABLE_BOTH);

                // Disable the scrollbar arrow if it is at a limit
                Win32Calls.GetScrollInfo(Handle, Win32Calls.SB_VERT, ref si);
                if (Win32Calls.GetScrollPos(Handle, Win32Calls.SB_VERT) == (si.nMax - (si.nPage - 1)))
                    Win32Calls.EnableScrollBar(Handle, Win32Calls.SB_VERT, Win32Calls.ESB_DISABLE_DOWN);
                else if (Win32Calls.GetScrollPos(Handle, Win32Calls.SB_VERT) == 0)
                    Win32Calls.EnableScrollBar(Handle, Win32Calls.SB_VERT, Win32Calls.ESB_DISABLE_UP);

                // Control the position of the scroll
                PropertyVisibleDeepEnumerator enumerator = _activePropertyCollection.GetVisibleDeepEnumerator();
                enumerator.MoveFirst();
                int pos = 0;
                while (enumerator != _firstDisplayedPropertyEnumerator)
                {
                    pos += enumerator.Property.HeightMultiplier;
                    enumerator.MoveNext();
                }
                if (_firstDisplayedPropertyEnumerator != _firstDisplayedPropertyEnumerator.RightBound)
                    pos += _firstDisplayedLine - 1;
                if (pos != Win32Calls.GetScrollPos(Handle, Win32Calls.SB_VERT))
                    Win32Calls.SetScrollPos(Handle, Win32Calls.SB_VERT, pos, true);
            }
            else
            {
                // If the properties can all fit in the grid, the scrollbar must be hidden

                if (IsScrollbarVisible())
                {
                    Win32Calls.ShowScrollBar(Handle, Win32Calls.SB_VERT, false);
                    Win32Calls.SetScrollPos(Handle, Win32Calls.SB_VERT, 0, true);

                    // Set the scrollbar parameters to 0 so that we can test these values to
                    // 0 elsewhere in the code (meaning no scroll is possible)
                    si.nMin = 0;
                    si.nMax = 0;
                    si.nPage = 0;
                    si.fMask = Win32Calls.SIF_PAGE | Win32Calls.SIF_RANGE;
                    Win32Calls.SetScrollInfo(Handle, Win32Calls.SB_VERT, ref si, true);

                    // Redraw only the value column
                    Invalidate(new Rectangle(LeftColumnWidth + LabelColumnWidth, 0, clientRect.Width - (LeftColumnWidth + LabelColumnWidth), clientRect.Height), false);
                    Invalidate(false);

                    // Invalidate the inplace control
                    if (_currentInPlaceControl != null)
                        _currentInPlaceControl.Refresh();
                }
            }

            // Resize current inplace control

            Property property = SelectedPropertyEnumerator.Property;
            if ((property != null) && property.Enabled)
            {
                Rectangle valueRect = GetItemRect(SelectedPropertyEnumerator);
                valueRect = property.GetValueRect(valueRect);

                PropertyFeel feel = property.Feel;
                if ((feel != null) && (feel != PropertyFeel.Empty))
                {
                    if ((valueRect.Bottom <= clientRect.Top) || (valueRect.Top >= clientRect.Bottom))
                        HideInPlaceControl();
                    else
                    {
                        if (_currentInPlaceControl == null)
                        {
                            // When we scroll and the selected property comes back into view, we need to restore the inplace control
                            ShowInPlaceControl(SelectedPropertyEnumerator);
                        }
                        else
                        {
                            feel.MoveControl(valueRect, SelectedPropertyEnumerator, false);
                            _currentInPlaceControl.Refresh();
                        }
                    }
                }
            }
        }

        private void ResetScrollPosToFirstDisplayedProperty()
        {
            if (_displayModeChangeInProgress)
                return;

            if (IsScrollbarVisible())
            {
                PropertyEnumerator propEnum = _activePropertyCollection.GetVisibleDeepEnumerator().MoveFirst();
                int delta = 0;
                int lineNumber = 1;
                while ((propEnum != FirstDisplayedProperty) || (lineNumber != _firstDisplayedLine))
                {
                    if (lineNumber == propEnum.Property.HeightMultiplier)
                    {
                        propEnum.MoveNext();
                        lineNumber = 1;
                    }
                    else
                        lineNumber++;

                    delta++;
                }

                Win32Calls.SetScrollPos(Handle, Win32Calls.SB_VERT, delta, true);
            }
        }

        public bool CheckPropertyVisibility(PropertyEnumerator propEnum)
        {
            PropertyEnumerator currentEnum = new PropertyDeepEnumerator(propEnum.Node);
            do
            {
                if (currentEnum.Property.Visible == false)
                    return false;

                if (currentEnum.HasParent)
                {
                    currentEnum = currentEnum.Parent;

                    if (currentEnum.Property.Expanded == false)
                        return false;
                }
            }
            while (currentEnum.HasParent);

            return true;
        }

        public bool EnsureVisible(PropertyEnumerator propEnum)
        {
	        if (propEnum == propEnum.RightBound)
		        return false;

	        if (_displayMode == PropertyGrid.DisplayModes.Categorized)
	        {
		        // Ensure that all ancestors are expanded and visible
                PropertyEnumerator parentEnum = propEnum;
                while(parentEnum.HasParent)
                {
                    parentEnum = parentEnum.Parent;
                    if (parentEnum.Property.Expanded == false)
                    {
                        ShowProperty(parentEnum, true);
                        ExpandProperty(parentEnum, true);
                    }
                }
	        }

	        Rectangle itemRect = GetAbsoluteItemRect(propEnum);
	        Rectangle clientRect = ClientRectangle;

	        // Make the item the first visible one at the top if it is above the control
	        if (itemRect.Top < clientRect.Top)
	        {
                _firstDisplayedLine = 1;
		        FirstDisplayedProperty = propEnum.GetVisibleDeepEnumerator();
	        }
	        // Make the item the last visible one at the bottom if it is below the control
	        else
	        {
		        while(itemRect.Bottom > clientRect.Bottom)
		        {
                    Win32Calls.SendMessage(Handle, Win32Calls.WM_VSCROLL, Win32Calls.MakeLong(Win32Calls.SB_LINEDOWN, 0), 0);
			        itemRect = GetAbsoluteItemRect(propEnum);
		        }
	        }

	        // We call OnSizeChanged here because this method checks to see if there
	        // is some space left at the bottom of the grid and scrolls it accordingly.
	        // It also calls CheckScrollbar()
	        OnSizeChanged(clientRect.Width, clientRect.Height);
            Refresh();

	        return true;
        }

        public void ShowProperty(PropertyEnumerator propEnum, bool show)
        {
            if (propEnum == propEnum.RightBound)
                return;

            if (propEnum.Property.Visible == show)
                return;

            propEnum.Property.Visible = show;

            InvalidateVisibleItemCount();

            if (!show)	// The item must be hidden
            {
                if (SelectedPropertyEnumerator == propEnum)
                {
                    PropertyEnumerator nextEnum = SelectedPropertyEnumerator.GetVisibleDeepEnumerator();
                    PropertyEnumerator prevEnum = SelectedPropertyEnumerator.GetVisibleDeepEnumerator().MovePrev();
                    if (nextEnum != nextEnum.RightBound)
                        SelectProperty(nextEnum);
                    else if (prevEnum != prevEnum.LeftBound)
                        SelectProperty(prevEnum);
                    else
                        SelectProperty(nextEnum);
                }

                if (_firstDisplayedPropertyEnumerator == propEnum)
                {
                    PropertyEnumerator nextEnum = _firstDisplayedPropertyEnumerator.GetVisibleDeepEnumerator();
                    PropertyEnumerator prevEnum = _firstDisplayedPropertyEnumerator.GetVisibleDeepEnumerator().MovePrev();
                    if (nextEnum != nextEnum.RightBound)
                        _firstDisplayedPropertyEnumerator = nextEnum as PropertyVisibleDeepEnumerator;
                    else if (prevEnum != prevEnum.LeftBound)
                        _firstDisplayedPropertyEnumerator = prevEnum as PropertyVisibleDeepEnumerator;
                    else
                        _firstDisplayedPropertyEnumerator = nextEnum as PropertyVisibleDeepEnumerator;
                }
            }

            if (!_lockRefresh)
            {
                if (IsHandleCreated)
                {
                    // We call OnSizeChanged here because this method checks to see if there
                    // is some space left at the bottom of the grid and scrolls it accordingly.
                    // It also calls CheckScrollbar()
                    Rectangle rect = ClientRectangle;
                    OnSizeChanged(rect.Width, rect.Height);
                    Refresh();
                }
            }
        }

        ToolTipCtrl ToolTip
        {
            get
            {
                if (ToolTipMode == PropertyGrid.ToolTipModes.None)
                    return null;

                if (_tooltipCtrl == null)
                    _tooltipCtrl = new ToolTipCtrl(this);

                return _tooltipCtrl;
            }
        }

        public void Clear()
        {
	        InvalidateVisibleItemCount();

	        HideInPlaceControl();

            _activePropertyCollection.Clear();
	        _flatPropertyCollection.Clear();

            _firstDisplayedPropertyEnumerator = _activePropertyCollection.GetVisibleDeepEnumerator().RightBound.GetVisibleDeepEnumerator();
            _selectedPropertyEnum = _activePropertyCollection.GetVisibleDeepEnumerator().RightBound.GetVisibleDeepEnumerator();

            Invalidate();

	        if (IsScrollbarVisible())
	        {
                Win32Calls.SetScrollPos(Handle, Win32Calls.SB_VERT, 0, true);
                CheckScrollbar();
	        }
        }

        public PropertyEnumerator FindProperty(int propertyId)
        {
	        return _categorizedPropertyCollection.Find(propertyId);
        }

        public PropertyEnumerator FindPropertyAfter(PropertyEnumerator afterEnumerator, int propertyId)
        {
            return _categorizedPropertyCollection.FindAfter(afterEnumerator, propertyId);
        }

        private int MeasureWidestLabel()
        {
	        int maxWidth = 0;

            PropertyEnumerator propEnum = _activePropertyCollection.GetVisibleDeepEnumerator().MoveFirst();
            while(propEnum != propEnum.RightBound)
	        {
                Property property = propEnum.Property;

                Graphics graphics = CreateGraphics();
                Size size = Win32Calls.GetTextExtent(graphics, property.DisplayName, Font);
                graphics.Dispose();

		        if (((property is RootCategory == false) || _parentCtrl.DrawManager.ShowCategoryVerticalLine) &&
                    (property is PropertyHyperLink == false))
		        {
			        int width = size.Width;

                    width += property.GetLabelShift(propEnum as PropertyVisibleDeepEnumerator);

                    if (property.CanBeDisabledManually)
                        width += (PropertyGrid.GlobalTextMargin + _basicPropertyHeight * property.HeightMultiplier);

                    if (width > maxWidth)
				        maxWidth = width;
		        }

		        propEnum.MoveNext();
	        }

	        if (maxWidth == 0)
		        return 0;

	        return maxWidth + 2 * PropertyGrid.GlobalTextMargin;
        }

        public void AdjustLabelColumn()
        {
	        int maxWidth = MeasureWidestLabel();
	        if (maxWidth > 0)
		        LabelColumnWidth = maxWidth;
        }

        [UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.AllWindows)]
        protected override bool ProcessDialogKey(Keys keyData)
        {
            Keys key = (keyData & Keys.KeyCode);

            if (key == Keys.Return)
            {
                if (_currentInPlaceControl != null)
                {
                    _parentCtrl.ActiveControl = _currentInPlaceControl;
//                    _currentInPlaceControl.Focus();
                    return true;
                }
            }
            else if (key == Keys.Escape)
                return true;

            return base.ProcessDialogKey(keyData);
        }

        void OnChildGotFocus(object sender, EventArgs e)
        {
            _dontShowInPlaceCtrlInGotFocus = false;
        }

        void OnChildLostFocus(object sender, EventArgs e)
        {
            if (Focused)
            {
                _dontShowInPlaceCtrlInGotFocus = true;
                if (e is FocusEventArgs)
                {
                    FocusEventArgs fea = (e as FocusEventArgs);

                    if (fea.FocusControl == null)
                    {
                        (Parent as ContainerControl).ActiveControl = this;
                        HideInPlaceControl();
                    }
                    else if (fea.FocusControl == this)
                    {
                        if ((_parentCtrl.NavigationKeyMode & PropertyGrid.NavigationKeyModes.TabKey) != 0)
                        {
                            if (fea.LeaveKey)
                            {
                                HideInPlaceControl();
                                _parentCtrl.TabToNextProperty();
                            }
                        }
                    }
                }
            }
            else
            {
                if (_currentInPlaceControl != null)
                {
                    if (_currentInPlaceControl.ContainsFocus == false)
                    {
                        // When another application is made active
                        if ((((ContainerControl)TopLevelControl).ActiveControl == _parentCtrl) &&
                            (e is FocusEventArgs) && (((FocusEventArgs)e).FocusControl == null))
                        {
                            _parentCtrl.ActiveControl = this;
                            HideInPlaceControl();
                        }

                        // The inplace control must not be hidden when it is a dropdown content that is opened
                        // (making the inplace control loose the focus)
                        if (_selectedPropertyEnum.Property.InPlaceCtrlInAction == null)
                            HideInPlaceControl();
                    }
                    else
                    {
                        if ((((ContainerControl)TopLevelControl).ActiveControl == _parentCtrl) &&
                            (e is FocusEventArgs) && ((FocusEventArgs)e).LeaveKey)
                        {
                            _parentCtrl.ActiveControl = this;
                        }
                    }
                }
            }

            Invalidate();
        }

        /// <summary>
        /// Removes a property or category from the PropertyGrid.
        /// </summary>
        /// <param name="propEnum">An enumerator to the property or category being removed.</param>
        /// <remarks> If the property or category being removed has descendants, they are all removed.</remarks>
        public void DeleteProperty(PropertyEnumerator propEnum)
        {
            DeletePropertyInternal(propEnum);
            
            if (IsHandleCreated)
            {
                // We call OnSizeChanged here because this method checks to see if there
                // is some space left at the bottom of the grid and scrolls it accordingly.
                // It also calls CheckScrollbar()
                Rectangle rect = ClientRectangle;
                OnSizeChanged(rect.Width, rect.Height);

                Invalidate();
            }
        }

        internal void DeletePropertyInternal(PropertyEnumerator propEnum)
        {
            if (_multiSelectMode != PropertyGrid.MultiSelectModes.None)
                _multiSelectedItems.Clear();

            bool changeSelect = (IsDescendantOf(_selectedPropertyEnum, propEnum) || (propEnum == _selectedPropertyEnum));
            bool changeFirstDisplayed = (IsDescendantOf(_firstDisplayedPropertyEnumerator, propEnum) || (propEnum == _firstDisplayedPropertyEnumerator));

            if (changeSelect)
            {
                // Unselect it before deletion
                SelectProperty(_categorizedPropertyCollection.GetVisibleDeepEnumerator().RightBound.GetVisibleDeepEnumerator());
            }

            PropertyEnumerator newEnumerator = _categorizedPropertyCollection.Delete(propEnum);

            if (changeFirstDisplayed)
                _firstDisplayedPropertyEnumerator = newEnumerator.GetVisibleDeepEnumerator();

            if (changeSelect)
                SelectProperty(newEnumerator.GetVisibleDeepEnumerator());

            InvalidateVisibleItemCount();
        }

        public PropertyEnumerator RightBound
        {
            get { return _activePropertyCollection.GetDeepEnumerator().RightBound; }
        }

        public PropertyEnumerator LeftBound
        {
            get { return _activePropertyCollection.GetDeepEnumerator().LeftBound; }
        }

        public PropertyEnumerator FirstProperty
        {
            get
            {
                PropertyEnumerator propEnum = _activePropertyCollection.GetDeepEnumerator();
                return propEnum.MoveFirst();
            }
        }

        public PropertyEnumerator LastProperty
        {
            get
            {
                PropertyEnumerator propEnum = _activePropertyCollection.GetDeepEnumerator();
                return propEnum.MoveLast();
            }
        }

        private void AssignValidator(PropertyEnumerator propEnum)
        {
            PropertyValue value = propEnum.Property.Value;

            // Try to find if the user specified a Validator for the property
            PropertyValidatorAttribute validatorAttr = (PropertyValidatorAttribute)value.GetAttribute(typeof(PropertyValidatorAttribute));
            if ((validatorAttr != null) && (validatorAttr.ChildPropertyName.Length == 0))
            {
                value.Validator = validatorAttr.Validator;
                value.Validator.Enumerator = propEnum;
            }
            else
            {
                // Try to find if the user specified a Validator for the property on its parent
                if ((propEnum.Parent.Property != null) && (propEnum.Parent.Property.Value != null))
                {
                    List<Attribute> attrs = propEnum.Parent.Property.Value.GetAttributes(typeof(PropertyValidatorAttribute));
                    foreach (PropertyValidatorAttribute attr in attrs)
                    {
                        if (attr.ChildPropertyName == propEnum.Property.DisplayName)
                        {
                            value.Validator = attr.Validator;
                            value.Validator.Enumerator = propEnum;
                        }
                    }
                }
            }
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            if (ToolTip != null)
                ToolTip.SetText("", null);
        }

        // When a property is not selected and a double-click is done in the value part, the inplace control is
        // first made visible and then a click is generated for him (in this.OnMouseDown). But the second click
        // is never treated as a double-click. That's why we hook the mouse messages so that we can generate this
        // lost message.
        public bool OnMouseHooked(IntPtr hWnd, uint message, Point pt, uint hitTest)
        {
            Control control = FromHandle(hWnd);
            if ((_currentInPlaceControl != null) && ((control == _currentInPlaceControl) || (_currentInPlaceControl.Contains(control))))
            {
                if (message == Win32Calls.WM_LBUTTONDOWN)
                {
                    if ((int)((DateTime.Now.Ticks - _lastTimeClickedFromParent) / 0x2710) < SystemInformation.DoubleClickTime)
                    {
                        bool removeMsg = false;
                        if ((Math.Abs(pt.X - _lastPosClickedInParent.X) < SystemInformation.DoubleClickSize.Width) &&
                            (Math.Abs(pt.Y - _lastPosClickedInParent.Y) < SystemInformation.DoubleClickSize.Height))
                        {
                            pt = _currentInPlaceControl.PointToClient(pt);
                            Win32Calls.PostMessage(control.Handle, Win32Calls.WM_LBUTTONDBLCLK, 0,
                                Win32Calls.MakeLong(pt.X, pt.Y));

                            removeMsg = true;
                        }

                        _lastPosClickedInParent = Point.Empty;
                        _lastTimeClickedFromParent = 0;
                        _mouseHook.HookMessages = false;

                        return removeMsg;
                    }
                }
            }

            return false;
        }

        private void ProcessDisable()
        {
            TabStop = true;

            if ((_disableMode & PropertyGrid.DisableModes.NoPropertySelection) != 0)
            {
                SelectProperty(RightBound);

                TabStop = false;

                if (ReadOnlyVisual == PropertyGrid.ReadOnlyVisuals.Disabled)
                    HideInPlaceControl();
            }
            else if ((_disableMode & PropertyGrid.DisableModes.NoValueSelection) != 0)
                HideInPlaceControl();
            else if ((_disableMode & PropertyGrid.DisableModes.Simple) != 0)
            {
                if (ReadOnlyVisual == PropertyGrid.ReadOnlyVisuals.Disabled)
                    HideInPlaceControl();
            }
        }
#if _XHEOSOURCECODE
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_license != null)
                {
                    _license.Dispose();
                    _license = null;
                }
            }
            base.Dispose(disposing);
        }
#endif
    }
}
