using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Media;
using System.Windows.Forms;
using DevComponents.DotNetBar.SuperGrid.Style;
namespace DevComponents.DotNetBar.SuperGrid
{
    /// 
    /// Defines Grid element with Items collection
    /// 
    public abstract class GridContainer : GridElement, IDisposable
    {
        #region Private variables
        private GridItemsCollection _Rows;
        private Cs _States;
        private int _Index;
        private int _FullIndex;
        private int _RowIndex;
        private int _GridIndex;
        private int _IndentLevel;
        private Rectangle _CheckBoxBounds;
        private Rectangle _ContainerBounds;
        private GridElement _MouseOverElement;
        private int _FixedRowHeight;
        private int _FixedHeaderHeight;
        private int _FirstOnScreenRowIndex;
        private ushort _DeleteUpdateCount;
        private ushort _ExpandedUpdateCount;
        private ushort _SelectionUpdateCount;
        private ushort _SelectionClearCount;
        private ushort _StyleUpdateCount;
        private ushort _MergeUpdateCount = 1;
        private RowVisualStyles _RowStyles;
        private RowVisualStyles _EffectiveRowStyles;
        private CellVisualStyles _CellVisualStyles;
        private string _RowHeaderText = "";
        private List _DisplayedCellRanges;
        private CellRange _LastCellRange;
        private int _DisplayedMergeLayoutCount;
        private bool _NeedMergeLayout;
        private MergeScan _MergeScan;
        private CellRange _SuspendedRange;
        #endregion
        #region Abstract methods
        /// 
        /// Creates the GridItemsCollection that hosts the items.
        /// 
        /// New instance of GridItemsCollection.
        protected abstract GridItemsCollection CreateItemsCollection();
        /// 
        /// Disposes of the GridItemsCollection that hosts the items.
        /// 
        protected abstract void DisposeItemsCollection(GridItemsCollection items);
        #endregion
        #region Public properties
        #region Bounds
        ///
        /// Gets the scroll adjusted bounds
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Rectangle Bounds
        {
            get
            {
                Rectangle r = BoundsRelative;
                r.X -= HScrollOffset;
                if (IsVFrozen == false)
                    r.Y -= VScrollOffset;
                return (r);
            }
        }
        #endregion
        #region CellStyles
        /// 
        /// Gets or sets the default Cell visual styles
        /// 
        [Category("Style")]
        [Description("Indicates the default Cell visual styles.")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public CellVisualStyles CellStyles
        {
            get
            {
                if (_CellVisualStyles == null)
                {
                    _CellVisualStyles = new CellVisualStyles();
                    UpdateChangeHandler(null, _CellVisualStyles);
                }
                return (_CellVisualStyles);
            }
            set
            {
                if (_CellVisualStyles != value)
                {
                    CellVisualStyles oldValue = _CellVisualStyles;
                    _CellVisualStyles = value;
                    OnStyleChanged("CellVisualStyles", oldValue, value);
                    if (oldValue != null)
                        oldValue.Dispose();
                }
            }
        }
        #endregion
        #region Checked
        ///
        /// Gets or sets the row CheckBox checked state
        ///
        [DefaultValue(false), Category("Appearance")]
        [Description("Indicates the row CheckBox checked state.")]
        public virtual bool Checked
        {
            get { return (TestState(Cs.Checked)); }
            set
            {
                if (Checked != value)
                {
                    SetState(Cs.Checked, value);
                    OnCheckedChanged();
                }
            }
        }
        #region OnCheckedChanged
        private void OnCheckedChanged()
        {
            GridPanel panel = GridPanel;
            if (panel != null)
            {
                if (HasCheckBox == true)
                {
                    Rectangle r = _CheckBoxBounds;
                    if (panel.IsSubPanel == true ||
                        (panel.PrimaryColumn != null && panel.PrimaryColumn.IsHFrozen == false))
                    {
                        r.X -= HScrollOffset;
                    }
                    if (IsVFrozen == false)
                        r.Y -= VScrollOffset;
                    InvalidateRender(r);
                }
                OnPropertyChanged("Checked");
                SuperGrid.DoAfterCheckEvent(panel, this);
            }
        }
        #endregion
        #endregion
        #region DisplayedRowCount
        ///
        /// Gets the count of visible rows on screen
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int DisplayedRowCount 
        {
            get
            {
                GridPanel panel = GridPanel;
                if (panel != null)
                {
                    GridContainer frow = FirstOnScreenRow;
                    GridContainer lrow = LastOnScreenRow;
                    if (frow != null && lrow != null)
                        return (lrow.GridIndex - frow.GridIndex + 1);
                }
                return (0);
            }
        }
        #endregion
        #region Expanded
        ///
        /// Gets or sets whether the row is
        /// expanded, permitting its child rows to be visible
        ///
        [DefaultValue(false), Category("Appearance")]
        [Description("Indicates whether the row is expanded, permitting its child rows to be visible.")]
        public bool Expanded
        {
            get { return (TestState(Cs.Expanded)); }
            set
            {
                if (Expanded != value)
                {
                    SetExpanded(value, ExpandSource.Expand);
                    OnPropertyChangedEx("Expanded", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region FirstOnScreenRow
        ///
        /// Gets the first visible row on screen
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public GridContainer FirstOnScreenRow
        {
            get
            {
                GridPanel panel = GridPanel;
                if (panel != null)
                {
                    int index = FirstOnScreenRowIndex;
                    if (panel.VirtualMode == true)
                    {
                        if (index < panel.VirtualRowCountEx)
                            return (panel.VirtualRows[index]);
                    }
                    else
                    {
                        if ((uint)index < Rows.Count)
                        {
                            GridContainer row = panel.Rows[index] as GridContainer;
                            if (row != null && row.Visible == true)
                            {
                                if (row.Expanded == true && row.Rows.Count > 0)
                                {
                                    GridContainer roe =
                                        GetFirstOnScreenRow(row.Rows, SuperGrid.ViewRect);
                                    if (roe != null)
                                        return (roe);
                                }
                                return (row);
                            }
                        }
                    }
                }
                return (null);
            }
            set
            {
                if (value != null)
                    value.ScrollToTop();
            }
        }
        #endregion
        #region FirstOnScreenRowIndex
        ///
        /// Gets the first visible on screen row index
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int FirstOnScreenRowIndex
        {
            get
            {
                GridPanel panel = GridPanel;
                if (panel != null)
                {
                    if ((VScrollOffset == 0 && panel.IsFiltered == false && panel.DeletedRowCount == 0) || 
                        (Parent != null && IsVFrozen == true))
                    {
                        _FirstOnScreenRowIndex = 0;
                    }
                    else
                    {
                        Rectangle r = SuperGrid.ViewRect;
                        _FirstOnScreenRowIndex = (panel.VirtualMode == true)
                             ? GetFirstOnScreenVirtualRowIndex(panel)
                             : GetFirstOnScreenRealRowIndex(r);
                    }
                }
                if (panel.VirtualMode == true)
                {
                    if (_FirstOnScreenRowIndex >= panel.VirtualRowCount)
                        _FirstOnScreenRowIndex = 0;
                }
                else
                {
                    if (_FirstOnScreenRowIndex >= Rows.Count)
                        _FirstOnScreenRowIndex = 0;
                }
                return (_FirstOnScreenRowIndex);
            }
            set
            {
                GridPanel panel = GridPanel;
                if (panel.VirtualMode == true)
                {
                    if ((uint)value < panel.VirtualRowCount)
                        FirstOnScreenRow = panel.VirtualRows[value];
                }
                else
                {
                    if ((uint)value < Rows.Count)
                        FirstOnScreenRow = Rows[value] as GridContainer;
                }
            }
        }
        #region GetFirstOnScreenVirtualRow
        private int GetFirstOnScreenVirtualRowIndex(GridPanel panel)
        {
            Rectangle r = BoundsRelative;
            int vrh = Dpi.Height(panel.VirtualRowHeight);
            r.Y += (FixedRowHeight - panel.FrozenRowCount * vrh);
            int y = VScrollOffset;
            if (Parent == null)
                y += (panel.FrozenRowCount * vrh);
            else
                y = (y - r.Y) + SuperGrid.PrimaryGrid.FixedRowHeight;
            int n = y / vrh - 0;
            return (n > 0 ? n : 0);
        }
        #endregion
        #region GetFirstOnScreenRealRowIndex
        private int GetFirstOnScreenRealRowIndex(Rectangle r)
        {
            int lo = 0;
            int hi = Rows.Count - 1;
            while (lo < hi)
            {
                int mid = (lo + hi) / 2;
                GridElement item = Rows[mid];
                Rectangle t = item is GridPanel ? ((GridPanel)item).ContainerBounds : item.BoundsRelative;
                if (item.IsVFrozen == false)
                    t.Y -= VScrollOffset;
                if (t.Bottom > r.Y)
                {
                    if (t.Y <= r.Y)
                    {
                        if (item.Visible == true)
                            return (mid);
                    }
                    hi = mid - 1;
                }
                else
                {
                    lo = mid + 1;
                }
            }
            while (lo < Rows.Count)
            {
                if (Rows[lo].Visible == true)
                    break;
                lo++;
            }
            return (lo);
        }
        #endregion
        #endregion
        #region GetFirstOnScreenRow
        private GridContainer
            GetFirstOnScreenRow(GridItemsCollection items, Rectangle t)
        {
            for (int i = 0; i < items.Count; i++)
            {
                GridContainer item = items[i] as GridContainer;
                if (item != null)
                {
                    Rectangle r = item.BoundsRelative;
                    if (item.IsVFrozen == false)
                        r.Y -= VScrollOffset;
                    if (r.Bottom > t.Top)
                    {
                        if (item.Expanded == true && item.Rows.Count > 0)
                        {
                            GridContainer row = GetFirstOnScreenRow(item.Rows, t);
                            return (row ?? item);
                        }
                        return (item);
                    }
                }
            }
            return (null);
        }
        #endregion
        #region FirstSelectableRow
        ///
        /// Gets the first selectable row
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public GridContainer FirstSelectableRow
        {
            get
            {
                GridPanel panel = GridPanel;
                if (panel != null)
                {
                    if (panel.VirtualMode == true)
                    {
                        if (panel.VirtualRowCountEx > 0)
                            return (panel.VirtualRows[0]);
                    }
                    else
                    {
                        foreach (GridContainer row in panel.Rows)
                        {
                            if (row.Visible == true && row.AllowSelection == true)
                                return (row);
                        }
                    }
                }
                return (null);
            }
        }
        #endregion
        #region FirstVisibleRow
        ///
        /// Gets the first visible row
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public GridContainer FirstVisibleRow
        {
            get
            {
                GridPanel panel = GridPanel;
                if (panel != null)
                {
                    if (panel.VirtualMode == true)
                    {
                        if (panel.VirtualRowCountEx > 0)
                            return (panel.VirtualRows[0]);
                    }
                    else
                    {
                        foreach (GridContainer row in panel.Rows)
                        {
                            if (row.Visible == true)
                                return (row);
                        }
                    }
                }
                return (null);
            }
        }
        #endregion
        #region FullIndex
        ///
        /// Gets the sequential index for the row
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int FullIndex
        {
            get
            {
                CheckIndicees();
                return (_FullIndex);
            }
            internal set { _FullIndex = value; }
        }
        #endregion
        #region GridIndex
        ///
        /// Gets the sequential index for the visible, expanded row
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int GridIndex
        {
            get
            {
                CheckIndicees();
                return (_GridIndex); 
            }
            internal set { _GridIndex = value; }
        }
        #endregion
        #region Index
        ///
        /// Gets the sequential, visible, local container index for the item
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int Index
        {
            get
            {
                CheckIndicees();
                
                return (_Index);
            }
            internal set { _Index = value; }
        }
        #endregion
        #region IsActive
        ///
        /// Gets whether the item is Active
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool IsActive
        {
            get { return (this == SuperGrid.ActiveRow); }
        }
        #endregion
        #region IsDeleted
        ///
        /// Gets whether the item is deleted
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual bool IsDeleted
        {
            get
            {
                GridPanel panel = GetParentPanel();
                if (panel != null)
                {
                    if (_DeleteUpdateCount != panel.DeleteUpdateCount)
                    {
                        SetState(Cs.Deleted, panel.IsRowDeleted(this));
                        _DeleteUpdateCount = panel.DeleteUpdateCount;
                    }
                }
                    
                return (TestState(Cs.Deleted));
            }
            set
            {
                SetState(Cs.Deleted, value);
                GridPanel panel = GetParentPanel();
                if (panel != null)
                {
                    if (panel.SetDeleted(this, value) == true)
                        _DeleteUpdateCount = panel.DeleteUpdateCount;
                }
            }
        }
        #endregion
        #region IsExpandedVisible
        ///
        /// Gets whether the item is visible
        /// and its parental hierarchy is expanded
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool IsExpandedVisible
        {
            get
            {
                if (Visible == false)
                    return (false);
                GridContainer row = Parent as GridContainer;
                while (row != null)
                {
                    if (row.Visible == false)
                        return (false);
                    if (row is GridPanel == false)
                    {
                        if (row.Expanded == false)
                            return (false);
                    }
                    row = row.Parent as GridContainer;
                }
                return (true);
            }
        }
        #endregion
        #region IsOnScreen
        ///
        /// Gets whether the item is visible on screen
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool IsOnScreen
        {
            get
            {
                if (Visible == true)
                {
                    GridPanel panel = GridPanel;
                    if (panel != null)
                    {
                        Rectangle t = SViewRect;
                        Rectangle bounds = Bounds;
                        bounds.Width = panel.ColumnHeader.BoundsRelative.Width;
                        return (t.IntersectsWith(bounds));
                    }
                }
                return (false);
            }
        }
        #endregion
        #region IsSelectable
        ///
        /// Gets whether the row can be selected by the user.
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool IsSelectable
        {
            get { return (AllowSelection == true); }
        }
        #endregion
        #region IsSelected
        ///
        /// Gets or sets whether the item is selected
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool IsSelected
        {
            get
            {
                if (AllowSelection == true)
                {
                    GridPanel panel = GetParentPanel();
                    if (panel != null)
                    {
                        if ((_SelectionUpdateCount != panel.SelectionUpdateCount) ||
                            (_ExpandedUpdateCount != panel.ExpandedUpdateCount))
                        {
                            if (ExpandedVisible(panel) == true)
                                Selected = panel.IsItemSelectedEx(this);
                            _SelectionUpdateCount = panel.SelectionUpdateCount;
                        }
                        return (Selected);
                    }
                }
                return (false);
            }
            set
            {
                GridPanel panel = GetParentPanel();
                if (panel != null)
                {
                    if (Selected != value)
                    {
                        Selected = value;
                        if (ExpandedVisible(panel) == true)
                            panel.SetSelectedEx(this, value);
                        _SelectionUpdateCount = panel.SelectionUpdateCount;
                        Rectangle r = ContainerBounds;
                        r.X -= HScrollOffset;
                        if (IsVFrozen == false)
                            r.Y -= VScrollOffset;
                        InvalidateRender(r);
                    }
                }
            }
        }
        #region ExpandedVisible
        internal bool ExpandedVisible(GridPanel panel)
        {
            if (_ExpandedUpdateCount != panel.ExpandedUpdateCount)
            {
                _ExpandedUpdateCount = panel.ExpandedUpdateCount;
                SetState(Cs.ExpandedVisible, IsExpandedVisible);
            }
            return (TestState(Cs.ExpandedVisible));
        }
        #endregion
        #endregion
        #region LastOnScreenRow
        ///
        /// Gets the last visible on screen row
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public GridContainer LastOnScreenRow
        {
            get
            {
                GridPanel panel = GridPanel;
                if (panel != null)
                {
                    if (panel.VirtualMode == true)
                    {
                        int index = LastOnScreenRowIndex;
                        if (index < panel.VirtualRowCountEx)
                            return (panel.VirtualRows[index]);
                    }
                    else
                    {
                        if (IsExpandedVisible == true)
                            return (GetLastOnScreenRow(panel.Rows, SuperGrid.ViewRect));
                    }
                }
                return (null);
            }
            set
            {
                if (value != null)
                    value.ScrollToBottom();
            }
        }
        #region GetLastOnScreenRow
        private GridContainer
            GetLastOnScreenRow(GridItemsCollection items, Rectangle t)
        {
            GridContainer lrow = null;
            for (int i = 0; i < items.Count; i++)
            {
                GridContainer item = items[i] as GridContainer;
                if (item != null && item.Visible == true)
                {
                    lrow = item;
                    Rectangle r = item.BoundsRelative;
                    if (item.IsVFrozen == false)
                        r.Y -= VScrollOffset;
                    if (r.Bottom >= t.Bottom || i == items.Count - 1)
                    {
                        if (item.Expanded == true && item.Rows.Count > 0)
                        {
                            GridContainer row = GetLastOnScreenRow(item.Rows, t);
                            return (row ?? item);
                        }
                        return (item);
                    }
                }
            }
            return (lrow);
        }
        #endregion
        #endregion
        #region LastOnScreenRowIndex
        ///
        /// Gets the last visible on screen row index
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int LastOnScreenRowIndex
        {
            get
            {
                if (IsExpandedVisible == true)
                {
                    GridPanel panel = GridPanel;
                    if (panel != null)
                    {
                        Rectangle t = SuperGrid.ViewRect;
                        return (panel.VirtualMode == true)
                                   ? (GetLastOnScreenVirtualRowIndex(panel, t))
                                   : (GetLastOnScreenRealRowIndex(panel, t));
                    }
                }
                return (0);
            }
            set
            {
                GridPanel panel = GridPanel;
                if (panel.VirtualMode == true)
                {
                    if ((uint)value < panel.VirtualRowCount)
                        LastOnScreenRow = panel.VirtualRows[value];
                }
                else
                {
                    if ((uint)value < Rows.Count)
                        LastOnScreenRow = Rows[value] as GridContainer;
                }
            }
        }
        #region GetLastOnScreenVirtualRowIndex
        private int GetLastOnScreenVirtualRowIndex(
            GridPanel panel, Rectangle t)
        {
            int index = FirstOnScreenRowIndex;
            GridRow row = panel.VirtualRows[index];
            int vrh = Dpi.Height(panel.VirtualRowHeight);
            Rectangle r = row.BoundsRelative;
            r.Y -= VScrollOffset;
            int n = (t.Bottom - r.Top + vrh - 1) / vrh;
            return (Math.Min(panel.VisibleRowCount - 1, index + n - 1));
        }
        #endregion
        #region GetLastOnScreenRealRowIndex
        private int GetLastOnScreenRealRowIndex(GridPanel panel, Rectangle t)
        {
            int index = FirstOnScreenRowIndex;
            while (index + 1 < Rows.Count)
            {
                index++;
                GridContainer item = (GridContainer)panel.Rows[index];
                Rectangle r = item.BoundsRelative;
                if (item.IsVFrozen == false)
                    r.Y -= VScrollOffset;
                if (r.Bottom >= t.Bottom)
                    return (index);
            }
            return (index);
        }
        #endregion
        #endregion
        #region LastSelectableRow
        ///
        /// Gets the last user selectable row
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public GridContainer LastSelectableRow
        {
            get
            {
                GridPanel panel = GridPanel;
                if (panel != null)
                {
                    if (panel.VirtualMode == true)
                    {
                        if (panel.VirtualRowCountEx > 0)
                            return (panel.VirtualRows[panel.VirtualRowCountEx - 1]);
                    }
                    else
                    {
                        return (GetLastSelectableRow(panel.Rows));
                    }
                }
                return (null);
            }
        }
        #region GetLastSelectableRow
        private GridContainer GetLastSelectableRow(GridItemsCollection rows)
        {
            for (int i = rows.Count - 1; i >= 0; i--)
            {
                GridContainer row = rows[i] as GridContainer;
                if (row != null)
                {
                    if (row.Visible == true && row.AllowSelection == true)
                    {
                        if (row.Rows.Count > 0 && row.Expanded == true)
                        {
                            GridContainer srow = GetLastSelectableRow(row.Rows);
                            if (srow != null)
                                row = srow;
                        }
                        return (row);
                    }
                }
            }
            return (null);
        }
        #endregion
        #endregion
        #region LastVisibleRow
        ///
        /// Gets the last visible row
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public GridContainer LastVisibleRow
        {
            get
            {
                GridPanel panel = GridPanel;
                if (panel != null)
                {
                    if (panel.VirtualMode == true)
                    {
                        if (panel.VirtualRowCountEx > 0)
                            return (panel.VirtualRows[panel.VirtualRowCountEx - 1]);
                    }
                    else
                    {
                        for (int i = panel.Rows.Count - 1; i >= 0;  i--)
                        {
                            GridContainer row = panel.Rows[i] as GridContainer;
                            if (row != null)
                            {
                                if (row.Visible == true)
                                    return (row);
                            }
                        }
                    }
                }
                return (null);
            }
        }
        #endregion
        #region NextVisibleRow
        ///
        /// Gets the next visible row, or null if no
        /// subsequent rows are defined
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public GridContainer NextVisibleRow
        {
            get
            {
                GridPanel panel = GetParentPanel();
                if (panel != null)
                {
                    int index = GridIndex + 1;
                    GridElement item = panel.GetRowFromIndex(index);
                    while (item != null)
                    {
                        if (ItemIsSelectable(panel, item) == true)
                            return ((GridContainer) item);
                        item = panel.GetRowFromIndex(++index);
                    }
                }
                return (null);
            }
        }
        private bool ItemIsSelectable(GridPanel panel, GridElement item)
        {
            if (item.Visible == false)
                return (false);
            
            if (item is GridGroup && panel.GroupHeaderKeyBehavior != GroupHeaderKeyBehavior.Select)
                return (false);
            return (item is GridContainer);
        }
        #endregion
        #region PrevVisibleRow
        ///
        /// Gets the previous visible row, or null if
        /// no previous rows are defined
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public GridContainer PrevVisibleRow
        {
            get
            {
                GridPanel panel = GetParentPanel();
                if (panel != null)
                {
                    int index = GridIndex;
                    while (--index >= 0)
                    {
                        GridElement item = panel.GetRowFromIndex(index);
                        if (item == null)
                            break;
                        if (ItemIsSelectable(panel, item) == true)
                            return ((GridContainer)item);
                    }
                }
                return (null);
            }
        }
        #endregion
        #region ReadOnly
        /// 
        /// Gets or sets whether the user can change the row contents
        /// 
        [DefaultValue(false), Category("Behavior")]
        [Description("Indicates whether the user can change the row contents.")]
        public bool ReadOnly
        {
            get { return (TestState(Cs.ReadOnly)); }
            set
            {
                if (value != ReadOnly)
                {
                    SetState(Cs.ReadOnly, value);
                    OnPropertyChangedEx("ReadOnly", VisualChangeType.Render);
                }
            }
        }
        #endregion
        #region RowHeaderText
        ///
        /// Gets or sets the associated row header text.
        ///
        [DefaultValue(""), Category("Appearance")]
        [Description("Indicates the associated row header text.).")]
        public string RowHeaderText
        {
            get { return (_RowHeaderText); }
            set
            {
                if (_RowHeaderText != value)
                {
                    _RowHeaderText = value;
                    NeedsMeasured = true;
                    OnPropertyChangedEx("RowHeaderText", VisualChangeType.Render);
                }
            }
        }
        #endregion
        #region RowIndex
        ///
        /// Gets the sequential, parental index of the item
        ///
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int RowIndex
        {
            get
            {
                CheckIndicees();
                return (_RowIndex);
            }
            internal set { _RowIndex = value; }
        }
        #region CheckIndicees
        private void CheckIndicees()
        {
            GridPanel panel = GridPanel;
            if (panel != null)
                panel.UpdateIndicees(panel, panel.Rows, true);
        }
        #endregion
        #endregion
        #region Rows
        /// 
        /// Gets the reference to the Rows collection
        /// 
        [DefaultValue(null), Category("Data")]
        [Description("Indicates the reference to the Rows collection.")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public virtual GridItemsCollection Rows
        {
            get
            {
                if (_Rows == null)
                    _Rows = CreateItemsCollection();
                return (_Rows);
            }
            set
            {
                if (_Rows != null)
                    DisposeItemsCollection(_Rows);
                _Rows = value;
            }
        }
        #endregion
        #region RowsUnresolved
        ///
        /// Gets or sets whether the rows collection is unknown and has not
        /// been resolved (presumes there are rows until set to false)
        ///
        [DefaultValue(false), Category("Data")]
        [Description("Indicates whether the rows collection is unresolved (presumes there are rows until set to false).")]
        public bool RowsUnresolved
        {
            get { return (TestState(Cs.RowsUnresolved)); }
            set
            {
                if (RowsUnresolved != value)
                {
                    SetState(Cs.RowsUnresolved, value);
                    OnPropertyChangedEx("RowsUnresolved", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region RowStyles
        /// 
        /// Gets or sets the visual styles assigned to the row elements
        /// 
        [Category("Style")]
        [Description("Indicates visual style assigned to the row elements")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public RowVisualStyles RowStyles
        {
            get
            {
                if (_RowStyles == null)
                {
                    _RowStyles = new RowVisualStyles();
                    UpdateChangeHandler(null, _RowStyles);
                }
                return (_RowStyles);
            }
            set
            {
                if (_RowStyles != value)
                {
                    RowVisualStyles oldValue = _RowStyles;
                    _RowStyles = value;
                    OnStyleChanged("RowStyles", oldValue, value);
                    if (oldValue != null)
                        oldValue.Dispose();
                }
            }
        }
        #endregion
        #region ShowCheckBox
        /// 
        /// Get or sets whether the row CheckBox is shown (Panel.CheckBoxes must also be true)
        /// 
        [DefaultValue(true), Category("Appearance")]
        [Description("Indicates whether the row CheckBox is shown (Panel.CheckBoxes must also be true).")]
        public bool ShowCheckBox
        {
            get { return (TestState(Cs.ShowCheckBox)); }
            set
            {
                if (ShowCheckBox != value)
                {
                    SetState(Cs.ShowCheckBox, value);
                    NeedsMeasured = true;
                    OnPropertyChangedEx("ShowCheckBox", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #region ShowTreeButton
        /// 
        /// Gets or sets whether expand / collapse
        /// buttons are shown if the row contains nested items 
        /// 
        [DefaultValue(true), Category("Appearance")]
        [Description("Indicates whether Tree expand / collapse buttons are shown if the row contains nested items.")]
        public bool ShowTreeButton
        {
            get { return (TestState(Cs.ShowTreeButton)); }
            set
            {
                if (ShowTreeButton != value)
                {
                    SetState(Cs.ShowTreeButton, value);
                    OnPropertyChangedEx("ShowTreeButton", VisualChangeType.Layout);
                }
            }
        }
        #endregion
        #endregion
        #region Constructors
        /// 
        /// GridContainer
        /// 
        protected GridContainer()
        {
            SetState(Cs.ShowCheckBox, true);
            SetState(Cs.ShowTreeButton, true);
        }
        #endregion
        #region Internal properties
        #region CanModify
        internal virtual bool CanModify
        {
            get
            {
                GridPanel panel = GridPanel;
                if (panel != null)
                {
                    if (panel.ReadOnly == true)
                        return (false);
                }
                return (ReadOnly == false && IsDeleted == false);
            }
        }
        #endregion
        #region CheckBoxBounds
        internal Rectangle CheckBoxBounds
        {
            get { return (_CheckBoxBounds); }
            set { _CheckBoxBounds = value; }
        }
        #endregion
        #region ContainerBounds
        internal Rectangle ContainerBounds
        {
            get { return (_ContainerBounds); }
            set { _ContainerBounds = value; }
        }
        #endregion
        #region DisplayedCellRanges
        internal List DisplayedCellRanges
        {
            get { return (_DisplayedCellRanges); }
            set { _DisplayedCellRanges = value; }
        }
        #endregion
        #region DisplayedMergeLayoutCount
        internal int DisplayedMergeLayoutCount
        {
            get { return (_DisplayedMergeLayoutCount); }
            set { _DisplayedMergeLayoutCount = value; }
        }
        #endregion
        #region FixedHeaderHeight
        /// 
        /// Get or sets the FixedHeaderHeight
        /// 
        internal int FixedHeaderHeight
        {
            get { return (_FixedHeaderHeight); }
            set { _FixedHeaderHeight = value; }
        }
        #endregion
        #region FixedRowHeight
        /// 
        /// Get or sets the FixedRowHeight
        /// 
        internal int FixedRowHeight
        {
            get { return (_FixedRowHeight); }
            set { _FixedRowHeight = value; }
        }
        #endregion
        #region HasCheckBox
        internal bool HasCheckBox
        {
            get
            {
                GridPanel ppanel = GetParentPanel();
                if (ppanel != null)
                {
                    if (ppanel.CheckBoxes != true)
                        return (false);
                }
                return (ShowCheckBox);
            }
        }
        #endregion
        #region HasVisibleItems
        internal bool HasVisibleItems
        {
            get { return (TestState(Cs.HasVisibleItems)); }
            set { SetState(Cs.HasVisibleItems, value); }
        }
        #endregion
        #region IndentLevel
        /// 
        /// Get or sets the panel indent level
        /// 
        internal int IndentLevel
        {
            get { return (_IndentLevel); }
            set { _IndentLevel = value; }
        }
        #endregion
        #region IsActiveRow
        internal bool IsActiveRow
        {
            get
            {
                GridPanel panel = GridPanel;
                return (panel.ActiveRow != null &&
                    panel.ActiveRow.GridIndex == GridIndex);
            }
        }
        #endregion
        #region IsDeletedEx
        internal bool IsDeletedEx
        {
            get { return (TestState(Cs.Deleted)); }
            set { IsDeleted = value; }
        }
        #endregion
        #region IsMergeSuspended
        internal bool IsMergeSuspended
        {
            get { return (_SuspendedRange != null); }
        }
        #endregion
        #region MaxRowIndex
        internal int MaxRowIndex
        {
            get
            {
                GridPanel panel = this as GridPanel;
                if (panel != null && panel.VirtualMode == true)
                    return (panel.VirtualRowCountEx - 1);
                return (Rows.Count - 1);
            }
        }
        #endregion
        #region MergeUpdateCount
        internal ushort MergeUpdateCount
        {
            get { return (_MergeUpdateCount); }
            set { _MergeUpdateCount = value; }
        }
        #endregion
        #region MergeScan
        internal MergeScan MergeScan
        {
            get
            {
                if (_MergeScan == null)
                    _MergeScan = new MergeScan(this);
                return (_MergeScan);
            }
            set { _MergeScan = value; }
        }
        #endregion
        #region MouseOverElement
        internal GridElement MouseOverElement
        {
            get { return (_MouseOverElement); }
        }
        #endregion
        #region NeedMergeLayout
        internal bool NeedMergeLayout
        {
            get { return (_NeedMergeLayout); }
            set { _NeedMergeLayout = value; }
        }
        #endregion
        #region Selected
        internal bool Selected
        {
            get
            {
                if (AllowSelection == false)
                    return (false);
                GridPanel panel = GetParentPanel();
                if (panel != null)
                {
                    if (_SelectionClearCount != panel.SelectionClearCount)
                    {
                        _SelectionClearCount = panel.SelectionClearCount;
                        Selected = false;
                        if (ExpandedVisible(panel) == true)
                            panel.SetSelectedEx(this, false);
                        InvalidateRender();
                    }
                }
                return (TestState(Cs.Selected));
            }
            set
            {
                SetState(Cs.Selected, value);
                GridPanel panel = GetParentPanel();
                if (panel != null)
                    _SelectionClearCount = panel.SelectionClearCount;
            }
        }
        #endregion
        #region SelectionClearCount
        internal ushort SelectionClearCount
        {
            get { return (_SelectionClearCount); }
            set { _SelectionClearCount = value; }
        }
        #endregion
        #region SuspendedRange
        /// 
        /// Get or sets the current suspended range
        /// 
        internal CellRange SuspendedRange
        {
            get { return (_SuspendedRange); }
            set { _SuspendedRange = value; }
        }
        #endregion
        #endregion
        #region TestState
        private bool TestState(Cs state)
        {
            return ((_States & state) == state);
        }
        #endregion
        #region SetState
        private void SetState(Cs state, bool value)
        {
            if (value == true)
                _States |= state;
            else
                _States &= ~state;
        }
        #endregion
        #region GetVisibleItemCount
        internal int GetVisibleItemCount()
        {
            int n = 0;
            if (Expanded == true)
            {
                foreach (GridElement item in Rows)
                {
                    if (item.Visible == true)
                    {
                        n++;
                        GridContainer row = item as GridContainer;
                        if (row != null)
                        {
                            if (row.Rows.Count > 0 && row.Expanded == true)
                                n += row.GetVisibleItemCount();
                        }
                    }
                }
            }
            return (n);
        }
        #endregion
        #region GetNextItem
        internal GridContainer GetNextItem()
        {
            GridContainer container = Parent as GridContainer;
            if (container != null)
            {
                GridPanel panel = container as GridPanel;
                if (panel != null && panel.VirtualMode == true)
                {
                    GridRow row = this as GridRow;
                    if (row != null)
                    {
                        int n = row.GridIndex + 1;
                        if (n < panel.VirtualRowCountEx)
                            return (panel.VirtualRows[n]);
                    }
                }
                else
                {
                    int index = RowIndex;
                    if (index >= 0)
                    {
                        for (int i = index + 1; i < container.Rows.Count; i++)
                        {
                            GridContainer item = container.Rows[i] as GridContainer;
                            if (item != null && item.Visible == true)
                                return (item);
                        }
                    }
                }
            }
            return (null);
        }
        #endregion
        #region GetPrevItem
        internal GridContainer GetPrevItem()
        {
            GridContainer container = Parent as GridContainer;
            if (container != null)
            {
                GridPanel panel = container as GridPanel;
                if (panel != null && panel.VirtualMode == true)
                {
                    GridRow row = this as GridRow;
                    if (row != null)
                    {
                        int n = row.GridIndex - 1;
                        if (n >= 0)
                            return (panel.VirtualRows[n]);
                    }
                }
                else
                {
                    for (int i = Index - 1; i >= 0; i--)
                    {
                        GridContainer item = container.Rows[i] as GridContainer;
                        if (item != null && item.Visible == true)
                            return (item);
                    }
                }
            }
            return (null);
        }
        #endregion
        #region FindGridPanel
        ///
        /// Finds the GridPanel with the given Name.
        /// Only the root Rows collection is searched.
        ///
        ///GridPanel, or null if not found.
        public GridPanel FindGridPanel(string name)
        {
            return (FindGridPanel(name, false));
        }
        ///
        /// Finds the GridPanel with the given Name.
        /// Nested Rows are searched if 'includeNested' is true.
        ///
        ///Name to search
        ///Whether to include nested rows in the search.
        ///GridPanel, or null if not found.
        public GridPanel FindGridPanel(string name, bool includeNested)
        {
            GridItemsCollection items = Rows;
            foreach (GridElement item in items)
            {
                GridPanel panel = item as GridPanel;
                if (panel != null)
                {
                    if (panel.Name != null && panel.Name.Equals(name))
                        return (panel);
                }
            }
            if (includeNested == true)
            {
                foreach (GridElement item in items)
                {
                    GridContainer container = item as GridContainer;
                    if (container != null)
                    {
                        GridPanel panel = container.FindGridPanel(name, true);
                        if (panel != null)
                            return (panel);
                    }
                }
            }
            return (null);
        }
        #endregion
        #region SetExpanded
        private void SetExpanded(bool value, ExpandSource source)
        {
            GridPanel panel = GridPanel;
            if (panel != null)
            {
                panel.FlushActiveRow();
                if (Expanded == false)
                {
                    bool dynanic = RowsUnresolved;
                    if (SuperGrid == null ||
                        SuperGrid.DoBeforeExpandEvent(panel, this, source) == false)
                    {
                        ProcessExpandChange(panel, value);
                        if (dynanic == true && RowsUnresolved == false)
                        {
                            if (panel.SortColumns.Count > 0)
                                panel.NeedsSorted = true;
                        }
                        if (SuperGrid != null)
                            SuperGrid.DoAfterExpandEvent(panel, this, source);
                    }
                }
                else
                {
                    if (SuperGrid == null ||
                        SuperGrid.DoBeforeCollapseEvent(panel, this, source) == false)
                    {
                        ProcessExpandChange(panel, value);
                        if (SuperGrid != null)
                            SuperGrid.DoAfterCollapseEvent(panel, this, source);
                    }
                }
            }
            else
            {
                SetState(Cs.Expanded, value);
            }
        }
        #region ProcessExpandChange
        private void ProcessExpandChange(GridPanel panel, bool value)
        {
            if (value == true)
                SetState(Cs.Expanded, true);
            //if (SuperGrid.IsUpdateSuspended == false)
            {
                int index = GridIndex;
                int count = GetVisibleItemCount();
                panel.ExpandSelectedAtIndex(index + 1, count, value);
                if (value == false)
                    SetState(Cs.Expanded, false);
                if (Parent is GridContainer)
                    ((GridContainer)Parent).InvalidateMerge();
            }
            //else
            //{
            //    if (value == false)
            //        SetState(Cs.Expanded, false);
            //}
            panel.ExpandedUpdateCount++;
        }
        #endregion
        #endregion
        #region ExpandItemTree
        /// 
        /// Expands the entire tree, as necessary, to display the given row.
        /// 
        /// 'true' if any expanding was actually performed
        public bool ExpandItemTree()
        {
            GridContainer row = Parent as GridContainer;
            bool expandChanged = false;
            while (row != null)
            {
                if (row is GridRow || row is GridGroup)
                {
                    if (row.Expanded == false)
                    {
                        if (row.Rows.Count > 0 || row.RowsUnresolved == true)
                        {
                            row.Expanded = true;
                            expandChanged = true;
                        }
                    }
                }
                row = row.Parent as GridContainer;
            }
            return (expandChanged);
        }
        #endregion
        #region ExpandAll
        ///
        /// Expands all rows in the Rows collection.
        ///
        public void ExpandAll()
        {
            ExpandAll(-1, true);
        }
        ///
        /// Expands all rows in the Rows collection to the provided depth.
        /// 
        /// If a depth is provided, then rows will be expanded only to the given depth.
        /// In other words, to expand only the first level of rows in the container, you would
        /// call ExpandAll(0). To expand the first level – as well as 2 levels under it,
        /// you would call ExpandAll(2).
        ///
        public void ExpandAll(int depth)
        {
            ExpandAll(depth, true);
        }
        private void ExpandAll(int depth, bool expand)
        {
            if (Rows.Count > 0)
            {
                SuperGrid.BeginUpdate();
                foreach (GridElement item in Rows)
                {
                    GridContainer row = item as GridContainer;
                    if (row != null)
                    {
                        if (row.Expanded != expand)
                            row.SetExpanded(expand, ExpandSource.ExpandAll);
                        if (depth != 0)
                            row.ExpandAll(depth - 1, expand);
                    }
                }
                SuperGrid.EndUpdate();
                InvalidateLayout();
                GridPanel.InvalidateMerge();
            }
        }
        #endregion
        #region CollapseAll
        ///
        /// Collapses all expanded rows.
        ///
        public void CollapseAll()
        {
            ExpandAll(-1, false);
        }
        ///
        /// Collapses all rows in the Rows collection to the provided depth.
        /// 
        /// If a depth is provided, then rows will be collapsed only to the given depth.
        /// In other words, to collapse only the first level of rows in the container, you would
        /// call CollapseAll(0). To collapse the first level – as well as 2 levels under it,
        /// you would call CollapseAll(2).
        ///
        public void CollapseAll(int depth)
        {
            ExpandAll(depth, false);
        }
        #endregion
        #region SetActive
        ///
        /// Makes the given row active
        ///
        ///true, if successful
        public bool SetActive()
        {
            return (SetActive(false));
        }
        ///
        /// Makes the given row active and
        /// optionally selects the given row
        ///
        ///true, if successful
        public bool SetActive(bool select)
        {
            GridPanel panel = GridPanel;
            if (panel != null)
            {
                if (panel.SetActiveRow(this) == true)
                {
                    if (select == true)
                    {
                        GridPanel.ClearAll();
                        IsSelected = true;
                        if (panel.SelectionRowAnchor == null)
                            panel.SelectionRowAnchor = this;
                    }
                    return (true);
                }
            }
            return (false);
        }
        #endregion
        #region EnsureVisible
        ///
        /// This routine will ensure that the row is visible on
        /// the screen.  If the row is not visible on screen, the
        /// view window will be scrolled to make it visible.  
        ///
        ///If 'true', the row will be centered on screen
        public override void EnsureVisible(bool center)
        {
            if (Visible == true)
            {
                GridPanel panel = GridPanel;
                if (ExpandItemTree() == true || FixedRowHeight <= 0 || panel.IsLayoutValid == false)
                    SuperGrid.ArrangeGrid();
                Rectangle t = SViewRect;
                Rectangle bounds = BoundsRelative;
                int fixedHeight = FixedRowHeight;
                if (panel.VirtualMode == true)
                {
                    int vrh = Dpi.Height(panel.VirtualRowHeight);
                    bounds = panel.BoundsRelative;
                    bounds.Y += (panel.FixedRowHeight - (panel.FrozenRowCount * vrh));
                    bounds.Y += (GridIndex * vrh);
                    fixedHeight = (this is GridRow) ? vrh : 0;
                }
                if (fixedHeight >= t.Height || bounds.Y - VScrollOffset < t.Y)
                {
                    int n = bounds.Y - t.Y;
                    if (center == false || fixedHeight >= t.Height)
                        SuperGrid.SetVScrollValue(n);
                    else
                        SuperGrid.SetVScrollValue(n - (t.Height - fixedHeight) / 2);
                }
                else if (bounds.Y - VScrollOffset > t.Bottom - fixedHeight)
                {
                    int n = bounds.Y - (t.Bottom - fixedHeight);
                    if (center == false)
                        SuperGrid.SetVScrollValue(n);
                    else
                        SuperGrid.SetVScrollValue(n + (t.Height - fixedHeight) / 2);
                }
            }
        }
        #endregion
        #region ScrollToTop
        /// 
        /// Scrolls the row to the 'logical' top of the grid display.
        /// 
        public void ScrollToTop()
        {
            if (Visible == true)
            {
                if (IsVFrozen == false)
                {
                    if (ExpandItemTree() == true)
                        SuperGrid.ArrangeGrid();
                    Rectangle t = SViewRect;
                    Rectangle bounds = BoundsRelative;
                    GridPanel panel = GridPanel;
                    if (panel.VirtualMode == true)
                    {
                        int vrh = Dpi.Height(panel.VirtualRowHeight);
                        bounds = panel.BoundsRelative;
                        bounds.Y += (panel.FixedRowHeight - (panel.FrozenRowCount * vrh));
                        bounds.Y += (GridIndex * vrh);
                    }
                    int n = bounds.Y - t.Y;
                    SuperGrid.SetVScrollValue(n);
                }
            }
        }
        #endregion
        #region ScrollToBottom
        /// 
        /// Scrolls the row to the 'logical' bottom of the grid display.
        /// 
        public void ScrollToBottom()
        {
            if (Visible == true)
            {
                if (IsVFrozen == false)
                {
                    ExpandItemTree();
                    SuperGrid.ArrangeGrid();
                    Rectangle t = SViewRect;
                    Rectangle bounds = BoundsRelative;
                    GridPanel panel = GridPanel;
                    if (panel.VirtualMode == true)
                    {
                        int vrh = Dpi.Height(panel.VirtualRowHeight);
                        bounds = panel.BoundsRelative;
                        bounds.Y += (panel.FixedRowHeight - (panel.FrozenRowCount * vrh));
                        bounds.Y += (GridIndex * vrh);
                    }
                    int n = bounds.Y - (t.Bottom) + FixedRowHeight;
                    SuperGrid.SetVScrollValue(n);
                }
            }
        }
        #endregion
        #region ExtendSelection
        internal void ExtendSelection(
            GridPanel panel, GridContainer endItem, bool extend)
        {
            if (panel.SelectionRowAnchor != null)
            {
                int startIndex = panel.SelectionRowAnchor.GridIndex;
                int endIndex = endItem.GridIndex;
                panel.NormalizeIndices(false, 0, ref startIndex, ref endIndex);
                if (panel.OnlyRowsSelected(startIndex, endIndex) == false)
                {
                    if (extend == false)
                        panel.ClearAllSelected();
                    else
                        panel.ClearAll(false);
                    panel.SetSelectedRows(startIndex, endIndex - startIndex + 1, true);
                    GridContainer row = GetLastProcessedRow(panel);
                    if (extend == true && row != null)
                    {
                        if (panel.SelectionRowAnchor.GridIndex < endItem.GridIndex)
                            startIndex = row.GridIndex;
                        else
                            endIndex = row.GridIndex;
                    }
                    InvalidateRows(panel, startIndex, endIndex, extend);
                }
            }
        }
        #region GetLastProcessedRow
        private GridContainer GetLastProcessedRow(GridPanel panel)
        {
            if (panel.LastProcessedItem is GridContainer)
                return ((GridContainer)panel.LastProcessedItem);
            if (panel.LastProcessedItem is GridCell)
                return (((GridCell)panel.LastProcessedItem).GridRow);
            return (null);
        }
        #endregion
        #endregion
        #region InvalidateRows
        internal void InvalidateRows(GridPanel panel, int start, int end, bool extend)
        {
            if (start > end)
            {
                int temp = start;
                start = end;
                end = temp;
            }
            start = Math.Max(0, start);
            if (extend == false && panel.FrozenRowCount > 0)
                InvalidateRowRange(panel, 0, panel.FirstOnScreenRowIndex);
            InvalidateRowRange(panel, start, end);
        }
        #region InvalidateRowRange
        private void InvalidateRowRange(GridPanel panel, int start, int end)
        {
            Rectangle t = SuperGrid.ClientRectangle;
            GridContainer rs = panel.GetRowFromIndex(start);
            GridContainer re = panel.GetRowFromIndex(end);
            if (rs != null && re != null)
            {
                Rectangle rsRect = rs.Bounds;
                Rectangle reRect = re.Bounds;
                if (rs is GridPanel)
                    rsRect = GetScrollBounds(rs.ContainerBounds);
                if (re is GridPanel)
                    reRect = GetScrollBounds(re.ContainerBounds);
                Rectangle r = new Rectangle(rsRect.X, rsRect.Y,
                                            reRect.Width, reRect.Bottom - rsRect.Y);
                if (r.IntersectsWith(t) == true)
                    panel.InvalidateRender(r);
                if (rs is GridRow)
                    rs.InvalidateRender();
                if (re != rs && re is GridRow)
                    re.InvalidateRender();
            }
        }
        #region GetScrollBounds
        private Rectangle GetScrollBounds(Rectangle r)
        {
            r.X -= HScrollOffset;
            if (IsVFrozen == false)
                r.Y -= VScrollOffset;
            return (r);
        }
        #endregion
        #endregion
        #endregion
        #region MeasureSubItems
        /// 
        /// MeasureSubItems
        /// 
        /// 
        /// 
        /// 
        /// 
        protected Size MeasureSubItems(
            GridLayoutInfo layoutInfo, GridLayoutStateInfo stateInfo, Size constraintSize)
        {
            Size sizeNeeded = Size.Empty;
            GridPanel panel = stateInfo.GridPanel;
            HasVisibleItems = false;
            GridItemsCollection items = Rows;
            foreach (GridElement item in items)
            {
                if (item.Visible == true)
                {
                    Size size;
                    GridPanel ipanel = item as GridPanel;
                    if (ipanel != null)
                    {
                        int n = GetRowIndent(panel, ipanel);
                        Rectangle r = layoutInfo.ClientBounds;
                        r.Inflate((panel.ShowDropShadow ? -5 : 0) - n, 0);
                        GridLayoutInfo itemLayoutInfo = new GridLayoutInfo(layoutInfo.Graphics, r);
                        GridLayoutStateInfo itemStateInfo = new GridLayoutStateInfo(ipanel, 0);
                        item.Measure(itemLayoutInfo, itemStateInfo, Size.Empty);
                        size = item.Size;
                        size.Width += n;
                        size.Height += Dpi.Height(panel.LevelIndentSize.Height * 2);
                    }
                    else
                    {
                        item.Measure(layoutInfo, stateInfo, constraintSize);
                        size = item.Size;
                    }
                    sizeNeeded.Width = Math.Max(sizeNeeded.Width, size.Width);
                    sizeNeeded.Height += size.Height;
                    HasVisibleItems = true;
                }
            }
            return (sizeNeeded);
        }
        #endregion
        #region ArrangeSubItems
        /// 
        /// ArrangeSubItems
        /// 
        /// 
        /// 
        /// 
        protected void ArrangeSubItems(GridLayoutInfo layoutInfo,
            GridLayoutStateInfo stateInfo, Rectangle layoutBounds)
        {
            Rectangle bounds = layoutBounds;
            GridPanel panel = stateInfo.GridPanel;
            int indentLevel = stateInfo.IndentLevel;
            GridItemsCollection items = Rows;
            foreach (GridElement item in items)
            {
                if (item.Visible == true)
                {
                    bounds.Height = item.Size.Height;
                    GridPanel ipanel = item as GridPanel;
                    if (ipanel != null)
                    {
                        ipanel.IndentLevel = indentLevel;
                        Rectangle r = layoutBounds;
                        r.Y = bounds.Y;
                        r.Height = bounds.Height + Dpi.Height(panel.LevelIndentSize.Height * 2);
                        ipanel.ContainerBounds = r;
                        int n = GetRowIndent(panel, ipanel);
                        r.X = layoutBounds.X + n;
                        r.Y += Dpi.Height(panel.LevelIndentSize.Height);
                        if (ipanel.ShowDropShadow == true)
                            r.Y--;
                        r.Width = ipanel.BoundsRelative.Width;
                        r.Height -= Dpi.Height(panel.LevelIndentSize.Height * 2);
                        ArrangeCheckBox(panel, ipanel, r);
                        stateInfo.GridPanel = ipanel;
                        stateInfo.IndentLevel = 0;
                        item.Arrange(layoutInfo, stateInfo, r);
                        bounds.Y += Dpi.Height(panel.LevelIndentSize.Height * 2);
                    }
                    else
                    {
                        stateInfo.GridPanel = panel;
                        stateInfo.IndentLevel = indentLevel;
                        item.Arrange(layoutInfo, stateInfo, bounds);
                    }
                    bounds.Y += item.Size.Height;
                }
                else
                {
                    item.BoundsRelative = bounds;
                }
            }
        }
        #region ArrangeCheckBox
        private void ArrangeCheckBox(
            GridPanel panel, GridPanel ipanel, Rectangle r)
        {
            if (ipanel.HasCheckBox == true)
            {
                int k = Math.Max(
                    Dpi.Width(panel.CheckBoxSize.Width + 3),
                    Dpi.Height(panel.CheckBoxSize.Height+ 3));
                r.X -= k;
                r.Width = Dpi.Width(panel.CheckBoxSize.Width);
                r.Y += (r.Height - Dpi.Height(panel.CheckBoxSize.Height)) / 2;
                r.Height = Dpi.Height(panel.CheckBoxSize.Height);
                ipanel.CheckBoxBounds = r;
            }
            else
            {
                ipanel.CheckBoxBounds = Rectangle.Empty;
            }
        }
        #endregion
        #endregion
        #region GetRowIndent
        /// 
        /// GetRowIndent
        /// 
        /// 
        /// 
        /// 
        protected int GetRowIndent(GridPanel panel, GridPanel ipanel)
        {
            int indentLevel = 0;
            GridContainer container = ipanel.Parent as GridContainer;
            if (container != null)
                indentLevel = container.IndentLevel + 1;
            int n = 0;
            if (panel.ShowRowHeaders == true)
                n += panel.RowHeaderWidthEx;
            if (panel.CheckBoxes == true)
            {
                n += Math.Max(
                    Dpi.Width(ipanel.CheckBoxSize.Width + 3),
                    Dpi.Height(ipanel.CheckBoxSize.Height + 3));
            }
            if (panel.PrimaryColumn != null &&
                panel.PrimaryColumn.Visible == true)
            {
                if (panel.ShowTreeButtons == true || panel.ShowTreeLines == true)
                    n += panel.TreeButtonIndent;
                n += Dpi.Width(panel.LevelIndentSize.Width * indentLevel);
                GridColumnCollection columns = panel.Columns;
                int[] map = columns.DisplayIndexMap;
                for (int i = 0; i < map.Length; i++)
                {
                    int index = map[i];
                    GridColumn column = columns[index];
                    if (index == panel.PrimaryColumnIndex)
                        break;
                    if (column.Visible == true)
                        n += column.Size.Width;
                }
            }
            else
            {
                n += 3;
            }
            return (n);
        }
        #endregion
        #region GetParentPanel
        ///
        /// Gets the Parent GridPanel for the item.
        ///
        ///GridPanel or null
        public GridPanel GetParentPanel()
        {
            GridElement parent = Parent;
            while (parent != null)
            {
                if (parent is GridPanel)
                    return ((GridPanel)parent);
                parent = parent.Parent;
            }
            return (null);
        }
        #endregion
        #region InvalidateRowHeader
        internal void InvalidateRowHeader()
        {
            InvalidateRowHeader(this);
        }
        internal void InvalidateRowHeader(GridContainer row)
        {
            if (row != null)
            {
                GridPanel panel = row.GetParentPanel();
                if (panel != null)
                {
                    if (panel.ShowRowHeaders == true)
                    {
                        Rectangle bounds = panel.BoundsRelative;
                        if (panel.IsSubPanel == true)
                            bounds.X -= HScrollOffset;
                        bounds.Y = row.ContainerBounds.Y;
                        if (row.IsVFrozen == false)
                            bounds.Y -= VScrollOffset;
                        bounds.Width = panel.RowHeaderWidthEx;
                        bounds.Height = row.ContainerBounds.Height;
                        InvalidateRender(bounds);
                    }
                }
            }
        }
        #endregion
        #region InvalidateMerge
        /// 
        /// Invalidates the merge state of the container.
        /// 
        public void InvalidateMerge()
        {
            MergeUpdateCount++;
            NeedMergeLayout = true;
            ResumeMerge();
            InvalidateLayout();
        }
        #endregion
        #region Mouse Handling
        #region InternalMouseLeave
        /// 
        /// Called by top-level control to pass message into the grid
        /// element. To handle it override corresponding On - virtual method.
        /// 
        /// 
        internal override void InternalMouseLeave(EventArgs e)
        {
            GridElement mouseOverElement = _MouseOverElement;
            if (mouseOverElement != null)
            {
                mouseOverElement.InternalMouseLeave(e);
                _MouseOverElement = null;
            }
            base.InternalMouseLeave(e);
        }
        #endregion
        #region InternalMouseMove
        /// 
        /// Called by top-level control to pass message into the grid
        /// element. To handle it override corresponding On - virtual method.
        /// 
        /// 
        internal override void InternalMouseMove(MouseEventArgs e)
        {
            GridElement element = GetElementAt(e);
            if (element != _MouseOverElement)
            {
                GridElement mouseOverElement = _MouseOverElement;
                if (mouseOverElement != null)
                    mouseOverElement.InternalMouseLeave(e);
                if (element != null)
                    element.InternalMouseEnter(e);
                _MouseOverElement = element;
            }
            if (element != null)
                element.InternalMouseMove(e);
            base.InternalMouseMove(e);
        }
        #endregion
        #region InternalMouseHover
        /// 
        /// Called by top-level control to pass message into the grid
        /// element. To handle it override corresponding On - virtual method.
        /// 
        /// 
        internal override void InternalMouseHover(EventArgs e)
        {
            GridElement mouseOverElement = _MouseOverElement;
            
            if (mouseOverElement != null)
                mouseOverElement.InternalMouseHover(e);
            base.InternalMouseHover(e);
        }
        #endregion
        #region InternalMouseClick
        /// 
        /// Called by top-level control to pass message into the grid
        /// element. To handle it override corresponding On - virtual method.
        /// 
        /// 
        internal override void InternalMouseClick(MouseEventArgs e)
        {
            GridElement mouseOverElement = _MouseOverElement;
            if (mouseOverElement == null)
                InternalMouseMove(e);
            mouseOverElement = _MouseOverElement;
            if (mouseOverElement != null)
                mouseOverElement.InternalMouseClick(e);
            base.InternalMouseClick(e);
        }
        #endregion
        #region InternalMouseDoubleClick
        /// 
        /// Called by top-level control to pass message into the grid
        /// element. To handle it override corresponding On - virtual method.
        /// 
        /// 
        internal override void InternalMouseDoubleClick(MouseEventArgs e)
        {
            GridElement mouseOverElement = _MouseOverElement;
            if (mouseOverElement != null)
                mouseOverElement.InternalMouseDoubleClick(e);
            base.InternalMouseDoubleClick(e);
        }
        #endregion
        #region InternalMouseDown
        /// 
        /// Called by top-level control to pass message into the grid
        /// element. To handle it override corresponding On - virtual method.
        /// 
        /// 
        internal override void InternalMouseDown(MouseEventArgs e)
        {
            GridElement mouseOverElement = _MouseOverElement;
            if (mouseOverElement == null)
            {
                MouseEventArgs e2 = new
                    MouseEventArgs(MouseButtons.None, 0, e.X, e.Y, e.Delta);
                InternalMouseMove(e2);
                mouseOverElement = _MouseOverElement;
            }
            if (mouseOverElement != null)
                mouseOverElement.InternalMouseDown(e);
            base.InternalMouseDown(e);
        }
        #endregion
        #region InternalMouseUp
        /// 
        /// Called by top-level control to pass message into the grid
        /// element. To handle it override corresponding On - virtual method.
        /// 
        /// 
        internal override void InternalMouseUp(MouseEventArgs e)
        {
            GridElement mouseOverElement = _MouseOverElement;
            if (mouseOverElement != null)
                mouseOverElement.InternalMouseUp(e);
            base.InternalMouseUp(e);
        }
        #endregion
        #endregion
        #region GetElementAt
        /// 
        /// Returns element at specified mouse coordinates.
        /// 
        /// Mouse event arguments
        /// Reference to child element or null if no element at specified coordinates
        public virtual GridElement GetElementAt(MouseEventArgs e)
        {
            return GetElementAt(e.X, e.Y);
        }
        /// 
        /// Returns element at specified mouse coordinates.
        /// 
        /// Horizontal position
        /// Vertical position
        /// Reference to child element or null if no element at specified coordinates
        public virtual GridElement GetElementAt(int x, int y)
        {
            GridPanel panel = GridPanel;
            if (panel != null)
            {
                Rectangle t = CViewRect;
                Rectangle bounds = Rectangle.Empty;
                if (t.Contains(x, y) == true)
                {
                    if (this is GridPanel || Expanded == true)
                    {
                        GridItemsCollection items = Rows;
                        for (int i = 0; i < items.Count; i++)
                        {
                            GridElement item = items[i];
                            if (item.IsVFrozen == false)
                                break;
                            if (IsElementAt(item, x, y, ref bounds) == true)
                                return (item);
                            if (bounds.Y > t.Bottom)
                                break;
                        }
                        for (int i = FirstOnScreenRowIndex; i < items.Count; i++)
                        {
                            GridElement item = items[i];
                            if (IsElementAt(item, x, y, ref bounds) == true)
                            {
                                GridGroup grp = item as GridGroup;
                                if (grp != null)
                                {
                                    item = grp.GetElementAt(x, y);
                                    if (item == null)
                                        return (grp);
                                }
                                return (item);
                            }
                            if (bounds.Y > y)
                                break;
                        }
                    }
                }
            }
            return (null);
        }
        private bool IsElementAt(
            GridElement item, int x, int y, ref Rectangle bounds)
        {
            if (item.Visible == true)
            {
                bounds = item.BoundsRelative;
                if (item.Visible == true)
                {
                    if (item is GridPanel)
                        bounds = ((GridPanel)item).ContainerBounds;
                    bounds.X -= HScrollOffset;
                    if (item.IsVFrozen == false)
                        bounds.Y -= VScrollOffset;
                    if (bounds.Contains(x, y))
                        return (true);
                }
            }
            return (false);
        }
        #endregion
        #region InternalGetElementAt
        internal GridElement InternalGetElementAt(MouseEventArgs e)
        {
            return (GetElementAt(e.X, e.Y));
        }
        internal GridElement InternalGetElementAt(int x, int y)
        {
            return (GetElementAt(x, y));
        }
        #endregion
        #region CanSetActiveRow
        internal bool CanSetActiveRow(bool beep)
        {
            return (CanSetActiveRow(GridPanel, this, beep));
        }
        internal bool CanSetActiveRow(
            GridPanel panel, GridContainer row, bool beep)
        {
            if (row == null || row.AllowSelection == false)
            {
                if (beep == true)
                {
                    if (SuperGrid.DoPlayingSoundEvent(panel, row, PlaySoundContext.RowActivate) == false)
                        SystemSounds.Beep.Play();
                }
                return (false);
            }
            if (row.IsActive == false)
            {
                GridContainer parent = row.Parent as GridContainer;
                if (parent != null)
                {
                    if ((uint)row.RowIndex > parent.MaxRowIndex)
                        return (false);
                    if (panel.SelectionGranularity != SelectionGranularity.Cell)
                    {
                        GridContainer cont = Parent as GridContainer;
                        if (cont != null)
                        {
                            CellRange cr = cont.SuspendedRange;
                            if (cr != null && (RowIndex < cr.RowStart || RowIndex > cr.RowEnd))
                                cont.ResumeMerge();
                        }
                    }
                    return (SuperGrid.DoRowActivatingEvent(panel, SuperGrid.ActiveRow, row) != true);
                }
            }
            return (row.IsActive);
        }
        #endregion
        #region FlushRow
        internal virtual void FlushRow()
        {
        }
        #endregion
        #region PurgeDeletedRows
        ///
        /// Purges all rows marked as 'deleted'. Once rows are purged
        /// they cannot be restored.
        ///
        public void PurgeDeletedRows()
        {
            PurgeDeletedRows(true);
        }
        ///
        /// Purges all rows marked as 'deleted'. Once rows are purged
        /// they cannot be restored.
        ///
        ///Determines whether nested rows are also purged.
        public void PurgeDeletedRows(bool includeNestedRows)
        {
            GridPanel panel = GridPanel;
            PurgeDeletedRowsEx(includeNestedRows, panel.IsDeleted);
        }
        private void PurgeDeletedRowsEx(bool includeNestedRows, bool isDeleted)
        {
            GridPanel panel = GridPanel;
            if (SuperGrid.DoRowsPurgingEvent(this, ref includeNestedRows) == false)
            {
                if (panel.DeletedRowCount > 0)
                {
                    if (panel.ActiveRow != null)
                        panel.SelectActiveRow = true;
                }
                if (panel.VirtualMode == true)
                    PurgeVirtualDeletedRows(panel);
                else
                    PurgeRealDeletedRows(panel, includeNestedRows, isDeleted);
                SuperGrid.DoRowsPurgedEvent(this);
            }
        }
        #region PurgeVirtualDeletedRows
        private void PurgeVirtualDeletedRows(GridPanel panel)
        {
            SelectedElements sec = panel.InternalDeletedRows;
            if (sec != null && sec.Count > 0)
            {
                int offset = 0;
                int topIndex = 0;
                int activeIndex =
                    (panel.ActiveRow != null) ? panel.ActiveRow.RowIndex : -1;
                int count = sec.Count;
                int index = sec.LastIndex + 1;
                try
                {
                    while (sec.GetPrevIndex(ref index) == true)
                    {
                        GridRow row = panel.VirtualRows[index];
                        topIndex = row.RowIndex - 1;
                        if (row.RowIndex < activeIndex)
                            offset++;
                        panel.DataBinder.RemoveRow(row);
                    }
                    sec.Clear();
                }
                finally
                {
                    panel.VirtualRowCount -= count;
                    panel.VirtualRows.MaxRowIndex = topIndex;
                }
                if (offset > 0)
                {
                    panel.LatentActiveRowIndex = activeIndex - offset;
                    panel.LatentActiveContainer = this;
                }
            }
        }
        #endregion
        #region PurgeRealDeletedRows
        private void PurgeRealDeletedRows(
            GridPanel panel, bool includeNestedRows, bool isDeleted)
        {
            if (panel.ActiveRow != null)
            {
                if (panel.ActiveRow.IsDeleted == true)
                {
                    if (panel.VirtualMode == false)
                    {
                        GridContainer cont = panel.ActiveRow.Parent as GridContainer;
                        if (cont != null)
                        {
                            panel.ActiveRow = cont.GetNextLocalItem(panel.ActiveRow.RowIndex);
                            panel.SuperGrid.ActiveElement = panel.ActiveRow;
                        }
                    }
                }
            }
            PurgeRealDeletedRowsEx(panel.Rows, includeNestedRows, isDeleted);
        }
        #region PurgeRealDeletedRowsEx
        private void PurgeRealDeletedRowsEx(
            GridItemsCollection rows, bool includeNestedRows, bool isDeleted)
        {
            for (int i = rows.Count - 1; i >= 0; i--)
            {
                GridContainer row = rows[i] as GridContainer;
                if (row != null)
                {
                    bool rowDeleted = (isDeleted | row.IsDeleted);
                    if (includeNestedRows == true)
                    {
                        if (row.Rows.Count > 0)
                        {
                            if (row is GridPanel)
                                row.PurgeDeletedRowsEx(true, rowDeleted);
                            else
                                row.PurgeRealDeletedRowsEx(row.Rows, true, rowDeleted);
                        }
                    }
                    if (rowDeleted == true)
                    {
                        row.IsDeleted = false;
                        rows.RemoveAt(i);
                    }
                }
            }
        }
        #endregion
        #endregion
        #region GetNextLocalItem
        internal GridContainer GetNextLocalItem(int index)
        {
            GridPanel panel = GridPanel;
            index = GetNextLocalItemIndex(index);
            if (panel.VirtualMode == true)
            {
                if ((uint)index < panel.VirtualRowCount)
                    return (panel.VirtualRows[index]);
            }
            else
            {
                if ((uint) index < Rows.Count)
                    return (Rows[index] as GridContainer);
            }
            return (null);
        }
        #endregion
        #region GetNextLocalItemIndex
        private int GetNextLocalItemIndex(int index)
        {
            if (GridPanel.VirtualMode == true)
                return (GetNextLocalVirtualItemIndex(index));
            return (GetNextLocalRealItemIndex(index));
        }
        #region GetNextLocalRealItemIndex
        internal int GetNextLocalRealItemIndex(int index)
        {
            if (Rows.Count > 0 && index >= 0)
            {
                if (index >= Rows.Count)
                    index = Rows.Count - 1;
                for (int i = index + 1; i < Rows.Count; i++)
                {
                    GridContainer item = Rows[i] as GridContainer;
                    if (item != null && item.Visible == true && item.IsDeleted == false)
                        return (i);
                }
                for (int i = index - 1; i >= 0; i--)
                {
                    GridContainer item = Rows[i] as GridContainer;
                    if (item != null && item.Visible == true && item.IsDeleted == false)
                        return (i);
                }
            }
            return (-1);
        }
        #endregion
        #region GetNextLocalVirtualItemIndex
        internal int GetNextLocalVirtualItemIndex(int index)
        {
            GridPanel panel = GridPanel;
            if (panel.VirtualRowCount > 0 && index >= 0)
            {
                if (index >= panel.VirtualRowCount)
                    index = panel.VirtualRowCount - 1;
                for (int i = index + 1; i < panel.VirtualRowCount; i++)
                {
                    GridContainer item = panel.VirtualRows[i];
                    if (item != null && item.IsDeleted == false)
                        return (i);
                }
                for (int i = index - 1; i >= 0; i--)
                {
                    GridContainer item = panel.VirtualRows[i];
                    if (item != null && item.IsDeleted == false)
                        return (i);
                }
            }
            return (-1);
        }
        #endregion
        #endregion
        #endregion
        #region DetachNestedRows
        internal void DetachNestedRows(bool dispose)
        {
            DetachNestedRows(this, dispose);
        }
        private void DetachNestedRows(GridContainer cont, bool dispose)
        {
            cont.MergeScan = null;
            if (dispose == true)
            {
                if (cont is GridPanel)
                {
                    ((GridPanel)cont).DataBinder.Dispose();
                    ((GridPanel)cont).DataBinder = null;
                }
            }
            if (cont is GridRow)
                DetachGridRow((GridRow)cont);
            if (cont.Rows.Count > 0)
            {
                foreach (GridContainer row in cont.Rows)
                {
                    if (row != null)
                        DetachNestedRows(row, dispose);
                }
            }
            if (SuperGrid != null)
            {
                if (SuperGrid.ActiveRow == cont)
                    SuperGrid.ActiveRow = null;
            }
            if (cont.GridPanel != null)
            {
                if (cont.GridPanel.ActiveRow == cont)
                    cont.GridPanel.ActiveRow = null;
            }
        }
        private void DetachGridRow(GridRow row)
        {
            foreach (GridCell cell in row.Cells)
            {
                cell.EditControl = null;
                cell.RenderControl = null;
            }
            //row.DataItem = null;
            //row.DataItemIndex = -1;
        }
        #endregion
        #region UpdateMergeFlags
        internal void UpdateMergeFlags()
        {
            GridPanel panel = GridPanel;
            if (panel.EnableCellMerging == true)
                DisplayedCellRanges = MergeScan.GetScanItems();
            else
                DisplayedCellRanges = null;
            _LastCellRange = null;
        }
        #endregion
        #region GetCellRange
        internal CellRange GetCellRange(GridCell cell)
        {
            if (DisplayedCellRanges != null)
            {
                int index = cell.GridPanel.Columns.GetDisplayIndex(cell.GridColumn);
                if (_LastCellRange != null)
                {
                    if (_LastCellRange.Contains(cell.RowIndex, index))
                        return (_LastCellRange);
                }
                foreach (CellRange cr in DisplayedCellRanges)
                {
                    if (cr.Contains(cell.RowIndex, index))
                    {
                        _LastCellRange = cr;
                        return (cr);
                    }
                }
            }
            return (null);
        }
        #endregion
        #region SuspendMerge
        ///
        ///Temporarily suspends the merged display of the
        ///cells in the given CellRange.
        ///
        ///CellRange to temporarily suspend
        public void SuspendMerge(CellRange cr)
        {
            if (cr != null && cr.Suspended == false)
            {
                ResumeMerge();
                if (cr.AllowSuspend == true)
                {
                    cr.Suspended = true;
                    InvalidateRender(cr.BackBounds);
                }
            }
            _SuspendedRange = cr;
        }
        #endregion
        #region ResumeMerge
        ///
        ///Resumes merged display of any current, temporarily
        ///suspended CellRange.
        ///
        public void ResumeMerge()
        {
            CellRange cr = _SuspendedRange;
            _SuspendedRange = null;
            if (cr != null && cr.Suspended == true)
            {
                cr.Suspended = false;
                if (cr.Modified == true)
                {
                    UpdateCellResumeState(cr);
                    cr.Modified = false;
                    NeedMergeLayout = true;
                    InvalidateLayout();
                }
                GridPanel.SelectionUpdateCount++;
                InvalidateRender(cr.BackBounds);
            }
        }
        #region UpdateCellResumeState
        private void UpdateCellResumeState(CellRange cr)
        {
            ushort n = MergeUpdateCount;
            GridPanel panel = GridPanel;
            GridColumnCollection columns = panel.Columns;
            int[] map = columns.DisplayIndexMap;
            for (int i = cr.RowStart; i < cr.RowEnd; i++)
            {
                for (int j = cr.ColumnStart; j < cr.ColumnEnd; j++)
                {
                    GridCell cell = GetCell(i, map[j]);
                    if (cell != null && cell.Modified == true)
                    {
                        cell.MergeUpdateCount = --n;
                        cell.Modified = false;
                    }
                }
            }
        }
        #endregion
        #endregion
        #region SetMergeSelection
        internal void SetMergeSelection(int startRowIndex,
            int endRowIndex, int startColumnIndex, int endColumnIndex, int selected)
        {
            List cellRanges = DisplayedCellRanges;
            if (cellRanges != null)
            {
                GridPanel panel = GridPanel;
                foreach (CellRange cr in cellRanges)
                {
                    if (cr.RowStart <= endRowIndex && cr.RowEnd > startRowIndex &&
                        cr.ColumnStart <= endColumnIndex && cr.ColumnEnd > startColumnIndex)
                    {
                        cr.SelectionUpdateCount = panel.SelectionUpdateCount - 1;
                        InvalidateRender(cr.BackBounds);
                    }
                }
            }
        }
        #endregion
        #region ClearAllMergeSelected
        internal virtual void ClearAllMergeSelected()
        {
            GridPanel panel = GridPanel;
            List ranges = DisplayedCellRanges;
            if (ranges != null)
            {
                foreach (CellRange range in ranges)
                    range.SelectionUpdateCount = panel.SelectionUpdateCount - 1;
            }
            foreach (GridContainer row in Rows)
            {
                if (row != null)
                    row.ClearAllMergeSelected();
            }
        }
        #endregion
        #region ResolveRows
        /// 
        /// Resolves the row if marked as RowsUnresolved.
        /// 
        public void ResolveRow()
        {
            ResolveRow(GridPanel, false);
        }
        /// 
        /// Resolves the row if marked as RowsUnresolved.  If includeNested
        /// is true, then all RowsUnresolved sub-Rows are also resolved.
        /// 
        /// 
        public void ResolveRow(bool includeNested)
        {
            ResolveRow(GridPanel, includeNested);
        }
        internal void ResolveRow(GridPanel panel, bool includeNested)
        {
            panel.DataBinder.ResolveRow(this);
            if (includeNested == true)
                ResolveRows(true);
        }
        /// 
        /// Resolves all rows marked as RowsUnresolved.
        /// 
        /// 
        public void ResolveRows(bool includeNested)
        {
            if (Rows.Count > 0)
            {
                GridPanel panel = GridPanel;
                foreach (GridContainer row in Rows)
                {
                    if (row != null)
                        row.ResolveRow(panel, includeNested);
                }
            }
        }
        #endregion
        #region Style support routines
        #region OnStyleChanged
        private void OnStyleChanged(string property,
            INotifyPropertyChanged oldValue, INotifyPropertyChanged newValue)
        {
            UpdateChangeHandler(oldValue, newValue);
            OnPropertyChanged(property);
        }
        #endregion
        #region UpdateChangeHandler
        private void UpdateChangeHandler(
            INotifyPropertyChanged oldValue, INotifyPropertyChanged newValue)
        {
            NeedsMeasured = true;
            if (oldValue != null)
                oldValue.PropertyChanged -= StyleChanged;
            if (newValue != null)
                newValue.PropertyChanged += StyleChanged;
        }
        #endregion
        #region StyleChanged
        /// 
        /// StyleChanged
        /// 
        /// 
        /// 
        protected virtual void StyleChanged(object sender, PropertyChangedEventArgs e)
        {
            if (SuperGrid != null)
                SuperGrid.UpdateStyleCount();
            VisualChangeType changeType = ((VisualPropertyChangedEventArgs)e).ChangeType;
            if (changeType == VisualChangeType.Layout)
            {
                NeedsMeasured = true;
                InvalidateLayout();
            }
            else
            {
                if (SuperGrid != null)
                    InvalidateRender();
            }
        }
        #endregion
        #region GetEffectiveRowStyle
        ///
        /// Gets the 'Effective' row style for the row. The
        /// 'Effective' Style is the cached summation of SuperGrid,
        /// Panel, Row, and Alternate Row styles.  It is the Style
        /// that is used to render each row element for the row.
        ///
        ///RowVisualStyle
        public RowVisualStyle GetEffectiveRowStyle()
        {
            return (GetEffectiveRowStyle(this));
        }
        internal RowVisualStyle GetEffectiveRowStyle(GridContainer item)
        {
            StyleState rowState = GetRowState(item);
            return (GetEffectiveRowStyle(item, rowState));
        }
        internal RowVisualStyle GetEffectiveRowStyle(
            GridContainer item, StyleState rowState)
        {
            return (GetRowStateStyle(item, rowState));
        }
        #region GetRowState
        internal StyleState GetRowState(GridContainer item)
        {
            StyleState rowState = StyleState.Default;
            if (IsMouseOver == true)
            {
                Point pt = SuperGrid.PointToClient(Control.MousePosition);
                Rectangle r = (item is GridPanel)
                                  ? item.ContainerBounds
                                  : item.BoundsRelative;
                r.X -= HScrollOffset;
                if (item.IsVFrozen == false)
                    r.Y -= VScrollOffset;
                Rectangle t = ViewRect;
                r.Intersect(t);
                if (r.Contains(pt) == true)
                    rowState |= StyleState.MouseOver;
            }
            if (item.IsSelected == true)
                rowState |= StyleState.Selected;
            return (rowState);
        }
        #endregion
        #region GetRowStateStyle
        private RowVisualStyle GetRowStateStyle(GridContainer item, StyleState rowState)
        {
            ValidateRowStyle();
            switch (rowState)
            {
                case StyleState.MouseOver:
                    return (GetRowStyle(item, StyleType.MouseOver));
                case StyleState.Selected:
                    return (GetRowStyle(item, StyleType.Selected));
                case StyleState.Selected | StyleState.MouseOver:
                    return (GetRowStyle(item, StyleType.SelectedMouseOver));
                case StyleState.ReadOnly:
                    return (GetRowStyle(item, StyleType.ReadOnly));
                case StyleState.ReadOnly | StyleState.MouseOver:
                    return (GetRowStyle(item, StyleType.ReadOnlyMouseOver));
                case StyleState.ReadOnly | StyleState.Selected:
                    return (GetRowStyle(item, StyleType.ReadOnlySelected));
                case StyleState.ReadOnly | StyleState.MouseOver | StyleState.Selected:
                    return (GetRowStyle(item, StyleType.ReadOnlySelectedMouseOver));
                default:
                    return (GetRowStyle(item, StyleType.Default));
            }
        }
        #endregion
        #region GetRowStyle
        private RowVisualStyle GetRowStyle(GridContainer item, StyleType e)
        {
            if (_EffectiveRowStyles.IsValid(e) == false)
            {
                RowVisualStyle style = new RowVisualStyle();
                StyleType[] css = style.GetApplyStyleTypes(e);
                if (css != null)
                {
                    GridPanel panel = GridPanel;
                    foreach (StyleType cs in css)
                    {
                        style.ApplyStyle(SuperGrid.BaseVisualStyles.RowStyles[cs]);
                        style.ApplyStyle(SuperGrid.DefaultVisualStyles.RowStyles[cs]);
                        style.ApplyStyle(GridPanel.DefaultVisualStyles.RowStyles[cs]);
                        style.ApplyStyle(item.RowStyles[cs]);
                        if (panel != null && panel.UseAlternateRowStyle == true)
                        {
                            if ((GridIndex % 2) > 0)
                            {
                                style.ApplyStyle(SuperGrid.BaseVisualStyles.AlternateRowCellStyles[cs]);
                                style.ApplyStyle(SuperGrid.DefaultVisualStyles.AlternateRowCellStyles[cs]);
                                style.ApplyStyle(GridPanel.DefaultVisualStyles.AlternateRowCellStyles[cs]);
                            }
                        }
                        style.ApplyStyle(item.CellStyles[cs]);
                        style.ApplyStyle(item.CellStyles[cs]);
                    }
                }
                SuperGrid.DoGetRowStyleEvent(this, e, ref style);
                RowHeaderVisualStyle style2 = style.RowHeaderStyle;
                SuperGrid.DoGetRowHeaderStyleEvent(this, e, ref style2);
                if (style.Background == null || style.Background.IsEmpty == true)
                    style.Background = new Background(Color.White);
                _EffectiveRowStyles[e] = style;
            }
            return (_EffectiveRowStyles[e]);
        }
        #endregion
        #endregion
        #region ValidateRowStyle
        private void ValidateRowStyle()
        {
            if (_EffectiveRowStyles == null ||
                (_StyleUpdateCount != SuperGrid.StyleUpdateCount))
            {
                if (_EffectiveRowStyles != null)
                    _EffectiveRowStyles.Dispose();
                _EffectiveRowStyles = new RowVisualStyles();
                _StyleUpdateCount = SuperGrid.StyleUpdateCount;
            }
        }
        #endregion
        #region InvalidateStyle
        ///
        ///Invalidates the cached Style
        ///definition for all defined StyleTypes
        ///
        public virtual void InvalidateStyle()
        {
            if (_EffectiveRowStyles != null)
            {
                _EffectiveRowStyles.Dispose();
                _EffectiveRowStyles = null;
            }
            InvalidateLayout();
        }
        ///
        ///Invalidate the cached Style
        ///definition for the given StyleType
        ///
        ///
        public void InvalidateStyle(StyleType type)
        {
            if (_EffectiveRowStyles != null)
            {
                if (_EffectiveRowStyles[type] != null)
                {
                    _EffectiveRowStyles[type].Dispose();
                    _EffectiveRowStyles[type] = null;
                    InvalidateLayout();
                }
            }
        }
        #endregion
        #endregion
        #region IsParentOf
        ///
        /// Determines whether the row is
        /// a parent row of the given container row.
        ///
        ///
        ///true if the row is a parent of the given row.
        public bool IsParentOf(GridContainer row)
        {
            if (row != null)
                return (row.IsChildOf(this));
            return (false);
        }
        #endregion
        #region IsChildOf
        ///
        /// Determines whether the row is
        /// a child row of the given container row.
        ///
        ///
        ///true if the row is a child of the given row.
        public bool IsChildOf(GridContainer row)
        {
            if (row != null)
            {
                GridContainer parent = Parent as GridContainer;
                while (parent != null)
                {
                    if (parent == row)
                        return (true);
                    parent = parent.Parent as GridContainer;
                }
            }
            return (false);
        }
        #endregion
        #region GetCell
        ///
        /// Gets the GridCell for the given row and column index
        ///
        ///
        ///
        ///GridCell, or null if not a valid cell
        public GridCell GetCell(int rowIndex, int columnIndex)
        {
            GridPanel panel = GridPanel;
            if (panel != null)
            {
                GridRow row = null;
                if (panel.VirtualMode == true)
                {
                    if ((uint)rowIndex < panel.VirtualRowCount)
                        row = panel.VirtualRows[rowIndex];
                }
                else
                {
                    if ((uint) rowIndex < Rows.Count)
                        row = Rows[rowIndex] as GridRow;
                }
                if (row != null && columnIndex < row.Cells.Count)
                    return (row.Cells[columnIndex]);
            }
            return (null);
        }
        #endregion
        #region Dispose
        /// 
        /// Dispose
        /// 
        public virtual void Dispose()
        {
            if (_EffectiveRowStyles != null)
            {
                _EffectiveRowStyles.Dispose();
                _EffectiveRowStyles = null;
            }
            CellStyles = null;
            RowStyles = null;
            if (Rows != null && Rows.Count > 0)
            {
                foreach (GridElement item in Rows)
                {
                    GridContainer row = item as GridContainer;
                    if (row != null)
                        row.Dispose();
                }
            }
        }
        #endregion
        #region ContainerStates
        [Flags]
        private enum Cs
        {
            Checked = (1 << 0),
            Deleted = (1 << 1),
            Expanded = (1 << 2),
            HasVisibleItems = (1 << 3),
            ReadOnly = (1 << 4),
            RowsUnresolved = (1 << 5),
            Selected = (1 << 6),
            ShowCheckBox = (1 << 7),
            ShowTreeButton = (1 << 8),
            ExpandedVisible = (1 << 9),
        }
        #endregion
    }
    #region enums
    #region ExpandSource
    ///
    /// Operation source resulting in the Expand call
    ///
    public enum ExpandSource
    {
        ///
        /// Expand operation
        ///
        Expand,
        ///
        /// ExpandAll operation
        ///
        ExpandAll,
    }
    #endregion
    #endregion
}