//------------------------------------------------------------------------------
// <copyright file=”*.cs” company=”EhLib Team”>
//     Copyright (c) 2017 Dmitry V. Bolshakov   
// </copyright>
//------------------------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Design;
//using EhLib.Design;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;

namespace EhLib
{

  public enum LocateTextDirection
  {
    Up, Down, All
  }

  public enum LocateTextMatching
  {
    Whole, StartOf, AnyPartOf
  }

  public enum DataGridPaintEmptySpaceStyle
  {
    NoPaint, Solid, Gradient
  }

  public enum DataGridHorzEmptySpaceStyle
  {
    NoPaint, ExtendTitleWideSpace, ExtendGridWideSpace
  }

  public enum SortMarkerStyle
  {
    Default, Framed, Solid, Themed
  }

  //[Flags]
  //public enum GridAllowedSelections
  //{
  //  Rows = 1,
  //  Cells = 2,
  //  Columns = 4,
  //  All = 8
  //}

  public enum GridSelectionType
  {
    None, Rows, Columns, CellsBox, All
  }

  public enum DataGridSelectionState
  {
    None, RowSelection, ColumnSelection, CellSelection,
  }

  public enum DataGridState
  {
    Normal,
    ColumnsSelecting,
    RowsSelecting,
    CellsRectSelecting
  }

  public enum DataGridTextWrapMode
  {
    Auto,
    WordWrap,
    NoWrap,
    ForceSingleLine
    //, WordBreak
  }

  public enum DataGridSearchBoxScope
  {
    CurrentColumn,
    EntireGrid
  }

  public enum DataGridCellAreaHorzType
  {
    Invalid, Indicator, Data, Contra
  }

  public enum DataGridCellAreaVertType
  {
    Invalid, Title, Data, Footer
  }

  public enum DataGridCellItemPaintTime
  {
    Always, Never, WhenHot, WhenAreaHot, WhenAreaHotOrActive
  }

  public enum DataGridActiveArea
  {
    Cell, Row
  }

  public enum HeightUnits
  {
    Pixels, TextLines    
  }

  public enum CellMergeDuplicatesPaintKind
  {
    ClassicPaint,
    MergedPaint,
    ClassicPaintBackground
  }

  public struct CellAreaType
  {
    public DataGridCellAreaHorzType HorzType;
    public DataGridCellAreaVertType VertType;
  }

  public interface IDataGridDesigner
  {
    void PaintCellDesignData(DataGridEh grid, Graphics graphics, int col, int row, Rectangle rect, BasePaintCellStates state);
    void PaintSuperTitleCellDesignData(DataGridEh grid, DataGridSuperTitle dataGridSuperTitle, Graphics graphics, Rectangle rect);
    void InteractiveSetColWidths(int colIndex, int newSize);
    void InteractiveMoveColumn(int fromIndex, int toIndex);
    void GridMouseDown(MouseEventArgs e);
    void GridMouseUp(MouseEventArgs e);
    void GridMouseMove(MouseEventArgs e);
  }

  [DesignerCategory("Code")]
  //[Designer("EhLib.Design.DataGridDesigner, EhLib.WinForms.Design")]
  [Designer("EhLib.Design.DataGridDesigner, EhLib.WinForms.Design, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d379614f4f89b099")]
  //[Designer("EhLib.Design.DataGridDesigner"+EhLibUtils.EhLibDesignDesignerVersionInfo)]
  [ToolboxItem(true)]
  [ToolboxBitmap(typeof(DataGridEh), "ToolboxBitmaps.EhLib_DataGrid.bmp")]
  //[ToolboxBitmap(typeof(DataGridEh))]
  [ComplexBindingProperties("DataSource", "DataMember")]
  [Description("Displays rows and columns of data in a grid you can customize")]
  public class DataGridEh : DataAxisGrid
  {
    #region private consts
    private const string N0Str = "0";

    private static readonly object EventKeyDataCellMouseDown = new object();
    private static readonly object EventKeyDataCellClick = new object();
    private static readonly object EventKeyDataCellContentClick = new object();
    private static readonly object EventKeyDataCellContextMenuStripNeeded = new object();
    private static readonly object EventKeyColumnTitleContextMenuStripNeeded = new object();
    private static readonly object EventKeyDefaultContextMenuStripNeeded = new object();
    private static readonly object EventKeyRowIsSelectable = new object();
    private static readonly object EventKeyDataGridSelectionChanged = new object();
    private static readonly object EventKeyDataGridRowHeightQuerying = new object();
    private static readonly object EventKeyDataGridHorzLineParamsNeeded = new object();
    private static readonly object EventKeyDataGridOrderedColumnsListChanged = new object();
    private static readonly object EventKeyDataGridVisibleRowsListChanged = new object();
    private static readonly object EventKeyDataGridColumnWidthChanged = new object();
    private static readonly object EventKeyDataGridDisplayColumnsMoved = new object();
    private static readonly object EventKeyDataCellQueryFillFormatParams = new object();
    private static readonly object EventKeyCreatingDynamicPropBarsForDataProperty = new object();
    #endregion private consts

    #region privates
    private readonly DataGridRows rows;

    internal readonly DataGridVisibleRows visibleRowList;
    //private readonly ReadOnlyCollection<DataGridRow> visibleRows;

    private readonly DataGridFooter footer;
    private readonly DataGridColumnOptions columnOptions;
    private readonly DataGridRowOptions rowOptions;
    private readonly DataGridFooterCellMan footerCell;
    private readonly DataGridSelection selection;

    private readonly DataGridEmptyTitleCellMan emptyTitleCell;
    internal readonly DataGridTitleCellMan titleCellMan;
    //private DataGridIndicatorDataCell emptyIndicatorCell;
    private readonly DataGridBaseCellMan emptyDataCell;
    //private DataGridHorzEmptySpaceCell horzEmptySpaceCell;

    private readonly DataGridIndicatorDataCellMan indicatorCell;
    private readonly DataGridIndicatorTitleCellMan titleIndicatorCell;
    private bool gridIsEmpty;
    private readonly DataGridAutoSizeColumnOptions autoSizeColumnOptions;
    private DataGridIndicatorColumn indicatorColumn;
    private DataGridIndicatorTitle indicatorTitle;
    private object addedSrcRow;
    //private readonly GridDataLink dataLink;
    private readonly DataGridSortCollection sortMarkers;
    private GridEmptyDataInfo emptyDataInfo;

    private readonly DataGridSearchBox searchBox;
    private readonly DataGridLocateTextService locateTextService;

    private readonly DataGridAllowedOperations allowedOperations;
    private bool titleTreePainted;
    private bool[,] dataCellPaintedArray = new bool[0,0];

    //private bool footerHaveAggreageFunction;
    private DataGridState dataGridState = DataGridState.Normal;

    //private bool columnSelectIsSelect;
    private readonly DataGridEditActions editActions;
    private int internalCurrentRowIndex;
    private bool inValidatingCode;

    private Padding leftAlignDefaultPadding;
    private Padding centerAlignDefaultPadding;
    private Padding rightAlignDefaultPadding;

    private int defaultRowHeight;
    private int titleRowIndex;

    //private DataGridSettingsKeeper settingsKeeper;

    internal DataGridSearchBoxControl SearchBoxControl;
    public IDataGridDesigner DataGridDesigner;
    private DataGridPrintService printService;
    private DataGridDataView dataView;
    private BindingSource dataViewBindingSource;
    private bool internalDataViewCurrencyManagerPositionSetting;

    #endregion privates

    public DataGridEh()
    {
      rows = new DataGridRows(this);
      visibleRowList = new DataGridVisibleRows(this);

      Options = GridOptions.DrawFocusSelected | GridOptions.Editing |
                 //GridOptions.RowSizing | 
                 GridOptions.ColSizing |
                 //GridOption.RowMoving | //GridOption.ColMoving | 
                 GridOptions.Tabs |
                 GridOptions.ContraHorzBoundaryLine | GridOptions.ContraVertBoundaryLine;

      this.ColCount = 2;
      this.RowCount = 2;

      sortMarkers = new DataGridSortCollection(this);

      columnOptions = new DataGridColumnOptions(this);
      UpdatePaddingsForSidePadding();

      rowOptions = new DataGridRowOptions(this);

      footer = new DataGridFooter(this);
      footerCell = new DataGridFooterCellMan();
      footerCell.Grid = this;

      emptyTitleCell = new DataGridEmptyTitleCellMan();
      emptyTitleCell.Grid = this;
      titleCellMan = new DataGridTitleCellMan();
      titleCellMan.Grid = this;
      //emptyIndicatorCell = new DataGridIndicatorDataCell();
      //emptyIndicatorCell.grid = this;
      emptyDataCell = new DataGridEmptyDataCellMan();
      emptyDataCell.Grid = this;
      indicatorCell = new DataGridIndicatorDataCellMan();
      indicatorCell.Grid = this;
      titleIndicatorCell = new DataGridIndicatorTitleCellMan();
      titleIndicatorCell.Grid = this;
      //horzEmptySpaceCell = new DataGridHorzEmptySpaceCell();
      //horzEmptySpaceCell.grid = this;

      autoSizeColumnOptions = new DataGridAutoSizeColumnOptions(this);

      SearchBoxControl = new DataGridSearchBoxControl(this);
      Controls.Add(SearchBoxControl);
      searchBox = new DataGridSearchBox(this);
      locateTextService = new DataGridLocateTextService(this);

      selection = new DataGridSelection(this);
      editActions = new DataGridEditActions(this);
      allowedOperations = new DataGridAllowedOperations(this);
      emptyDataInfo = new GridEmptyDataInfo(this);

      ContextMenuBuildingMode = ContextMenuBuildingMode.LocalAndGlobalMenuCompound;

      dataView = new DataGridDataView(this);
      dataViewBindingSource = new BindingSource();
      dataViewBindingSource.PositionChanged += DataViewCurrencyManagerPositionChanged;
      dataViewBindingSource.DataSource = dataView;

      //settingsKeeper = new DataGridSettingsKeeper();

      InitData();

      UpdateBaseFixedBands();
      UpdateColumnsList();
      UpdateDataRows();

    }

    internal void InitData()
    {
      indicatorColumn = CreateIndicatorColumn();
      indicatorTitle = CreateIndicatorTitle();
      //keyboardOptions = CreateKeyKeyboardOptions();
      UpdateGridState();
    }

    #region designtime properties

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public DataGridBaseCellMan EmptyDataCell
    {
      get { return emptyDataCell; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    //[Editor(typeof(Design.DataGridColumnsEditor), typeof(UITypeEditor))]
    [Editor("EhLib.Design.DataGridColumnsEditor" + EhLibUtils.EhLibDesignDesignerVersionInfo, "System.Drawing.Design.UITypeEditor, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
    public DataGridStaticColumnCollection StaticColumns
    {
      get { return (DataGridStaticColumnCollection)base.StaticPropBars; }
    }

    //[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    //public List<DataGridColumn> StaticColumns2
    //{
    //  get { return staticColumns2; }
    //}

    //[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    //public List<DataGridColumnTitle> StaticColumnTitles2
    //{
    //  get { return staticColumnTitles2; }
    //}

    //[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    //public List<IMultiTitleNodeProvider> MultiTitleNodes
    //{
    //  get { return multiTitleNodes; }
    //}

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridSelection Selection
    {
      get { return selection; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridColumnOptions ColumnOptions
    {
      get { return columnOptions; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridRowOptions RowOptions
    {
      get { return rowOptions; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridFooter Footer
    {
      get { return footer; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public GridEmptyDataInfo EmptyDataInfo
    {
      get { return emptyDataInfo; }
    }
    
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridAllowedOperations AllowedOperations
    {
      get
      {
        return allowedOperations;
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public new DataGridKeyboardOptions KeyboardOptions
    {
      get
      {
        return (DataGridKeyboardOptions)base.KeyboardOptions;
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridTitle Title
    {
      get { return (DataGridTitle)base.TitleBar; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public new DataGridHorzScrollBar HorzScrollBar
    {
      get { return (DataGridHorzScrollBar)base.HorzScrollBar; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public new DataGridVertScrollBar VertScrollBar
    {
      get { return (DataGridVertScrollBar)base.VertScrollBar; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridAutoSizeColumnOptions AutoSizeColumnOptions
    {
      get { return autoSizeColumnOptions; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridIndicatorColumn IndicatorColumn
    {
      get { return indicatorColumn; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridIndicatorTitle IndicatorTitle
    {
      get { return indicatorTitle; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridEditActions EditActions
    {
      get { return editActions; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridSearchBox SearchBox
    {
      get { return searchBox; }
      //      set { FVertScrollBar = value; }
    }

    public bool AutoGenerateColumns
    {
      get { return base.AutoGeneratePropBars; }
      set { base.AutoGeneratePropBars = value; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridLineOptions LineOptions
    {
      get { return (DataGridLineOptions)GridLineColors; }
    }

    [Browsable(true)]
    public new bool UseVisualStyles
    {
      get
      {
        return base.UseVisualStyles;
      }

      set
      {
        base.UseVisualStyles = value;
      }
    }

    [Browsable(true)]
    public new CellBackFiller FixedBackFiller
    {
      get
      {
        return base.FixedBackFiller;
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public new GridBackground Background
    {
      get { return base.Background; }
    }

    [DefaultValue(ContextMenuBuildingMode.LocalAndGlobalMenuCompound)]
    public ContextMenuBuildingMode ContextMenuBuildingMode
    {
      get;
      set;
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    //[Editor("EhLib.Design.ObjectSelectorEditorByType" + EhLibUtils.EhLibDesignDesignerVersionInfo, "System.Drawing.Design.UITypeEditor, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
    [Editor("EhLib.Design.PrintServiceComponentEditor" + EhLibUtils.EhLibDesignDesignerVersionInfo, "System.Drawing.Design.UITypeEditor, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
    [DefaultValue(null)]
    public DataGridPrintService PrintService
    {
      get
      {
        return printService;
      }
      set
      {
        if (printService != value)
        {
          if (printService != null)
            printService.Dispose();

          printService = value;
        }
      }
    }
    #endregion designtime properties

    #region runtime properties
    [Browsable(false)]
    public int TitleRowIndex
    {
      get { return titleRowIndex; }
    }

    [Browsable(false)]
    public bool GridIsEmpty
    {
      get { return gridIsEmpty; }
    }

    protected internal DataGridState DataGridState
    {
      get
      {
        return dataGridState;
      }
      set
      {
        dataGridState = value;
      }
    }

    [Browsable(false)]
    public override int CurrentDataColIndex
    {
      get { return Col - StartDataColIndex; }
    }

    [Browsable(false)]
    public override int CurrentDataRowIndex
    {
      get { return Row - FixedRowCount; }
    }

    [Browsable(false)]
    public DataGridReadOnlyColumnCollection DynamicColumns
    {
      get { return (DataGridReadOnlyColumnCollection)base.DynamicPropBars; }
    }

    [Browsable(false)]
    public DataGridMainColumnCollection Columns
    {
      get { return (DataGridMainColumnCollection)base.PropBars; }
    }

    [Browsable(false)]
    public DataGridReadOnlyColumnCollection ViewOrderedColumns
    {
      get { return (DataGridReadOnlyColumnCollection)base.ViewOrderedPropBars; }
    }

    [Browsable(false)]
    public DataGridReadOnlyColumnCollection VisibleColumns
    {
      get { return (DataGridReadOnlyColumnCollection)base.VisiblePropBars; }
    }

    [Browsable(false)]
    public DataGridRows Rows
    {
      get { return rows; }
    }

    [Browsable(false)]
    public DataGridVisibleRows VisibleRows
    {
      get { return visibleRowList; }
    }

    [Browsable(false)]
    public DataGridDataView DataView
    {
      get { return dataView; }
    }

    [Browsable(false)]
    public BindingSource DataViewBindingSource
    {
      get { return dataViewBindingSource; }
    }

    [Browsable(false)]
    public DataGridSortCollection SortMarkers
    {
      get { return sortMarkers; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public int CurrentColumnIndex
    {
      get { return Col - FixedColCount; }
      set { Col = value + FixedColCount; }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public int CurrentRowIndex
    {
      get
      {
        return InternalCurrentRowIndex;
      }

      set
      {
        DataLink.Position = VisibleRows[value].Index;
      }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public DataGridRow CurrentRow
    {
      get
      {
        if (VisibleRows.Count == 0)
          return null;
        else
          return VisibleRows[CurrentRowIndex];
      }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public int NewRowIndex
    {
      get
      {
        if (DataLink.CurrentListItemState == RowEditState.Add)
          return Row;
        else if (AllowedOperations.AllowAdd)
          return VisibleRows.Count + FixedRowCount;
        else
          return -1;
      }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    protected internal int InternalCurrentRowIndex
    {
      get
      {
        return internalCurrentRowIndex;
      }

      set
      {
        if (internalCurrentRowIndex != value)
        {
          internalCurrentRowIndex = value;
          if (internalCurrentRowIndex != -1)
            Row = internalCurrentRowIndex + FixedRowCount;
          else
            InvalidateRow(Row);
        }
      }
    }

    //[Browsable(false)]
    //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    //public new DataGridBaseCell CurrentCellMan
    //{
    //  get
    //  {
    //    return (DataGridBaseCell)base.CurrentCellMan;
    //  }
    //}

    //[Browsable(false)]
    //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    //public override ISite Site
    //{
    //  get
    //  {
    //    return base.Site;
    //  }
    //  set
    //  {
    //    base.Site = value;

    //    if (this.Site != null)
    //    {
    //      INestedContainer nc = (INestedContainer)this.Site.GetService(typeof(INestedContainer));
    //      if (nc != null)
    //      {
    //        nc.Add(this.SearchBox, "SearchBox");
    //      }
    //    }
    //  }
    //}

    protected internal new DataGridScrollBarPanelControl HorzScrollBarPanelControl
    {
      get { return (DataGridScrollBarPanelControl)base.HorzScrollBarPanelControl; }
    }

    [Browsable(false)]
    public int IndicatorColIndex
    {
      get
      {
        if (IndicatorColumn.Visible)
          return 0;
        else
          return -1;
      }
    }

    [Browsable(false)]
    public int StartDataColIndex
    {
      get
      {
        return IndicatorColIndex + 1;
      }
    }

    //[Browsable(false)]
    //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    //public DataGridSettingsKeeper SettingsKeeper
    //{
    //  get { return settingsKeeper; }
    //}

    protected override PropertyAxisBar CurrentPropBar
    {
      get
      {
        if (CurrentColumnIndex < VisibleColumns.Count)
          return VisibleColumns[CurrentColumnIndex];
        else
          return null;
      }
    }

    protected override object CurrentListItemBar
    {
      get { return CurrentRow; }
    }

    protected override bool FullRedrawOnScroll
    {
      get
      {
        bool result = base.FullRedrawOnScroll;
        if (!result)
        {
          foreach (DataGridColumn col in VisibleColumns)
          {
            if (col.IsFullInvalidateOnVertScroll())
            {
              result = true;
              break;
            }
          }
        }
        return result;
      }
    }
    #endregion runtime properties

    #region events
    //public event KeyEventHandler MyKeyDown
    //{
    //  add
    //  remove
    //}

    public event DataGridDataCellEventHandler DataCellClick
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellClick, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellClick, value);
      }
    }

    public event DataGridDataCellEventHandler DataCellContentClick
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellContentClick, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellContentClick, value);
      }
    }

    public event DataGridDataCellMouseEventHandler DataCellMouseDown
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellMouseDown, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellMouseDown, value);
      }
    }

    public event EventHandler<DataGridDataCellContextMenuStripNeededEventArgs> DataCellContextMenuStripNeeded
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellContextMenuStripNeeded, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellContextMenuStripNeeded, value);
      }
    }

    //public event DataGridColumnTitleContextMenuStripNeededEventHandler ColumnTitleContextMenuStripNeeded
    //{
    //  add { this.Events.AddHandler(EventKeyColumnTitleContextMenuStripNeeded, value); }
    //  remove { this.Events.RemoveHandler(EventKeyColumnTitleContextMenuStripNeeded, value); }
    //}

    public event DataGridDefaultContextMenuStripNeededEventHandler DefaultContextMenuStripNeeded
    {
      add { this.Events.AddHandler(EventKeyDefaultContextMenuStripNeeded, value); }
      remove { this.Events.RemoveHandler(EventKeyDefaultContextMenuStripNeeded, value); }
    }

    public event DataGridRowIsSelectableEventHandler RowIsSelectable
    {
      add { this.Events.AddHandler(EventKeyRowIsSelectable, value); }
      remove { this.Events.RemoveHandler(EventKeyRowIsSelectable, value); }
    }

    public event DataGridEventHandler SelectionChanged
    {
      add
      {
        this.Events.AddHandler(EventKeyDataGridSelectionChanged, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataGridSelectionChanged, value);
      }
    }

    public event DataGridRowHeightQueryingEventHandler RowHeightQuerying
    {
      add
      {
        this.Events.AddHandler(EventKeyDataGridRowHeightQuerying, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataGridRowHeightQuerying, value);
      }
    }

    public event DataGridHorzLineParamsNeededEventHandler HorzLineParamsNeeded
    {
      add
      {
        this.Events.AddHandler(EventKeyDataGridHorzLineParamsNeeded, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataGridHorzLineParamsNeeded, value);
      }
    }

    public event EventHandler OrderedColumnsListChanged
    {
      add
      {
        Events.AddHandler(EventKeyDataGridOrderedColumnsListChanged, value);
      }
      remove
      {
        Events.RemoveHandler(EventKeyDataGridOrderedColumnsListChanged, value);
      }
    }

    public event EventHandler VisibleRowsListChanged
    {
      add
      {
        Events.AddHandler(EventKeyDataGridVisibleRowsListChanged, value);
      }
      remove
      {
        Events.RemoveHandler(EventKeyDataGridVisibleRowsListChanged, value);
      }
    }

    public event EventHandler<DataGridColumnEventArgs> ColumnWidthChanged
    {
      add
      {
        this.Events.AddHandler(EventKeyDataGridColumnWidthChanged, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataGridColumnWidthChanged, value);
      }
    }

    public event EventHandler<DataGridDisplayColumnsMovedEventArgs> DisplayColumnsMoved
    {
      add
      {
        this.Events.AddHandler(EventKeyDataGridDisplayColumnsMoved, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataGridDisplayColumnsMoved, value);
      }
    }

    public event EventHandler<DataGridDataCellFormatParamsEventArgs> DataCellQueryFillFormatParams
    {
      add
      {
        this.Events.AddHandler(EventKeyDataCellQueryFillFormatParams, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataCellQueryFillFormatParams, value);
      }
    }

    public event EventHandler<DataGridCreatingDynamicColumnsForDataPropertyEventArgs> CreatingDynamicColumnsForDataProperty
    {
      add                                  
      {
        this.Events.AddHandler(EventKeyCreatingDynamicPropBarsForDataProperty, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyCreatingDynamicPropBarsForDataProperty, value);
      }
    }

    #endregion events

    #region public methods
    public override void GetDrawSizingLineBound(out int startPos, out int finishPos, int lineIndex)
    {
      base.GetDrawSizingLineBound(out startPos, out finishPos, lineIndex);
      if ((GridState == BaseGridState.ColSizing) && (Title.MultiTitle.Active))
      {
        int columnIndex = RawToDataColumnIndex(lineIndex);
        if (columnIndex >= 0)
        {
          DataGridColumn column = VisibleColumns[columnIndex];
          Title.MultiTitle.FixSizingLineBound(ref startPos, ref finishPos, column);
        }
      }
    }

    public int RawToDataColumnIndex(int col)
    {
      return col - (FixedColCount - FrozenColCount);
    }

    public int DataToRawCol(int columnIndex)
    {
      return columnIndex + (FixedColCount - FrozenColCount);
    }

    public int RawToDataRowIndex(int row)
    {
      return row - FixedRowCount;
    }

    public int DataToRawRow(int dataRowIndex)
    {
      return dataRowIndex + FixedRowCount;
    }

    public GridCoord RawToDataCell(GridCoord rawGridCoord)
    {
      return new GridCoord(RawToDataColumnIndex(rawGridCoord.X), RawToDataRowIndex(rawGridCoord.Y));
    }

    public GridCoord DataToRawCell(GridCoord dataGridCoord)
    {
      return new GridCoord(DataToRawCol(dataGridCoord.X), DataToRawRow(dataGridCoord.Y));
    }

    public void GetColumnRowByDataColRowIndex(int areaColIndex, int areaRowIndex, 
      out DataGridColumn column, out DataGridRow row)
    {
      if (areaColIndex < VisibleColumns.Count)
        column = VisibleColumns[areaColIndex];
      else
        column = null;

      if (areaRowIndex < VisibleRows.Count)
        row = VisibleRows[areaRowIndex];
      else
        row = null;
    }

    public void PutFocus()
    {
      FocusGrid();
    }

    public void MoveDisplayColumns(DataGridColumn[] columns, int toIndex)
    {
      SetDisplayIndexForColumnsRange(columns, toIndex);
    }

    #endregion

    #region nopublic methods
    //AutoGenerateColumns
    protected virtual bool DefaultAutoGenerateColumns()
    {
      return DefaultAutoGeneratePropBars();
    }

    protected virtual bool ShouldSerializeAutoGenerateColumns()
    {
      return ShouldSerializeAutoGeneratePropBars();
    }

    public virtual void ResetAutoGenerateColumns()
    {
      ResetAutoGeneratePropBars();
    }

    //Others
    protected override GridKeyboardOptions CreateKeyboardOptions()
    {
      return new DataGridKeyboardOptions(this);
    }

    internal virtual bool OnIndicatorTitleMouseDownEvent(BaseGridCellMouseEventArgs e)
    {
      return false;
    }

    protected internal virtual void MultiTitleChanged()
    {
      InvalidateGrid();
      UpdateColumnsView();
      UpdateBaseFixedBands();
    }

    protected override DataAxisGridReadOnlyPropBarCollection CreatePropBarReadOnlyCollection(IList<PropertyAxisBar> list)
    {
      return new DataGridReadOnlyColumnCollection(this, list);
    }

    protected override DataAxisGridMainPropBarCollection CreatePropBarMainCollection(IList<PropertyAxisBar> list)
    {
      return new DataGridMainColumnCollection(this, list);
    }

    protected override DataAxisGridStaticPropBarCollection CreateStaticPropBarCollection()
    {
      return new DataGridStaticColumnCollection(this);
    }

    internal protected override DataAxisGridTitleBar CreateTitleBar()
    {
      return new DataGridTitle(this);
    }

    protected internal override void OnGetCellBorderParams(BaseGridCellManager cell, BaseGridCellBorderEventArgs e)
    {
      base.OnGetCellBorderParams(cell, e);

      if (e.ColIndex == -1 && ContraColCount > 0 && e.BorderType == GridCellBorderType.Right)
        e.Visible = false;
      else if (LineOptions.GridBoundaries)
      {
        if ((e.BorderType == GridCellBorderType.Right) &&
            (e.ColIndex == ColCount - 1) &&
            (e.RowIndex < RowCount))
        {
          e.Visible = true;
          if (e.RowIndex >= FixedRowCount)
            e.Color = LineOptions.DataBoundaryColor;
          e.Visible = true;
        }
        else if ((e.BorderType == GridCellBorderType.Bottom) &&
            (e.RowIndex == RowCount - 1) &&
            (e.ColIndex < ColCount))
        {
          e.Visible = true;
          if (e.ColIndex >= FixedColCount)
            e.Color = LineOptions.DataBoundaryColor;
          e.IsExtent = true;
        }
      }

    }

    protected internal virtual void OnHorzLineParamsNeeded(DataGridHorzLineParamsNeededEventArgs e)
    {
      var eh = this.Events[EventKeyDataGridHorzLineParamsNeeded] as DataGridHorzLineParamsNeededEventHandler;
      if (eh != null && !this.IsDisposed)
      {
        eh(this, e);
      }
    }

    protected override GridLineColors CreateGridLineColors()
    {
      return new DataGridLineOptions(this);
    }

    protected internal override void PrepareForShowEditor()
    {
      base.PrepareForShowEditor();
      if (VisibleRows.Count == 0 && AllowedOperations.AllowAdd)
        DataLink.AddNew();
    }

    protected internal override void ShowEditor(bool selectAll)
    {
      if (VisibleRows.Count == 0 && AllowedOperations.AllowAdd)
        DataLink.AddNew();

      base.ShowEditor(selectAll);
    }

    protected override void OnShowEditor()
    {
      Selection.CheckClear();
    }

    protected internal override bool CanShowEditor()
    {
      return !EditorBanned && ColumnOptions.CanShowEditor();
    }

    protected internal override void EditorTextChanged(EventArgs e)
    {
      base.EditorTextChanged(e);
      if (EditorMode)
      {
        UpdateBaseRowCount();
      }
    }

    protected override void OnKeyDown(KeyEventArgs e)
    {
      int nextPageRow, prevPageRow;

      base.OnKeyDown(e);
      if (e.Handled) return;

      if (!e.Shift && !e.Alt && !e.Control)
      {
        switch (e.KeyCode)
        {
          case Keys.Down:
            if (VisibleRows.Count == 0 &&
                RowCount - FixedRowCount == 1 &&
                DataLink.CurrentListItemState == RowEditState.Browse &&
                AllowedOperations.AllowAdd)
            {
              DataLink.AddNew();
            }
            break;
        }
      }
      else if (e.Shift &&
          (Selection.CellsSelectionIsAllowed || Selection.RowsSelectionIsAllowed)
         )
      {
        GridCoord newFreeEndCell;
        GridCoord curFreeEndCell;

        if (Selection.RowsSelectionIsAllowed && !Selection.CellsSelectionIsAllowed)
        {
          if (Selection.FreeEndDataRowIndex >= 0)
            newFreeEndCell = new GridCoord(CurrentDataColIndex, Selection.FreeEndDataRowIndex);
          else
            newFreeEndCell = new GridCoord(CurrentDataColIndex, CurrentDataRowIndex);
        }
        else if (Selection.SelectionType == GridSelectionType.CellsBox)
          newFreeEndCell = Selection.FreeEndCell;
        else
          newFreeEndCell = new GridCoord(CurrentDataColIndex, CurrentDataRowIndex);
        curFreeEndCell = newFreeEndCell;
        switch (e.KeyCode)
        {
          case Keys.Up:
            newFreeEndCell.Y--;
            break;
          case Keys.Down:
            newFreeEndCell.Y++;
            break;
          case Keys.Left:
            newFreeEndCell.X--;
            break;
          case Keys.Right:
            newFreeEndCell.X++;
            break;
          case Keys.Home:
            newFreeEndCell.X = 0;
            break;
          case Keys.End:
            newFreeEndCell.X = Columns.Count - 1;
            break;
          case Keys.PageDown:
            CalcPageExtents(out nextPageRow, out prevPageRow);
            newFreeEndCell.Y = nextPageRow;
            break;
          case Keys.PageUp:
            CalcPageExtents(out nextPageRow, out prevPageRow);
            newFreeEndCell.Y = prevPageRow;
            break;
        }
        Restrict(ref newFreeEndCell, 0, 0, VisibleColumns.Count - 1, VisibleRows.Count - 1);
        if (Selection.CellsSelectionIsAllowed && 
           (curFreeEndCell != newFreeEndCell))
        {
          Selection.SetSelectedFreeEndCell(newFreeEndCell);
          ClampInView(DataToRawCell(newFreeEndCell), true, true);
        }
        else if (Selection.RowsSelectionIsAllowed &&
                (curFreeEndCell.Y != newFreeEndCell.Y))
        {
          newFreeEndCell.X = curFreeEndCell.X;
          if (Selection.AnchorDataRowIndex == -1)
            StartRowSelection(VisibleRows[CurrentRowIndex], true, false, false);
          Selection.SetFreeEndRow(newFreeEndCell.Y);
          ClampInView(DataToRawCell(newFreeEndCell), true, true);
        }
      }

      switch (e.KeyData & Keys.KeyCode)
      {
        case Keys.F2:
          {
            e.Handled = ProcessF2Key(e.KeyData);
            return;
          }
        case Keys.Tab:
          {
            e.Handled = ProcessTabKey(e.KeyData);
            return;
          }
        case Keys.Delete:
          {
            if (e.Control)
                e.Handled = ProcessControlDelete(e.KeyData);
            return;
          }
      }
    }

    protected override void OnKeyPress(KeyPressEventArgs e)
    {
      base.OnKeyPress(e);
    }

    protected override void OnKeyUp(KeyEventArgs e)
    {
      base.OnKeyUp(e);
      if (e.Handled) return;

      switch (e.KeyData & Keys.KeyCode)
      {
        case Keys.ControlKey:
          {
            if (Title.MultiSortMarking)
              SortMarkers.CommitChanges();
            break;
          }
      }
    }

    protected override bool IsInputKey(Keys keyData)
    {
      switch (keyData & Keys.KeyCode)
      {
        case Keys.Tab:
          {
            Keys altData = (keyData & (Keys.Control | Keys.Shift | Keys.Alt));
            if ((altData == 0 || altData == Keys.Shift) && ((GridOptions.Tabs & Options) != 0))
              return (KeyboardOptions.TabKeyAction == GridKeyboardAction.NextColCell);
            else
              break;
          }
      }
      return base.IsInputKey(keyData);
    }

    protected override bool ProcessKeyPreview(ref Message m)
    {
      KeyEventArgs ke = new KeyEventArgs((Keys)((int)m.WParam) | ModifierKeys);

      if (m.Msg == NativeMethods.WM_KEYDOWN || m.Msg == NativeMethods.WM_SYSKEYDOWN)
      {
        if (ProcessDataGridKeyPreview(ke))
          return true;
      }
      return base.ProcessKeyPreview(ref m);
    }

    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
      if (((int)keyData == (int)SearchBox.Shortcut) && 
          (SearchBox.Enabled))
      {
        SearchBox.Visible = true;
        SearchBox.Active = true;
        return true;
      }
      else
        return base.ProcessCmdKey(ref msg, keyData);
    }

    protected override bool ProcessDialogKey(Keys keyData)
    {
      if (SearchBox.Active)
        return base.ProcessDialogKey(keyData);

      if (EditorMode &&
          ((IDataAxisGridCellInPlaceEditor)CellEditControl).EditorWantsInputKey(keyData, true))
      {
        return base.ProcessDialogKey(keyData); 
      }

      Keys key = (keyData & Keys.KeyCode);

      switch (key)
      {
        case Keys.Enter:
          {
            if (ProcessEnterKey(keyData))
              return true;
            else
              break;
          }
        case Keys.Escape:
          {
            if (ProcessEscapeKey(keyData))
              return true;
            else
              break;
          }
        case Keys.C:
        case Keys.Insert:
        case Keys.V:
        case Keys.X:
        case Keys.Delete:
          if (ProcessCopyKey(keyData))
            return true;
          else if (ProcessPasteKey(keyData))
            return true;
          else if (ProcessCutKey(keyData))
            return true;
          else
            break;
        case Keys.Tab:
          if (/*(KeyboardOptions.TabKeyAction == DataGridKeyboardActions.None) && */EditorMode)
          {
            if (HideEditor(true))
            {
              if (KeyboardOptions.TabKeyAction == GridKeyboardAction.NextColCell)
              {
                ProcessTabKey(keyData);
                return true;
              }
            }
            else
              return true; //Stayed in Editor
          }
          break;
      }

      return base.ProcessDialogKey(keyData);
    }

    protected virtual bool ProcessDataGridKeyPreview(KeyEventArgs e)
    {
      if (EditorMode &&
          ((IDataAxisGridCellInPlaceEditor)CellEditControl).EditorWantsInputKey(e.KeyData, true))
      {
        return false;
      }

      switch (e.KeyCode)
      {
        case Keys.Escape:
          {
            return ProcessEscapeKey(e.KeyData);
          }
      }
      return false;
    }

    protected override bool ProcessTabKey(Keys keyData)
    {
      HideEditor(true);
      return base.ProcessTabKey(keyData);
    }

    protected virtual bool ProcessControlDelete(Keys keyData)
    {
      if (AllowedOperations.AllowRemove && VisibleRows.Count > 0)
      {
        DataLink.DeleteCurrent();
        return true;
      }
      else
      {
        return false;
      }
    }

    protected internal virtual void StartColumnSelection(DataGridColumn column, bool addToSelection)
    {

      Rectangle noScrollRect = Rectangle.Empty;

      dataGridState = DataGridState.ColumnsSelecting;
      //columnSelectIsSelect = !column.Selected;

      noScrollRect.X = HorzAxis.FixedBoundary;
      noScrollRect.Width = HorzAxis.RollClientLen;
      noScrollRect.Y = VertAxis.GridClientStart;
      noScrollRect.Height = VertAxis.GridClientStop - VertAxis.GridClientStart;

      MoveNScrollService.Capture(this, noScrollRect, ColSelectServiceEventHandler, true, false);

      if (addToSelection)
        Selection.AddSelectedColumn(column, !column.Selected);
      else
        Selection.SetSelectedColumn(column);
      Selection.InitAnchorCol(column.VisibleIndex);
    }

    protected internal virtual void ColSelectServiceEventHandler(MoveAndScrollService service, MouseEventArgs e)
    {
      int freeEndCol = Selection.FreeEndCol;

      if (e.X > MoveNScrollService.ClientRect.Right)
      {
        SafeScrollData(HorzAxis.GetScrollStep(), 0);
        freeEndCol = HorzAxis.RollLastVisCell + HorzAxis.FixedCellCount;
        freeEndCol = RawToDataColumnIndex(freeEndCol);
      }
      else if (e.X < MoveNScrollService.ClientRect.Left)
      {
        SafeScrollData(-HorzAxis.GetScrollStep(), 0);
        freeEndCol = HorzAxis.RollStartVisCell + HorzAxis.FixedCellCount;
        freeEndCol = RawToDataColumnIndex(freeEndCol);
      }
      else
      {
        GridCoord cellHit = MouseCoord(e.X, e.Y);
        if (cellHit.X >= 0)
        {
          freeEndCol = RawToDataColumnIndex(cellHit.X);
        }
      }
      Selection.SetFreeEndCol(freeEndCol);

    }

    protected internal virtual void StartRowSelection(DataGridRow row, bool addToSelection, bool captureMnsService, bool shiftMode)
    {

      bool canSelectRow;
      Rectangle noScrollRect = Rectangle.Empty;

      dataGridState = DataGridState.RowsSelecting;

      noScrollRect.X = HorzAxis.GridClientStart;
      noScrollRect.Width = HorzAxis.GridClientStop - HorzAxis.GridClientStart;
      noScrollRect.Y = VertAxis.FixedBoundary;
      noScrollRect.Height = VertAxis.RollClientLen;

      if (addToSelection == false || row.Selected == false)
        canSelectRow = CanSelectRow(row);
      else
        canSelectRow = true;

      if (canSelectRow)
      {
        if (captureMnsService)
          MoveNScrollService.Capture(this, noScrollRect, RowSelectServiceEventHandler, false, true);

        if (shiftMode)
          Selection.SetFreeEndRow(row.VisibleIndex);
        else
        {
          if (addToSelection)
            Selection.AddSelectedRow(row, !row.Selected);
          else
            Selection.SetSelectedRow(row);
          Selection.InitAnchorRow(row.VisibleIndex, row.Selected);
        }
      }
    }

    protected internal virtual bool CanSelectRow(DataGridRow row)
    {
      DataGridRowIsSelectableEventHandler eh = this.Events[EventKeyRowIsSelectable] as DataGridRowIsSelectableEventHandler;
      if (eh != null && !this.IsDisposed)
      {
        DataGridRowIsSelectableEventArgs e = new DataGridRowIsSelectableEventArgs(row);
        e.RowIsSelectable = true;
        eh(this, e);
        return e.RowIsSelectable;
      }
      else
      {
        return true;
      }
    }

    protected internal virtual void RowSelectServiceEventHandler(MoveAndScrollService service, MouseEventArgs e)
    {
      int freeEndDataRowIndex = Selection.FreeEndDataRowIndex;
      if (e.Y > MoveNScrollService.ClientRect.Bottom)
      {
        SafeScrollData(0, HorzAxis.GetScrollStep());
        freeEndDataRowIndex = VertAxis.RollLastVisCell + VertAxis.FixedCellCount;
        freeEndDataRowIndex = RawToDataRowIndex(freeEndDataRowIndex);
      }
      else if (e.Y < MoveNScrollService.ClientRect.Top)
      {
        SafeScrollData(0, -HorzAxis.GetScrollStep());
        freeEndDataRowIndex = VertAxis.RollStartVisCell + VertAxis.FixedCellCount;
        freeEndDataRowIndex = RawToDataRowIndex(freeEndDataRowIndex);
      }
      else
      {
        GridCoord cellHit = MouseCoord(e.X, e.Y);
        if (cellHit.Y >= 0)
        {
          freeEndDataRowIndex = RawToDataRowIndex(cellHit.Y);
        }
      }
      if (freeEndDataRowIndex >= VisibleRows.Count)
        freeEndDataRowIndex = VisibleRows.Count - 1;
      //Debug.WriteLine("RowSelectServiceEventHandler: " + FreeEndDataRowIndex.ToString());
      Selection.SetFreeEndRow(freeEndDataRowIndex);

    }

    protected internal virtual void StartCellRectSelectionMode(MouseEventArgs e)
    {
      dataGridState = DataGridState.CellsRectSelecting;
      GridCoord cellHit = MouseCoord(e.X, e.Y);
      GridCoord dataCellHit = new GridCoord(RawToDataColumnIndex(cellHit.X), RawToDataRowIndex(cellHit.Y));

      if (dataCellHit.X < 0) dataCellHit.X = 0;
      if (dataCellHit.X >= VisibleColumns.Count) dataCellHit.X = ViewOrderedColumns.Count - 1;
      if (dataCellHit.Y < 0) dataCellHit.Y = 0;
      if (dataCellHit.Y >= VisibleRows.Count) dataCellHit.Y = VisibleRows.Count - 1;

      //Debug.Assert(dataCellHit.X >= 0 && dataCellHit.Y >= 0, "DataGridEh.StartCellRectSelectionMode << cellHit.X < 0 || cellHit.Y < 0 >> ");
      if (dataCellHit.X >= 0 && dataCellHit.Y >= 0)
        Selection.StartCellsRectSelection(new GridCoord(CurrentDataColIndex, CurrentDataRowIndex), dataCellHit);
    }

    protected virtual DataGridIndicatorColumn CreateIndicatorColumn()
    {
      return new DataGridIndicatorColumn(this);
    }

    protected virtual DataGridIndicatorTitle CreateIndicatorTitle()
    {
      return new DataGridIndicatorTitle(this);
    }

    protected override void OnResize(EventArgs e)
    {
      base.OnResize(e);
      UpdateSearchBox();
      UpdateFitColWidthsToClient();
    }

    protected override bool CanResizeCol(int colIndex, int rowIndex, int xPos, int yPos, int inCellXPos, int inCellYPos)
    {
      bool result = base.CanResizeCol(colIndex, rowIndex, xPos, yPos, inCellXPos, inCellYPos);

      if (!result)
        return false;
      else if (VisibleColumns.Count == 0)
      {
        return false;
      }
      else
      {
        if (Title.MultiTitle.Active)
        {
          int dataColIndex = BaseToDataColIndex(colIndex);
          if (dataColIndex >= VisibleColumns.Count) return false;
          DataGridColumn column = VisibleColumns[dataColIndex];
          DataGridTitleNode titleNode = column.Title.TitleNode;
          DataGridTitleNode upNode = titleNode;

          int subTitleHeight = titleNode.Bounds.Height;
          while (upNode.Parent != Title.MultiTitle.Root)
          {
            if (upNode.Parent.VisibleItems[upNode.Parent.VisibleItems.Count - 1] == upNode)
            {
              upNode = upNode.Parent;
              subTitleHeight = subTitleHeight + upNode.Bounds.Height;
            }
            else
              break;
          }

          if (inCellYPos >= RowHeights[rowIndex] - subTitleHeight)
            return true;
          else
            return false;
        }
        else
        {
          return true;
        }
      }
    }

    public override void InteractiveFocusCell(int col, int row, InteractiveActionSource actionSource)
    {
      if ((col == Col) && (row == Row)) return;
      if (!PrepareChangeCellPos()) return;
      //if ((ModifierKeys & Keys.Shift) != 0) return;
      if (!DataLink.Active) return;
      if ((row - FixedRowCount) == VisibleRows.Count)
        DataLink.AddNew();
      else
        DataLink.Position = VisibleRows[row - FixedRowCount].Index;

      if (Selection.RowSelect)
        MoveCurrent(Col, row, false, true);
      else
        FocusCell(col, Row, false);
    }

    protected override void CurrentCellMoved(GridCoord oldCurCell)
    {
      Selection.StopSelectionState();
      Selection.CheckClear();
      if (oldCurCell.Y != Row)
      {
        InvalidateRow(oldCurCell.Y);
        InvalidateRow(Row);
      }
      HorzScrollBarPanelControl.RealignControls();
      VertScrollBarPanelControl.RealignControls();
    }

    protected override void InteractiveSetColWidths(int colIndex, int newSize)
    {
      if (DesignMode && DataGridDesigner != null)
      {
        DataGridDesigner.InteractiveSetColWidths(colIndex, newSize);
        return;
      }

      if (colIndex >= StartDataColIndex)
      {
        DataGridColumn column = VisibleColumns[colIndex - StartDataColIndex];

        if (AutoSizeColumnOptions.FitToClient)
          SetColumnWidthFitClientMode(column, newSize);
        else
        {

          if (Selection.SelectionType == GridSelectionType.Columns &&
              column.Selected
             )
          {
            foreach (DataGridColumn col in VisibleColumns)
              if (col.Selected)
                col.Width = newSize;

          }
          else
          {
            column.Width = newSize;
          }
        }
      }
      else
        base.InteractiveSetColWidths(colIndex, newSize);

      if (EditorMode)
        UpdateCellEditorBounds();
    }

    public override PropertyAxisBar CreatePropBarFromType(Type type)
    {
      return DataGridManager.DefaultManager.GetDataGridColumnForType(type);
    }

    public override Type GetAxisBarTypeForDataType(Type type)
    {
      return DataGridManager.DefaultManager.GetDataGridColumnTypeForDataType(type);
    }

    protected override void InitDynaPropBar(PropertyAxisBar bar, PropertyDescriptor prop)
    {
      base.InitDynaPropBar(bar, prop);

      DataGridColumn col = (DataGridColumn)bar;
      col.DefaultWidth = col.CalcDefaultWidth();
    }

    private void ColumnsDisplayProperiesChanged()
    {
      UpdateColumnsView();
    }

    protected internal override void PropertyAxisBarVisibleChanged(PropertyAxisBar propAxisBar, bool value)
    {
      if (Title.MultiTitle.Active)
        ((DataGridColumn)propAxisBar).Title.TitleNode.VisibleChanged();
      base.PropertyAxisBarVisibleChanged(propAxisBar, value);
    }

    protected internal override bool PropBarCanBeVisible(PropertyAxisBar bar)
    {
      if (Title.MultiTitle.Active)
        return Title.MultiTitle.ColumnCanBeVisible((DataGridColumn)bar);
      else
        return true;
    }

    protected internal void UpdateColumnsList()
    {
      UpdatePropBarsList();
    }

    protected override void PropBarsListUpdated()
    {
      base.PropBarsListUpdated();
      if (Title.MultiTitle.Active)
        Title.MultiTitle.SynchroniseWithGridColumns();
      UpdateRowsForChangedColumns();
    }

    protected override void OnOrderedColumnsListChanged(EventArgs e)
    {
      var handler = (EventHandler)Events[EventKeyDataGridOrderedColumnsListChanged];
      if (handler != null)
        handler(this, e);
    }

    protected internal virtual void OnVisibleRowsListChanged(EventArgs e)
    {
      var handler = (EventHandler)Events[EventKeyDataGridVisibleRowsListChanged];
      if (handler != null)
        handler(this, e);
    }

    protected internal override void SetPropBarDisplayIndex(PropertyAxisBar propertyAxisBar, int newDisplayIndex)
    {
      if (InInitialization) return;
      DataGridColumn curGridColumn = VisibleColumns[CurrentColumnIndex];

      base.SetPropBarDisplayIndex(propertyAxisBar, newDisplayIndex);
      if (Columns.Updating) return;

      ColumnsDisplayProperiesChanged();

      SetCurColByGridColumn(curGridColumn);
      if (EditorMode)
        UpdateCellEditorBounds();
    }

    protected override void VisibleColumnsListChanged()
    {
      if (Title.MultiTitle.Active)
        Title.MultiTitle.ColumnWidthsChanged();
    }

    protected internal virtual void UpdateColumnsView()
    {
      UpdatePropBarsView();
    }

    protected internal override void UpdatePropBarsView()
    {
      base.UpdatePropBarsView();
      UpdateGridState();
      UpdateBaseGridColumns();
      UpdateFitColWidthsToClient();
    }

    protected override int CompareDisplayOrderColumns(PropertyAxisBar x, PropertyAxisBar y)
    {
      DataGridColumn xc = (DataGridColumn)x;
      DataGridColumn yc = (DataGridColumn)y;

      if (xc.Frozen != yc.Frozen)
      {
        if (xc.Frozen == DataGridColumnFrozenState.ToLeftSide)
          return -1;
        else if (yc.Frozen == DataGridColumnFrozenState.ToLeftSide)
          return 1;
        else if (xc.Frozen == DataGridColumnFrozenState.None)
          return -1;
        else if (yc.Frozen == DataGridColumnFrozenState.None)
          return 1;
        else
          return 0;
      }
      else if (xc.DisplayIndex < yc.DisplayIndex)
      {
        return -1;
      }
      else if (xc.DisplayIndex > yc.DisplayIndex)
      {
        return 1;
      }
      else
      {
        //if (x.DisplayIndexQuery && !y.DisplayIndexQuery)
        //  return -1;
        //else if (!x.DisplayIndexQuery && y.DisplayIndexQuery)
        //  return 1;
        //else if (x.DisplayIndexQuery && y.DisplayIndexQuery && x.DisplayIndexQueryIndex < y.DisplayIndexQueryIndex)
        //  return -1;
        //else if (x.DisplayIndexQuery && y.DisplayIndexQuery && x.DisplayIndexQueryIndex > y.DisplayIndexQueryIndex)
        //  return -1;
        //else 
        int xcIndex = Columns.IndexOf(xc);
        int ycIndex = Columns.IndexOf(yc);
        if (xcIndex < ycIndex)
          return -1;
        else if (xcIndex < ycIndex)
          return 1;
        else
          return 0;
      }
    }

    protected internal override void PropBarsUpdateCommitted()
    {
      base.PropBarsUpdateCommitted();
      UpdateRowsForChangedColumns();
      InvalidateGrid();
    }

    internal void UpdateRowsForChangedColumns()
    {
      UpdateRowHeights();
      //titleRow.RecreateCells();
      //dummyDataRow.RecreateCells();
    }

    protected internal virtual void OnColumnWidthChanged(DataGridColumn column)
    {
      if ((InInitialization) || Columns.Updating) return;
      //if (Title.MultiTitle.Active)
      //  Title.MultiTitle.ColumnWidthsChanged();
      UpdateRowHeights();
      UpdateBaseGridColumns();

      var eh = this.Events[EventKeyDataGridColumnWidthChanged] as EventHandler<DataGridColumnEventArgs>;
      if (eh != null && !this.IsDisposed)
      {
        eh(this, new DataGridColumnEventArgs(column));
      }
    }

    protected internal virtual void OnDisplayColumnsMoved(DataGridDisplayColumnsMovedEventArgs e)
    {
      if ((InInitialization) || Columns.Updating) return;
      var eh = this.Events[EventKeyDataGridDisplayColumnsMoved] as EventHandler<DataGridDisplayColumnsMovedEventArgs>;
      if (eh != null && !this.IsDisposed)
      {
        eh(this, e);
      }
    }

    internal void UpdateBaseGridColumns()
    {
      if ((InInitialization) || Columns.Updating) return;

      int newFixedColCount = 0;
      int leftFrozenCount = 0;
      int rightFrozenCount = 0;
      int newColCount;

      if (IndicatorColumn.Visible)
        newFixedColCount = 1;

      foreach (DataGridColumn col in VisibleColumns)
      {
        if (col.Frozen == DataGridColumnFrozenState.ToLeftSide)
          leftFrozenCount = leftFrozenCount + 1;
        else if (col.Frozen == DataGridColumnFrozenState.ToRightSide)
          rightFrozenCount = rightFrozenCount + 1;
        col.PerformLayout();
      }

      newFixedColCount = newFixedColCount + leftFrozenCount;

      SetFixedFrozenColCount(newFixedColCount, leftFrozenCount);

      newColCount = FixedColCount - FrozenColCount + VisibleColumns.Count - rightFrozenCount;
      if (VisibleColumns.Count == 0)
        newColCount = FixedColCount + 1;
      else if ((newColCount <= FixedColCount) && FrozenColCount > 0)
      {
        FrozenColCount = FrozenColCount - 1;
        FixedColCount = FixedColCount - 1;
      }
      else if ((newColCount <= FixedColCount) && rightFrozenCount > 0)
        rightFrozenCount = rightFrozenCount - 1;

      ColCount = newColCount;
      ContraColCount = rightFrozenCount;

      bool ColWidthsChanged = false;

      for (int i = 0; i < VisibleColumns.Count; i++)
      {
        DataGridColumn col = VisibleColumns[i];
        int bi = StartDataColIndex + i;
        int newWidth = col.Width + LineOptions.VertLineSpace;
        if (this.ColWidths[bi] != newWidth)
        {
          this.ColWidths[bi] = newWidth;
          ColWidthsChanged = true;
        }
      }

      if (ColWidthsChanged)
      {
        if (Title.MultiTitle.Active)
          Title.MultiTitle.ColumnWidthsChanged();
      }

      UpdateBaseIndicatorCols();

//-      if (Title.HeightOptions.AutoExpand)
      UpdateBaseFixedBands();
    }

    internal void SetFixedFrozenColCount(int newFixedColCount, int leftFrozenCount)
    {
      if (ColCount + 1 < newFixedColCount)
        ColCount = newFixedColCount + 1;
      if (newFixedColCount > FixedColCount)
      {
        FixedColCount = newFixedColCount;
        FrozenColCount = leftFrozenCount;
      }
      else
      {
        FrozenColCount = leftFrozenCount;
        FixedColCount = newFixedColCount;
      }
    }

    internal void UpdateDataRows()
    {
      Rows.Clear();
      if (CurrencyManager != null)
      {
        for (int i = 0; i < CurrencyManager.Count; i++)
        {
          InternalAddDataRow(i);
        }
      }

      InternalRebuildVisibleRows(false, false, false);
      CheckRecalcFooters();

      foreach (DataGridColumn column in Columns)
      {
        if (!String.IsNullOrEmpty(column.Title.Text) || (column.PropDescr != null))
          column.DefaultWidth = column.CalcDefaultWidth();
        else
          column.DefaultWidth = 64;
      }

      UpdateBaseGridColumns();
      UpdateDataRowHeights();

      UpdateBaseRowCount();
      UpdateBaseRowHeights();
      InvalidateGrid();
    }

    protected internal virtual void InternalRebuildVisibleRows(bool stopOnEscape, bool stopOnAnyKey, bool useWaitCursor)
    {
      int ticks = Environment.TickCount;
      bool waitCursorSet = false;

      foreach (DataGridRow row in Rows)
      {
        row.Visible = OnCheckRowVisible(row);

        if ((stopOnEscape == true) && EhLibUtils.CheckKeyPressed(this, Keys.Escape, true))
          break;

        if ((stopOnAnyKey == true) && EhLibUtils.IsAnyKeyPressed(this))
          break;

        if (useWaitCursor &&
            (Environment.TickCount - ticks > 1000) &&
            ((Cursor.Current == Cursors.Default) || (Cursor.Current == null)) &&
            (waitCursorSet == false))
        {
          Cursor.Show();
          Cursor.Current = Cursors.WaitCursor;
          waitCursorSet = true;
        }
      }

      if (waitCursorSet)
        Cursor.Current = null;

    }

    protected internal virtual void RebuildVisibleRows(bool stopOnEscape, bool stopOnAnyKey, bool useWaitCursor)
    {
      InternalRebuildVisibleRows(stopOnEscape, stopOnAnyKey, useWaitCursor);
      CheckRecalcFooters();
      UpdateBaseRowCount();
      UpdateGridRowIndexFromCurrencyManagerPosition();
      Invalidate();
    }

    protected internal virtual bool OnCheckRowVisible(DataGridRow row)
    {
      bool searchBoxRowVisible = SearchBox.CheckRowVisible(row);
      bool titleFilterRowVisible = Title.Filter.CheckRowVisible(row);
      return searchBoxRowVisible && titleFilterRowVisible;
    }

    protected internal override void OnCurrentListItemStateChanged()
    {
      UpdateBaseRowCount();
    }

    protected internal override void OnCurrentListItemModifiedStateChanged()
    {
      UpdateBaseRowCount();
    }

    protected internal override void OnEditorHasValueToPushChanged()
    {
      UpdateBaseRowCount();
    }

    protected internal override void UpdateBaseFixedBands()
    {
      int fixedRowCount = 0;

      if (Title.Visible)
      {
        fixedRowCount = fixedRowCount + 1;
        titleRowIndex = 0;
      }
      else
      {
        titleRowIndex = -1;
      }

      FixedRowCount = fixedRowCount;

      if (TitleRowIndex >= 0)
      {
        if (Title.MultiTitle.Active)
        {
          int titleAreaHeight;
          //Title.MultiTitle.ResetNodesBound();
          if (Title.MultiTitle.Root.Items.Count == 0)
          {
            titleAreaHeight = Title.CalcTitleHeight() + Title.HorzLineSpace;
          }
          else
          {
            Title.MultiTitle.ResetNodesBound();
            titleAreaHeight = Title.MultiTitle.FullHeight;
          }

          RowHeights[TitleRowIndex] = titleAreaHeight;
          Title.Height = titleAreaHeight - Title.HorzLineSpace;
        }
        else
        {
          Title.Height = Title.CalcTitleHeight();
          RowHeights[TitleRowIndex] = Title.Height + Title.HorzLineSpace;
        }


        foreach (DataGridColumn c in VisibleColumns)
        {
          Size sz;
          if (Title.MultiTitle.Active)
          {
            sz = new Size(c.Width, c.Title.TitleNode.Bounds.Height);
            sz.Height = sz.Height - Title.HorzLineSpace;
          }
          else
            sz = new Size(c.Width, Title.Height);
          c.Title.UpdateMetrics(sz);
        }

      }
      else
      {
        Title.Height = 0;
      }

      if (Footer.Rows.Count > 0)
      {
        ContraRowCount = Footer.Rows.Count;
        for (int i = 0; i < Footer.Rows.Count; i++)
        {
          DataGridFooterRow ftr = Footer.Rows[i];
          RowHeights[RowCount + i] = ftr.Height;
        }
      }
      else
      {
        ContraRowCount = 0;
      }

      InvalidateGrid();
    }

    protected internal virtual void UpdateRowHeights()
    {
      UpdateBaseFixedBands();
      UpdateDataRowHeights();
      UpdateBaseRowHeights();
    }

    protected virtual void UpdateDataRowHeights()
    {
      int rowMaxHeight = RowOptions.MaxHeight();

      defaultRowHeight = CalcDefaultRowHeight();

      foreach (DataGridRow row in Rows)
      {
        int rowHeight = CalcRowHeight(row);
        if (rowMaxHeight > 0 && rowHeight > RowOptions.MaxHeight())
          rowHeight = rowMaxHeight;
        row.HeightInternal = rowHeight;
      }

      foreach (DataGridFooterRow footerRow in Footer.Rows)
      {
        footerRow.Height = footerRow.GetFooterHeight();
      }
    }

    protected virtual int CalcDefaultRowHeight()
    {
      int maxh = 0;

      if (VisibleColumns.Count == 0)
      {
        Size sz;

        if (RowOptions.HeightOptions.Unit == GridRowHeightUnit.TextLine)
        {
          sz = TextRenderer.MeasureText(EhLibUtils.DisplayGraphicsCash, N0Str, Font);
          maxh = sz.Height * RowOptions.HeightOptions.ContentHeight;
          maxh = maxh + ColumnOptions.SidePadding.Top + ColumnOptions.SidePadding.Bottom + LineOptions.HorzLineSpace;
        }
        else
        {
          maxh = RowOptions.HeightOptions.ContentHeight;
          maxh = maxh + ColumnOptions.SidePadding.Top + ColumnOptions.SidePadding.Bottom + LineOptions.HorzLineSpace;
        }
      }
      else
      {
        foreach (DataGridColumn col in VisibleColumns)
        {
          int colh = col.CalcDefaultRowHeight();
          if (colh > maxh)
            maxh = colh;
        }
      }

      return maxh;
    }

    protected virtual int CalcColumnsRowHeight(DataGridRow row)
    {
      int maxh;

      maxh = 0;
      foreach (DataGridColumn col in VisibleColumns)
      {
        int colh = col.CalcRowHeight(row);
        if (colh > maxh)
          maxh = colh;
      }


      if (RowOptions.HeightOptions.MaxContentHeight > 0)
      {
        int rowMaxHeight;

        if (RowOptions.HeightOptions.Unit == GridRowHeightUnit.TextLine)
        {
          int fh = EhLibUtils.GetFontHeight(Font);
          rowMaxHeight = fh * RowOptions.HeightOptions.MaxContentHeight;
          rowMaxHeight = rowMaxHeight + Padding.Top + Padding.Bottom;
        }
        else
        {
          rowMaxHeight = RowOptions.HeightOptions.MaxContentHeight;
          rowMaxHeight = rowMaxHeight + Padding.Top + Padding.Bottom;
        }

        if (maxh > rowMaxHeight)
          maxh = rowMaxHeight;
      }

      return maxh;
    }

    public virtual int DefaultCalcRowHeight(DataGridRow row)
    {
      int indicatorColCellHeight = 0;
      int dataCellsHeight = 0;

      if (IndicatorColumn.Visible)
        indicatorColCellHeight = IndicatorColumn.CalcHeight(row);

      if (RowOptions.HeightOptions.AutoExpand)
        dataCellsHeight = CalcColumnsRowHeight(row);
      else
        dataCellsHeight = defaultRowHeight;

      return Math.Max(indicatorColCellHeight, dataCellsHeight);
    }

    protected virtual int CalcRowHeight(DataGridRow row)
    {
      var eh = Events[EventKeyDataGridRowHeightQuerying] as DataGridRowHeightQueryingEventHandler;
      if (eh != null && !IsDisposed)
      {
        var e = new DataGridRowHeightQueryingEventArgs(row);
        eh(this, e);
        if (e.Processed)
          return e.RowHeight;
      }

      return DefaultCalcRowHeight(row); 
    }

    protected virtual void UpdateBaseIndicatorCols()
    {
      if (IndicatorColumn.Visible)
        this.ColWidths[0] = IndicatorColumn.CalcWidth();
    }

    internal virtual void UpdateGridState()
    {
      gridIsEmpty = (Columns.Count == 0) && (Rows.Count == 0);
    }

    protected internal override void CurrencyManagerListChanged(object sender, ListChangedEventArgs e)
    {
      switch (e.ListChangedType)
      {
        case ListChangedType.Reset:
          Rows.Clear();
          UpdateColumnsList();
          CheckPropBarsPropDescr();
          UpdateTitleSortMarkersFromDataLink();
          UpdateDataRows();
          if (CurrencyManager != null)
            CurrencyManagerPositionChanged(null, null);
          CurrencyManagerChangedNotifyColumns(sender, e);
          break;

        case ListChangedType.ItemMoved:
          UpdateDataRows();
          CurrencyManagerChangedNotifyColumns(sender, e);
          break;

        case ListChangedType.ItemAdded:
          object row = CurrencyManager.List[e.NewIndex];
          if ((e.NewIndex < Rows.Count) && (addedSrcRow == row))
            EhLibUtils.DoNothing();
          else
          {
            AddDataRow(e.NewIndex);
            addedSrcRow = row;
            CheckRecalcFooters();
            if (InternalCurrentRowIndex == -1)
              CurrencyManagerPositionChanged(sender, e);
            CurrencyManagerChangedNotifyColumns(sender, e);
          }
          break;

        case ListChangedType.ItemChanged:
          UpdateDataRow(e.NewIndex);
          CheckRecalcFooters();
          CurrencyManagerChangedNotifyColumns(sender, e);
          break;

        case ListChangedType.ItemDeleted:
          DeleteItem(e.NewIndex);
          CheckRecalcFooters();
          CurrencyManagerChangedNotifyColumns(sender, e);
          break;

        default:
          UpdateColumnsList();
          UpdateDataRows();
          CurrencyManagerChangedNotifyColumns(sender, e);
          break;
      }

      HorzScrollBarPanelControl.GridDataChanged();
    }

    protected internal virtual void CurrencyManagerChangedNotifyColumns(object sender, ListChangedEventArgs e)
    {
      foreach (DataGridColumn column in Columns)
        column.CurrencyManagerChanged(sender, e);
    }

    protected internal override void CurrencyManagerPositionChanged(object sender, EventArgs e)
    {
      UpdateGridRowIndexFromCurrencyManagerPosition();
      UpdateDataViewCurrencyManagerPosition();
    }

    protected internal virtual void DataViewCurrencyManagerListChanged(object sender, ListChangedEventArgs e)
    {

    }

    protected internal virtual void DataViewCurrencyManagerPositionChanged(object sender, EventArgs e)
    {
      if (internalDataViewCurrencyManagerPositionSetting) return;

      internalDataViewCurrencyManagerPositionSetting = true;
      try
      {
        if (dataViewBindingSource.Position >= 0)
          CurrentRowIndex = dataViewBindingSource.Position;
      }
      finally
      {
        internalDataViewCurrencyManagerPositionSetting = false;
      }
    }

    internal void UpdateDataViewCurrencyManagerPosition()
    {
      if (internalDataViewCurrencyManagerPositionSetting) return;

      internalDataViewCurrencyManagerPositionSetting = true;
      try
      {
        if (InternalCurrentRowIndex >= 0 && dataViewBindingSource.Count > 0)
          dataViewBindingSource.Position = InternalCurrentRowIndex;
      }
      finally
      {
        internalDataViewCurrencyManagerPositionSetting = false;
      }
    }

    internal void UpdateGridRowIndexFromCurrencyManagerPosition()
    {
      if (CurrencyManager.Position >= 0 &&
          Rows.Count > CurrencyManager.Position)
      {
        InternalCurrentRowIndex = Rows[CurrencyManager.Position].VisibleIndex;
      }
      else
      {
        InternalCurrentRowIndex = -1;
      }
    }

    private void AddDataRow(int index)
    {
      InternalAddDataRow(index);
      UpdateBaseGridColumns();
      UpdateBaseRowCount();
    }

    internal void UpdateBaseRowCount()
    {
      int newRowCount;
      if (VisibleRows.Count == 0)
        newRowCount = FixedRowCount + 1;
      else
        newRowCount = FixedRowCount + VisibleRows.Count;

      if ( (AllowedOperations.AllowAdd && 
            DataLink.CurrentListItemState != RowEditState.Add) 
          ||
           (DataLink.CurrentListItemState == RowEditState.Add && 
            (DataLink.CurrentRowModified || DataLink.EditorHasValueToPush))
         )
      {
        if (VisibleRows.Count != 0)
          newRowCount = newRowCount + 1;
      }

      this.RowCount = newRowCount;
    }

    internal void UpdateBaseRowHeights()
    {
      for (int i = 0; i < VisibleRows.Count; i++)
      {
        RowHeights[FixedRowCount + i] = VisibleRows[i].Height + LineOptions.HorzLineSpace;
      }

      int defRowHeight = CalcDefaultRowHeight();
      if (LineOptions.VertLines)
        defRowHeight = defRowHeight + GridLineWidth;
      DefaultRowHeight = defRowHeight;

      for (int i = VisibleRows.Count; i < RowCount - FixedRowCount; i++)
      {
        RowHeights[FixedRowCount + i] = DefaultRowHeight;
      }
    }

    //private void InternalAddDataRow(int index, DataGridRow rawDataRow)
    //{
    //  InitDataRow(rawDataRow, index);
    //  Rows.Insert(index, rawDataRow);
    //}

    private void InternalAddDataRow(int index)
    {
      DataGridRow item = CreateGridRow(index);
      InitDataRow(item, index);
      Rows.Insert(index, item);
    }

    protected virtual void UpdateDataRow(int index)
    {
      Invalidate();
    }

    protected virtual DataGridRow CreateGridRow(int index)
    {
      DataGridRow row;
      row = new DataGridRow();

      return row;
    }

    private void InitDataRow(DataGridRow row, int index)
    {
      object listItem = CurrencyManager.List[index];
      row.SourceItem = listItem;
    }

    private void DeleteItem(int index)
    {
      int visibleIndex;
      DataGridRow row;

      if (index >= 0 && index < Rows.Count)
      {
        row = Rows[index];
        visibleIndex = row.VisibleIndex;
        Rows.RemoveAt(index);
        DeleteRow(visibleIndex + FixedRowCount);
        UpdateBaseGridColumns();
        UpdateBaseRowCount();
      }
    }

    //private void ListViewDataBinding_SelectedIndexChanged(object sender, EventArgs e)
    //{
    //  try
    //  {
    //    //if (SelectedIndices.Count > 0 && CurrencyManager.Position != SelectedIndices[0])
    //    //  CurrencyManager.Position = SelectedIndices[0];
    //  }
    //  catch
    //  {
    //  }
    //}

    public virtual CellAreaType GetCellAreaTypeByColRow(int col, int row)
    {
      CellAreaType result = new CellAreaType();

      if (col == -1 || col >= FullColCount)
        result.HorzType = DataGridCellAreaHorzType.Invalid;
      else if (col < FixedColCount)
        result.HorzType = DataGridCellAreaHorzType.Indicator;
      else if (col < ColCount)
        result.HorzType = DataGridCellAreaHorzType.Data;
      else
        result.HorzType = DataGridCellAreaHorzType.Contra;

      if (row == -1 || row >= FullRowCount)
        result.VertType = DataGridCellAreaVertType.Invalid;
      else if (row < FixedRowCount)
        result.VertType = DataGridCellAreaVertType.Title;
      else if (row < RowCount)
        result.VertType = DataGridCellAreaVertType.Data;
      else
        result.VertType = DataGridCellAreaVertType.Footer;

      return result;
    }

    public override BaseGridCellManager CellByColRow(int colIndex, int rowIndex)
    {
      //if ((col == -1) && (row >= 0))
      //  return horzEmptySpaceCell;
      //else 
      if (colIndex >= 0 && colIndex == IndicatorColIndex)
        if (rowIndex >= 0 && rowIndex < FixedRowCount)
          return titleIndicatorCell;
        else
          return indicatorCell;
      else if (rowIndex >= 0 && rowIndex < FixedRowCount)
      {
        if (gridIsEmpty)
          return emptyTitleCell;
        else if (VisibleColumns.Count > 0)
          return titleCellMan;
        else
          return titleCellMan;
      }
      else if (rowIndex >= RowCount)
      {
        if (gridIsEmpty)
          return emptyDataCell;
        else
          return footerCell;
      }
      else
      {
        if (gridIsEmpty || colIndex == -1)
          return emptyDataCell;
        else if (VisibleRows.Count == 0)
          return emptyDataCell;
        else
        {
          if (VisibleColumns.Count > 0)
          {
            DataGridColumn column = VisibleColumns[colIndex - StartDataColIndex];
            if (rowIndex - FixedRowCount < VisibleRows.Count)
              return column.RowCells[VisibleRows[rowIndex - FixedRowCount]];
            else
              return column.NewVirtualRowCell;
          }
          else
            return emptyDataCell;
        }
      }
    }

    //public virtual new DataGridBaseCell CellByColRow(int col, int row)
    //{
    //  BaseGridBaseCellManager cell = base.CellByColRow(col, row);
    //  return (DataGridBaseCell)cell;
    //}

    //public virtual new DataGridBaseCell CellByColRow(int colIndex, int rowIndex, out int localColIndex, out int localRowIndex)
    //{
    //  BaseGridBaseCellManager cell = (DataGridBaseCell)base.CellByColRow(colIndex, rowIndex, out localColIndex, out localRowIndex);
    //  return (DataGridBaseCell)cell;
    //}

    public virtual DataGridBaseCellMan EmptyAreaCellColRow(int colIndex, int rowIndex)
    {
      return (DataGridBaseCellMan)CellByColRow(colIndex, rowIndex);  
    }

    protected virtual bool CheckSpecPaintCellAction(Graphics graphics, int colIndex, int rowIndex, 
      ref Rectangle rect, BasePaintCellStates state)
    {
      if ((colIndex >= FixedColCount) &&
          (rowIndex < FixedRowCount) &&
          (Columns.Count > 0) &&
          (Title.Visible == true) &&
          (Title.MultiTitle.Active == true) &&
          (VisibleColumns.Count > 0))
      {
        if (titleTreePainted == true) return true;
        Rectangle titlePaintRect = new Rectangle();
        Point paintShift;

        titlePaintRect.X = (int)(HorzAxis.FixedBoundary - HorzAxis.RollStartVisPos);
        titlePaintRect.Width = HorzAxis.RollClientLen;
        titlePaintRect.Y = VertAxis.GridClientStart;
        titlePaintRect.Height = VertAxis.FixedBoundary;
        paintShift = titlePaintRect.Location;

        Title.MultiTitle.PaintTitleTree(graphics, titlePaintRect, paintShift);
        titleTreePainted = true;
        return true;
      }
      else
      {
        return false;
      }

    }

    protected virtual bool CheckSpecPaintCellAreaAction(Graphics graphics, int colIndex, int rowIndex, 
      ref Rectangle rect, BasePaintCellStates state)
    {
      int dataColIndex = colIndex - FixedColCount;
      int dataRowIndex = rowIndex - FixedRowCount;
      bool result = false;

      if ((dataColIndex >= 0) && (dataColIndex < VisibleColumns.Count) &&
          (dataRowIndex >= 0) && (dataRowIndex < VisibleRows.Count))
      {
        DataGridColumn col = VisibleColumns[dataColIndex];
        DataGridRow row = VisibleRows[dataRowIndex];
        if (col.MergeDuplicates)
        {
          DataGridRow masterRow;
          int masterRowIndex;
          int mergeRowCount;
          Rectangle masterCellRect;
          Rectangle paintRect;
          CellMergeDuplicatesPaintKind paintKind;

          if (IsCellPainted(colIndex, rowIndex)) return true;

          FillMergePaintInfo(rowIndex, row, col, rect, out masterRow, out masterRowIndex, out mergeRowCount, out masterCellRect, out paintKind);

          if (paintKind != CellMergeDuplicatesPaintKind.ClassicPaint)
          {
            result = true;
            if (paintKind == CellMergeDuplicatesPaintKind.MergedPaint)
            {
              List<Color> backFilledColors = new List<Color>();
              int gridMasterRowIndex = DataToRawRow(masterRowIndex);
              int gridMasterBorderRowIndex = gridMasterRowIndex + mergeRowCount - 1;
//              DrawBordersForCellArea(graphics, colIndex, gridMasterBorderRowIndex, ref masterCellRect, state);
              paintRect = CalcMergePaintRect(rowIndex, row, col, rect, masterRow, masterRowIndex, mergeRowCount, masterCellRect, paintKind);
              PaintMergedCellsBackground(graphics, colIndex, rowIndex, masterCellRect, state, masterRow, masterRowIndex, mergeRowCount, paintRect, backFilledColors);
              PaintMergedCellsForeground(graphics, colIndex, rowIndex, masterCellRect, state, masterRow, masterRowIndex, mergeRowCount, paintRect, backFilledColors);
              SetCellsPaintedState(colIndex, gridMasterRowIndex, 1, mergeRowCount, true);
            }
          }
        }
      }

      return result;
    }

    private Rectangle CalcMergePaintRect(int rowIndex, DataGridRow row, DataGridColumn col, Rectangle rect, 
      DataGridRow masterRow, int masterRowIndex, int mergeRowCount, Rectangle masterCellRect, 
      CellMergeDuplicatesPaintKind paintKind)
    {
      Rectangle paintRect = masterCellRect;

      paintRect = masterCellRect;

      if (paintRect.Y < VertAxis.FixedBoundary)
      {
        int delta = VertAxis.FixedBoundary - paintRect.Y;
        paintRect.Y = VertAxis.FixedBoundary;
        paintRect.Height = paintRect.Height - delta;
      }

      if (paintRect.Bottom > VertAxis.ContraStart)
        paintRect.Height = paintRect.Height - (paintRect.Bottom - VertAxis.ContraStart);

      return paintRect;
    }

    private void FillMergePaintInfo(int rowIndex, DataGridRow row, DataGridColumn col, Rectangle cellRect,
      out DataGridRow masterRow, out int masterRowIndex, out int mergeRowCount, out Rectangle masterCellRect, 
      out CellMergeDuplicatesPaintKind paintKind)
    {
      masterRow = null;
      masterRowIndex = -1;
      mergeRowCount = -1;
      //clipRect = Rectangle.Empty;
      masterCellRect = cellRect;
      paintKind = CellMergeDuplicatesPaintKind.ClassicPaint;

      int dataRowIndex = RawToDataRowIndex(rowIndex);
      if (dataRowIndex >= col.MergeDuplicatesList.Count) return;

      MergeDuplicatesData mergeData = col.MergeDuplicatesList[dataRowIndex];
      if (mergeData == null) return;

      paintKind = CellMergeDuplicatesPaintKind.MergedPaint;
      masterCellRect = cellRect;

      if (mergeData.MasterDataRowIndex < dataRowIndex)
      {
        for (int i = mergeData.MasterDataRowIndex; i < dataRowIndex; i++)
        {
          int gridRowIndex = i + FixedRowCount;
          masterCellRect.Y = masterCellRect.Y - RowHeights[gridRowIndex];
        }
      }

      masterCellRect.Height = 0;
      for (int i = 0; i < mergeData.MergeRowCount; i++)
      {
        int gridRowIndex = i + mergeData.MasterDataRowIndex + FixedRowCount;
        masterCellRect.Height = masterCellRect.Height + RowHeights[gridRowIndex];
      }

      masterRowIndex = mergeData.MasterDataRowIndex;
      mergeRowCount = mergeData.MergeRowCount;
      masterRow = VisibleRows[masterRowIndex];
    }

    private void PaintMergedCellsBackground(Graphics graphics, int colIndex, int rowIndex, Rectangle rect, 
      BasePaintCellStates state, DataGridRow masterRow, int masterRowIndex, int mergeRowCount, 
      Rectangle paintRect, List<Color> backFilledColors)
    {
      Rectangle cellRect = rect;
      Color backFilledColor;
      for (int i = 0; i < mergeRowCount; i++)
      {
        int gridRowIndex = i + masterRowIndex + FixedRowCount;
        cellRect.Height = RowHeights[gridRowIndex];

        if (cellRect.Bottom > VertAxis.FixedBoundary &&
            cellRect.Top < VertAxis.ContraStart)
        {
          BasePaintCellStates cellPaintState = GetCellPaintState(colIndex, gridRowIndex, Focused);
          bool drawBottomBorder = (i == mergeRowCount- 1);
          Rectangle cellAreaRect = cellRect;

          DrawBordersForCellArea(graphics, colIndex, gridRowIndex, ref cellAreaRect, state, true, drawBottomBorder);
          PaintMergedCellBackground(graphics, colIndex, gridRowIndex, cellAreaRect, cellPaintState, out backFilledColor);
          backFilledColors.Add(backFilledColor);
        }
        else
        {
          backFilledColors.Add(Color.Empty);
        }

        cellRect.Y = cellRect.Y + cellRect.Height;
      }
    }

    private void PaintMergedCellBackground(Graphics graphics, int colIndex, int rowIndex, Rectangle cellRect, 
      BasePaintCellStates state, out Color backFilledColor)
    {
      backFilledColor = Color.Empty;
      if (cellRect == Rectangle.Empty) return;

      //state = state & ~BasePaintCellStates.Focused;
      //state = state & ~BasePaintCellStates.Current;

      int areaColIndex;
      int areaRowIndex;

      BaseGridCellManager cell = CellByColRow(colIndex, rowIndex, out areaColIndex, out areaRowIndex);
      Debug.Assert(cell != null, "BaseGridControl.PaintCell Cell = null");

      Point inCellMousePos = new Point(-1, -1);

      BaseGridCellPaintEventArgs pea = 
        cell.GetCellPaintParams(graphics, colIndex, rowIndex, cellRect, state, areaColIndex, areaRowIndex, inCellMousePos);
      DataAxisGridDataCellPaintEventArgs dpea = pea as DataAxisGridDataCellPaintEventArgs;
      if (dpea != null)
      {
        dpea.IsPaintForeground = false;
      }

      cell.ProcessPaint(pea);
      backFilledColor = dpea.BackFilledColor;
    }

    private bool ColorIsDark(Color color)
    {
      float brightest = color.GetBrightness();
      if (color.A != 255)
      {
        float af = (float)color.A / 255;
        brightest = brightest / af;
      }
      return brightest < 0.5;
    }

    private void PaintMergedCellsForeground(Graphics graphics, int colIndex, int rowIndex, Rectangle rect, 
      BasePaintCellStates state, DataGridRow masterRow, int masterRowIndex, int mergeRowCount, 
      Rectangle paintRect, List<Color> backFilledColors)
    {
      Rectangle clipCellRect = rect;
      //Color backFilledColor;
      bool backFilledColorDark = ColorIsDark(backFilledColors[0]);
      bool nextBackFilledColorDark;
      int gridMasterRowIndex = masterRowIndex + FixedRowCount;
      bool firstHit = true;

      clipCellRect.Height = 0;

      for (int i = 0; i < mergeRowCount; i++)
      {
        int gridRowIndex = i + masterRowIndex + FixedRowCount;

        if (clipCellRect.Bottom + RowHeights[gridRowIndex] < VertAxis.FixedBoundary)
        {
          clipCellRect.Y = clipCellRect.Y + RowHeights[gridRowIndex];
        }
        else if (clipCellRect.Top >= VertAxis.ContraStart)
        {
          break;
        }
        else
        {
          if (firstHit)
          {
            backFilledColorDark = ColorIsDark(backFilledColors[i]);
            clipCellRect.Height = clipCellRect.Height + RowHeights[gridRowIndex];
            firstHit = false;
          }
          else
          {
            nextBackFilledColorDark = ColorIsDark(backFilledColors[i]);
            if (backFilledColorDark != nextBackFilledColorDark)
            {
              PaintMergedCellForeground(graphics, colIndex, gridMasterRowIndex, rect, state, 
                masterRow, masterRowIndex, mergeRowCount, paintRect, backFilledColorDark, clipCellRect);

              clipCellRect.Y = clipCellRect.Bottom;
              clipCellRect.Height = 0;
              backFilledColorDark = nextBackFilledColorDark;
            }
            clipCellRect.Height = clipCellRect.Height + RowHeights[gridRowIndex];
          }
        }
      }

      if (clipCellRect.Height > 0)
      {
        PaintMergedCellForeground(graphics, colIndex, gridMasterRowIndex, rect, state, 
          masterRow, masterRowIndex, mergeRowCount, paintRect, backFilledColorDark, clipCellRect);
      }
    }

    private void PaintMergedCellForeground(Graphics graphics, int colIndex, int rowIndex, Rectangle rect, 
      BasePaintCellStates state, DataGridRow masterRow, int masterRowIndex, int mergeRowCount, 
      Rectangle paintRect, bool backFilledColorDark, Rectangle clipCellRect)
    {
      if (paintRect == Rectangle.Empty) return;

      state = state & ~BasePaintCellStates.Focused;
      state = state & ~BasePaintCellStates.Current;

      int areaColIndex;
      int areaRowIndex;

      BaseGridCellManager cell = CellByColRow(colIndex, rowIndex, out areaColIndex, out areaRowIndex);
      Debug.Assert(cell != null, "BaseGridControl.PaintCell Cell = null");

      Point inCellMousePos = new Point(-1, -1);

      BaseGridCellPaintEventArgs pea = cell.GetCellPaintParams(graphics, colIndex, rowIndex, paintRect, state, areaColIndex, areaRowIndex, inCellMousePos);
      DataAxisGridDataCellPaintEventArgs dpea = pea as DataAxisGridDataCellPaintEventArgs;
      if (dpea != null)
      {
        dpea.IsPaintBackground = false;
        if (backFilledColorDark)
          dpea.ForeColor = SystemColors.HighlightText;
      }

      Region oldClip = null;

      if (clipCellRect != Rectangle.Empty)
      {
        oldClip = graphics.Clip;
        graphics.SetClip(clipCellRect, CombineMode.Intersect);
      }

      cell.ProcessPaint(pea);

      if (oldClip != null)
        graphics.Clip = oldClip;
    }

    protected override void OnPaint(PaintEventArgs e)
    {
      titleTreePainted = false;
      ResetDataCellPaintedArray();
      base.OnPaint(e);
      if (EmptyDataInfo.Showing)
        EmptyDataInfo.PaintEmptyDataInfo(e.Graphics);
    }

    private void ResetDataCellPaintedArray()
    {
      if (dataCellPaintedArray.GetLength(0) != HorzAxis.RollVisCellCount || dataCellPaintedArray.GetLength(1) != VertAxis.RollVisCellCount)
      {
        dataCellPaintedArray = new bool[HorzAxis.RollVisCellCount, VertAxis.RollVisCellCount];
      }
      else
      {
        Array.Clear(dataCellPaintedArray, 0, dataCellPaintedArray.Length);
      }
    }

    private void SetCellsPaintedState(int colIndex, int rowIndex, int colCount, int rowCount, bool isPainted)
    {
      for (int ci = 0; ci < colCount; ci++)
      {
        int vci = colIndex + ci - HorzAxis.StartVisCell;
        for (int ri = 0; ri < rowCount; ri++)
        {
          int vri = rowIndex + ri - VertAxis.StartVisCell;
          if (vci >= 0 && vci < dataCellPaintedArray.GetLength(0) &&
              vri >= 0 && vri < dataCellPaintedArray.GetLength(1))
          {
            dataCellPaintedArray[vci, vri] = isPainted;
          }
        }
      }
    }

    private bool IsCellPainted(int colIndex, int rowIndex)
    {
      int visColIndex = colIndex - HorzAxis.StartVisCell;
      int visRowIndex = rowIndex - VertAxis.StartVisCell;
      return dataCellPaintedArray[visColIndex, visRowIndex];
    }

    protected override void PaintCell(Graphics g, int colIndex, int rowIndex, Rectangle rect, BasePaintCellStates state)
    {
      if (!CheckSpecPaintCellAction(g, colIndex, rowIndex, ref rect, state))
      {
        if (Selection.CellIsSelected(colIndex, rowIndex))
          state = state | BasePaintCellStates.Selected;

        base.PaintCell(g, colIndex, rowIndex, rect, state);

        if (DesignMode)
        {
          IDesignerHost idh = (IDesignerHost)GetService(typeof(IDesignerHost));
          if (idh == null) return;
          //Debug.Assert(idh != null, "PaintCell DesignMode == true but GetService(typeof(IDesignerHost)) returns null");
          var grd = idh.GetDesigner(this) as IDataGridDesigner;
          if (grd != null)
            grd.PaintCellDesignData(this, g, colIndex, rowIndex, rect, state);
        }
      }
    }

    protected override void PaintCellArea(Graphics g, int colIndex, int rowIndex, Rectangle rect, BasePaintCellStates state)
    {
      if (!CheckSpecPaintCellAreaAction(g, colIndex, rowIndex, ref rect, state))
      {
        DrawBordersForCellArea(g, colIndex, rowIndex, ref rect, state);
        PaintCell(g, colIndex, rowIndex, rect, state);
      }
    }

    private void DrawEmptyAreaCellLine(Graphics g, Color fromColor, Color toColor, DashStyle lStyle, 
      Point fromPoint, Point toPoint)
    {
      if ((LineOptions.VertEmptySpaceStyle == DataGridPaintEmptySpaceStyle.Gradient) && (fromColor != toColor))
      {
        Point grFromPoint = fromPoint;
        grFromPoint.Y = grFromPoint.Y - 1;

        using (Brush grdntBr = new LinearGradientBrush(grFromPoint, toPoint, fromColor, toColor))
        {
          using (Pen grdntPen = new Pen(grdntBr))
          {
            if (lStyle != DashStyle.Solid)
            {
              PaintingDrawLine(g, BackColor, DashStyle.Solid, BackColor, fromPoint, toPoint);
            }
            grdntPen.DashStyle = lStyle;
            g.DrawLine(grdntPen, fromPoint, toPoint);
          }
        }
      }
      else
      {
        PaintingDrawLine(g, fromColor, lStyle, BackColor, fromPoint, toPoint);
      }
    }

    protected override void PaintEmptyAreaCell(Graphics g, int col, int row, Rectangle rect)
    {
      BasePaintCellStates cellPaintState;
      bool lineIsPaint;
      Color lineColor;
      DashStyle lineStyle;
      bool isExtent;

      if ((col < 0) && (row >= 0))
      {
        if (LineOptions.HorzEmptySpaceStyle == DataGridHorzEmptySpaceStyle.NoPaint)
          base.PaintEmptyAreaCell(g, col, row, rect);
        else
        {
          if (col == -1 && row == RowCount)
          {
            //BaseGridCellBorderEventArgs e = new BaseGridCellBorderEventArgs(col, row, col, row, GridCellBorderType.Top);
            //OnGetCellBorderParams(e);
            ProcessGetCellBorders(col, row, GridCellBorderType.Top, out lineIsPaint, out lineColor, out lineStyle, out isExtent);
            if (lineIsPaint)
            {
              PaintingDrawLine(g, lineColor, lineStyle, BackColor, new Point(rect.Left, rect.Top), new Point(rect.Right - 1, rect.Top));
              rect.Y = rect.Y + 1;
              rect.Height = rect.Height - 1;
            }
          }

          DrawBordersForCellArea(g, col, row, ref rect, 0);

          int areaColIndex;
          int areaRowIndex;

          DataGridBaseCellMan cell = (DataGridBaseCellMan)CellByColRow(col, row);
          Debug.Assert(cell != null, "DataGridEh.PaintCell Cell = null");

          cell.GridCellPosToAreaCellPos(col, row, out areaColIndex, out areaRowIndex);

          if (row == Row)
            cellPaintState = BasePaintCellStates.CurrentRow;
          else
            cellPaintState = 0;

          BaseGridCellPaintEventArgs pea = cell.GetCellPaintEmptyAreaEventArgs(g, col, row, rect, cellPaintState, areaColIndex, areaRowIndex, new Point(-1, -1));

          cell.OnPaintEmptyArea(pea);
          //cell.PaintEmptyArea(g, col, row, ref rect, cellPaintState, areaColIndex, areaRowIndex);
        }
      }
      else if (col >= 0)
      {
        if (LineOptions.VertEmptySpaceStyle == DataGridPaintEmptySpaceStyle.NoPaint)
          base.PaintEmptyAreaCell(g, col, row, rect);
        else
        {
          Color fromColor, toColor;
          //BaseGridCellBorderEventArgs er = new BaseGridCellBorderEventArgs(col, RowCount - 1, col, RowCount - 1, GridCellBorderType.Right);
          //BaseGridCellBorderEventArgs el = new BaseGridCellBorderEventArgs(col, RowCount - 1, col, RowCount - 1, GridCellBorderType.Left);

          toColor = BackColor;

          ProcessGetCellBorders(col, RowCount - 1, GridCellBorderType.Right, out lineIsPaint, out lineColor, out lineStyle, out isExtent);
          //OnGetCellBorderParams(er);

          if (lineIsPaint)
          {
            DrawEmptyAreaCellLine(g, lineColor, toColor, lineStyle, new Point(rect.Right - 1, rect.Top), new Point(rect.Right - 1, rect.Bottom));
            rect.Width = rect.Width - 1;
          }

          if (col == ColCount)
          {
            ProcessGetCellBorders(col, RowCount - 1, GridCellBorderType.Left, out lineIsPaint, out lineColor, out lineStyle, out isExtent);
            //OnGetCellBorderParams(el);
            if (lineIsPaint)
            {
              DrawEmptyAreaCellLine(g, lineColor, toColor, lineStyle, new Point(rect.Left, rect.Top), new Point(rect.Left, rect.Bottom));
              rect.X = rect.X + 1;
              rect.Width = rect.Width - 1;
            }
          }

          fromColor = BackColor;
          int dataColumnIndex = RawToDataColumnIndex(col);
          if ((dataColumnIndex >= 0) && (VisibleColumns.Count > 0))
          {
            DataGridColumn column = VisibleColumns[dataColumnIndex];
            if ((column.BackColor != BackColor))
              fromColor = column.BackColor;
          }

          if (!Background.Visible || fromColor != toColor)
          {
            if ((LineOptions.VertEmptySpaceStyle == DataGridPaintEmptySpaceStyle.Gradient) && (fromColor != toColor))
            {
              if (fromColor.A != 255)
                toColor = Color.FromArgb(fromColor.A, toColor);
              EhLibUtils.FillRectangleGradient(g, rect, fromColor, toColor);
            }
            else
              EhLibUtils.FillRectangle(g, rect, fromColor);
          }
        }
      }
      else
        base.PaintEmptyAreaCell(g, col, row, rect);
    }

    //internal void ColumnTitleSortMarkerChanged(DataGridColumnTitle dataGridColumnTitle)
    //{
    //  throw new NotImplementedException();
    //}

    internal void UpdateTitleSortMarkersFromDataLink()
    {
      IList sortDescription = DataLink.GetDataSortDescription();

      SortMarkers.UpdateDataFromListSortDescription(sortDescription);

    }

    internal void UpdateSearchBox()
    {
      Rectangle schBoxRect = new Rectangle();
      Rectangle cliRect = ClientBounds;

      if (!IsHandleCreated) return;

      schBoxRect.X = cliRect.Left;
      schBoxRect.Y = cliRect.Top;
      schBoxRect.Width = cliRect.Width - OutBoundaryData.RightIndent - VertScrollBarPanelControl.Width;
      schBoxRect.Height = SearchBoxControl.CalcAutoHeight();
      if (schBoxRect != SearchBoxControl.Bounds)
        SearchBoxControl.SetBounds(schBoxRect.Left, schBoxRect.Top, schBoxRect.Right, schBoxRect.Bottom);
    }

    protected internal override void UpdateOutBoundaryIndents()
    {
      base.UpdateOutBoundaryIndents();

      SearchBoxControl.Visible = searchBox.Visible;
      if (SearchBox.Visible)
      {
        UpdateSearchBox();
        OutBoundaryData.TopIndent = OutBoundaryData.TopIndent + SearchBox.InGridHeight;
      }
    }

    internal void LocateText(string s, DataGridLocateTextArgs args)
    {
      locateTextService.SearchText = s;
      locateTextService.SearchParams = args;
      locateTextService.SearchNext();
      locateTextService.SearchText = "";
      locateTextService.SearchParams = null;
    }

    protected override void OnEndInitialization()
    {
      UpdateBaseFixedBands();
      UpdateColumnsList();
      InitColumnsFillWeight();
      UpdateDataRows();
      UpdateGridState();
    }

    protected internal virtual void OnColumnNameChanged(DataGridColumn dataGridColumn)
    {
      //
    }

    protected internal override void OnPropBarAdded(PropertyAxisBar propBar)
    {
      DataGridColumn column = (DataGridColumn)propBar;

      column.UpdateDefaultPadding();
      //if (!InInitialization)
      //{
      //  if (Title.MultiTitle.Active)
      //  {
      //    Title.MultiTitle.BeginUpdate();
      //    try
      //    {
      //      DataGridTitleNode node = null;

      //      if (column.DisplayIndex >= 0 && column.DisplayIndex < Columns.Count)
      //        node = Title.MultiTitle.GetNodeByDisplayIndex(column.DisplayIndex);

      //      if (node != null)
      //      {
      //        Title.MultiTitle.Subtitles.Insert(node.Index, column);
      //      }
      //      else
      //      {
      //        Title.MultiTitle.Subtitles.Add(column);
      //      }
      //    }
      //    finally
      //    {
      //      Title.MultiTitle.EndUpdate(false);
      //    }
      //  }
      //}
    }

    protected internal override void OnPropBarRemoved(PropertyAxisBar propBar)
    {
      DataGridColumn column = (DataGridColumn)propBar;

      //if (!InInitialization)
      //{
      //  if (Title.MultiTitle.Active)
      //  {
      //    Title.MultiTitle.BeginUpdate();
      //    try
      //    {
      //      column.Title.TitleNode.Parent.Items.Remove(column.Title.TitleNode);
      //      //Title.MultiTitle. Subtitles.Add(column);
      //    }
      //    finally
      //    {
      //      Title.MultiTitle.EndUpdate(false);
      //    }
      //  }
      //}
    }

    public void BeginCurrentEdit()
    {
      DataLink.BeginCurrentEdit();
    }

    public void CancelCurrentEdit()
    {
      DataLink.CancelCurrentEdit();
    }

    public void EndCurrentEdit()
    {
      DataLink.EndCurrentEdit();
    }

    protected override void OnFontChanged(EventArgs e)
    {
      base.OnFontChanged(e);
      IndicatorColumn.UpdateDefaultFont();
      UpdateBaseIndicatorCols();
      UpdateRowHeights();
    }

    protected internal virtual void FooterAdded(DataGridFooterRow footer, int index)
    {
      if (InInitialization) return;

      foreach (DataGridColumn column in Columns)
      {
        column.GridFooterAdded(footer, index);
      }
      RecalcFooters();
    }

    protected internal virtual void FooterRemoved(DataGridFooterRow footer, int index)
    {
      if (InInitialization) return;

      foreach (DataGridColumn column in Columns)
      {
        column.GridFooterRemoved(footer, index);
      }
      UpdateHaveAggreageFunctionVar();
      CheckRecalcFooters();
    }

    protected internal virtual void FooterRowMoved(int oldIndex, int newIndex)
    {
      if (InInitialization) return;

      foreach (DataGridColumn column in Columns)
      {
        column.GridFooterRowMoved(oldIndex, newIndex);
      }
      UpdateHaveAggreageFunctionVar();
      CheckRecalcFooters();
    }

    internal void FooterCollectionListChanged()
    {
      if (InInitialization) return;

      UpdateBaseFixedBands();
    }

    public virtual void RecalcFooters()
    {
      foreach (DataGridColumn column in Columns)
      {
        foreach (DataGridColumnFooterItem columnFooter in column.Footer.Items)
        {
          //columnFooter.Recalc();
          columnFooter.Recalculate();
        }
      }
    }

    public virtual bool FooterHaveAggregateFunction()
    {
      foreach (DataGridColumn column in Columns)
      {
        foreach (DataGridColumnFooterItem columnFooter in column.Footer.Items)
        {
          if (columnFooter.CalcValueFunction != null)
          {
            return true;
          }
        }
      }
      return false;
    }

    public virtual void CheckRecalcFooters()
    {
      if (FooterHaveAggregateFunction())
        RecalcFooters();
    }

    internal void FooterValueFunctionChanged(DataGridColumnFooterItem dataGridColumnFooter)
    {
      if (dataGridColumnFooter != null)
        dataGridColumnFooter.Recalculate();
      UpdateHaveAggreageFunctionVar();
      InvalidateGrid();
    }

    internal void UpdateHaveAggreageFunctionVar()
    {
      foreach (DataGridColumn column in Columns)
      {
        foreach (DataGridColumnFooterItem columnFooter in column.Footer.Items)
        {
          if (columnFooter.CalcValueFunction != null)
          {
            return;
          }
        }
      }
    }

    internal bool GetDesignHitTest(Point point)
    {

      BaseGridState state = BaseGridState.Normal;
      int index;
      int pos;
      int ofs;

      if (GridState == BaseGridState.ColMoving)
        return true;

      if (GridState == BaseGridState.Normal)
      {
        CalcSizingState(point.X, point.Y, out state, out index, out pos, out ofs);
      }

      if (state == BaseGridState.ColSizing)
      {
        //MessageBox.Show("State == BaseGridState.ColSizing", "GetDesignHitTest", MessageBoxButtons.OK, MessageBoxIcon.Information);
        return true;
      }

      Control childControl = GetChildAtPoint(point, GetChildAtPointSkip.None);

      if (childControl is BaseGridScrollBarPanelControl)
        return true;

      //GridCoord cellCoord = CalcCellCoordFromPoint(point.X, point.Y);
      //if ((cellCoord.X >= 1) && (cellCoord.Y == 0))
      //{
      //  //        MessageBox.Show(cellCoord.X.ToString() +":"+ cellCoord.Y.ToString());
      //  return true;
      //}

      return false;
    }

    protected override void OnCellMouseDown(BaseGridCellManager cell, BaseGridCellMouseEventArgs e)
    {
      CellAreaType area = GetCellAreaTypeByColRow(e.ColIndex, e.RowIndex);

      if (area.HorzType == DataGridCellAreaHorzType.Data &&
          area.VertType == DataGridCellAreaVertType.Data &&
          Selection.RowSelect)
      {
        if (Selection.RowsSelectionIsAllowed && VisibleRows.Count > 0)
        {
          if ((Control.ModifierKeys & Keys.Control) != 0)
            Selection.InternalKeepSelect = true;
          try
          {
            base.OnCellMouseDown(cell, e);
          }
          finally
          {
            Selection.InternalKeepSelect = false;
          }
          bool addToSelection = ((Control.ModifierKeys & Keys.Control) != 0) || Selection.KeepSelect;
          bool shiftMode = (Control.ModifierKeys & Keys.Shift) != 0;
          StartRowSelection(VisibleRows[e.AreaRowIndex], addToSelection, true, shiftMode);
        }
      }
      else if ((Control.ModifierKeys & Keys.Shift) != 0 &&
               (Col != e.ColIndex || Row != e.RowIndex) && 
               (area.HorzType == DataGridCellAreaHorzType.Data && area.VertType == DataGridCellAreaVertType.Data)
       )
      {
        //base.OnCellMouseDown(cell, e);
        StartCellRectSelectionMode(e.GridMouseArgs);
      }
      else
      {
        base.OnCellMouseDown(cell, e);
      }
    }

    protected override void OnCellMouseEnter(BaseGridCellManager cell, BaseGridCellEnterEventArgs e)
    {
      //if (ColumnOptions.EditItemOptions.ActiveArea == DataGridActiveArea.Row)
      //  InvalidateRow(e.RowIndex);
      InvalidateCell(e.ColIndex, e.RowIndex);
      base.OnCellMouseEnter(cell, e);
    }

    protected override void OnCellMouseLeave(BaseGridCellManager cell, BaseGridCellLeaveEventArgs e)
    {
      //if (ColumnOptions.EditItemOptions.ActiveArea == DataGridActiveArea.Row)
      //  InvalidateRow(e.RowIndex);
      InvalidateCell(e.ColIndex, e.RowIndex);
      base.OnCellMouseLeave(cell, e);
    }

    protected override void OnCellMouseMove(BaseGridCellManager cell, BaseGridCellMouseEventArgs e)
    {
      base.OnCellMouseMove(cell, e);
      if (Capture &&
         (e.GridMouseArgs.Button == MouseButtons.Left))
      {
        if (!e.CellRect.Contains(e.GridMouseArgs.Location) &&
            !GridMouseSpecialStateActive()
           )
        {
          if (Selection.CellsSelectionIsAllowed)
            StartCellRectSelectionMode(e.GridMouseArgs);
          //else if (Grid.Selection.CanSelectRows)
          //  ;
        }
      }
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
      if (DesignMode && DataGridDesigner != null)
      {
        DataGridDesigner.GridMouseDown(e);
      }
      else
      {
        base.OnMouseDown(e);
      }
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
      if (DesignMode &&
          DataGridDesigner != null &&
          GridState == BaseGridState.Normal)
      {
        DataGridDesigner.GridMouseMove(e);
        return;
      }

      base.OnMouseMove(e);

      switch (dataGridState)
      {
        case DataGridState.ColumnsSelecting:
        case DataGridState.RowsSelecting:
        case DataGridState.CellsRectSelecting:
          if (MoveNScrollService.Active)
            MoveNScrollService.MouseMove(e);
          break;
      }

      if (GridState == BaseGridState.ColMoving && DataGridTitleDragWin.GetTitleDragWin().Visible)
        DrawMove();
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
      if (DesignMode && 
          DataGridDesigner != null &&
          GridState == BaseGridState.Normal)
      {
        DataGridDesigner.GridMouseUp(e);
        return;
      }

      base.OnMouseUp(e);
      switch (dataGridState)
      {
        case DataGridState.ColumnsSelecting:
        case DataGridState.RowsSelecting:
        case DataGridState.CellsRectSelecting:
          if (MoveNScrollService.Active)
            MoveNScrollService.Release();
          break;
      }
      dataGridState = DataGridState.Normal;
    }

    protected override void OnMouseDoubleClick(MouseEventArgs e)
    {
      BaseGridState newState;

      //OnDoubleClick(e);

      if (DesignMode) return;

      if ((e.Button == MouseButtons.Left) &&
          (ColumnOptions.FitSizeOnSizingDoubleClick))
      {
        int sznIndex;
        int sznPos;
        int sznOfs;
        int dataColIndex;

        CalcSizingState(e.X, e.Y, out newState, out sznIndex, out sznPos, out sznOfs);

        if (newState == BaseGridState.ColSizing)
        {
          dataColIndex = RawToDataColumnIndex(sznIndex);

          if ((dataColIndex >= 0) && (dataColIndex < VisibleColumns.Count))
          {
            DataGridColumn col = VisibleColumns[dataColIndex];
            if (col.Selected)
            {
              foreach (DataGridColumn iCol in VisibleColumns)
                if (iCol.Selected)
                  iCol.Width = iCol.CalcDefaultWidth();
            }
            else
            {
              col.Width = col.CalcDefaultWidth();
            }

            GridState = BaseGridState.Normal;
            return;
          }
        }
      }

      base.OnMouseDoubleClick(e);
    }

    protected internal override void OnDataCellContentClick(DataAxisGridDataCellEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellContentClick] as DataGridDataCellEventHandler;
      if (eh != null && !this.IsDisposed)
      {
        eh(this, (DataGridDataCellEventArgs)e);
      }
    }

    protected internal override void OnDataCellMouseDownEvent(DataAxisGridDataCellMouseEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellMouseDown] as DataGridDataCellMouseEventHandler;
      if (eh != null && !this.IsDisposed)
      {
        eh(this, (DataGridDataCellMouseEventArgs)e);
      }
    }

    public void OnDataCellMouseDownDefaultHandler(DataGridDataCellMouseEventArgs e)
    {
      e.Cell.OnMouseDown(e);
    }

    protected internal override void OnDataCellClick(DataAxisGridDataCellEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellClick] as DataGridDataCellEventHandler;
      if (eh != null && !this.IsDisposed)
      {
        eh(this, (DataGridDataCellEventArgs)e);
      }
    }

    protected internal virtual void OnDataCellContentClick(DataGridDataCellEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellContentClick] as DataGridDataCellEventHandler;
      if (eh != null && !this.IsDisposed)
      {
        eh(this, e);
      }
    }

    protected override ContextMenuStrip GetCellContextMenuStrip(Point mousePos, int col, int row)
    {
      return base.GetCellContextMenuStrip(mousePos, col, row);
    }

    public virtual ContextMenuStrip GetDefaultContextMenuStrip()
    {
      int localColIndex, localRowIndex;
      DataGridColumn col;
      DataGridRow row;
      ContextMenuStrip menu = null;

      CellByColRow(Col, Row, out localColIndex, out localRowIndex);
      if ((localColIndex >= 0) && 
          (localColIndex < VisibleColumns.Count) && 
          (localRowIndex >= 0) &&
          (localRowIndex < VisibleRows.Count))
      {
        col = VisibleColumns[localColIndex];
        row = VisibleRows[localRowIndex];
        menu = col.GetContextMenuStripAtRow(row); //ContextMenuStrip;
      }

      if (menu == null)
        menu = this.ContextMenuStrip;

      DataGridDefaultContextMenuStripNeededEventArgs ea = new DataGridDefaultContextMenuStripNeededEventArgs(menu);
      OnDefaultContextMenuStripNeeded(ea);
      menu = ea.ContextMenuStrip;

      return menu;
    }

    protected internal virtual void OnDefaultContextMenuStripNeeded(DataGridDefaultContextMenuStripNeededEventArgs e)
    {
      var eh = this.Events[EventKeyDefaultContextMenuStripNeeded] as DataGridDefaultContextMenuStripNeededEventHandler;
      if (eh != null && !this.IsDisposed)
      {
        eh(this, e);
      }
    }

    //protected internal virtual void OnColumnTitleContextMenuStripNeeded(DataGridColumnTitleContextMenuStripNeededEventArgs e)
    //{
    //  var eh = this.Events[EventKeyColumnTitleContextMenuStripNeeded] as DataGridColumnTitleContextMenuStripNeededEventHandler;
    //  if (eh != null && !this.IsDisposed)
    //  {
    //    eh(this, e);
    //  }
    //}

    protected internal override void HandleDataCellMouseContextMenuStripNeededEvent(DataAxisGridDataCellContextMenuStripNeededEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellContextMenuStripNeeded] as EventHandler<DataGridDataCellContextMenuStripNeededEventArgs>;
      if (eh != null)
        eh(this, (DataGridDataCellContextMenuStripNeededEventArgs)e);
    }

    protected override void CancelMode()
    {
      if (EhLibUtils.DebugIgnoreMouseCancelMode) return;
      base.CancelMode();
      if (dataGridState != DataGridState.Normal)
      {
        dataGridState = DataGridState.Normal;
        if (MoveNScrollService.Active)
          MoveNScrollService.Release();
        InvalidateGrid();
      }
    }

    protected override void CellCancelMode(int colIndex, int rowIndex)
    {
      BaseGridCellManager cell = CellByColRow(colIndex, rowIndex);
      Debug.Assert(cell != null, "DataGridEh.PaintCell Cell = null");
      cell.OnMouseCaptureCanceled();

      base.CellCancelMode(colIndex, rowIndex);
    }

    protected override void TestSetCursor(MouseEventArgs e, ref Cursor newCursor)
    {
      int areaColIndex;
      int areaRowIndex;
      Rectangle cellRect;
      Point cellMousePos = new Point();
      GridCoord cellHit;

      base.TestSetCursor(e, ref newCursor);
      if (GridMouseSpecialStateActive()) return;
      if (newCursor != null) return;
      if (DesignMode) return;
      if (dataGridState == DataGridState.ColumnsSelecting)
      {
        newCursor = GetDrawStyle().DownArrowSelectCursor();
      }
      else if (dataGridState == DataGridState.RowsSelecting)
      {
        newCursor = GetDrawStyle().RightArrowSelectCursor();
      }

      cellHit = CalcCellCoordFromPoint(e.X, e.Y);
      if ((cellHit.X < 0) || (cellHit.Y < 0)) return;

      cellRect = CellRect(cellHit.X, cellHit.Y);
      cellMousePos.X = e.X - cellRect.Left;
      cellMousePos.Y = e.Y - cellRect.Top;

      BaseGridCellManager cell = CellByColRow(cellHit.X, cellHit.Y, out areaColIndex, out areaRowIndex);
      Debug.Assert(cell != null, "DataGridEh.PaintCell Cell = null");

      BaseGridCellMouseEventArgs de = new BaseGridCellMouseEventArgs(cell, cellHit.X, cellHit.Y, areaColIndex, areaRowIndex, cellMousePos.X, cellMousePos.Y, cellRect, e);
      cell.SetCursor(de, ref newCursor);

    }

    public override bool CheckBeginColumnDrag(ref int moveFromIndex, ref int moveToIndex, Point mousePos)
    {
      if (Title.MultiTitle.Active)
      {
        return Title.MultiTitle.CheckBeginColumnDrag(ref moveFromIndex, ref moveToIndex, mousePos);
      }
      else
      {
        return true;
      }
    }

    public override void StartColMoving(int colIndex, int moveToIndex, int x, int y)
    {
      Point inCellPos;
      Rectangle cellRect;

      if (Title.MultiTitle.Active)
      {
        DataGridTitleNode tn = Title.MultiTitle.GetNodeAtGridAtPos(new Point(x, y), out inCellPos, out cellRect);
        Title.MultiTitle.TitleMovingFromNode = tn;
        Title.MultiTitle.TitleMovingBaseMouseY = tn.Bounds.Top + VertAxis.GridClientStart;
      }

      base.StartColMoving(colIndex, moveToIndex, x, y);
      Invalidate();
    }

    public override bool CheckColumnDrag(ref int moveFromIndex, ref int moveToIndex, Point mousePos)
    {
      if (Title.MultiTitle.Active)
      {
        return Title.MultiTitle.CheckColumnDrag(ref moveFromIndex, ref moveToIndex, mousePos);
      }
      else
      {
        return true;
      }
    }

    protected override void InteractiveMoveColumn(int fromIndex, int toIndex)
    {
      if (DesignMode && DataGridDesigner != null)
        DataGridDesigner.InteractiveMoveColumn(fromIndex, toIndex);
      else
        MoveColumn(fromIndex, toIndex);
    }

    protected internal override void MoveColumn(int fromIndex, int toIndex)
    {
      int dataFromColIndex = BaseToDataColIndex(fromIndex);
      int dataToColIndex = BaseToDataColIndex(toIndex);

      if (Title.MultiTitle.Active)
      {
        Title.MultiTitle.MoveColumn(dataFromColIndex, dataToColIndex);
      }
      else
      {
        bool moveToPosRightSite = false;

        if (dataToColIndex == VisibleColumns.Count)
        {
          dataToColIndex = dataToColIndex - 1;
          moveToPosRightSite = true;
        }
        int dataToColDisplayIndex = VisibleColumns[dataToColIndex].DisplayIndex;

        if (moveToPosRightSite) dataToColDisplayIndex++;

        //List<DataGridColumn> selCols = new List<DataGridColumn>();
        if (VisibleColumns[dataFromColIndex].Selected)
        {
          DataGridColumn[] selCols = Selection.GetSelectedColumns();
          SetDisplayIndexForColumnsRange(selCols, dataToColDisplayIndex);
          Selection.SetSelectedColumns(selCols);
        }
        else
        {
          var selCols = new DataGridColumn[1];
          selCols[0] = VisibleColumns[dataFromColIndex];
          SetDisplayIndexForColumnsRange(selCols, dataToColDisplayIndex);
        }
      }
    }

    protected override void GetColMovingLineBounds(out Point linePos, out int lineSize)
    {
      base.GetColMovingLineBounds(out linePos, out lineSize);
      if (Title.MultiTitle.Active)
      {
        int offset = Title.MultiTitle.TitleMovingFromNode.Bounds.Top;
        linePos.Y = linePos.Y + offset;
        lineSize = lineSize - offset;
      }
    }

    protected internal override void HideMove()
    {
      Rectangle cellToRect;
      //int MoveFromDataIndex;

      if (MoveToIndex == ColCount)
      {
        cellToRect = CellRect(MoveToIndex - 1, 0);
        cellToRect.Offset(ColWidths[MoveToIndex - 1], 0);
      } else
      {
        cellToRect = CellRect(MoveToIndex, 0);
      }

      //if (IsUseMultiTitle)
      //{
      //  MoveFromDataIndex = RawToDataColumn(FMoveFromIndex);
      //  ACellToRect.Top = ACellToRect.Bottom - FLeafFieldArr[MoveFromDataIndex].FLeaf.Height;
      //}

      cellToRect.Width = ColWidths[MoveFromIndex];

      cellToRect.Location = PointToScreen(cellToRect.Location);

      if (Title.MultiTitle.Active)
      {
        DataGridTitleNode fromNode = Title.MultiTitle.TitleMovingFromNode;
        cellToRect.Y = cellToRect.Y + fromNode.Bounds.Top;
        cellToRect.Width = fromNode.Bounds.Width;
        cellToRect.Height = fromNode.Bounds.Height;
      }

      if (MoveFromIndex < MoveToIndex)
      {
        cellToRect.Offset(-cellToRect.Width, 0);
      }

      DataGridTitleDragWin dragWin = DataGridTitleDragWin.GetTitleDragWin();
      dragWin.HideAnimated(cellToRect);

      //DataGridTitleDragWin.GetTitleDragWin().Hide();
    }

    protected internal override void DrawMove()
    {
      //base.DrawMove();

      DataGridTitleDragWin dragWin = DataGridTitleDragWin.GetTitleDragWin();
      if (GridState == BaseGridState.ColMoving)
      {
        Rectangle dragWinRect;
        Rectangle sourceBounds;
        int movePos;
        int moveSize;
        GetTitleDragWinBounds(out sourceBounds, out dragWinRect, out movePos, out moveSize);
        //Point tmp = dragWin.PointToClient(new Point(movePos, 0));
        //movePos = tmp.X;

        if (dragWin.Visible)
          dragWin.SetBounds(dragWinRect.X, dragWinRect.Y, dragWinRect.Width, dragWinRect.Height, movePos, moveSize);
        else
        {
          object drawObject;
          if (Title.MultiTitle.Active)
            drawObject = Title.MultiTitle.TitleMovingFromNode;
          else
            drawObject = VisibleColumns[RawToDataColumnIndex(MoveFromIndex)].Title;
          //- dragWin.StartShow(this, drawObject, dragWinRect.Location, dragWinRect.Width, dragWinRect.Height, movePos, moveSize);
          dragWin.StartShowAnimated(this, drawObject, sourceBounds, dragWinRect, movePos, moveSize);
        }
      }
    }

    private void GetTitleDragWinBounds(out Rectangle sourceBounds, out Rectangle bounds, out int movePos, out int lineSize)
    {
      bounds = Rectangle.Empty;
      Point scMousePos = Control.MousePosition;
      Rectangle cellFromRect = CellRect(MoveFromIndex, 0);
      cellFromRect.Width = ColWidths[MoveFromIndex];

      Point cellToPoint = Point.Empty;
      if (MoveToIndex == ColCount)
      {
        Rectangle cellRect = CellRect(MoveToIndex - 1, 0);
        cellToPoint.X = cellRect.Right;
        cellToPoint.Y = cellRect.Y;
      }
      else
      {
        cellToPoint = CellRect(MoveToIndex, 0).Location;
        cellToPoint.X = cellToPoint.X - 1;
      }

      if (cellToPoint.X > HorzAxis.ContraStart)
        cellToPoint.X = (int)Math.Min(HorzAxis.ContraStart, HorzAxis.RollStopVisPos + HorzAxis.FixedBoundary - 1);

      cellToPoint = PointToScreen(cellToPoint);

      cellFromRect.Size = new Size(cellFromRect.Width + 2, cellFromRect.Height + 2);
      cellFromRect.Location = PointToScreen(cellFromRect.Location);
      sourceBounds = cellFromRect;

      bounds.X = scMousePos.X - MoveFromCellOriginDistance;

      if (Title.MultiTitle.Active)
      {
        DataGridTitleNode fromNode = Title.MultiTitle.TitleMovingFromNode;
        bounds.Width = fromNode.Bounds.Width + 2;
        bounds.Height = fromNode.Bounds.Height + 2;
        bounds.Y = cellFromRect.Y + fromNode.Bounds.Top - 5 - bounds.Height;
        lineSize = VertAxis.GridClientLen - fromNode.Bounds.Top;
        sourceBounds.Y = cellFromRect.Y + fromNode.Bounds.Top;
        sourceBounds.Height = bounds.Height;
        sourceBounds.Width = bounds.Width;
      }
      else
      {
        bounds.Y = cellFromRect.Y - 5 - cellFromRect.Height;
        bounds.Size = cellFromRect.Size;
        lineSize = VertAxis.GridClientLen;
      }

      if (bounds.X < cellToPoint.X && bounds.Right < cellToPoint.X + 4)
      {
        bounds.Width = bounds.Width + (cellToPoint.X + 4 - bounds.Right);
      }
      else if (bounds.Right > cellToPoint.X && bounds.X > cellToPoint.X - 4)
      {
        bounds.Width = bounds.Width + (bounds.X - cellToPoint.X - 4);
        bounds.X = cellToPoint.X - 4;
      }

      movePos = cellToPoint.X;

    }

    private void SetCurColByGridColumn(DataGridColumn curGridColumn)
    {
      int curGridColumnIndex = -1;
      int colIndex;

      for (int i = 0; i < VisibleColumns.Count; i++)
      {
        if (VisibleColumns[i] == curGridColumn)
        {
          curGridColumnIndex = i;
          break;
        }
      }

      Debug.Assert(curGridColumnIndex >= 0, "DataGridEh.SetCurColByGridColumn curGridColumnIndex == -1");
      colIndex = DataToRawCol(curGridColumnIndex);
      MoveCurrent(colIndex, Row, false, false);
    }

    private void SetDisplayIndexForColumnsRange(DataGridColumn[] columns, int newDisplayIndex)
    {
      DataGridColumn insertBeforeColumn;
      DataGridColumn afterColumn;
      int insertNewIndex;
      DataGridColumn curGridColumn = VisibleColumns[CurrentColumnIndex];
      List<DataGridColumn> newViewOrderedColumnsList = new List<DataGridColumn>();
      List<DataGridColumn> columnsToMove = new List<DataGridColumn>();
      List<DataGridColumn> columnsList = new List<DataGridColumn>(columns);

      foreach (DataGridColumn col in columns)
        Debug.Assert(col.Grid == this, "SetDisplayIndexForColumnsRange: DataGridColumn do not belong to Grid");

      if (newDisplayIndex < VisibleColumns.Count)
      {
        if (VisibleColumns[newDisplayIndex].Selected)
          return;
      }

      foreach (DataGridColumn col in ViewOrderedColumns)
        newViewOrderedColumnsList.Add(col);

      for (int i = 0; i < newViewOrderedColumnsList.Count; i++)
      {
        DataGridColumn col = newViewOrderedColumnsList[i];
        if (columnsList.IndexOf(col) >= 0)
        {
          columnsToMove.Add(col);
          newViewOrderedColumnsList[i] = null;
        }
      }

      newViewOrderedColumnsList.RemoveAll(col => col == null);

      for (int i = newDisplayIndex; i < ViewOrderedColumns.Count; i++)
      {
        DataGridColumn col = ViewOrderedColumns[i];
        if (columnsList.IndexOf(col) > 0)
          newDisplayIndex++;
        else
          break;
      }

      if (newDisplayIndex < ViewOrderedColumns.Count)
      {
        insertBeforeColumn = ViewOrderedColumns[newDisplayIndex];
        insertNewIndex = newViewOrderedColumnsList.IndexOf(insertBeforeColumn);
        newViewOrderedColumnsList.InsertRange(insertNewIndex, columnsToMove);
      }
      else
      {
        newViewOrderedColumnsList.AddRange(columnsToMove);
      }

      if (newDisplayIndex > 0)
        afterColumn = ViewOrderedColumns[newDisplayIndex - 1];
      else
        afterColumn = null;

      Debug.Assert(ViewOrderedColumns.Count == newViewOrderedColumnsList.Count, "SetDisplayIndexForColumnsRange: viewOrderedColumnsList.Count != newViewOrderedColumnsList.Count");

      Collection<PropertyAxisBar> newDispOrderedPropBars = new Collection<PropertyAxisBar>();
      foreach (PropertyAxisBar bar in newViewOrderedColumnsList)
        newDispOrderedPropBars.Add(bar);

      SetPropBarsDisplayOrder(newDispOrderedPropBars);

      SetCurColByGridColumn(curGridColumn);
      if (EditorMode)
        UpdateCellEditorBounds();

      var e = new DataGridDisplayColumnsMovedEventArgs(columns, newDisplayIndex, afterColumn);
      OnDisplayColumnsMoved(e);
    }

    protected override void FillPropBarsViewOrderedList(List<PropertyAxisBar> voColList)
    {
      if (Title.MultiTitle.Active)
        Title.MultiTitle.FillColumnsViewList(voColList);
      else
        base.FillPropBarsViewOrderedList(voColList);
    }

    public int BaseToDataColIndex(int baseColIndex)
    {
      int dataColIndex = baseColIndex - (FixedColCount - FrozenColCount);
      if (Columns.Count == 0)
        return -1;
      else
        return dataColIndex;
    }

    protected internal int DataToBaseColIndex(int dataColIndex)
    {
      return dataColIndex + FixedColCount;
    }

    protected internal void AddChangeSortMarking(DataGridColumn column)
    {
      bool isMultiSortMarking = ((ModifierKeys & Keys.Control) != 0);
      SortMarkers.ChangeStateAsTitleClick(column, isMultiSortMarking);
      if (!isMultiSortMarking)
        SortMarkers.CommitChanges();
    }

    protected internal void OnSortmarkingChangeCommitted()
    {
      DataLink.Sort(SortMarkers);
    }

    public virtual DataGridDrawStyle GetDrawStyle()
    {
      return EhLibDrawStyle.DefaultDataGridDrawStyle;
    }

    protected internal virtual void RowSelectStateChanged()
    {
      if (Selection.RowSelect)
      {
        Options = (Options | GridOptions.RowSelect) & ~GridOptions.Editing;
      }
      else
        Options = Options & ~GridOptions.RowSelect;
    }

    public override bool GridMouseSpecialStateActive()
    {
      bool result = base.GridMouseSpecialStateActive();
      if (result)
        return true;
      else
      {
        if (dataGridState != DataGridState.Normal)
          return true;
        else
          return false;
      }
    }

    public virtual DataObject GetContentAsDataObject(DataGridExportArea area)
    {
      DataObject dataObject = new DataObject();

      DataGridTextExporter textExp = new DataGridTextExporter()
      {
        Grid = this,
        ImportArea = area,
        CellDelimiter = ((char)Keys.Tab).ToString(),
        LineBreak = "" + (char)Keys.Return + (char)Keys.LineFeed,
        QuoteChar = ""
      };

      string gridAsStr = textExp.BuildExportString();

      dataObject.SetData(DataFormats.Text, false /*autoConvert*/, gridAsStr);
      dataObject.SetData(DataFormats.UnicodeText, false /*autoConvert*/, gridAsStr);

      DataGridLibTableDataExchangeExporter ehLibDataExchExp = new DataGridLibTableDataExchangeExporter()
      {
        Grid = this,
        ImportArea = area
      };

      object ehLibDataExch = ehLibDataExchExp.BuildExportObject();

      dataObject.SetData("EhLib.Table.DataExchange", false /*autoConvert*/, ehLibDataExch);

      return dataObject;
    }

    public virtual void PutContentFromDataObject(IDataObject dataObject)
    {
      if (dataObject.GetDataPresent(DataFormats.UnicodeText))
      {
        string strVal = (string)dataObject.GetData(DataFormats.UnicodeText);
        using (var textImp = new DataGridTextImporter() { Grid = this })
        {
          textImp.DoImport(strVal);
        }
      }
    }

    public virtual void CopyContentToClipboard(DataGridExportArea area)
    {
      DataObject dataObject = GetContentAsDataObject(area);
      if (dataObject != null)
      {
        Clipboard.SetDataObject(dataObject, true);
      }
    }

    public virtual void PastContentFromClipboard()
    {
      IDataObject iData = Clipboard.GetDataObject();
      PutContentFromDataObject(iData);
    }

    protected bool ProcessCopyKey(Keys keyData)
    {
      if (!Focused) return false;
      Keys altCtlShiftMask = keyData & (Keys.Shift | Keys.Control | Keys.Alt);
      Keys keyCode = keyData & Keys.KeyCode;
      if ((altCtlShiftMask == Keys.Control && keyCode == Keys.Insert) ||
           (altCtlShiftMask == Keys.Control && keyCode == Keys.C) ||
           ((altCtlShiftMask == (Keys.Control | Keys.Shift)) && keyCode == Keys.C)
         )
      {
        CopyContentToClipboard(DataGridExportArea.SelectedArea);
        return true;
      }
      else
      {
        return false;
      }
    }

    protected bool ProcessPasteKey(Keys keyData)
    {
      if (!Focused) return false;
      Keys altCtlShiftMask = keyData & (Keys.Shift | Keys.Control | Keys.Alt);
      Keys keyCode = keyData & Keys.KeyCode;
      if ((altCtlShiftMask == Keys.Shift && keyCode == Keys.Insert) ||
           (altCtlShiftMask == Keys.Control && keyCode == Keys.V) ||
           ((altCtlShiftMask == (Keys.Control | Keys.Shift)) && keyCode == Keys.V)
         )
      {
        PastContentFromClipboard();
        return true;
      }
      else
      {
        return false;
      }
    }

    protected bool ProcessCutKey(Keys keyData)
    {
      if (!Focused) return false;
      Keys altCtlShiftMask = keyData & (Keys.Shift | Keys.Control | Keys.Alt);
      Keys keyCode = keyData & Keys.KeyCode;
      if (EditActions.CutEnabled &&
          (altCtlShiftMask == Keys.Shift && keyCode == Keys.Delete) ||
          (altCtlShiftMask == Keys.Control && keyCode == Keys.X) ||
          ((altCtlShiftMask == (Keys.Control | Keys.Shift)) && keyCode == Keys.X)
         )
      {
        EditActions.Cut();
        return true;
      }
      else
      {
        return false;
      }
    }

    protected internal virtual void ColumnPaddingChanged(DataGridColumn dataGridColumn)
    {
      Invalidate();
    }

    protected internal override void UpdatePaddingsForSidePadding()
    {
      leftAlignDefaultPadding = ColumnOptions.SidePadding;
      leftAlignDefaultPadding.Right = 0;

      centerAlignDefaultPadding = ColumnOptions.SidePadding;
      centerAlignDefaultPadding.Right = 0;
      centerAlignDefaultPadding.Left = 0;

      rightAlignDefaultPadding = ColumnOptions.SidePadding;
      rightAlignDefaultPadding.Left = 0;
    }

    protected internal override void SidePaddingChanged()
    {
      UpdatePaddingsForSidePadding();
      UpdateRowHeights();
    }

    protected internal override Padding GetDefaultPaddingForAlign(HorizontalAlignment horzAlign, VerticalAlignment vertAlign)
    {
      switch (horzAlign)
      {
        case HorizontalAlignment.Left:
          return leftAlignDefaultPadding;

        case HorizontalAlignment.Center:
          return centerAlignDefaultPadding;

        case HorizontalAlignment.Right:
          return rightAlignDefaultPadding;

        default:
          return Padding.Empty;
      }
    }

    protected internal override Padding GetDataCellSidePadding()
    {
      return ColumnOptions.SidePadding;
    }

    protected internal override VerticalAlignment DefaultVertAlign()
    {
      return ColumnOptions.VertAlign;
    }

    protected internal virtual void SetColWidthsToClient()
    {
      int rolClientWidth = HorzAxis.RollClientLen - (LineOptions.VertLineSpace * VisibleColumns.Count);
      float fullFillWeight = 0;
      int draftColWidths = 0;
      int restBit;
      int sign;

      foreach (DataGridColumn col in VisibleColumns)
      {
        if (col.OmitFromWidthCalculation == false)
          fullFillWeight = fullFillWeight + col.FillWeight;
        else
          rolClientWidth = rolClientWidth - col.Width;
      }

      foreach (DataGridColumn col in VisibleColumns)
      {
        if (col.OmitFromWidthCalculation == false)
        {
          col.WidthInternal = (int)Math.Round(col.FillWeight / fullFillWeight * rolClientWidth);
          col.WidthStored = true;
          draftColWidths = draftColWidths + col.Width;
        }
      }

      restBit = rolClientWidth - draftColWidths;
      if (restBit > 0)
        sign = 1;
      else
      {
        sign = -1;
        restBit = -restBit;
      }

      foreach (DataGridColumn col in VisibleColumns)
      {
        if (col.OmitFromWidthCalculation == false)
        {
          if (restBit == 0) break;
          col.WidthInternal = col.Width + sign;
          restBit = restBit - 1;
        }
      }
    }

    protected internal virtual void UpdateFitColWidthsToClient()
    {
      int newColWidth;
      bool secondPass;

      if (InInitialization) return;
      if (!IsHandleCreated) return;
      if (!AutoSizeColumnOptions.FitToClient) return;

      foreach (DataGridColumn col in VisibleColumns)
        col.OmitFromWidthCalculation = false;

      SetColWidthsToClient();

      secondPass = false;
      foreach (DataGridColumn col in VisibleColumns)
      {
        newColWidth = col.AdjustWidth(col.Width);
        if (newColWidth != col.Width)
        {
          col.WidthInternal = newColWidth;
          col.OmitFromWidthCalculation = true;
          secondPass = true;
        }
      }

      if (secondPass)
        SetColWidthsToClient();

      UpdateBaseGridColumns();
      if (RowOptions.HeightOptions.AutoExpand)
        UpdateRowHeights();
    }

    protected internal virtual void InitColumnsFillWeight()
    {
      if (InInitialization) return;
      if (!AutoSizeColumnOptions.FitToClient) return;
      foreach (DataGridColumn col in VisibleColumns)
      {
        col.FillWeightInternal = col.Width;
      }
    }

    protected internal virtual void SetColumnWidthFitClientMode(DataGridColumn col, int newWidth)
    {
      //TODO: Node
      //TODO: Fix problem when newWidth goes out of grid right part.

      if (InInitialization) return;
      if (!AutoSizeColumnOptions.FitToClient) return;

      int rightClientWidth;
      int rightWidth = 0;
      int draftColWidths = 0;
      int restBit;
      int sign;

      for (int i = col.VisibleIndex + 1; i < VisibleColumns.Count; i++)
      {
        rightWidth = rightWidth + VisibleColumns[i].Width;
      }

      rightClientWidth = rightWidth + (col.Width - newWidth);

      for (int i = col.VisibleIndex + 1; i < VisibleColumns.Count; i++)
      {
        DataGridColumn iCol = VisibleColumns[i];

        iCol.Width = (int)Math.Round((float)iCol.Width / rightWidth * rightClientWidth);
        if (iCol.Width <= 0) iCol.Width = 1;
        iCol.WidthStored = true;
        draftColWidths = draftColWidths + iCol.Width;
      }

      restBit = rightClientWidth - draftColWidths;
      if (restBit > 0)
        sign = 1;
      else
      {
        sign = -1;
        restBit = -restBit;
      }

      for (int i = col.VisibleIndex + 1; i < VisibleColumns.Count; i++)
      {
        DataGridColumn iCol = VisibleColumns[i];

        if (restBit == 0) break;
        iCol.Width = iCol.Width + sign;
        restBit = restBit - 1;
      }

      col.WidthInternal = newWidth;
      col.WidthStored = true;

      InitColumnsFillWeight();
      UpdateFitColWidthsToClient();
    }

    protected internal override bool CanShowScrollBar(Orientation kind)
    {
      if ((kind == Orientation.Horizontal) &&
          (AutoSizeColumnOptions.FitToClient))
        return false;
      else
        return base.CanShowScrollBar(kind);
    }

    protected override BaseGridHorzScrollBar CreateHorzScrollBar()
    {
      return new DataGridHorzScrollBar(this, Orientation.Horizontal);
    }

    protected override BaseGridVertScrollBar CreateVertScrollBar()
    {
      return new DataGridVertScrollBar(this, Orientation.Vertical);
    }

    protected override BaseGridScrollBarPanelControl CreateHorzScrollBarPanelControl()
    {
      return new DataGridScrollBarPanelControl(this, Orientation.Horizontal);
    }

    protected internal virtual void OnSelectionChanged()
    {
      Invalidate();
      HorzScrollBarPanelControl.GridSelectionChanged();

      var eh = this.Events[EventKeyDataGridSelectionChanged] as DataGridEventHandler;
      if (eh != null && !this.IsDisposed)
        eh(this, EventArgs.Empty);
    }

    protected internal override void CellLenChanged(GridAxisData axis, int index, int oldLen)
    {
      base.CellLenChanged(axis, index, oldLen);
      //GridLayoutChanged();
    }

    protected internal virtual GridKeyboardOptions CreateKeyKeyboardOptions()
    {
      return new GridKeyboardOptions(this);
    }

    protected override void OnValidating(CancelEventArgs e)
    {
      if (inValidatingCode || EditorDataPushing) return;
      inValidatingCode = true;
      try
      {
        if (EditorMode)
        {
          bool editorClosed = HideEditor(true);
          if (!editorClosed)
            e.Cancel = true;
        }
        //{
        //  e.Cancel = true;
        //  return;
        //}
        base.OnValidating(e);
      }
      finally
      {
        inValidatingCode = false;
      }
    }

    protected internal override void FixedFillOptionsChanged()
    {
      Footer.UpdateDefaults();
    }

    protected internal virtual void ColumnFrozenChanged(DataGridColumn dataGridColumn, DataGridColumnFrozenState frozen)
    {
      UpdateColumnsView();
    }

    protected override void RollPosChanged(long oldRowPosX, long oldRowPosY)
    {
      base.RollPosChanged(oldRowPosX, oldRowPosY);
      Columns.OnRollPosChanged();
      UpdateCellEditorBounds();
    }

    protected internal virtual void AllowRowResizeChanged()
    {
      if (RowOptions.AllowResize)
        Options = Options | GridOptions.RowSizing;
      else
        Options = Options & ~GridOptions.RowSizing;
    }

    internal void RowHeightAutoExpandChanged()
    {
      if (!InInitialization)
        UpdateRowHeights();
    }

    internal void RowOptionsContentHeightInTextLinesChanged()
    {
      if (!InInitialization)
        UpdateRowHeights();
    }

    internal void RowOptionsMaxContentHeightInTextLinesChanged()
    {
      if (!InInitialization)
        UpdateRowHeights();
    }

    internal void RowOptionsHeightInPixelsChanged()
    {
      if (!InInitialization)
        UpdateRowHeights();
    }

    internal void RowOptionsMaxHeightInPixelsChanged()
    {
      if (!InInitialization)
        UpdateRowHeights();
    }

    internal virtual void ColumnHeightAutoExpandChanged()
    {
      RowHeightAffectPropertyChanged();
    }

    protected internal override void RowHeightAffectPropertyChanged()
    {
      if (!InInitialization)
        UpdateRowHeights();
    }

    protected internal new virtual object GetService(Type service)
    {
      return base.GetService(service);
    }

    public virtual Dictionary<string, object> GetStorableSettings()
    {
      var settings = new Dictionary<string, object>();
      DataGridManager.DefaultManager.WriteGridSettings(this, settings);

      if (Title.MultiTitle.Active)
      {
        Dictionary<string, object> multiTitleSettings = GetMultiTitleSettings();
        settings.Add("MultiTitleItems", multiTitleSettings);
      }
      else
      {
        Dictionary<string, object> columnsSettings = GetColumnsSettings();
        settings.Add("Columns", columnsSettings);
      }

      return settings;
    }

    public virtual Dictionary<string, object> GetColumnsSettings()
    {
      var columnsSettings = new Dictionary<string, object>();

      foreach (DataGridColumn col in Columns)
      {
        string keyValue;

        if (String.IsNullOrEmpty(col.Name))
          keyValue = col.DataPropertyName;
        else
          keyValue = col.Name;

        var colSettings = new Dictionary<string, object>();
        DataGridManager.DefaultManager.WriteColumnSettings(this, col, colSettings);

        columnsSettings.Add(keyValue, colSettings);
      }

      return columnsSettings;
    }

    public virtual Dictionary<string, object> GetMultiTitleSettings()
    {
      return Title.MultiTitle.GetStorableSettings();
    }

    public virtual void ReadStorableSettings(Dictionary<string, object> settings)
    {
      DataGridManager.DefaultManager.ReadGridSettings(this, settings);

      if (Title.MultiTitle.Active)
      {
        object multiTitleSettingsObj;
        Dictionary<string, object> multiTitleSettings = null;
        if (settings.TryGetValue("MultiTitleItems", out multiTitleSettingsObj))
        {
          multiTitleSettings = multiTitleSettingsObj as Dictionary<string, object>;
        }
        if (multiTitleSettings != null)
          ReadMultiTitleSettings(multiTitleSettings);
      }
      else
      {
        object columnsSettingsObj;
        Dictionary<string, object> columnsSettings = null;
        if (settings.TryGetValue("Columns", out columnsSettingsObj))
        {
          columnsSettings = columnsSettingsObj as Dictionary<string, object>;
        }
        if (columnsSettings != null)
          ReadColumnsSettings(columnsSettings);
      }
    }

    public virtual void ReadColumnsSettings(Dictionary<string, object> columnsSettings)
    {
      Columns.BeginUpdate();
      try
      {
        foreach (KeyValuePair<string, object> colSet in columnsSettings)
        {
          DataGridColumn col;
          col = Columns.FindColumnByName(colSet.Key);
          if (col == null)
            col = Columns.FindColumnByPropertyName(colSet.Key);

          var columnSettings = colSet.Value as Dictionary<string, object>;
          if (col != null && columnSettings != null)
          {
            DataGridManager.DefaultManager.ReadColumnSettings(this, col, columnSettings);
          }
        }
      }
      finally
      {
        Columns.EndUpdate();
      }
    }

    public virtual void ReadMultiTitleSettings(Dictionary<string, object> mtSettings)
    {
      Columns.BeginUpdate();
      try
      {
        Title.MultiTitle.ReadStorableSettings(mtSettings);
      }
      finally
      {
        Columns.EndUpdate();
      }
    }

    public override bool IsDrawHotState()
    {
      return base.IsDrawHotState() && DataGridState == DataGridState.Normal;
    }

    protected internal override string GetHighlightSearchingData(PropertyAxisBar propAxisBar, object listItemBar, string cellText, out CharacterRange[] charRanges)
    {
      if ((SearchBox.HighlightSearchingText == true) &&
          (!string.IsNullOrEmpty(SearchBox.SearchingText)))
      {
        if (!SearchBox.CheckTextHit((DataGridColumn)propAxisBar, cellText, SearchBox.SearchingText))
        {
          charRanges = null;
          return null;
        }
        else
        {
          charRanges = SearchBox.GetHitRanges((DataGridColumn)propAxisBar, (DataGridRow)listItemBar, cellText);
          return SearchBox.SearchingText;
        }
      }
      else
      {
        charRanges = null;
        return null;
      }
    }

    protected internal override void OnFillDataCellFormatParams(DataAxisGridDataCellFormatParamsEventArgs e)
    {
      var eh = this.Events[EventKeyDataCellQueryFillFormatParams] as EventHandler<DataGridDataCellFormatParamsEventArgs>;
      if (eh != null)
      {
        eh(this, (DataGridDataCellFormatParamsEventArgs)e);
      }
    }

    protected override DataAxisCreatingDynamicColumnsForDataPropertyEventArgs GetDataAxisCreatingDynamicColumnsForDataPropertyEventArgs(
      PropertyDescriptor propDescriptor, bool inStaticColumns)
    {
      return new DataGridCreatingDynamicColumnsForDataPropertyEventArgs(this, propDescriptor, inStaticColumns);
    }

    protected override void ProcessCreateDynamicPropBarsForDataPropertyEvent(DataAxisCreatingDynamicColumnsForDataPropertyEventArgs e)
    {
      var eh = this.Events[EventKeyCreatingDynamicPropBarsForDataProperty] as EventHandler<DataGridCreatingDynamicColumnsForDataPropertyEventArgs>;
      if (eh != null)
      {
        eh(this, (DataGridCreatingDynamicColumnsForDataPropertyEventArgs)e);
      }
    }

    protected internal override void OnDataCellContextMenuStripNeeded(DataAxisGridDataCellContextMenuStripNeededEventArgs age)
    {
      DataGridManager.DefaultManager.BuildDataCellContextMenu(this, age);
    }

    //protected internal virtual void OnTitleCellContextMenuStripNeeded(DataGridTitleCellContextMenuStripNeededEventArgs age)
    //{
    //  DataGridManager.DefaultManager.BuildTitleCellContextMenu(this, age);
    //}

    internal protected override void DeleteCurrentListItem()
    {
      int curDataRowIndex = CurrentRowIndex;
      CurrencyManager.RemoveAt(this.CurrencyManager.Position);
      if (VisibleRows.Count > 0)
      {
        if (curDataRowIndex >= VisibleRows.Count)
          CurrentRowIndex = VisibleRows.Count - 1;
        else
          CurrentRowIndex = curDataRowIndex;
      }
    }

    internal protected virtual void ColumnMergeDuplicatesChanged(DataGridColumn dataGridColumn, bool value)
    {
      Invalidate();
    }
    #endregion nopublic methods
  }

  public class DataGridRow : object
  {
    #region Privates
    private int index = -1;
    private int visibleIndex = -1;
    private DataGridRows rows;
    private bool visible = true;
    private object srcRow;

    internal int HeightInternal;
    internal bool SelectedInternal;
    #endregion Privates

    public DataGridRow()
    {
    }

    #region Properties
    //internal List<DataGridBaseCell> Cells { get; set; }

    public DataGridEh Grid { get { return rows.Grid; } }

    public DataGridRows Rows
    {
      get
      {
        return rows;
      }

      internal set
      {
        rows = value;
      }
    }

    [DefaultValue(false)]
    [Browsable(false)]
    public bool Selected
    {
      get
      {
        return SelectedInternal;
      }

      set
      {
        if (value != SelectedInternal)
        {
          if (Grid == null)
            SelectedInternal = value;
          else
            Grid.Selection.AddSelectedRow(this, value);
        }
      }
    }

    [Browsable(false)]
    public int Index
    {
      get
      {
        Rows.EnsureIndexesActual();
        return index;
      }

      internal set
      {
        index = value;
      }
    }

    [Browsable(false)]
    public int VisibleIndex
    {
      get
      {
        Rows.Grid.VisibleRows.EnsureIndexesActual();
        return visibleIndex;
      }

      internal set
      {
        visibleIndex = value;
      }
    }

    [Browsable(false)]
    public bool Visible
    {
      get
      {
        return visible;
      }

      internal set
      {
        if (visible != value)
        {
          visible = value;
          Grid.VisibleRows.IndexesIsDirty = true;
        }
      }
    }

    [Browsable(false)]
    public int Height
    {
      get
      {
        return HeightInternal;
      }

      set
      {
        if (value != Height)
          Grid.RowHeights[Grid.FixedRowCount + VisibleIndex] = value;
      }
    }

    [Browsable(false)]
    public object SourceItem
    {
      get { return srcRow; }
      internal set { srcRow = value; }
    }

    #endregion Properties

    #region Methods
    #endregion Methods
  }

  public class DataGridRows : DataGridObject, IList<DataGridRow>
  {
    #region Privates
    private bool indexesIsDirty;
    private readonly List<DataGridRow> list;
    #endregion Privates

    public DataGridRows(DataGridEh grid) : base(grid)
    {
      list = new List<DataGridRow>();
    }

    #region Properties
    public int Count
    {
      get
      {
        //CheckMakeIndexesActual();
        return list.Count;
      }
    }

    public DataGridRow this[int index]
    {
      get
      {
        //CheckMakeIndexesActual();
        return list[index];
      }
      set
      {
        list[index] = value;
      }
    }

    public bool IsReadOnly
    {
      get { return false; }  
    }

    #endregion Properties

    #region Methods
    public void Insert(int index, DataGridRow item)
    {
      item.Rows = this;
      list.Insert(index, item);
      indexesIsDirty = true;
      Grid.VisibleRows.IndexesIsDirty = true;
    }

    public bool Remove(DataGridRow item)
    {
      if (list.Remove(item))
      {
        indexesIsDirty = true;
        Grid.VisibleRows.IndexesIsDirty = true;
        return true;
      }
      else
        return false;
    }

    public int RemoveAll(Predicate<DataGridRow> match)
    {
      indexesIsDirty = true;
      Grid.VisibleRows.IndexesIsDirty = true;
      return list.RemoveAll(match);
    }

    public void RemoveAt(int index)
    {
      indexesIsDirty = true;
      Grid.VisibleRows.IndexesIsDirty = true;
      list.RemoveAt(index);
    }

    public void RemoveRange(int index, int count)
    {
      indexesIsDirty = true;
      Grid.VisibleRows.IndexesIsDirty = true;
      list.RemoveRange(index, count);
    }

    public void Reverse()
    {
      indexesIsDirty = true;
      Grid.VisibleRows.IndexesIsDirty = true;
      list.Reverse();
    }

    public void Reverse(int index, int count)
    {
      indexesIsDirty = true;
      Grid.VisibleRows.IndexesIsDirty = true;
      list.Reverse(index, count);
    }

    public void Clear()
    {
      indexesIsDirty = true;
      Grid.VisibleRows.IndexesIsDirty = true;
      list.Clear();
    }

    public IEnumerator<DataGridRow> GetEnumerator()
    {
      return list.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
      return list.GetEnumerator();
    }

    public int IndexOf(DataGridRow item)
    {
      return list.IndexOf(item);
    }

    public void Add(DataGridRow item)
    {
      list.Add(item);
      indexesIsDirty = true;
      Grid.VisibleRows.IndexesIsDirty = true;
    }

    public bool Contains(DataGridRow item)
    {
      return list.Contains(item);
    }

    public void CopyTo(DataGridRow[] array, int arrayIndex)
    {
      list.CopyTo(array, arrayIndex);
    }

    public void EnsureIndexesActual()
    {
      if (indexesIsDirty)
        MakeIndexesActual();
    }

    protected internal virtual void MakeIndexesActual()
    {
      for (int i = 0; i < list.Count; i++)
      {
        list[i].Index = i;
      }
      indexesIsDirty = false;
    }
    #endregion Methods
  }

  public class DataGridVisibleRows : IList<DataGridRow>, IEnumerable<DataGridRow>
  {
    #region Privates
    private readonly DataGridEh grid;
    private List<DataGridRow> items = new List<DataGridRow>();

    internal bool IndexesIsDirty { get; set; }
    #endregion Privates

    public DataGridVisibleRows(DataGridEh grid)
    {
      this.grid = grid;
    }

    #region Properties
    public int Count
    {
      get
      {
        EnsureIndexesActual();
        return items.Count;
      }
    }

    public bool IsReadOnly
    {
      get
      {
        return true;
      }
    }

    public DataGridRow this[int index]
    {
      get
      {
        EnsureIndexesActual();
        return items[index];
      }
      set
      {
        items[index] = value;
      }
    }
    #endregion Properties

    #region Methods
    internal void EnsureIndexesActual()
    {
      if (IndexesIsDirty)
        MakeIndexesActual();
    }

    protected internal virtual void MakeIndexesActual()
    {
      int vi = 0;

      ClearInternal();

      foreach (DataGridRow row in grid.Rows)
      {
        if (row.Visible)
        {
          row.VisibleIndex = vi;
          AddInternal(row);
          vi = vi + 1;
        }
        else
        {
          row.VisibleIndex = -1;
        }
      }

      FireChangeEvent(new ListChangedEventArgs(ListChangedType.Reset, -1));

      IndexesIsDirty = false;
    }

    public int IndexOf(DataGridRow item)
    {
      return items.IndexOf(item);
    }

    public bool Contains(DataGridRow item)
    {
      return items.Contains(item);
    }

    public void CopyTo(DataGridRow[] array, int arrayIndex)
    {
      items.CopyTo(array, arrayIndex);
    }

    // Internals
    internal void ClearInternal()
    {
      items.Clear();
    }

    internal void AddInternal(DataGridRow item)
    {
      items.Add(item);
    }

    private void FireChangeEvent(ListChangedEventArgs e)
    {
      grid.OnVisibleRowsListChanged(EventArgs.Empty);
      grid.DataView.FireEvent(e);
    }

    // IEnumerator
    public IEnumerator GetEnumerator()
    {
      EnsureIndexesActual();
      return items.GetEnumerator();
    }

    IEnumerator<DataGridRow> IEnumerable<DataGridRow>.GetEnumerator()
    {
      EnsureIndexesActual();
      return items.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
      EnsureIndexesActual();
      return GetEnumerator();
    }

    // IList
    void IList<DataGridRow>.Insert(int index, DataGridRow item)
    {
      throw new InvalidOperationException("Collection is ReadOnly");
    }

    void IList<DataGridRow>.RemoveAt(int index)
    {
      throw new InvalidOperationException("Collection is ReadOnly");
    }

    void ICollection<DataGridRow>.Add(DataGridRow item)
    {
      throw new InvalidOperationException("Collection is ReadOnly");
    }

    void ICollection<DataGridRow>.Clear()
    {
      throw new InvalidOperationException("Collection is ReadOnly");
    }

    bool ICollection<DataGridRow>.Remove(DataGridRow item)
    {
      throw new InvalidOperationException("Collection is ReadOnly");
    }

    #endregion Methods

  }

  public class DataGridObject : object
  {
    private readonly DataGridEh grid;

    public DataGridObject(DataGridEh grid)
    {
      this.grid = grid;
    }

    [Browsable(false)]
    public DataGridEh Grid
    {
      get { return grid; }
    }

  }

  [ToolboxItem(false)]
  public class DataGridBaseComponent : Component
  {
    private readonly DataGridEh grid;

    public DataGridBaseComponent(DataGridEh grid)
    {
      this.grid = grid;
    }

    [Browsable(false)]
    public DataGridEh Grid
    {
      get { return grid; }
    }

  }

  public enum DataGridColumnAutoSizeConsiderRowsMode
  {
    None,
    All,
    VisibleRows,
    ConsiderRowCount
    //,StopOnExcessTime
  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataGridAutoSizeColumnOptions : DataGridObject
  {

    bool fitToClient;
    int maxAutoWidth;
    bool maxAutoWidthStored = false;

    public DataGridAutoSizeColumnOptions(DataGridEh grid) : base(grid)
    {
      ConsiderTitle = true;
      ConsiderRowCount  = 100;
      MaxAutoWidth = 0;
      ConsiderRowsMode = DataGridColumnAutoSizeConsiderRowsMode.ConsiderRowCount;
    }

    [DefaultValue(true)]
    public bool ConsiderTitle { get; set; }

    [DefaultValue(DataGridColumnAutoSizeConsiderRowsMode.ConsiderRowCount)]
    public DataGridColumnAutoSizeConsiderRowsMode ConsiderRowsMode { get; set; }

    [DefaultValue(100)]
    public int ConsiderRowCount { get; set; }

    [DefaultValue(0)]
    public int MaxAutoWidth
    {
      get
      {
        if (maxAutoWidthStored)
          return maxAutoWidth;
        else
          return DefaultMaxAutoWidth();
      }

      set
      {
        if (value != maxAutoWidth)
        {
          maxAutoWidth = value;
          maxAutoWidthStored = true;
        }
      }
    }

    [DefaultValue(false)]
    public bool FitToClient
    {
      get
      {
        return fitToClient;
      }
      set
      {
        if (value != fitToClient)
        {
          fitToClient = value;
          if (fitToClient)
          {
            Grid.InitColumnsFillWeight();
            Grid.UpdateFitColWidthsToClient();
          }
        }
      }
    }

    //MaxAutoWidth
    private int DefaultMaxAutoWidth()
    {
      return DataGridManager.DefaultManager.AutoSizeColumnOptionsMaxAutoWidth();
    }

  }

  //public class GridDataLink : DataGridObject
  //{
  //  #region GridDataLink privates
  //  private readonly ListChangedEventHandler listChangedHandler;
  //  private readonly EventHandler positionChangedHandler;

  //  private object dataSource;
  //  private string dataMember;
  //  private CurrencyManager currencyManager;
  //  private NewRowEditState newCurrentRowState = NewRowEditState.Unchanged;
  //  #endregion GridDataLink Properties

  //  public GridDataLink(DataGridEh grid) : base(grid)
  //  {
  //    listChangedHandler = CurrencyManagerListChanged;
  //    positionChangedHandler = CurrencyManager_PositionChanged;
  //  }

  //  #region properties
  //  public bool Active
  //  {
  //    get { return (CurrencyManager != null); }
  //  }

  //  public bool AllowAdd
  //  {
  //    get
  //    {
  //      var bList = List as IBindingList;

  //      if ((bList != null) && 
  //          bList.AllowNew &&
  //          bList.SupportsChangeNotification &&
  //          (List != null) &&
  //          !List.IsReadOnly &&
  //          !List.IsFixedSize
  //      )
  //        return true;
  //      else
  //        return false;
  //    }
  //  }

  //  public bool AllowEdit
  //  {
  //    get
  //    {
  //      var bList = List as IBindingList;

  //      if ((bList != null) &&
  //          bList.AllowEdit &&
  //          (List != null) &&
  //          !List.IsReadOnly
  //      )
  //        return true;
  //      else
  //        return false;
  //    }
  //  }

  //  public bool AllowRemove
  //  {
  //    get
  //    {
  //      var bList = List as IBindingList;

  //      if ((bList != null) &&
  //          bList.AllowRemove &&
  //          bList.SupportsChangeNotification &&
  //          (List != null) &&
  //          !List.IsReadOnly &&
  //          !List.IsFixedSize
  //      )
  //        return true;
  //      else
  //        return false;
  //    }
  //  }

  //  public RowEditState CurrentRowState
  //  {
  //    get; private set;
  //  }

  //  public bool CurrentRowModified
  //  {
  //    get; private set;
  //  }

  //  public int Position
  //  {
  //    get
  //    {
  //      return currencyManager.Position;
  //    }
  //    set
  //    {
  //      if (currencyManager.Position != value)
  //      {
  //        if (CurrentRowState != RowEditState.Browse)
  //        {
  //          Grid.PushEditorData();
  //          if (CurrentRowModified)
  //            EndCurrentEdit();
  //          else
  //            CancelCurrentEdit();
  //        }
  //        currencyManager.Position = value;
  //      }
  //    }
  //  }

  //  public object DataSource
  //  {
  //    get
  //    {
  //      return this.dataSource;
  //    }
  //    set
  //    {
  //      if (this.dataSource != value)
  //      {
  //        this.dataSource = value;
  //        TryDataBinding();
  //      }
  //    }
  //  }

  //  public string DataMember
  //  {
  //    get
  //    {
  //      return this.dataMember;
  //    }
  //    set
  //    {
  //      if (this.dataMember != value)
  //      {
  //        this.dataMember = value;
  //        TryDataBinding();
  //      }
  //    }
  //  }

  //  public CurrencyManager CurrencyManager
  //  {
  //    get
  //    {
  //      return this.currencyManager;
  //    }
  //  }

  //  public IList List
  //  {
  //    get
  //    {
  //      if (this.currencyManager != null)
  //      {
  //        return this.currencyManager.List;
  //      }
  //      else
  //      {
  //        return null;
  //      }
  //    }
  //  }

  //  public bool SupportsSorting
  //  {
  //    get
  //    {
  //      IBindingList bList = null;

  //      if (CurrencyManager != null)
  //        bList = CurrencyManager.List as IBindingList;

  //      if (bList != null && bList.SupportsSorting)
  //        return true;
  //      else
  //        return false;
  //    }
  //  }

  //  public bool SupportsAdvancedSorting
  //  {
  //    get
  //    {
  //      IBindingList bList = null;
  //      IBindingListView bListView = null;

  //      if (CurrencyManager != null)
  //        bList = CurrencyManager.List as IBindingList;

  //      if (bList != null)
  //        bListView = bList as IBindingListView;

  //      if (bListView != null && bListView.SupportsAdvancedSorting)
  //        return true;
  //      else
  //        return false;
  //    }
  //  }
  //  #endregion properties

  //  #region Methods

  //  public void SetCurrentRowValue(PropertyDescriptor propDescr, object value)
  //  {
  //    object srcRow = Grid.CurrencyManager.Current;
  //    propDescr.SetValue(srcRow, value);
  //    CurrentRowModified = true;
  //  }

  //  internal void TryDataBinding()
  //  {
  //    CurrencyManager cm;

  //    if (this.DataSource == null || Grid.BindingContext == null)
  //    {
  //      cm = null;
  //    }
  //    else
  //    {
  //      //try
  //      //{
  //      cm = (CurrencyManager)Grid.BindingContext[this.DataSource, this.DataMember];
  //      //}
  //      //catch (System.ArgumentException)
  //      //{
  //      //  return;
  //      //}
  //    }

  //    if (this.currencyManager != cm)
  //    {
  //      if (this.currencyManager != null)
  //      {
  //        this.currencyManager.ListChanged -= listChangedHandler;
  //        this.currencyManager.PositionChanged -= positionChangedHandler;
  //      }

  //      this.currencyManager = cm;

  //      if (this.currencyManager != null)
  //      {
  //        this.currencyManager.ListChanged += listChangedHandler;
  //        this.currencyManager.PositionChanged += positionChangedHandler;
  //      }

  //      CurrencyManagerListChanged(currencyManager, new ListChangedEventArgs(ListChangedType.Reset, -1));
  //    }
  //  }

  //  private void CurrencyManagerListChanged(object sender, ListChangedEventArgs e)
  //  {
  //    if (newCurrentRowState == NewRowEditState.Add)
  //      CurrentRowState = RowEditState.Add;
  //    else if (newCurrentRowState == NewRowEditState.Browse)
  //      CurrentRowState = RowEditState.Browse;
  //    else if (newCurrentRowState == NewRowEditState.Edit)
  //      CurrentRowState = RowEditState.Edit;

  //    Grid.CurrencyManagerListChanged(sender, e);
  //  }

  //  private void CurrencyManager_PositionChanged(object sender, EventArgs e)
  //  {
  //    Grid.CurrencyManagerPositionChanged(sender, e);
  //  }

  //  public void AddNew()
  //  {
  //    newCurrentRowState = NewRowEditState.Add;
  //    this.currencyManager.AddNew();
  //    newCurrentRowState = NewRowEditState.Unchanged;
  //  }

  //  public void BeginCurrentEdit()
  //  {
  //    var iEditObj = this.currencyManager.Current as IEditableObject;
  //    if (iEditObj != null)
  //    {
  //      newCurrentRowState = NewRowEditState.Edit;
  //      iEditObj.BeginEdit();
  //      newCurrentRowState = NewRowEditState.Unchanged;
  //      Grid.InvalidateGrid();
  //    }
  //  }

  //  public void CancelCurrentEdit()
  //  {
  //    newCurrentRowState = NewRowEditState.Browse;
  //    this.currencyManager.CancelCurrentEdit();
  //    newCurrentRowState = NewRowEditState.Unchanged;
  //    CurrentRowModified = false;
  //    Grid.InvalidateGrid();
  //  }

  //  public void EndCurrentEdit()
  //  {
  //    this.currencyManager.EndCurrentEdit();
  //    CurrentRowState = RowEditState.Browse;
  //    CurrentRowModified = false;
  //    Grid.InvalidateGrid();
  //  }

  //  public int MoveBy(int distance)
  //  {
  //    int maxDisc;

  //    if (distance > 0)
  //    {
  //      maxDisc = (currencyManager.Count - Position - 1);
  //      if (distance > maxDisc)
  //        distance = maxDisc;
  //      Position = Position + distance;
  //      return distance;
  //    }
  //    else
  //    {
  //      maxDisc = Position;
  //      if (-distance > maxDisc)
  //        distance = -maxDisc;
  //      Position = Position + distance;
  //      return distance;
  //    }
  //  }

  //  internal IList GetDataSortDescription()
  //  {
  //    IBindingList bList = null;
  //    IBindingListView bListView = null;
  //    IList res;
  //    ListSortDescription lsDesc;

  //    if (Grid.CurrencyManager != null)
  //      bList = Grid.CurrencyManager.List as IBindingList;

  //    if (bList != null)
  //      bListView = bList as IBindingListView;

  //    if (bList == null || !bList.SupportsSorting || !bList.IsSorted)
  //    {
  //      res = new List<ListSortDescription>();

  //    }
  //    else if (bList.SortProperty != null)
  //    {
  //      res = new List<ListSortDescription>();
  //      lsDesc = new ListSortDescription(bList.SortProperty, bList.SortDirection);
  //      res.Add(lsDesc);

  //    }
  //    else if (bListView != null)
  //    {
  //      res = bListView.SortDescriptions;
  //    }
  //    else
  //    {
  //      res = null;
  //    }

  //    return res;
  //  }

  //  internal virtual void Sort(DataGridColumn column, SortOrder sortOrder)
  //  {
  //    Debug.Assert(column.IsDataBound, "GridDataLink.Sort(..) column.IsDataBound = false");
  //    Debug.Assert(this.List is IBindingList, "GridDataLink.Sort(..) List is not IBindingList");

  //    IBindingList bndList = ((IBindingList)this.List);
  //    if (sortOrder == SortOrder.Ascending)
  //      bndList.ApplySort(column.PropDescr, ListSortDirection.Ascending);
  //    else if (sortOrder == SortOrder.Descending)
  //      bndList.ApplySort(column.PropDescr, ListSortDirection.Descending);
  //    else
  //      bndList.RemoveSort();
  //  }

  //  internal virtual void Sort(DataGridSortCollection sortMarkers)
  //  {
  //    Debug.Assert(SupportsSorting, "GridDataLink.Sorting is not Supported");
  //    if (sortMarkers.Count > 1)
  //      Debug.Assert(SupportsAdvancedSorting, "GridDataLink Sorting by multiple columns are not Supported");

  //    IBindingListView bListView = (IBindingListView)List;

  //    if (SupportsAdvancedSorting)
  //    {
  //      //ListSortDescriptionCollection sorts = new ListSortDescriptionCollection();
  //      List<ListSortDescription> sdList = new List<ListSortDescription>();

  //      foreach (DataGridSortItem sni in sortMarkers)
  //      {
  //        ListSortDescription sd = new ListSortDescription(sni.Column.PropDescr, sni.SortDirection);
  //        sdList.Add(sd);
  //      }
  //      bListView.ApplySort(new ListSortDescriptionCollection(sdList.ToArray()));
  //    }
  //  }

  //  public void DeleteCurrentRow()
  //  {
  //    this.currencyManager.RemoveAt(this.currencyManager.Position);
  //  }
  //  #endregion Methods
  //}

  public class DataGridSortItem : object
  {
    public DataGridColumn Column { get; set; }
    public ListSortDirection SortDirection { get; set; }
  }

  public class DataGridSortCollection : DataGridObject, IEnumerable<DataGridSortItem>
  {

    private readonly List<DataGridSortItem> sortCollection;
    private bool sortMarkersChanged;

    public DataGridSortCollection(DataGridEh grid) : base(grid)
    {
      sortCollection = new List<DataGridSortItem>();
    }

    public int Count { get { return sortCollection.Count; } }

    public DataGridSortItem this[int index] { get { return sortCollection[index]; } }

    public IEnumerator<DataGridSortItem> GetEnumerator()
    {
      return (sortCollection as IEnumerable<DataGridSortItem>).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
      return (sortCollection as IEnumerable).GetEnumerator();
    }

    protected internal void AddSortItem(DataGridColumn column, ListSortDirection sortDirection)
    {
      if (IndexOf(column) >= 0)
        throw new InvalidOperationException("column is not unique in DataGridSortCollection");
      DataGridSortItem sortItem = new DataGridSortItem() { Column = column, SortDirection = sortDirection };
      sortCollection.Add(sortItem);
      sortMarkersChanged = true;
    }

    protected internal void Clear()
    {
      sortCollection.Clear();
      sortMarkersChanged = true;
    }

    protected internal bool Remove(DataGridColumn column)
    {
      for (int i = 0; i < Count; i++)
      {
        DataGridSortItem si = this[i];
        if (si.Column == column)
        {
          sortCollection.RemoveAt(i);
          sortMarkersChanged = true;
        }
      }
      return false;
    }

    protected internal void SetSortState(DataGridColumn column, ListSortDirection sortDirection)
    {
      Clear();
      AddSortItem(column, sortDirection);
      sortMarkersChanged = true;
    }

    public void UpdateDataFromListSortDescription(IList listDescCollection)
    {
      DataGridSortItem sortItem;
      DataGridColumn column;
      ListSortDescription sortDesc;

      Clear();
      foreach (object lsd in listDescCollection)
      {
        sortDesc = (lsd as ListSortDescription);
        Debug.Assert(sortDesc != null, "sortDesc != null");
        column = Grid.Columns.FindColumnByPropertyName(sortDesc.PropertyDescriptor.Name);
        if (column != null)
        {
          sortItem = new DataGridSortItem();
          sortItem.SortDirection = sortDesc.SortDirection;
          sortItem.Column = column;
          sortCollection.Add(sortItem);
        }
      }
      sortMarkersChanged = false;
    }

    public int IndexOf(DataGridColumn column)
    {
      int index = 0;
      foreach (DataGridSortItem si in sortCollection)
      {
        if (si.Column == column)
          return index;
        index = index + 1;
      }
      return -1;
    }

    public void ChangeStateAsTitleClick(DataGridColumn column, bool isMultiSortMarking)
    {
      DataGridSortItem si;
      int siIndex;

      siIndex = IndexOf(column);
      if (isMultiSortMarking)
      {
        if (siIndex >= 0)
        {
          si = this[siIndex];
          if (si.SortDirection == ListSortDirection.Ascending)
            si.SortDirection = ListSortDirection.Descending;
          else
            Remove(column);
        }
        else
        {
          AddSortItem(column, ListSortDirection.Ascending);
        }
      }
      else
      {
        if (siIndex >= 0)
        {
          si = this[siIndex];
          if (si.SortDirection == ListSortDirection.Ascending)
            SetSortState(column, ListSortDirection.Descending);
          else
            SetSortState(column, ListSortDirection.Ascending);
        }
        else
        {
          SetSortState(column, ListSortDirection.Ascending);
        }
      }
      sortMarkersChanged = true;
    }

    public void CommitChanges()
    {
      if (sortMarkersChanged)
      {
        Grid.OnSortmarkingChangeCommitted();
        sortMarkersChanged = false;
      }
    }

    public void SetChangedStatus(bool isChanged)
    {
      sortMarkersChanged = isChanged;
    }
  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataGridSearchBoxOptionsMenuItems
  {
    public DataGridSearchBoxOptionsMenuItems()
    {
      SearchScopes = true;
      CaseSensitive = true;
      WholeWords = true;
      BeginsWith = true;
    }

    [DefaultValue(true)]
    public bool SearchScopes { get; set; }

    [DefaultValue(true)]
    public bool CaseSensitive { get; set; }

    [DefaultValue(true)]
    public bool WholeWords { get; set; }

    [DefaultValue(true)]
    public bool BeginsWith { get; set; }

    public virtual bool HasVisibleItem()
    {
      return SearchScopes || CaseSensitive || WholeWords || BeginsWith;
    }
  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataGridSearchBoxVisibleButtons
  {

    private readonly DataGridSearchBox searchBox;
    private bool applyFilterClear;
    private bool optionsPopupMenu;
    private bool findPrior;
    private bool findNext;

    public DataGridSearchBoxVisibleButtons(DataGridSearchBox searchBox)
    {
      this.searchBox = searchBox;
      applyFilterClear = true;
      findNext = true;
      findPrior = true;
      optionsPopupMenu = true;
    }

    [DefaultValue(true)]
    public bool ApplyFilterClear
    {
      get
      {
        return applyFilterClear;
      }
      set
      {
        if (value != applyFilterClear)
        {
          applyFilterClear = value;
          searchBox.VisibleButtonsChanged();
        }
      }
    }

    [DefaultValue(true)]
    public bool FindNext
    {
      get
      {
        return findNext;
      }
      set
      {
        if (value != findNext)
        {
          findNext = value;
          searchBox.VisibleButtonsChanged();
        }
      }
    }

    [DefaultValue(true)]
    public bool FindPrior
    {
      get
      {
        return findPrior;
      }
      set
      {
        if (value != findPrior)
        {
          findPrior = value;
          searchBox.VisibleButtonsChanged();
        }
      }
    }

    [DefaultValue(true)]
    public bool OptionsPopupMenu
    {
      get
      {
        return optionsPopupMenu;
      }
      set
      {
        if (value != optionsPopupMenu)
        {
          optionsPopupMenu = value;
          searchBox.VisibleButtonsChanged();
        }
      }
    }
  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  [ToolboxItem(false)]
  [DesignTimeVisible(false)]
  public class DataGridSearchBox : Component
  //public class SearchBoxParams : Object, IComponent
  {

    #region private consts
    private static readonly object EventKeyDataGridSearchBoxCheckRowHitSearch = new object();
    private static readonly object EventKeyDataGridSearchBoxCheckCellHitSearch = new object();
    private static readonly object EventKeyDataGridSearchGetHighlightedRanges = new object();
    #endregion private consts

    #region privates
    private readonly DataGridEh grid;
    private bool enabled;
    private bool visible;
    private bool caseSensitive;
    private DataGridSearchBoxScope searchScope = DataGridSearchBoxScope.EntireGrid;
    private bool cellBeginsWithMode;
    private bool wholeWords;
    private readonly DataGridSearchBoxOptionsMenuItems optionsPopupMenuItems;
    private readonly DataGridSearchBoxVisibleButtons visibleButtons;
    private bool persistentShowing = true;

    private string filterText = "";
    private bool highlightSearchingText;
    #endregion privates

    public DataGridSearchBox(DataGridEh grid)
    {
      this.grid = grid;
      enabled = false;
      visible = false;
      optionsPopupMenuItems = new DataGridSearchBoxOptionsMenuItems();
      visibleButtons = new DataGridSearchBoxVisibleButtons(this);
      Shortcut = Shortcut.CtrlF;
      FilterEnabled = true;
      FilterOnTyping = false;
    }

    #region design-time properties

    [DefaultValue(false)]
    public virtual bool Enabled
    {
      get
      {
        return enabled;
      }
      set
      {
        if (enabled != value)
        {
          enabled = value;
          UpdateVisibleState();
        }
      }
    }

    [DefaultValue(false)]
    public bool CaseSensitive
    {
      get
      {
        return caseSensitive;
      }
      set
      {
        if (caseSensitive != value)
        {
          caseSensitive = value;
          Grid.Invalidate();
        }
      }
    }

    [DefaultValue(DataGridSearchBoxScope.EntireGrid)]
    public DataGridSearchBoxScope SearchScope
    {
      get
      {
        return searchScope;
      }
      set
      {
        if (searchScope != value)
        {
          searchScope = value;
          Grid.Invalidate();
        }
      }
    }

    [DefaultValue(false)]
    public bool CellBeginsWithMode
    {
      get
      {
        return cellBeginsWithMode;
      }
      set
      {
        if (cellBeginsWithMode != value)
        {
          cellBeginsWithMode = value;
          Grid.Invalidate();
        }
      }
    }

    [DefaultValue(false)]
    public bool WholeWords
    {
      get
      {
        return wholeWords;
      }
      set
      {
        if (wholeWords != value)
        {
          wholeWords = value;
          Grid.Invalidate();
        }
      }
    }

    [DefaultValue(Shortcut.CtrlF)]
    public Shortcut Shortcut { get; set; }

    [DefaultValue(true)]
    public bool FilterEnabled { get; set; }

    [DefaultValue(false)]
    public bool FilterOnTyping { get; set; }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridSearchBoxOptionsMenuItems OptionsPopupMenuItems
    {
      get { return optionsPopupMenuItems; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridSearchBoxVisibleButtons VisibleButtons
    {
      get { return visibleButtons; }
    }

    [DefaultValue(true)]
    public bool PersistentShowing
    {
      get
      {
        return persistentShowing;
      }
      set
      {
        if (persistentShowing != value)
        {
          persistentShowing = value;
          UpdateVisibleState();
          Grid.Invalidate();
        }
      }
    }

    #endregion design-time properties

    #region run-time properties
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public DataGridEh Grid
    {
      get { return grid; }
    }

    [Browsable(false)]
    [DefaultValue(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public virtual bool Visible
    {
      get
      {
        return visible;
      }
      set
      {
        if (visible != value)
        {
          visible = value;
          Grid.UpdateBoundaries();
        }
      }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public int InGridHeight
    {
      get
      {
        if (Visible)
          return Grid.SearchBoxControl.CalcAutoHeight();
        else
          return 0;
      }
    }

    [Browsable(false)]
    [DefaultValue(false)]
    public virtual bool Active
    {
      get
      {
        return Grid.SearchBoxControl.ContainsFocus;
      }

      set
      {
        if (value == true)
        {
          if (Grid.ContainsFocus)
            Grid.SearchBoxControl.FindEditor.Focus();
        }
        else
        {
          Grid.Focus();
        }
      }
    }

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public string SearchingText
    {
      get { return Grid.SearchBoxControl.FindEditor.Text; }
      set { Grid.SearchBoxControl.FindEditor.Text = value; }
    }

    [Browsable(false)]
    public bool FilterActive
    {
      get { return /*Enabled &&*/ !string.IsNullOrEmpty(FilterText); }
    }

    [Browsable(false)]
    public string FilterText
    {
      get { return filterText; }
    }

    [DefaultValue(false)]
    [Browsable(false)]
    public bool HighlightSearchingText
    {
      get
      {
        return highlightSearchingText;
      }
      set
      {
        if (highlightSearchingText != value)
        {
          highlightSearchingText = value;
          Grid.Invalidate();
        }
      }
    }

    #endregion run-time properties

    #region events
    //public event KeyEventHandler KeyDown
    //{
    //  add { }
    //  remove { }
    //}

    //public event KeyPressEventHandler KeyPress
    //{
    //  add { }
    //  remove { }
    //}

    //public event KeyEventHandler KeyUp
    //{
    //  add { }
    //  remove { }
    //}

    public event DataGridSearchBoxCheckRowHitSearchEventHandler CheckRowHitSearch
    {
      add
      {
        this.Events.AddHandler(EventKeyDataGridSearchBoxCheckRowHitSearch, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataGridSearchBoxCheckRowHitSearch, value);
      }
    }

    public event DataGridSearchBoxCheckCellHitSearchEventHandler CheckCellHitSearch
    {
      add
      {
        this.Events.AddHandler(EventKeyDataGridSearchBoxCheckCellHitSearch, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataGridSearchBoxCheckCellHitSearch, value);
      }
    }

    public event DataGridSearchGetHighlightedRangesEventHandler GetHighlightedRanges
    {
      add
      {
        this.Events.AddHandler(EventKeyDataGridSearchBoxCheckRowHitSearch, value);
      }
      remove
      {
        this.Events.RemoveHandler(EventKeyDataGridSearchBoxCheckRowHitSearch, value);
      }
    }

    #endregion events

    #region methods
    public void FindNext()
    {
      DataGridLocateTextArgs locateTextArgs = new DataGridLocateTextArgs()
      {
        CaseSensitive = this.CaseSensitive,
        AllFields = (this.SearchScope == DataGridSearchBoxScope.EntireGrid),
        MatchFormat = true,
        IgnoreCurrentPos = true,
        StopOnEscape = true,
        StopOnAnyKey = true,
        AroundCircle = true,
        Direction = LocateTextDirection.Down,
        Timeout = 0
      };
      if (WholeWords)
        locateTextArgs.Matching = LocateTextMatching.Whole;
      else if (CellBeginsWithMode)
        locateTextArgs.Matching = LocateTextMatching.StartOf;
      else
        locateTextArgs.Matching = LocateTextMatching.AnyPartOf;

      Grid.LocateText(SearchingText, locateTextArgs);
    }

    public void FindPrev()
    {
      DataGridLocateTextArgs locateTextArgs = new DataGridLocateTextArgs()
      {
        CaseSensitive = this.CaseSensitive,
        AllFields = (this.SearchScope == DataGridSearchBoxScope.EntireGrid),
        MatchFormat = true,
        IgnoreCurrentPos = true,
        StopOnEscape = true,
        StopOnAnyKey = true,
        AroundCircle = true,
        Direction = LocateTextDirection.Up,
        Matching = LocateTextMatching.AnyPartOf,
        Timeout = 0
      };
      if (WholeWords)
        locateTextArgs.Matching = LocateTextMatching.Whole;
      else if (CellBeginsWithMode)
        locateTextArgs.Matching = LocateTextMatching.StartOf;
      else
        locateTextArgs.Matching = LocateTextMatching.AnyPartOf;

      Grid.LocateText(SearchingText, locateTextArgs);
    }

    public void RestartFind()
    {
      DataGridLocateTextArgs locateTextArgs = new DataGridLocateTextArgs()
      {
        CaseSensitive = this.CaseSensitive,
        AllFields = (this.SearchScope == DataGridSearchBoxScope.EntireGrid),
        MatchFormat = true,
        IgnoreCurrentPos = false,
        StopOnEscape = true,
        StopOnAnyKey = true,
        AroundCircle = false,
        Direction = LocateTextDirection.All,
        Timeout = 0
      };
      if (WholeWords)
        locateTextArgs.Matching = LocateTextMatching.Whole;
      else if (CellBeginsWithMode)
        locateTextArgs.Matching = LocateTextMatching.StartOf;
      else
        locateTextArgs.Matching = LocateTextMatching.AnyPartOf;

      Grid.LocateText(SearchingText, locateTextArgs);
    }

    public void ApplyFilter(string text)
    {
      filterText = text;
      Grid.RebuildVisibleRows(true, true, true);
      if ((Grid.InternalCurrentRowIndex == -1) &&
          (Grid.VisibleRows.Count > 0))
      {
        Grid.CurrentRowIndex = 0;
      }
      Grid.SearchBoxControl.RealignControls();
    }

    public void CancelFilter()
    {
      filterText = "";
      Grid.RebuildVisibleRows(false, false, false);
      Grid.SearchBoxControl.FindEditor.Text = "";
      Grid.SearchBoxControl.RealignControls();
    }

    public bool CheckTextHit(DataGridColumn column, string srcText, string searchText)
    {
      int stri;
      StringComparison comparisonType;

      if (srcText == null) return false;

      if ((SearchScope == DataGridSearchBoxScope.CurrentColumn) &&
          (column.VisibleIndex != Grid.CurrentColumnIndex))
        return false;

      if (CaseSensitive)
        comparisonType = StringComparison.Ordinal;
      else
        comparisonType = StringComparison.OrdinalIgnoreCase;

      if (WholeWords == true)
      {
        if (string.Equals(srcText, searchText, comparisonType) == true)
          stri = 0;
        else
          stri = -1;
      }
      else if (CellBeginsWithMode == true)
      {
        stri = srcText.IndexOf(searchText, comparisonType);
        if (stri > 0)
          stri = -1;
      }
      else
        stri = srcText.IndexOf(searchText, comparisonType);

      if (stri >= 0)
        return true;
      else
        return false;
    }

    public CharacterRange[] GetHitRanges(DataGridColumn column, DataGridRow row, string text)
    {
      CharacterRange[] charRanges = null;
      StringComparison comparisonType;

      if (CaseSensitive)
        comparisonType = StringComparison.Ordinal;
      else
        comparisonType = StringComparison.OrdinalIgnoreCase;

      if (WholeWords == true)
      {
        if (string.Equals(text, SearchingText, comparisonType) == true)
          charRanges = new[] { new CharacterRange(0, text.Length) };
      }
      else if (CellBeginsWithMode == true)
      {
        int stri = text.IndexOf(SearchingText, comparisonType);
        if (stri == 0)
          charRanges = new[] { new CharacterRange(0, SearchingText.Length) };
      }
      else
      {
        int[] strPList = EhLibUtils.StringAllIndexsOf(text, SearchingText, comparisonType, true);

        charRanges = new CharacterRange[strPList.Length];

        for (int i = 0; i < strPList.Length; i++)
        {
          charRanges[i].First = strPList[i];
          charRanges[i].Length = SearchingText.Length;
        }
      }

      ProcessGetHighlightedRangesEvent(column, row, text, charRanges);

      return charRanges;
    }

    public void UpdateVisibleState()
    {
      if ((persistentShowing || Active) &&
          (Enabled == true))
      {
        Visible = true;
      }
      else
      {
        Active = false;
        Visible = false;
      }
      //else if ((persistentShowing == false) && (Active == false))
      //{
      //  Visible = false;
      //}
    }

    protected internal virtual bool CheckRowVisible(DataGridRow row)
    {
      if (!FilterActive) return true;

      bool result = false;

      foreach (DataGridColumn col in Grid.VisibleColumns)
      {
        string s; 
        bool hitTest; 

        s = col.GetRowDisplayText(row);
        hitTest = CheckTextHit(col, s, FilterText);

        ProcessCheckCellHitSearchEvent(col, row, FilterText, ref hitTest);

        if (hitTest == true)
        {
          result = true;
          break;
        }
      }

      ProcessCheckRowHitSearchEvent(row, FilterText, ref result);

      return result;
    }
    
    private void ProcessCheckRowHitSearchEvent(DataGridRow row, string hitSearchText, ref bool isHitSearch)
    {
      var eh = this.Events[EventKeyDataGridSearchBoxCheckRowHitSearch] as DataGridSearchBoxCheckRowHitSearchEventHandler;
      if (eh != null && !Grid.IsDisposed)
      {
        var e = new DataGridSearchBoxCheckRowHitSearchEventArgs(hitSearchText, row);
        e.RowIsHitSearch = isHitSearch;
        eh(this, e);
        isHitSearch = e.RowIsHitSearch;
      }
    }

    private void ProcessCheckCellHitSearchEvent(DataGridColumn column, DataGridRow row, string hitSearchText, ref bool isHitSearch)
    {
      var eh = this.Events[EventKeyDataGridSearchBoxCheckCellHitSearch] as DataGridSearchBoxCheckCellHitSearchEventHandler;
      if (eh != null && !Grid.IsDisposed)
      {
        DataGridSearchBoxCheckCellHitSearchEventArgs e = new DataGridSearchBoxCheckCellHitSearchEventArgs(hitSearchText, row, column);
        e.CellIsHitSearch = isHitSearch;
        eh(this, e);
      }
    }

    private void ProcessGetHighlightedRangesEvent(DataGridColumn column, DataGridRow row, string hitSearchText, CharacterRange[] ranges)
    {
      var eh = this.Events[EventKeyDataGridSearchGetHighlightedRanges] as DataGridSearchGetHighlightedRangesEventHandler;
      if (eh != null && !Grid.IsDisposed)
      {
        DataGridSearchGetHighlightedRangesEventArgs e = new DataGridSearchGetHighlightedRangesEventArgs(hitSearchText, row, column, ranges);
        eh(this, e);
      }
    }

    internal void VisibleButtonsChanged()
    {
      Grid.SearchBoxControl.RealignControls();
    }

    #endregion methods
  }

  public class DataGridLocateTextArgs
  {
    public DataGridLocateTextArgs()
    {
      CaseSensitive = false;
      AllFields = true;
      MatchFormat = true;
      IgnoreCurrentPos = true;
      StopOnEscape = true;
      StopOnAnyKey = true;
      AroundCircle = false;
      Direction = LocateTextDirection.Down;
      Matching = LocateTextMatching.Whole;
      Timeout = 0;
    }

    public bool CaseSensitive { get; set; }
    public bool AllFields { get; set; }
    public bool MatchFormat { get; set; }
    public bool IgnoreCurrentPos { get; set; }
    public bool StopOnEscape { get; set; }
    public bool StopOnAnyKey { get; set; }
    public bool AroundCircle { get; set; }
    public LocateTextDirection Direction { get; set; }
    public LocateTextMatching Matching { get; set; }
    public int Timeout { get; set; }
  }

  public class DataGridLocateTextService
  {
    private readonly DataGridEh grid;
    int nextColIndex, nextRowIndex;

    public DataGridLocateTextService(DataGridEh grid)
    {
      this.grid = grid;
    }

    [Browsable(false)]
    public DataGridEh Grid { get { return grid; } }
    public string SearchText { get; set; }
    public DataGridLocateTextArgs SearchParams { get; set; }

    public bool SearchNext()
    {

      int ticks = Environment.TickCount;
      bool waitCursorSet = false;
      bool result = false;
      int oldNextRowIndex = Grid.CurrentColumnIndex;

      if (grid.VisibleRows.Count == 0) return false;

      nextColIndex = Grid.CurrentColumnIndex;
      nextRowIndex = Grid.CurrentRowIndex;

      if (SearchParams.Direction == LocateTextDirection.All)
        RestartCell();
      if (SearchParams.IgnoreCurrentPos == true)
      {
        SetNextCell();
        if ((nextColIndex == Grid.CurrentColumnIndex) &&
            (nextRowIndex == Grid.CurrentRowIndex))
          return false;
      }

      while (true)
      {
        if (CheckMatch() == true)
        {
          Grid.CurrentColumnIndex = nextColIndex;
          Grid.CurrentRowIndex = nextRowIndex;
          result = true;
          break;
        }
        else if (CheckEndOfData() == true)
          break;
        else
          SetNextCell();

        if (oldNextRowIndex != nextRowIndex)
        {
          if ((SearchParams.StopOnEscape) && IsEscapePressed())
            break;

          if ((SearchParams.StopOnAnyKey) && IsAnyKeyPressed())
            break;

          if ((Environment.TickCount - ticks > 1000) &&
              (Application.UseWaitCursor == false) &&
              (waitCursorSet == false))
          {
            Cursor.Show();
            Cursor.Current = Cursors.WaitCursor;
            waitCursorSet = true;
          }
          oldNextRowIndex = nextRowIndex;
        }
      }

      if (waitCursorSet)
        Cursor.Current = Cursors.Default;
      return result;
    }

    public bool CheckMatch()
    {
      int stri;
      StringComparison comparisonType;
      if (grid.VisibleRows.Count == 0) return false;

      string cellStr = grid.VisibleColumns[nextColIndex].GetRowDisplayText(grid.VisibleRows[nextRowIndex]);

      if (SearchParams.CaseSensitive)
        comparisonType = StringComparison.Ordinal;
      else
        comparisonType = StringComparison.OrdinalIgnoreCase;

      if (SearchParams.Matching == LocateTextMatching.Whole)
      {
        if (string.Equals(cellStr, SearchText, comparisonType) == true)
          stri = 0;
        else
          stri = -1;
      }
      else if (SearchParams.Matching == LocateTextMatching.StartOf)
      {
        stri = cellStr.IndexOf(SearchText, comparisonType);
        if (stri > 0)
          stri = -1;
      }
      else
        stri = cellStr.IndexOf(SearchText, comparisonType);

      if (stri >= 0)
        return true;
      else
        return false;
    }

    public void SetNextCell()
    {
      int minColIndex;
      int maxColIndex;

      if (SearchParams.AllFields)
      {
        minColIndex = 0;
        maxColIndex = Grid.VisibleColumns.Count - 1;
      }
      else
      {
        minColIndex = Grid.CurrentColumnIndex;
        maxColIndex = Grid.CurrentColumnIndex;
      }

      if ((SearchParams.Direction == LocateTextDirection.Down) ||
         (SearchParams.Direction == LocateTextDirection.All))
      {
        if (nextColIndex < maxColIndex)
        {
          nextColIndex = nextColIndex + 1;
        }
        else if (nextRowIndex < Grid.VisibleRows.Count - 1)
        {
          nextRowIndex = nextRowIndex + 1;
          nextColIndex = minColIndex;
        }
        else if (SearchParams.AroundCircle == true)
        {
          nextRowIndex = 0;
          nextColIndex = minColIndex;
        }
      }
      else
      {
        if (nextColIndex > minColIndex)
        {
          nextColIndex = nextColIndex - 1;
        }
        else if (nextRowIndex > 0)
        {
          nextRowIndex = nextRowIndex - 1;
          nextColIndex = maxColIndex;
        }
        else if (SearchParams.AroundCircle == true)
        {
          nextRowIndex = Grid.VisibleRows.Count - 1;
          nextColIndex = maxColIndex;
        }
      }
    }

    public void RestartCell()
    {
      nextRowIndex = 0;
      if (SearchParams.AllFields)
        nextColIndex = 0;
    }

    public bool CheckEndOfData()
    {
      bool result;
      int minColIndex;
      int maxColIndex;

      if (SearchParams.AllFields)
      {
        minColIndex = 0;
        maxColIndex = Grid.VisibleColumns.Count - 1;
      }
      else
      {
        minColIndex = Grid.CurrentColumnIndex;
        maxColIndex = Grid.CurrentColumnIndex;
      }

      if (SearchParams.AroundCircle == true)
        result =
            ((nextColIndex == Grid.CurrentColumnIndex) &&
             (nextRowIndex == Grid.CurrentRowIndex));
      else if (SearchParams.Direction == LocateTextDirection.Up)
        result = ((nextColIndex == minColIndex) && (nextRowIndex == 0));
      else
        result = ((nextColIndex == maxColIndex) &&
                  (nextRowIndex == Grid.VisibleRows.Count - 1));
      return result;
    }

    private bool IsAnyKeyPressed()
    {
      return EhLibUtils.IsAnyKeyPressed(Grid);
    }

    private bool IsEscapePressed()
    {
      return EhLibUtils.CheckKeyPressed(Grid, Keys.Escape, true);
    }

    //internal void OldLocateText(string s, DataGridLocateTextArgs args)
    //{
    //  string cellText;

    //  for (int ir = 0; ir < Grid.VisibleRows.Count; ir++)
    //  {
    //    for (int ic = 0; ic < Grid.VisibleColumns.Count; ic++)
    //    {
    //      DataGridColumn col = Grid.VisibleColumns[ic];

    //      cellText = col.GetRowDisplayText(Grid.VisibleRows[ir]);

    //    }
    //  }
    //}

  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataGridLineOptions : GridLineColors
  {
    #region privates
    private bool horzLines = true;
    private bool vertLines = true;
    private bool dataBoundaryColorStored;
    private Color dataBoundaryColor = Color.Empty;
    private bool gridBoundaries;
    private DataGridPaintEmptySpaceStyle vertEmptySpaceStyle = DataGridPaintEmptySpaceStyle.Gradient;
    private DataGridHorzEmptySpaceStyle horzEmptySpaceStyle = DataGridHorzEmptySpaceStyle.ExtendTitleWideSpace;
    #endregion privates

    public DataGridLineOptions(BaseGridControl grid) : base(grid)
    {
    }

    #region design-time properties
    public new Color DarkColor
    {
      get { return base.DarkColor; }
      set { base.DarkColor = value; }
    }

    public new Color BrightColor
    {
      get { return base.BrightColor; }
      set { base.BrightColor = value; }
    }

    [DefaultValue(true)]
    public bool HorzLines
    {
      get { return horzLines; }
      set
      {
        if (horzLines != value)
        {
          horzLines = value;
          HorzLinesChanged();
        }
      }
    }

    [DefaultValue(true)]
    public bool VertLines
    {
      get { return vertLines; }
      set
      {
        if (vertLines != value)
        {
          vertLines = value;
          VertLinesChanged();
        }
      }
    }

    public Color DataBoundaryColor
    {
      get
      {
        if (dataBoundaryColorStored)
          return dataBoundaryColor;
        else
          return DefaultDataBoundaryColor();
      }
      set
      {
        if ((dataBoundaryColorStored == false) || (dataBoundaryColor != value))
        {
          dataBoundaryColorStored = true;
          dataBoundaryColor = value;
          DataBoundaryColorChanged();
        }
      }
    }

    [DefaultValue(false)]
    public bool GridBoundaries
    {
      get { return gridBoundaries; }
      set
      {
        if (GridBoundaries != value)
        {
          gridBoundaries = value;
          GridBoundariesChanged();
        }
      }
    }

    [DefaultValue(DataGridPaintEmptySpaceStyle.Gradient)]
    public DataGridPaintEmptySpaceStyle VertEmptySpaceStyle
    {
      get { return vertEmptySpaceStyle; }
      set
      {
        if (vertEmptySpaceStyle != value)
        {
          vertEmptySpaceStyle = value;
          VertEmptySpaceStyleChanged();
        }
      }
    }

    [DefaultValue(DataGridHorzEmptySpaceStyle.ExtendTitleWideSpace)]
    public DataGridHorzEmptySpaceStyle HorzEmptySpaceStyle
    {
      get { return horzEmptySpaceStyle; }
      set
      {
        if (horzEmptySpaceStyle != value)
        {
          horzEmptySpaceStyle = value;
          HorzEmptySpaceStyleChanged();
        }
      }
    }
    #endregion

    #region run-time properties
    [Browsable(false)]
    protected new DataGridEh Grid
    {
      get { return (DataGridEh)base.Grid; }
    }

    [Browsable(false)]
    public int VertLineSpace
    {
      get
      {
        if (VertLines)
          return Grid.GridLineWidth;
        else
          return 0;
      }
    }

    [Browsable(false)]
    public int HorzLineSpace
    {
      get
      {
        if (HorzLines)
          return Grid.GridLineWidth;
        else
          return 0;
      }
    }
    #endregion

    #region methods
    protected virtual void VertEmptySpaceStyleChanged()
    {
      Grid.InvalidateGrid();
    }

    protected virtual void HorzEmptySpaceStyleChanged()
    {
      Grid.InvalidateGrid();
    }

    protected virtual void GridBoundariesChanged()
    {
      Grid.InvalidateGrid();
    }

    protected virtual void HorzLinesChanged()
    {
      if (HorzLines)
        Grid.Options = Grid.Options | GridOptions.HorzLines;
      else
        Grid.Options = Grid.Options & ~GridOptions.HorzLines;

      Grid.UpdateBaseRowHeights();
    }

    protected virtual void VertLinesChanged()
    {
      Grid.UpdateColumnsView();
    }

    public virtual void DataBoundaryColorChanged()
    {
      Grid.InvalidateGrid();
    }

    protected virtual Color DefaultDataBoundaryColor()
    {
      return DarkColor;
    }

    protected virtual bool ShouldSerializeDataBoundaryColor()
    {
      return (dataBoundaryColorStored == true);
    }

    public virtual void ResetDataBoundaryColor()
    {
      dataBoundaryColorStored = false;
      DataBoundaryColorChanged();
    }
    #endregion methods

  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataGridColumnOptions : DataGridObject, IGridLineHost
  {

    #region privates
    private bool allowResizeColumns = true;
    private bool allowMoveColumns = true;
    private bool allowShowEditor = true;
    private bool fitsizeOnSizingDoubleClick = true;
    private bool foreColorStored;
    private Color foreColor = Color.Empty;
    private Padding sidePadding = new Padding(2, 2, 2, 2);
    private bool sidePaddingStored;
    private Font font;
    private DataGridTextWrapMode wrapMode = DataGridTextWrapMode.Auto;
    private VerticalAlignment vertAlign = VerticalAlignment.Top;
    private readonly DataGridEditItemOptions editItemOptions;
    private readonly GridLine vertLine;
    #endregion privates

    public DataGridColumnOptions(DataGridEh grid) : base(grid)
    {
      this.editItemOptions = new DataGridEditItemOptions(this);
      this.vertLine = new GridLine(this);
    }

    #region properties

    [DefaultValue(true)]
    public bool AllowResizeColumns
    {
      get
      {
        return allowResizeColumns;
      }
      set
      {
        if ((allowResizeColumns != value))
        {
          allowResizeColumns = value;
          if (allowResizeColumns || Grid.DesignMode)
          {
            Grid.Options = Grid.Options | GridOptions.ColSizing;
          }
          else
          {
            Grid.Options = Grid.Options & ~GridOptions.ColSizing;
          }
        }
      }
    }

    [DefaultValue(true)]
    public bool AllowMoveColumns
    {
      get
      {
        return allowMoveColumns;
      }
      set
      {
        if ((allowMoveColumns != value))
        {
          allowMoveColumns = value;
        }
      }
    }

    [DefaultValue(true)]
    public bool AllowShowEditor
    {
      get
      {
        return allowShowEditor;
      }
      set
      {
        if ((allowShowEditor != value))
        {
          allowShowEditor = value;
        }
      }
    }

    [DefaultValue(true)]
    public bool FitSizeOnSizingDoubleClick
    {
      get
      {
        return fitsizeOnSizingDoubleClick;
      }
      set
      {
        if ((fitsizeOnSizingDoubleClick != value))
        {
          fitsizeOnSizingDoubleClick = value;
        }
      }
    }

    public Color ForeColor
    {
      get
      {
        if (foreColorStored)
          return foreColor;
        else
          return DefaultForeColor();
      }
      set
      {
        if ((foreColorStored == false) || (foreColor != value))
        {
          foreColorStored = true;
          foreColor = value;
          ForeColorChanged();
        }
      }
    }

    public Font Font
    {
      get
      {
        if (font != null)
          return font;
        else
          return DefaultFont();
      }
      set
      {
        font = value;
        FontChanged();
      }
    }

    public Padding SidePadding
    {
      get
      {
        if (sidePaddingStored)
          return sidePadding;
        else
          return DefaultSidePadding();
      }
      set
      {
        if ((sidePaddingStored == false) || (sidePadding != value))
        {
          sidePaddingStored = true;
          sidePadding = value;
          SidePaddingChanged();
        }
      }
    }

    [DefaultValue(DataGridTextWrapMode.Auto)]
    public DataGridTextWrapMode WrapMode
    {
      get
      {
        return wrapMode;
      }
      set
      {
        if (wrapMode != value)
        {
          wrapMode = value;
          WrapModeChanged();
        }
      }
    }

    [DefaultValue(VerticalAlignment.Top)]
    public VerticalAlignment VertAlign
    {
      get
      {
        return vertAlign;
      }
      set
      {
        if (vertAlign != value)
        {
          vertAlign = value;
          VertAlignChanged();
        }
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridEditItemOptions EditItemOptions
    {
      get { return editItemOptions; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public GridLine VertLine
    {
      get
      {
        return vertLine;
      }
    }

    [DefaultValue(null)]
    public virtual ContextMenuStrip ContextMenuStrip { get; set; }
    #endregion properties

    #region methods

    //Font
    protected virtual Font DefaultFont()
    {
      return Grid.Font;
    }

    protected virtual bool ShouldSerializeFont()
    {
      return (font != null);
    }

    public virtual void ResetFont()
    {
      font = null;
      FontChanged();
    }

    protected virtual void FontChanged()
    {
      Grid.UpdateRowHeights();
    }

    //IGridLineHost
    void IGridLineHost.GridLineChanged(GridLine gl)
    {
      GridLineChanged(gl);
    }

    protected virtual void GridLineChanged(GridLine gl)
    {
      Grid.Invalidate();
    }

    public virtual bool GridLineDefaultVisible(GridLine gl)
    {
      return Grid.LineOptions.VertLines;
    }

    public virtual Color GridLineDefaultColor(GridLine gl)
    {
      return Grid.LineOptions.BrightColor;
    }

    public virtual DashStyle GridLineDefaultStyle(GridLine gl)
    {
      return DashStyle.Solid;
    }

    //Others

    protected virtual void VertAlignChanged()
    {
      Grid.Invalidate();
    }

    private void WrapModeChanged()
    {
      Grid.UpdateRowHeights();
    }

    protected virtual void ForeColorChanged()
    {
      Grid.InvalidateGrid();
    }

    public virtual Color DefaultForeColor()
    {
      return Grid.ForeColor;
    }

    protected virtual bool ShouldSerializeForeColor()
    {
      return (foreColorStored == true);
    }

    public virtual void ResetForeColor()
    {
      foreColorStored = false;
      ForeColorChanged();
    }

    protected virtual void SidePaddingChanged()
    {
      Grid.SidePaddingChanged();
    }

    private Padding DefaultSidePadding()
    {
      return Grid.GetDrawStyle().GetColumnOptionsSidePadding();
    }

    protected virtual bool ShouldSerializeSidePadding()
    {
      return (sidePaddingStored == true);
    }

    public virtual void ResetSidePadding()
    {
      sidePaddingStored = false;
      SidePaddingChanged();
    }

    protected virtual void HeightTextLinesChanged()
    {
      Grid.UpdateRowHeights();
    }

    public virtual bool CanShowEditor()
    {
      if (AllowShowEditor && Grid.Options.HasFlag(GridOptions.Editing))
        return true;
      else
        return false;
    }

    internal void EditItemOptionsChanged()
    {
      Grid.Invalidate();
    }

    #endregion methods

  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataGridRowOptions : DataGridObject, IGridLineHost, IGridRowHeightOptionsOwner
  {
    #region privates
    private Color oddColor;
    private Color evenColor;
    private bool allowResize = false;

    private readonly GridLine horzLine;
    private readonly GridRowHeightOptions heightOptions;
    #endregion

    #region constructor
    public DataGridRowOptions(DataGridEh grid)
      : base(grid)
    {
      horzLine = new GridLine(this);
      heightOptions = new GridRowHeightOptions(this);
    }
    #endregion

    #region design-time properties
    public Color OddColor
    {
      get 
      { 
        return oddColor; 
      }
      
      set 
      {
        if (value != oddColor)
        {
          oddColor = value;
          Grid.Invalidate();
        }
      }
    }

    public Color EvenColor
    {
      get 
      { 
        return evenColor; 
      }

      set 
      {
        if (value != evenColor)
        {
          evenColor = value;
          Grid.Invalidate();
        }
      }
    }

    [DefaultValue(false)]
    public bool AllowResize
    {
      get 
      { 
        return allowResize; 
      }
      
      set 
      {
        if (allowResize != value)
        {
          allowResize = value;
          Grid.AllowRowResizeChanged();
        }
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public GridRowHeightOptions HeightOptions
    {
      get
      {
        return heightOptions;
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public GridLine HorzLine
    {
      get
      {
        return horzLine;
      }
    }
    #endregion

    #region methods
    // OddColor
    protected void OddColorChanged()
    {
      Grid.InvalidateGrid();
    }

    public Color DefaultOddColor()
    {
      return Color.Empty;
    }

    protected bool ShouldSerializeOddColor()
    {
      return (oddColor != Color.Empty);
    }

    public void ResetOddColor()
    {
      oddColor = Color.Empty;
      OddColorChanged();
    }

    // EvenColor
    protected void EvenColorChanged()
    {
      Grid.InvalidateGrid();
    }

    public Color DefaultEvenColor()
    {
      return Color.Empty;
    }

    protected bool ShouldSerializeEvenColor()
    {
      return (evenColor != Color.Empty);
    }

    public void ResetEvenColor()
    {
      evenColor = Color.Empty;
      EvenColorChanged();
    }

    //IGridLineHost
    void IGridLineHost.GridLineChanged(GridLine gl)
    {
      Grid.Invalidate();
    }

    bool IGridLineHost.GridLineDefaultVisible(GridLine gl)
    {
      return Grid.LineOptions.HorzLines;
    }

    Color IGridLineHost.GridLineDefaultColor(GridLine gl)
    {
      return Grid.LineOptions.BrightColor;
    }

    DashStyle IGridLineHost.GridLineDefaultStyle(GridLine gl)
    {
      return DashStyle.Solid;
    }

    //IGridRowHeightOptionsOwner
    void IGridRowHeightOptionsOwner.HeightOptionsChanged(GridRowHeightOptions heightOptions)
    {
      if (Grid != null)
        Grid.RowHeightAutoExpandChanged();
    }

    bool IGridRowHeightOptionsOwner.HeightOptionsDefaultAutoExpand(GridRowHeightOptions heightOptions)
    {
      return false;
    }

    int IGridRowHeightOptionsOwner.HeightOptionsDefaultContentHeight(GridRowHeightOptions heightOptions)
    {
      return 1;
    }

    int IGridRowHeightOptionsOwner.HeightOptionsDefaultMaxContentHeight(GridRowHeightOptions heightOptions)
    {
      return 0;
    }

    GridRowHeightUnit IGridRowHeightOptionsOwner.HeightOptionsDefaultUnit(GridRowHeightOptions heightOptions)
    {
      return GridRowHeightUnit.TextLine;
    }

    //Other
    public int MaxHeight()
    {
      int maxHeight;

      if (HeightOptions.Unit == GridRowHeightUnit.Pixel)
      {
        maxHeight = HeightOptions.MaxContentHeight;

      }
      else
      {
        maxHeight = EhLibUtils.GetFontHeight(Grid.ColumnOptions.Font) * HeightOptions.MaxContentHeight;
      }

      if (maxHeight > 0)
        maxHeight = maxHeight + Grid.ColumnOptions.SidePadding.Top + Grid.ColumnOptions.SidePadding.Bottom;

      return maxHeight;
    }
    #endregion
  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataGridEditItemOptions
  {
    #region privates
    private readonly DataGridColumnOptions columnOptions;
    private DataGridCellItemPaintTime paintBackgroundTime = DataGridCellItemPaintTime.WhenAreaHotOrActive;
    private DataGridCellItemPaintTime paintTime = DataGridCellItemPaintTime.Always;
    private DataGridActiveArea activeArea = DataGridActiveArea.Row;
    #endregion

    public DataGridEditItemOptions(DataGridColumnOptions columnOptions)
    {
      this.columnOptions = columnOptions;
    }

    #region properties
    [DefaultValue(DataGridCellItemPaintTime.WhenAreaHotOrActive)]
    public DataGridCellItemPaintTime PaintBackgroundTime
    {
      get
      {
        return paintBackgroundTime;
      }

      set
      {
        if (paintBackgroundTime != value)
        {
          paintBackgroundTime = value;
          columnOptions.EditItemOptionsChanged();
        }
      }
    }

    [DefaultValue(DataGridCellItemPaintTime.Always)]
    public DataGridCellItemPaintTime PaintTime
    {
      get
      {
        return paintTime;
      }

      set
      {
        if (paintTime != value)
        {
          paintTime = value;
          columnOptions.EditItemOptionsChanged();
        }
      }
    }

    [DefaultValue(DataGridActiveArea.Row)]
    public DataGridActiveArea ActiveArea
    {
      get
      {
        return activeArea;
      }
      set
      {
        if (activeArea != value)
        {
          activeArea = value;
          columnOptions.EditItemOptionsChanged();
        }
      }
    }
    #endregion
  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class GridAllowedSelections
  {
    #region privates
    DataGridSelection dataGridSelection;
    #endregion

    public GridAllowedSelections(DataGridSelection dataGridSelection)
    {
      this.dataGridSelection = dataGridSelection;
      Rows = true;
      Cells = true;
      Columns = true;
      All = true;
    }

    #region properties
    [DefaultValue(true)]
    public bool Rows { get; set; }

    [DefaultValue(true)]
    public bool Cells { get; set; }

    [DefaultValue(true)]
    public bool Columns { get; set; }

    [DefaultValue(true)]
    public bool All { get; set; }
    #endregion

    public void SetAllowedSelections(bool rows, bool cells, bool columns, bool all)
    {
      Rows = rows;
      Cells = cells;
      Columns = columns;
      All = all;
    }
  }

/// <summary> 
/// Controls the selection of cells, records and columns in the DataGridEh.
/// Use DataGridEh.Selection property access properties and methods of this type.
/// </summary>
[TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataGridSelection : DataGridObject
  {

    #region privates
    private GridAllowedSelections allowedSelection;
    private bool rowHighlight = true;
    private bool rowSelect;
    private bool keepSelect;
    private GridSelectionType selectionType = GridSelectionType.None;
    private DataGridSelectionState selectionState = DataGridSelectionState.None;
    private bool selectedStateIsSelected = true;
    private readonly List<bool> oldSelectedState;
    private bool selectedRowCountObsolete = true;
    private int selectedRowCount;

    protected internal int AnchorCol;
    protected internal int FreeEndCol;
    protected internal int AnchorDataRowIndex;
    protected internal int FreeEndDataRowIndex;
    protected internal GridCoord AnchorCell;
    protected internal GridCoord FreeEndCell;
    protected internal bool InternalKeepSelect = false;
    private int updateCount;
    #endregion privates

    public DataGridSelection(DataGridEh grid) : base(grid)
    {
      allowedSelection = new GridAllowedSelections(this);
      oldSelectedState = new List<bool>();
    }

    #region design-time properties
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public GridAllowedSelections AllowedSelection
    {
      get
      {
        return allowedSelection;
      }
      set
      {
        allowedSelection = value;
      }
    }

    [DefaultValue(false)]
    public bool RowSelect
    {
      get
      {
        return rowSelect;
      }
      set
      {
        if (rowSelect != value)
        {
          rowSelect = value;
          Grid.RowSelectStateChanged();
        }
      }
    }

    [DefaultValue(true)]
    public bool RowHighlight
    {
      get
      {
        return rowHighlight;
      }
      set
      {
        if (rowHighlight != value)
        {
          rowHighlight = value;
          Grid.RowSelectStateChanged();
        }
      }
    }

    [DefaultValue(false)]
    public bool KeepSelect
    {
      get
      {
        return keepSelect;
      }
      set
      {
        if (keepSelect != value)
        {
          keepSelect = value;
          Grid.RowSelectStateChanged();
        }
      }
    }

    #endregion design-time properties

    #region run-time properties
    [Browsable(false)]
    public GridSelectionType SelectionType
    {
      get { return selectionType; }
    }

    [Browsable(false)]
    public DataGridSelectionState SelectionState
    {
      get { return selectionState; }
    }

    [Browsable(false)]
    public GridRect SelectedBox
    {
      get
      {
        if (SelectionType == GridSelectionType.None)
        {
          return new GridRect(Grid.CurrentColumnIndex, Grid.CurrentRowIndex, Grid.CurrentColumnIndex, Grid.CurrentRowIndex);
        }
        else if (SelectionType == GridSelectionType.CellsBox)
        {
          GridRect rec;

          if (AnchorCell.X < FreeEndCell.X)
          {
            rec.Left = AnchorCell.X;
            rec.Right = FreeEndCell.X;
          }
          else
          {
            rec.Left = FreeEndCell.X;
            rec.Right = AnchorCell.X;
          }

          if (AnchorCell.Y < FreeEndCell.Y)
          {
            rec.Top = AnchorCell.Y;
            rec.Bottom = FreeEndCell.Y;
          }
          else
          {
            rec.Top = FreeEndCell.Y;
            rec.Bottom = AnchorCell.Y;
          }

          return rec;
        }
        else
        {
          return new GridRect(-1, -1, -1, -1);
        }
      }
    }

    [Browsable(false)]
    public int SelectedRowCount
    {
      get
      {
        if (selectedRowCountObsolete)
          UpdateSelectedRowCount();
        return selectedRowCount;
      }
    }

    [Browsable(false)]
    public bool RowsSelectionIsAllowed
    {
      get
      {
        if ( AllowedSelection.Rows &&
             (Grid.GridState == BaseGridState.Normal) &&
             (Grid.DataGridState == DataGridState.Normal)
        )
          return true;
        else
          return false;
      }
    }

    [Browsable(false)]
    public bool ColumnsSelectionIsAllowed
    {
      get
      {
        if ((AllowedSelection.Columns) &&
            (RowSelect == false) &&
            (Grid.GridState == BaseGridState.Normal) &&
            (Grid.DataGridState == DataGridState.Normal)
        )
          return true;
        else
          return false;
      }
    }

    [Browsable(false)]
    public bool CellsSelectionIsAllowed
    {
      get
      {
        if ((AllowedSelection.Cells) &&
            (RowSelect == false) &&
            (Grid.GridState == BaseGridState.Normal) &&
            (Grid.DataGridState == DataGridState.Normal)
        )
          return true;
        else
          return false;
      }
    }

    [Browsable(false)]
    public bool Updating
    {
      get { return (updateCount > 0); }
    }
    #endregion run-time properties

    #region internal methods
    private void UpdateSelectedRowCount()
    {
      selectedRowCount = 0;

      foreach (DataGridRow irow in Grid.Rows)
      {
        if (irow.SelectedInternal)
          selectedRowCount = selectedRowCount + 1;
      }

      selectedRowCountObsolete = false;
    }

    internal bool CellIsSelected(int col, int row)
    {
      switch (SelectionType)
      {
        case GridSelectionType.All:
          {
            return true;
          }

        case GridSelectionType.CellsBox:
        case GridSelectionType.Rows:
        case GridSelectionType.Columns:
          {
            int areaColIndex;
            int areaRowIndex;

            BaseGridCellManager cell = Grid.CellByColRow(col, row, out areaColIndex, out areaRowIndex);
            Debug.Assert(cell != null, "DataGridEh.PaintCell Cell = null");

            return cell.IsSelected(areaColIndex, areaRowIndex);
          }

        default:
          {
            return false;
          }
      }
    }

    internal void SetFreeEndCol(int newFreeEndCol)
    {
      if (newFreeEndCol > FreeEndCol)
      {
        for (int i = FreeEndCol; i <= newFreeEndCol; i++)
        {
          if (!((FreeEndCol > AnchorCol) && (i == FreeEndCol))
              && !((newFreeEndCol < AnchorCol) && (i == newFreeEndCol))
              && (i != AnchorCol)
             )
          {
            AddSelectedColumn(Grid.VisibleColumns[i], !Grid.VisibleColumns[i].Selected);
          }
        }
      }
      else if (newFreeEndCol < FreeEndCol)
      {
        for (int i = newFreeEndCol; i <= FreeEndCol; i++)
        {
          if (!((newFreeEndCol > AnchorCol) && (i == newFreeEndCol))
               && !((FreeEndCol < AnchorCol) && (i == FreeEndCol))
               && (i != AnchorCol)
             )
          {
            AddSelectedColumn(Grid.VisibleColumns[i], !Grid.VisibleColumns[i].Selected);
          }
        }
      }
      FreeEndCol = newFreeEndCol;
    }

    internal void InitAnchorCol(int anchorCol)
    {
      this.AnchorCol = anchorCol;
      this.FreeEndCol = anchorCol;
    }

    internal void InitAnchorRow(int anchorDataRowIndex, bool selectedStateIsSelected)
    {
      this.AnchorDataRowIndex = anchorDataRowIndex;
      this.FreeEndDataRowIndex = anchorDataRowIndex;
      this.selectionState = DataGridSelectionState.RowSelection;
      this.selectedStateIsSelected = selectedStateIsSelected;
    }

    internal void SetFreeEndRow(int newFreeEndRow)
    {
      int stepIndex;
      DataGridRow row;
      bool oldSelState;

      if (newFreeEndRow > FreeEndDataRowIndex)
      {
        BeginUpdate();
        try
        {
          stepIndex = Math.Min(AnchorDataRowIndex, newFreeEndRow);

          for (int i = FreeEndDataRowIndex; i < stepIndex; i++)
          {
            oldSelState = DeleteOldStateSelectedRow();
            row = Grid.VisibleRows[i];
            if (Grid.CanSelectRow(row))
              AddSelectedRow(row, oldSelState);
          }

          stepIndex = Math.Max(AnchorDataRowIndex + 1, FreeEndDataRowIndex + 1);

          for (int i = stepIndex; i <= newFreeEndRow; i++)
          {
            AddOldStateSelectedRow(Grid.VisibleRows[i].Selected);
            row = Grid.VisibleRows[i];
            if (Grid.CanSelectRow(row))
              AddSelectedRow(row, selectedStateIsSelected);
          }
        }
        finally
        {
          EndUpdate(true);
        }
      }
      else if (newFreeEndRow < FreeEndDataRowIndex)
      {
        BeginUpdate();
        try
        {
          stepIndex = Math.Max(AnchorDataRowIndex, newFreeEndRow);

        for (int i = FreeEndDataRowIndex; i > stepIndex; i--)
        {
          oldSelState = DeleteOldStateSelectedRow();
          row = Grid.VisibleRows[i];
          if (Grid.CanSelectRow(row))
            AddSelectedRow(Grid.VisibleRows[i], oldSelState);
        }

        stepIndex = Math.Min(AnchorDataRowIndex - 1, FreeEndDataRowIndex - 1);

        for (int i = stepIndex; i >= newFreeEndRow; i--)
        {
          AddOldStateSelectedRow(Grid.VisibleRows[i].Selected);
          row = Grid.VisibleRows[i];
          if (Grid.CanSelectRow(row))
            AddSelectedRow(row, selectedStateIsSelected);
        }
        }
        finally
        {
          EndUpdate(true);
        }

      }
      FreeEndDataRowIndex = newFreeEndRow;
    }

    internal void StartCellsRectSelection(GridCoord anchorCell, GridCoord freeEndCell)
    {
      Rectangle noScrollRect = Rectangle.Empty;

      if (SelectionType != GridSelectionType.CellsBox)
        Clear();
      if (anchorCell == freeEndCell)
        Clear();
      else
      {
        if (Grid.VisibleColumns.Count == 0 || Grid.VisibleRows.Count == 0) return;

        this.AnchorCell = anchorCell;
        //Debug.WriteLine("StartCellsRectSelection:" + FreeEndCell.ToString());
        this.FreeEndCell = freeEndCell;
        SetSelectionType(GridSelectionType.CellsBox);
        Grid.InvalidateGrid();

        noScrollRect.X = Grid.HorzAxis.FixedBoundary;
        noScrollRect.Width = Grid.HorzAxis.RollClientLen;
        noScrollRect.Y = Grid.VertAxis.FixedBoundary;
        noScrollRect.Height = Grid.VertAxis.RollClientLen;

        Grid.MoveNScrollService.Capture(Grid, noScrollRect, CellsBoxSelectServiceEventHandler, true, true);

      }
    }

    protected internal virtual void CellsBoxSelectServiceEventHandler(MoveAndScrollService service, MouseEventArgs e)
    {
      GridCoord cellHit;
      GridCoord newFreeEndCell = FreeEndCell;
      int newColIndex;
      int newRowIndex;

      //Debug.WriteLine("RowSelectServiceEventHandler-" + e.Y.ToString());
      cellHit = Grid.MouseCoord(e.X, e.Y);
      if (service.ClientRect.Contains(e.Location))
      {
        if ((cellHit.Y >= 0) && (cellHit.X >= 0))
        {
          newFreeEndCell = new GridCoord(Grid.RawToDataColumnIndex(cellHit.X), Grid.RawToDataRowIndex(cellHit.Y));
        }
      }

      if (e.X > service.ClientRect.Right)
      {
        Grid.SafeScrollData(Grid.HorzAxis.GetScrollStep(), 0);
        newColIndex = Grid.HorzAxis.RollLastVisCell + Grid.HorzAxis.FixedCellCount;
        newFreeEndCell.X = Grid.RawToDataColumnIndex(newColIndex);
      }
      else if (e.X < service.ClientRect.Left)
      {
        Grid.SafeScrollData(-Grid.HorzAxis.GetScrollStep(), 0);
        newColIndex = Grid.HorzAxis.RollStartVisCell + Grid.HorzAxis.FixedCellCount;
        newFreeEndCell.X = Grid.RawToDataColumnIndex(newColIndex);
      }
      else if (cellHit.X >= 0)
      {
        newFreeEndCell.X = Grid.RawToDataColumnIndex(cellHit.X);
      }

      if (e.Y > service.ClientRect.Bottom)
      {
        Grid.SafeScrollData(0, Grid.HorzAxis.GetScrollStep());
        newRowIndex = Grid.VertAxis.RollLastVisCell + Grid.VertAxis.FixedCellCount;
        newFreeEndCell.Y = Grid.RawToDataRowIndex(newRowIndex);
      }
      else if (e.Y < service.ClientRect.Top)
      {
        Grid.SafeScrollData(0, -Grid.HorzAxis.GetScrollStep());
        newRowIndex = Grid.VertAxis.RollStartVisCell + Grid.VertAxis.FixedCellCount;
        newFreeEndCell.Y = Grid.RawToDataRowIndex(newRowIndex);
      }
      else if (cellHit.Y >= 0)
      {
        newFreeEndCell.Y = Grid.RawToDataColumnIndex(cellHit.Y);
      }

      //Debug.WriteLine(newFreeEndCell);

      if (newFreeEndCell.Y >= Grid.VisibleRows.Count)
        newFreeEndCell.Y = Grid.VisibleRows.Count - 1;
      SetFreeEndCell(newFreeEndCell);
    }

    protected internal void SetFreeEndCell(GridCoord newFreeEndCell)
    {
      if (newFreeEndCell != FreeEndCell)
      {
        FreeEndCell = newFreeEndCell;
        OnSelectionChanged();
      }
    }

    internal bool CellsRectContains(int areaColIndex, int areaRowIndex)
    {
      bool containsAreaCol;
      bool containsAreaRow;

      if (AnchorCell.X < FreeEndCell.X)
        containsAreaCol = (AnchorCell.X <= areaColIndex) && (areaColIndex <= FreeEndCell.X);
      else
        containsAreaCol = (AnchorCell.X >= areaColIndex) && (areaColIndex >= FreeEndCell.X);

      if (AnchorCell.Y < FreeEndCell.Y)
        containsAreaRow = (AnchorCell.Y <= areaRowIndex) && (areaRowIndex <= FreeEndCell.Y);
      else
        containsAreaRow = (AnchorCell.Y >= areaRowIndex) && (areaRowIndex >= FreeEndCell.Y);

      return containsAreaCol && containsAreaRow;
    }

    protected virtual void SetSelectionType(GridSelectionType newSelectionType)
    {
      if (selectionType != newSelectionType)
      {
        Clear();
        if (newSelectionType != GridSelectionType.None)
          Grid.HideEditor(true);
        selectionType = newSelectionType;
        //OnSelectionChanged();
      }
    }

    private void BeginUpdate()
    {
      updateCount = updateCount + 1;
    }

    private void EndUpdate(bool selectionChanged)
    {
      Debug.Assert(updateCount > 0);
      updateCount = updateCount - 1;
      if (!Updating)
      {
        if (selectionChanged)
          OnSelectionChanged();
      }
    }

    private void OnSelectionChanged()
    {
      if (!Updating)
        Grid.OnSelectionChanged();
    }
    #endregion internal methods

    #region public methods
    public void Clear()
    {
      if (SelectionType == GridSelectionType.None) return;

      switch (SelectionType)
      {
        case GridSelectionType.All:
          {
            break;
          }

        case GridSelectionType.CellsBox:
          {
            AnchorCell = new GridCoord(-1, -1);
            FreeEndCell = new GridCoord(-1, -1);
            break;
          }

        case GridSelectionType.Columns:
          {
            foreach (DataGridColumn col in Grid.Columns)
              col.SelectedInternal = false;
            break;
          }

        case GridSelectionType.Rows:
          {
            foreach (DataGridRow row in Grid.VisibleRows)
              row.SelectedInternal = false;
            break;
          }
      }
      selectionType = GridSelectionType.None;
      selectedRowCountObsolete = true;
      OnSelectionChanged();
    }

    public void CheckClear()
    {
      if (!KeepSelect && !InternalKeepSelect)
        Clear();
    }

    public void SetSelectedColumn(DataGridColumn column)
    {
      CheckClear();
      SetSelectionType(GridSelectionType.Columns);
      column.SelectedInternal = true;
      OnSelectionChanged();
    }

    public void AddSelectedColumn(DataGridColumn column, bool setToSelected)
    {
      if (setToSelected && (column.SelectedInternal == false))
      {
        if (SelectionType != GridSelectionType.Columns)
          Clear();
        SetSelectionType(GridSelectionType.Columns);
        column.SelectedInternal = true;
        OnSelectionChanged();
      }
      else if (!setToSelected && (column.SelectedInternal == true))
      {
        bool haveSelected = false;

        column.SelectedInternal = false;
        foreach (DataGridColumn col in Grid.Columns)
        {
          if (col.SelectedInternal)
          {
            haveSelected = true;
            break;
          }
        }
        if (!haveSelected)
          selectionType = GridSelectionType.None;
        OnSelectionChanged();
      }
    }

    public void AddSelectedRow(DataGridRow row, bool setToSelected)
    {
      if (setToSelected && (row.SelectedInternal == false))
      {
        if (SelectionType != GridSelectionType.Rows)
          Clear();
        SetSelectionType(GridSelectionType.Rows);
        row.SelectedInternal = true;
        selectedRowCountObsolete = true;
        OnSelectionChanged();
      }
      else if (!setToSelected && (row.SelectedInternal == true))
      {
        bool haveSelected = false;

        row.SelectedInternal = false;
        foreach (DataGridRow irow in Grid.Rows)
        {
          if (irow.SelectedInternal)
          {
            haveSelected = true;
            break;
          }
        }
        if (!haveSelected)
          selectionType = GridSelectionType.None;
        selectedRowCountObsolete = true;
        OnSelectionChanged();
      }
    }

    public void AddOldStateSelectedRow(bool isSelected)
    {
      oldSelectedState.Add(isSelected);
    }

    public bool DeleteOldStateSelectedRow()
    {
      bool result = oldSelectedState[oldSelectedState.Count - 1];
      oldSelectedState.RemoveAt(oldSelectedState.Count - 1);
      return result;
    }

    public void SetSelectedRow(DataGridRow row)
    {
      CheckClear();
      SetSelectionType(GridSelectionType.Rows);
      row.SelectedInternal = true;
      selectedRowCountObsolete = true;
      OnSelectionChanged();
    }

    public void SetSelectedFreeEndCell(GridCoord newFreeEndCell)
    {
      if (SelectionType != GridSelectionType.CellsBox)
      {
        Clear();
        AnchorCell = new GridCoord(Grid.CurrentDataColIndex, Grid.CurrentDataRowIndex);
      }
      if (AnchorCell == FreeEndCell)
        Clear();
      else
      {
        //this.AnchorCell = new GridCoord(Grid.dataColIndex, Grid.DataRow);
        SetSelectionType(GridSelectionType.CellsBox);
        this.FreeEndCell = newFreeEndCell;
        OnSelectionChanged();
      }
    }

    public void GetSelectedColumns(Collection<DataGridColumn> selCols)
    {
      foreach (DataGridColumn col in Grid.VisibleColumns)
        if (col.Selected)
          selCols.Add(col);
    }

    public DataGridColumn[] GetSelectedColumns()
    {
      List<DataGridColumn> selCols = new List<DataGridColumn>();
      foreach (DataGridColumn col in Grid.VisibleColumns)
        if (col.Selected)
          selCols.Add(col);
      return selCols.ToArray();
    }

    public void SetSelectedColumns(Collection<DataGridColumn> selCols)
    {
      Clear();
      foreach (DataGridColumn col in selCols)
        col.Selected = true;
    }

    public void SetSelectedColumns(DataGridColumn[] selCols)
    {
      Clear();
      foreach (DataGridColumn col in selCols)
        col.Selected = true;
    }

    public void SelectAll()
    {
      if (SelectionType != GridSelectionType.All)
        Clear();
      SetSelectionType(GridSelectionType.All);
      OnSelectionChanged();
    }

    public void DeleteSelectedArea()
    {
      switch (SelectionType)
      {
        case GridSelectionType.All:
          {
            try
            {
              Grid.DataLink.CurrencyManager.List.Clear();
            }
            catch (Exception e)
            {
              if (EhLibUtils.IsCriticalException(e))
              {
                throw;
              }
              else
              {
                IList list = Grid.DataLink.CurrencyManager.List;
                while (list.Count > 0)
                {
                  list.RemoveAt(list.Count - 1);
                }
              }
            }
            break;
          }

        case GridSelectionType.CellsBox:
          {
            GridRect selBox = Grid.Selection.SelectedBox;

            for (int rowIndex = selBox.Top; rowIndex <= selBox.Bottom; rowIndex++)
            {
              object rowDesc = Grid.VisibleRows[rowIndex].SourceItem;

              for (int colIndex = selBox.Left; colIndex <= selBox.Right; colIndex++)
              {
                DataGridColumn col = Grid.VisibleColumns[colIndex];
                PropertyDescriptor propDescr = col.PropDescr;
                if (propDescr != null)
                {
                  bool canReset;
                  if (rowDesc is DataRowView)
                    canReset = (rowDesc as DataRowView).Row.Table.Columns[propDescr.Name].AllowDBNull;
                  else
                    canReset = propDescr.CanResetValue(rowDesc);
                  if (canReset)
                    propDescr.ResetValue(rowDesc);
                }
              }
            }

            break;
          }

        case GridSelectionType.Columns:
          {
            foreach (DataGridRow row in Grid.VisibleRows)
            {
              object rowDesc = row.SourceItem;
              foreach (DataGridColumn col in Grid.VisibleColumns)
              {
                PropertyDescriptor propDescr = col.PropDescr;
                if (col.Selected && (propDescr != null))
                {
                  bool canReset;
                  if (rowDesc is DataRowView)
                    canReset = (rowDesc as DataRowView).Row.Table.Columns[propDescr.Name].AllowDBNull;
                  else
                    canReset = propDescr.CanResetValue(rowDesc);
                  if (canReset)
                    propDescr.ResetValue(rowDesc);
                }
              }
            }
            break;
          }

        case GridSelectionType.Rows:
          {
            List<object> rowsDescForDel = new List<object>();
            IList list = Grid.DataLink.CurrencyManager.List;

            foreach (DataGridRow row in Grid.VisibleRows)
            {
              if (row.Selected)
                rowsDescForDel.Add(row.SourceItem);
            }

            foreach (object rowDesc in rowsDescForDel)
              list.Remove(rowDesc);

            break;
          }

        case GridSelectionType.None:
          {                                                     
            if (Grid.VisibleColumns.Count == 0 || Grid.CurrentRow == null)
              break;
            object rowDesc = Grid.CurrentRow.SourceItem;
            DataGridColumn col = Grid.VisibleColumns[Grid.CurrentColumnIndex];
            Grid.SafePushValue(col, null);

            break;
          }
      }
    }

    public void StopSelectionState()
    {
      selectionState = DataGridSelectionState.None;
      AnchorDataRowIndex = -1;
      FreeEndDataRowIndex = -1;
      oldSelectedState.Clear();
    }
    #endregion public methods

  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataGridEditActions : DataGridObject
  {

    #region privates
    private bool copyEnabled = true;
    private bool pasteEnabled = true;
    private bool cutEnabled = true;
    private bool deleteEnabled = true;
    private bool confirmDelete = true;
    private bool selectAllEnabled = true;
    #endregion privates

    public DataGridEditActions(DataGridEh grid) : base(grid)
    {
    }

    #region design-time properties
    [DefaultValue(true)]
    public bool CopyEnabled
    {
      get
      {
        return copyEnabled;
      }
      set
      {
        copyEnabled = value;
      }
    }

    [DefaultValue(true)]
    public bool PasteEnabled
    {
      get
      {
        return pasteEnabled;
      }
      set
      {
        pasteEnabled = value;
      }
    }

    [DefaultValue(true)]
    public bool CutEnabled
    {
      get
      {
        return cutEnabled;
      }
      set
      {
        cutEnabled = value;
      }
    }

    [DefaultValue(true)]
    public bool DeleteEnabled
    {
      get
      {
        return deleteEnabled;
      }
      set
      {
        deleteEnabled = value;
      }
    }

    [DefaultValue(true)]
    public bool ConfirmDelete
    {
      get
      {
        return confirmDelete;
      }
      set
      {
        confirmDelete = value;
      }
    }

    [DefaultValue(true)]
    public bool SelectAllEnabled
    {
      get
      {
        return selectAllEnabled;
      }
      set
      {
        selectAllEnabled = value;
      }
    }
    #endregion  design-time properties

    #region run-time properties
    #endregion  run-time properties

    #region internal methods
    #endregion internal methods

    #region public methods
    public void Copy()
    {
      Grid.CopyContentToClipboard(DataGridExportArea.SelectedArea);
    }

    public bool CanCopy()
    {
      return CopyEnabled;
    }

    public void Paste()
    {
      Grid.PastContentFromClipboard();
    }

    public bool CanPaste()
    {
      return PasteEnabled && Clipboard.ContainsText();
    }

    public void Cut()
    {
      if ((Grid.Selection.SelectionType != GridSelectionType.None) && (ConfirmDelete))
      {
        if (!ShowConfirmDeleteDialog()) return;
      }

      DataObject dataObject = Grid.GetContentAsDataObject(DataGridExportArea.SelectedArea);
      if (dataObject != null)
      {
        Grid.Selection.DeleteSelectedArea();
        Clipboard.SetDataObject(dataObject, true);
      }
    }

    public bool CanCut()
    {
      return CutEnabled;
    }

    public bool ShowConfirmDeleteDialog()
    {
      string text = "";

      switch (Grid.Selection.SelectionType)
      {
        case GridSelectionType.All:
          {
            text = "Delete all records?";
            break;
          }

        case GridSelectionType.CellsBox:
          {
            text = "Clear selected cells?";
            break;
          }

        case GridSelectionType.Columns:
          {
            text = "Clear selected cells?";
            break;
          }

        case GridSelectionType.Rows:
          {
            text = "Delete all selected rows?";
            break;
          }
        case GridSelectionType.None:
          {
            text = "Delete row?";
            break;
          }
      }

      DialogResult result = MessageBox.Show(text, @"Delete data", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);

      if (result == DialogResult.Yes)
        return true;
      else
        return false;
    }

    public void Delete()
    {
      Grid.Selection.DeleteSelectedArea();
    }

    public bool CanDelete()
    {
      return DeleteEnabled;
    }

    public void SelectAll()
    {
      Grid.Selection.SelectAll();
    }

    public bool CanSelectAll()
    {
      return SelectAllEnabled;
    }

    public void MoveCurrentTo(int newCol, int newRow)
    {
      GridCoord newCurrent;
      newCurrent = new GridCoord(newCol, newRow);
      Grid.Restrict(ref newCurrent,
        Grid.FixedColCount - Grid.FrozenColCount, Grid.FixedRowCount - Grid.FrozenRowCount,
        Grid.ColCount - 1, Grid.RowCount - 1);
      if ((newCurrent.X != Grid.Col) || (newCurrent.Y != Grid.Row))
        Grid.InteractiveFocusCell(newCurrent.X, newCurrent.Y, InteractiveActionSource.Keyboard);
    }

    public void MoveCurrentToNextRow()
    {
      MoveCurrentTo(Grid.Col, Grid.Row + 1);
    }

    public bool CanMoveCurrentToNextRow()
    {
      if (Grid.Row < Grid.RowCount - 1)
        return true;
      else
        return false;
    }

    public void MoveCurrentToPriorRow()
    {
      MoveCurrentTo(Grid.Col, Grid.Row - 1);
    }

    public bool CanMoveCurrentToPriorRow()
    {
      if (Grid.Row > Grid.FixedRowCount)
        return true;
      else
        return false;
    }

    public void MoveCurrentToFirstRow()
    {
      MoveCurrentTo(Grid.Col, Grid.FixedRowCount);
    }

    public bool CanMoveCurrentToFirstRow()
    {
      if (Grid.Row != Grid.FixedRowCount)
        return true;
      else
        return false;
    }

    public void MoveCurrentToLastRow()
    {
      MoveCurrentTo(Grid.Col, Grid.FixedRowCount + Grid.VisibleRows.Count-1);
    }

    public bool CanMoveCurrentToLastRow()
    {
      if (Grid.Row < Grid.FixedRowCount + Grid.VisibleRows.Count - 1)
        return true;
      else
        return false;
    }

    public void MoveCurrentToNewRow()
    {
      if (Grid.VisibleRows.Count == 0)
        Grid.DataLink.AddNew();
      else
        MoveCurrentTo(Grid.Col, Grid.NewRowIndex);
      //Grid.InteractiveFocusCell(Grid.Col, Grid.NewRowIndex, InteractiveActionSource.Other);
    }

    public bool CanMoveCurrentToNewRow()
    {
      if (Grid.AllowedOperations.AllowAdd && 
          Grid.VisibleRows.Count == 0 && 
          Grid.DataLink.Active)
        return true;
      else if ((Grid.Row == Grid.NewRowIndex) ||
          (Grid.AllowedOperations.AllowAdd == false))
        return false;
      else
        return true;
    }

    public void DeleteCurrentRow()
    {
      Grid.DataLink.DeleteCurrent();
    }

    public bool CanDeleteCurrentRow()
    {
      if ((Grid.VisibleRows.Count > 0) && 
          (Grid.AllowedOperations.AllowAdd == true)
      )
        return true;
      else
        return false;
    }

    #endregion public methods

  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataGridHorzScrollBarExtraBarVisibleItems
  {
    private readonly DataGridHorzScrollBarExtraBar extraBar;
    private bool recordsInfo = true;
    private bool navigator = true;
    private bool selectAggregationInfo = true;

    public DataGridHorzScrollBarExtraBarVisibleItems(DataGridHorzScrollBarExtraBar extraBar)
    {
      this.extraBar = extraBar;
    }

    [DefaultValue(true)]
    public bool RecordsInfo
    {
      get
      {
        return recordsInfo;
      }
      set
      {
        if (recordsInfo != value)
        {
          recordsInfo = value;
          extraBar.VisibleItemsChanged();
        }
      }
    }

    [DefaultValue(true)]
    public bool Navigator
    {
      get
      {
        return navigator;
      }
      set
      {
        if (navigator != value)
        {
          navigator = value;
          extraBar.VisibleItemsChanged();
        }
      }
    }

    [DefaultValue(true)]
    public bool SelectAggregationInfo
    {
      get
      {
        return selectAggregationInfo;
      }
      set
      {
        if (selectAggregationInfo != value)
        {
          selectAggregationInfo = value;
          extraBar.VisibleItemsChanged();
        }
      }
    }

  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataGridHorzScrollBarExtraBar
  {
    private readonly DataGridHorzScrollBar scrollBar;
    private readonly DataGridHorzScrollBarExtraBarVisibleItems visibleItems;
    private bool visible;

    public DataGridHorzScrollBarExtraBar(DataGridHorzScrollBar scrollBar)
    {
      this.scrollBar = scrollBar;
      visibleItems = new DataGridHorzScrollBarExtraBarVisibleItems(this);
    }

    #region design-time properties
    [DefaultValue(false)]
    public bool Visible
    {
      get
      {
        return visible;
      }
      set
      {
        if (visible != value)
        {
          visible = value;
          VisibleItemsChanged();
        }
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridHorzScrollBarExtraBarVisibleItems VisibleItems
    {
      get { return visibleItems; }
    }
    #endregion design-time properties

    [Browsable(false)]
    public DataGridHorzScrollBar ScrollBar
    {
      get { return scrollBar; }
    }

    internal void VisibleItemsChanged()
    {
      scrollBar.Grid.UpdateBoundaries();
    }
  }

  [ToolboxItem(false)]
  public class DataGridHorzScrollBar : BaseGridHorzScrollBar
  {
    private readonly DataGridHorzScrollBarExtraBar extraBar;

    public DataGridHorzScrollBar(BaseGridControl grid, Orientation kind) :
      base(grid, kind)
    {
      extraBar = new DataGridHorzScrollBarExtraBar(this);
    }

    #region Properties
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DataGridHorzScrollBarExtraBar ExtraBar
    {
      get { return extraBar; }
    }
    #endregion

    #region Methods
    public override bool CheckScrollBarMustBeShown()
    {
      if (ExtraBar.Visible)
        return true;
      else
        return base.CheckScrollBarMustBeShown();
    }
    #endregion

    #region events
    public new event EventHandler<EventArgs> ScrollPosChanged
    {
      add
      {
        base.ScrollPosChanged += value;
      }

      remove
      {
        base.ScrollPosChanged -= value;
      }
    }

    public new event EventHandler<EventArgs> RollParamsChanged
    {
      add
      {
        base.RollParamsChanged += value;
      }

      remove
      {
        base.RollParamsChanged -= value;
      }
    }
    #endregion

  }

  [ToolboxItem(false)]
  public class DataGridVertScrollBar : BaseGridVertScrollBar
  {

    public DataGridVertScrollBar(BaseGridControl grid, Orientation kind) :
      base(grid, kind)
    {
    }

    #region events
    public new event EventHandler<EventArgs> ScrollPosChanged
    {
      add
      {
        base.ScrollPosChanged += value;
      }

      remove
      {
        base.ScrollPosChanged -= value;
      }
    }

    public new event EventHandler<EventArgs> RollParamsChanged
    {
      add
      {
        base.RollParamsChanged += value;
      }

      remove
      {
        base.RollParamsChanged -= value;
      }
    }
    #endregion

  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataGridAllowedOperations : DataGridObject
  {

    #region privates
    private bool addRecord = true;
    private bool changeRecord = true;
    private bool deleteRecord = true;
    #endregion privates

    public DataGridAllowedOperations(DataGridEh grid) : base(grid)
    {
    }

    #region design-time properties
    [DefaultValue(true)]
    public bool AddRecord
    {
      get { return addRecord; }
      set { addRecord = value; }
    }

    [DefaultValue(true)]
    public bool ChangeRecord
    {
      get { return changeRecord; }
      set { changeRecord = value; }
    }

    [DefaultValue(true)]
    public bool DeleteRecord
    {
      get { return deleteRecord; }
      set { deleteRecord = value; }
    }
    #endregion  design-time properties

    #region run-time properties
    [Browsable(false)]
    public bool AllowAdd
    {
      get { return AddRecord && Grid.DataLink.AllowAdd && !Grid.ReadOnly; }
    }

    [Browsable(false)]
    public bool AllowEdit
    {
      get { return ChangeRecord && Grid.DataLink.AllowEdit && !Grid.ReadOnly; }
    }

    [Browsable(false)]
    public bool AllowRemove
    {
      get { return DeleteRecord && Grid.DataLink.AllowRemove && !Grid.ReadOnly; }
    }
    #endregion  run-time properties

    #region internal methods
    #endregion internal methods

    #region public methods
    #endregion public methods

  }


  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class DataGridKeyboardOptions : GridKeyboardOptions
  {

    public DataGridKeyboardOptions(DataAxisGrid grid) : base(grid)
    {
      base.TabKeyAction = GridKeyboardAction.NextColCell;
    }

    [DefaultValue(GridKeyboardAction.NextColCell)]
    public override GridKeyboardAction TabKeyAction
    {
      get { return base.TabKeyAction; }
      set { base.TabKeyAction = value; }
    }
  }
}
