home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 October / Chip_2001-10_cd1.bin / zkuste / delphi / kolekce / d456 / DCSLIB25.ZIP / DCDBGrids.pas < prev    next >
Pascal/Delphi Source File  |  2001-06-28  |  197KB  |  6,726 lines

  1. {
  2.  BUSINESS CONSULTING
  3.  s a i n t - p e t e r s b u r g
  4.  
  5.          Components Library for Borland Delphi 4.x - 6.x
  6.          Copyright (c) 1998-2001 Alex'EM
  7.  
  8. }
  9. unit DCDBGrids;
  10.  
  11. {$R-}
  12. {$G+}
  13.  
  14. interface
  15. {$I DCConst.inc}
  16.  
  17. uses
  18.   Windows, SysUtils, Messages, Classes, Controls, Forms, StdCtrls,
  19.   {$IFDEF DELPHI_V6}
  20.     Variants,
  21.   {$ENDIF}
  22.   Graphics, DCGrids, grids, DBCtrls, Db, Menus, ImgList, DbTables, DCConst, DCEditTools;
  23.  
  24. type
  25.   TColumnValue = (cvColor, cvWidth, cvFont, cvAlignment, cvReadOnly, cvTitleColor,
  26.     cvTitleCaption, cvTitleAlignment, cvTitleFont, cvImeMode, cvImeName, cvDisplayFormat);
  27.   TColumnValues = set of TColumnValue;
  28.  
  29. const
  30.   ColumnTitleValues = [cvTitleColor..cvTitleFont];
  31.   CM_DEFERLAYOUT    = WM_USER + 100;
  32.   
  33.   db_TitleGridDelimiter = #13#10;
  34.   db_LinesGridDelimiter = #10;
  35.  
  36. { TColumn defines internal storage for column attributes.  If IsStored is
  37.   True, values assigned to properties are stored in this object, the grid-
  38.   or field-based default sources are not modified.  Values read from
  39.   properties are the previously assigned value, if any, or the grid- or
  40.   field-based default values if nothing has been assigned to that property.
  41.   This class also publishes the column attribute properties for persistent
  42.   storage.
  43.  
  44.   If IsStored is True, the column does not maintain local storage of
  45.   property values.  Assignments to column properties are passed through to
  46.   the underlying grid- or field-based default sources.  }
  47. type
  48.   TColumn = class;
  49.   TDCCustomDBGrid = class;
  50.  
  51.   TColumnTitle = class(TPersistent)
  52.   private
  53.     FColumn: TColumn;
  54.     FCaption: string;
  55.     FFont: TFont;
  56.     FColor: TColor;
  57.     FAlignment: TAlignment;
  58.     procedure FontChanged(Sender: TObject);
  59.     function GetAlignment: TAlignment;
  60.     function GetColor: TColor;
  61.     function GetCaption: string;
  62.     function GetFont: TFont;
  63.     function IsAlignmentStored: Boolean;
  64.     function IsColorStored: Boolean;
  65.     function IsFontStored: Boolean;
  66.     function IsCaptionStored: Boolean;
  67.     procedure SetAlignment(Value: TAlignment);
  68.     procedure SetColor(Value: TColor);
  69.     procedure SetFont(Value: TFont);
  70.     procedure SetCaption(const Value: string); virtual;
  71.   protected
  72.     procedure RefreshDefaultFont;
  73.   public
  74.     constructor Create(Column: TColumn);
  75.     destructor Destroy; override;
  76.     procedure Assign(Source: TPersistent); override;
  77.     function DefaultAlignment: TAlignment;
  78.     function DefaultColor: TColor;
  79.     function DefaultFont: TFont;
  80.     function DefaultCaption: string;
  81.     procedure RestoreDefaults; virtual;
  82.     property Column: TColumn read FColumn;
  83.   published
  84.     property Alignment: TAlignment read GetAlignment write SetAlignment
  85.       stored IsAlignmentStored;
  86.     property Caption: string read GetCaption write SetCaption stored IsCaptionStored;
  87.     property Color: TColor read GetColor write SetColor stored IsColorStored;
  88.     property Font: TFont read GetFont write SetFont stored IsFontStored;
  89.   end;
  90.  
  91.   TColumnButtonStyle = (cbsAuto, cbsEllipsis, cbsNone);
  92.   TColumnIndexStyle  = (idxNone, idxAscending, idxDescending);
  93.  
  94.   TColumn = class(TCollectionItem)
  95.   private
  96.     FField: TField;
  97.     FFieldName: string;
  98.     FColor: TColor;
  99.     FWidth: Integer;
  100.     FTitle: TColumnTitle;
  101.     FFont: TFont;
  102.     FImeMode: TImeMode;
  103.     FImeName: TImeName;
  104.     FPickList: TStrings;
  105.     FPopupMenu: TPopupMenu;
  106.     FDropDownRows: Cardinal;
  107.     FButtonStyle: TColumnButtonStyle;
  108.     FAlignment: TAlignment;
  109.     FReadonly: Boolean;
  110.     FAssignedValues: TColumnValues;
  111.     FVisible: Boolean;
  112.     FExpanded: Boolean;
  113.     FStored: Boolean;
  114.     FIndexStyle: TColumnIndexStyle;
  115.     FIndexed: Boolean;
  116.     FItemIndex: Integer;
  117.     FDisplayFormat: string;
  118.     FTag: integer;
  119.     FResize: boolean;
  120.     FComment: string;
  121.     FWordBreak: boolean;
  122.     procedure FontChanged(Sender: TObject);
  123.     function  GetAlignment: TAlignment;
  124.     function  GetColor: TColor;
  125.     function  GetExpanded: Boolean;
  126.     function  GetField: TField;
  127.     function  GetFont: TFont;
  128.     function  GetImeMode: TImeMode;
  129.     function  GetImeName: TImeName;
  130.     function  GetParentColumn: TColumn;
  131.     function  GetPickList: TStrings;
  132.     function  GetReadOnly: Boolean;
  133.     function  GetShowing: Boolean;
  134.     function  GetWidth: Integer;
  135.     function  GetVisible: Boolean;
  136.     function  IsAlignmentStored: Boolean;
  137.     function  IsColorStored: Boolean;
  138.     function  IsFontStored: Boolean;
  139.     function  IsImeModeStored: Boolean;
  140.     function  IsImeNameStored: Boolean;
  141.     function  IsReadOnlyStored: Boolean;
  142.     function  IsWidthStored: Boolean;
  143.     procedure SetAlignment(Value: TAlignment); virtual;
  144.     procedure SetButtonStyle(Value: TColumnButtonStyle);
  145.     procedure SetColor(Value: TColor);
  146.     procedure SetExpanded(Value: Boolean);
  147.     procedure SetField(Value: TField); virtual;
  148.     procedure SetFieldName(const Value: String);
  149.     procedure SetFont(Value: TFont);
  150.     procedure SetImeMode(Value: TImeMode); virtual;
  151.     procedure SetImeName(Value: TImeName); virtual;
  152.     procedure SetPickList(Value: TStrings);
  153.     procedure SetPopupMenu(Value: TPopupMenu);
  154.     procedure SetReadOnly(Value: Boolean); virtual;
  155.     procedure SetTitle(Value: TColumnTitle);
  156.     procedure SetWidth(Value: Integer); virtual;
  157.     procedure SetVisible(Value: Boolean);
  158.     function GetExpandable: Boolean;
  159.     procedure SetIndexed(Value: Boolean);
  160.     procedure SetItemIndex(Value: Integer);
  161.     procedure SetIndexStyle(const Value: TColumnIndexStyle);
  162.     procedure SetDisplayFormat(const Value: string);
  163.     procedure SetComment(const Value: string);
  164.     procedure SetWordBreak(const Value: boolean);
  165.   protected
  166.     function  CreateTitle: TColumnTitle; virtual;
  167.     function  GetGrid: TDCCustomDBGrid;
  168.     function GetDisplayName: string; override;
  169.     procedure RefreshDefaultFont;
  170.     procedure SetIndex(Value: Integer); override;
  171.     property IsStored: Boolean read FStored write FStored default True;
  172.   public
  173.     constructor Create(Collection: TCollection); override;
  174.     destructor Destroy; override;
  175.     procedure Assign(Source: TPersistent); override;
  176.     function DefaultAlignment: TAlignment;
  177.     function DefaultColor: TColor;
  178.     function DefaultFont: TFont;
  179.     function DefaultImeMode: TImeMode;
  180.     function DefaultImeName: TImeName;
  181.     function DefaultReadOnly: Boolean;
  182.     function DefaultWidth: Integer;
  183.     function Depth: Integer;
  184.     procedure RestoreDefaults; virtual;
  185.     property Grid: TDCCustomDBGrid read GetGrid;
  186.     property AssignedValues: TColumnValues read FAssignedValues;
  187.     property Expandable: Boolean read GetExpandable;
  188.     property Field: TField read GetField write SetField;
  189.     property ParentColumn: TColumn read GetParentColumn;
  190.     property Showing: Boolean read GetShowing;
  191.   published
  192.     property Alignment: TAlignment read GetAlignment write SetAlignment
  193.       stored IsAlignmentStored;
  194.     property ButtonStyle: TColumnButtonStyle read FButtonStyle write SetButtonStyle
  195.       default cbsAuto;
  196.     property Color: TColor read GetColor write SetColor stored IsColorStored;
  197.     property DropDownRows: Cardinal read FDropDownRows write FDropDownRows default 7;
  198.     property Expanded: Boolean read GetExpanded write SetExpanded default False;
  199.     property FieldName: String read FFieldName write SetFieldName;
  200.     property Font: TFont read GetFont write SetFont stored IsFontStored;
  201.     property ImeMode: TImeMode read GetImeMode write SetImeMode stored IsImeModeStored;
  202.     property ImeName: TImeName read GetImeName write SetImeName stored IsImeNameStored;
  203.     property PickList: TStrings read GetPickList write SetPickList;
  204.     property PopupMenu: TPopupMenu read FPopupMenu write SetPopupMenu;
  205.     property ReadOnly: Boolean read GetReadOnly write SetReadOnly
  206.       stored IsReadOnlyStored;
  207.     property Title: TColumnTitle read FTitle write SetTitle;
  208.     property Width: Integer read GetWidth write SetWidth stored IsWidthStored;
  209.     property Visible: Boolean read GetVisible write SetVisible default True;
  210.     property IndexStyle: TColumnIndexStyle read FIndexStyle write SetIndexStyle default idxNone;
  211.     property Indexed: Boolean read FIndexed  write SetIndexed default False;
  212.     property ItemIndex: Integer read FItemIndex  write SetItemIndex default -1;
  213.     property DisplayFormat: string read FDisplayFormat write SetDisplayFormat;
  214.     property Tag: integer read FTag write FTag default 0;
  215.     property Resize: boolean read FResize write FResize default True;
  216.     property Comment: string read FComment write SetComment;
  217.     property WordBreak: boolean read FWordBreak write SetWordBreak;
  218.   end;
  219.  
  220.   TColumnClass = class of TColumn;
  221.  
  222.   TDBGridColumnsState = (csDefault, csCustomized);
  223.  
  224.   TDBGridColumns = class(TCollection)
  225.   private
  226.     FGrid: TDCCustomDBGrid;
  227.     function GetColumn(Index: Integer): TColumn;
  228.     function InternalAdd: TColumn;
  229.     procedure SetColumn(Index: Integer; Value: TColumn);
  230.     procedure SetState(NewState: TDBGridColumnsState);
  231.     function GetState: TDBGridColumnsState;
  232.   protected
  233.     function GetOwner: TPersistent; override;
  234.     procedure Update(Item: TCollectionItem); override;
  235.   public
  236.     constructor Create(Grid: TDCCustomDBGrid; ColumnClass: TColumnClass);
  237.     function  Add: TColumn;
  238.     procedure LoadFromFile(const Filename: string);
  239.     procedure LoadFromStream(S: TStream);
  240.     procedure RestoreDefaults;
  241.     procedure RebuildColumns;
  242.     procedure SaveToFile(const Filename: string);
  243.     procedure SaveToStream(S: TStream);
  244.     property State: TDBGridColumnsState read GetState write SetState;
  245.     property Grid: TDCCustomDBGrid read FGrid;
  246.     property Items[Index: Integer]: TColumn read GetColumn write SetColumn; default;
  247.   end;
  248.  
  249.   TGridDataLink = class(TDataLink)
  250.   private
  251.     FGrid: TDCCustomDBGrid;
  252.     FFieldCount: Integer;
  253.     FFieldMap: array of Integer;
  254.     FModified: Boolean;
  255.     FInUpdateData: Boolean;
  256.     FSparseMap: Boolean;
  257.     function GetDefaultFields: Boolean;
  258.     function GetFields(I: Integer): TField;
  259.   protected
  260.     procedure ActiveChanged; override;
  261.     procedure BuildAggMap;
  262.     procedure DataSetChanged; override;
  263.     procedure DataSetScrolled(Distance: Integer); override;
  264.     procedure FocusControl(Field: TFieldRef); override;
  265.     procedure EditingChanged; override;
  266.     function IsAggRow(Value: Integer): Boolean; virtual;
  267.     procedure LayoutChanged; override;
  268.     procedure RecordChanged(Field: TField); override;
  269.     procedure UpdateData; override;
  270.     function  GetMappedIndex(ColIndex: Integer): Integer;
  271.   public
  272.     constructor Create(AGrid: TDCCustomDBGrid);
  273.     destructor Destroy; override;
  274.     function AddMapping(const FieldName: string): Boolean;
  275.     procedure ClearMapping;
  276.     procedure Modified;
  277.     procedure Reset;
  278.     property DefaultFields: Boolean read GetDefaultFields;
  279.     property FieldCount: Integer read FFieldCount;
  280.     property Fields[I: Integer]: TField read GetFields;
  281.     property SparseMap: Boolean read FSparseMap write FSparseMap;
  282.   end;
  283.  
  284.   TBookmarkList = class
  285.   private
  286.     FList: TStringList;
  287.     FGrid: TDCCustomDBGrid;
  288.     FCache: TBookmarkStr;
  289.     FCacheIndex: Integer;
  290.     FCacheFind: Boolean;
  291.     FLinkActive: Boolean;
  292.     function GetCount: Integer;
  293.     function GetCurrentRowSelected: Boolean;
  294.     function GetItem(Index: Integer): TBookmarkStr;
  295.     procedure SetCurrentRowSelected(Value: Boolean);
  296.   protected
  297.     function CurrentRow: TBookmarkStr;
  298.     function Compare(const Item1, Item2: TBookmarkStr): Integer;
  299.     procedure LinkActive(Value: Boolean);
  300.     procedure StringsChanged(Sender: TObject);
  301.   public
  302.     constructor Create(AGrid: TDCCustomDBGrid);
  303.     destructor Destroy; override;
  304.     procedure Clear;           // free all bookmarks
  305.     procedure Delete;          // delete all selected rows from dataset
  306.     function  Find(const Item: TBookmarkStr; var Index: Integer): Boolean;
  307.     function  IndexOf(const Item: TBookmarkStr): Integer;
  308.     function  Refresh: Boolean;// drop orphaned bookmarks; True = orphans found
  309.     procedure Save(List: TStringList);
  310.     procedure SelectAll;
  311.     procedure Load(List: TStringList);
  312.     property Count: Integer read GetCount;
  313.     property CurrentRowSelected: Boolean read GetCurrentRowSelected
  314.       write SetCurrentRowSelected;
  315.     property Items[Index: Integer]: TBookmarkStr read GetItem; default;
  316.   end;
  317.  
  318.   TDBGridOption = (dgEditing, dgAlwaysShowEditor, dgTitles, dgIndicator,
  319.     dgColumnResize, dgColLines, dgRowLines, dgTabs, dgRowSelect,
  320.     dgAlwaysShowSelection, dgConfirmDelete, dgCancelOnExit, dgMultiSelect,
  321.     dgMarker, dgTitleClicked, dgUserRowHeight, dgRowSizing, dgHighlightRow,
  322.     dgFlatButtons, dgCompleteLines, dgAutoSize);
  323.  
  324.   TDBGridOptionEx =(dgeInsertSelect, dgeMarkerMenu, dgeShadowSelection,
  325.     dgeDrawMemoAsText);
  326.  
  327.   TDBGridOptions   = set of TDBGridOption;
  328.   TDBGridOptionsEx = set of TDBGridOptionEx;
  329.  
  330.   { The DBGrid's DrawDataCell virtual method and OnDrawDataCell event are only
  331.     called when the grid's Columns.State is csDefault.  This is for compatibility
  332.     with existing code. These routines don't provide sufficient information to
  333.     determine which column is being drawn, so the column attributes aren't
  334.     easily accessible in these routines.  Column attributes also introduce the
  335.     possibility that a column's field may be nil, which would break existing
  336.     DrawDataCell code.   DrawDataCell, OnDrawDataCell, and DefaultDrawDataCell
  337.     are obsolete, retained for compatibility purposes. }
  338.   TDrawDataCellEvent = procedure (Sender: TObject; const Rect: TRect; Field: TField;
  339.     State: TGridDrawState) of object;
  340.  
  341.   { The DBGrid's DrawColumnCell virtual method and OnDrawColumnCell event are
  342.     always called, when the grid has defined column attributes as well as when
  343.     it is in default mode.  These new routines provide the additional
  344.     information needed to access the column attributes for the cell being
  345.     drawn, and must support nil fields.  }
  346.  
  347.   TDrawColumnCellEvent = procedure (Sender: TObject; const Rect: TRect;
  348.     DataCol: Integer; Column: TColumn; State: TGridDrawState) of object;
  349.   TDBGridClickEvent   = procedure (Column: TColumn) of object;
  350.   TDBGridClipEvent    = procedure (Sender: TObject; X, Y : LongInt; var Show: boolean) of object;
  351.   TDBGridCommentEvent = procedure(Sender: TObject; Mode: integer; Column: TColumn) of object;
  352.   TDBGridUpdMessageEvent = procedure(Sender: TObject; Canvas: TCanvas; ARect: TRect;
  353.     UpdateMessage: string) of object;
  354.   TDBGridDrawCompleteEvent = procedure(Sender: TObject; Canvas: TCanvas; ARect: TRect;
  355.     Selected: boolean; ARow: integer; var DefaultDrawing: boolean) of object;
  356.  
  357.   TBookmarkInfo = record
  358.     Row: integer;
  359.     Bookmark: TBookmark;
  360.     ActiveRecord: integer;
  361.   end;
  362.  
  363.   TDCCustomDBGrid = class(TDCCustomGrid)
  364.   private
  365.     FBookmarks: TBookmarkList;
  366.     FColumnCell: integer;
  367.     FColumns: TDBGridColumns;
  368.     FClipDown: boolean;
  369.     FClipPopup: TObject;
  370.     FClipPopupVisible: boolean;
  371.     FCurrentCol: Integer;
  372.     FCurrentPos: array[1..2] of TBookmarkInfo;
  373.     FDataLink: TGridDataLink;
  374.     FDataVisible: boolean;
  375.     FDBObject: TDCDBObject;
  376.     FDefaultDrawing: Boolean;
  377.     FDragCol: TColumn;
  378.     FDrawColumn: TColumn;
  379.     FEditText: string;
  380.     FFirstGridCell: integer;
  381.     FFrozenCols: integer;
  382.     FImageChangeLink: TChangeLink;
  383.     FImages: TImageList;
  384.     FInColExit: Boolean;
  385.     FIsESCKey: Boolean;
  386.     FLayoutFromDataset: Boolean;
  387.     FLayoutLock: Byte;
  388.     FMousePoint: TPoint;
  389.     FOnCellClick: TDBGridClickEvent;
  390.     FOnCellDblClick: TDBGridClickEvent;
  391.     FOnClipButtonClick: TNotifyEvent;
  392.     FOnClipClick: TDBGridClipEvent;
  393.     FOnColumnComment: TDBGridCommentEvent;
  394.     FOnColumnMoved: TMovedEvent;
  395.     FOnColEnter: TNotifyEvent;
  396.     FOnColExit: TNotifyEvent;
  397.     FOnDrawColumnCell: TDrawColumnCellEvent;
  398.     FOnDrawCompleteLine: TDBGridDrawCompleteEvent;
  399.     FOnDrawDataCell: TDrawDataCellEvent;
  400.     FOnEditButtonClick: TNotifyEvent;
  401.     FOnPaintEmptyMessage: TDBGridUpdMessageEvent;
  402.     FOnTitleClick:TDBGridClickEvent;
  403.     FOptions: TDBGridOptions;
  404.     FOptionsEx: TDBGridOptionsEx;
  405.     FOriginalImeMode: TImeMode;
  406.     FOriginalImeName: TImeName;
  407.     FPopupTitle: TPopupMenu;
  408.     FReadOnly: Boolean;
  409.     FSelecting: Boolean;
  410.     FSelectionAnchor: TBookmarkStr;
  411.     FSelfChangingTitleFont: Boolean;
  412.     FSelRow: Integer;
  413.     FSizingIndex: integer;
  414.     FSizingOff: integer;
  415.     FTitleFont: TFont;
  416.     FTitleOffset, FIndicatorOffset: Byte;
  417.     FUpdateLock: Byte;
  418.     FUserChange: Boolean;
  419.     FVisibleColumns: TList;
  420.     function AcquireFocus: Boolean;
  421.     function BoxRectEx(ALeft, ATop, ARight, ABottom: Longint): TRect;
  422.     procedure ClearSelection;
  423.     procedure DataChanged;
  424.     procedure DoSelection(Select: Boolean; Direction: Integer; Shift: TShiftState);
  425.     procedure EditingChanged;
  426.     function GetDataSource: TDataSource;
  427.     function GetDBObject: TDCDBObject;
  428.     function GetFieldCount: Integer;
  429.     function GetFields(FieldIndex: Integer): TField;
  430.     function GetFrozenCols: integer;
  431.     function GetPosition: TBookMark;
  432.     function GetSelectedField: TField;
  433.     function GetSelectedIndex: Integer;
  434.     procedure ImageListChange(Sender: TObject);
  435.     procedure InternalLayout;
  436.     function LeftTitleButton(Row, Col: integer): boolean;
  437.     procedure MoveCol(RawCol, Direction: Integer);
  438.     procedure NextRow(Select: Boolean);
  439.     procedure PriorRow(Select: Boolean);
  440.     function PtInExpandButton(X,Y: Integer; var MasterCol: TColumn): Boolean;
  441.     procedure ReadColumns(Reader: TReader);
  442.     procedure RecordChanged(Field: TField);
  443.     procedure SetIme;
  444.     procedure SetClipDown(const Value: boolean);
  445.     procedure SetColumns(Value: TDBGridColumns);
  446.     procedure SetDataSource(Value: TDataSource);
  447.     procedure SetDataVisible(const Value: boolean);
  448.     procedure SetDBObject(const Value: TDCDBObject);
  449.     procedure SetFrozenCols(Value: integer);
  450.     procedure SetImages(const Value: TImageList);
  451.     procedure SetOptions(Value: TDBGridOptions);
  452.     procedure SetOptionsEx(const Value: TDBGridOptionsEx);
  453.     procedure SetPopupTitle(const Value: TPopupMenu);
  454.     procedure SetPosition(const Value: TBookMark);
  455.     procedure SetSelectedField(Value: TField);
  456.     procedure SetSelectedIndex(Value: Integer);
  457.     procedure SetTitleFont(Value: TFont);
  458.     procedure SetTitleHeight;
  459.     procedure TitleFontChanged(Sender: TObject);
  460.     procedure UpdateData;
  461.     procedure UpdateActive;
  462.     procedure UpdateIme;
  463.     procedure UpdateScrollBar;
  464.     procedure UpdateRowCount;
  465.     procedure WriteColumns(Writer: TWriter);
  466.   protected
  467.     FUpdateFields: Boolean;
  468.     FAcquireFocus: Boolean;
  469.     function  RawToDataColumn(ACol: Integer): Integer; override;
  470.     function  DataToRawColumn(ACol: Integer): Integer;
  471.     function  AcquireLayoutLock: Boolean;
  472.     procedure CreateParams(var Params: TCreateParams); override;
  473.     procedure BeginLayout; override;
  474.     procedure BeginUpdate;
  475.     procedure CalcSizingState(X, Y: Integer; var State: TGridState;
  476.       var Index: Longint; var SizingPos, SizingOfs: Integer;
  477.       var FixedInfo: TGridDrawInfo); override;
  478.     procedure CancelLayout;
  479.     function  CanEditAcceptKey(Key: Char): Boolean; override;
  480.     function  CanEditModify: Boolean; override;
  481.     function  CanEditShow: Boolean; override;
  482.     procedure CellClick(Column: TColumn); dynamic;
  483.     procedure CellDblClick(Column: TColumn); dynamic;
  484.     procedure ColumnMoved(FromIndex, ToIndex: Longint); override;
  485.     function CalcTitleRect(Col: TColumn; ARow: Integer;
  486.       var MasterCol: TColumn): TRect;
  487.     function ColumnAtDepth(Col: TColumn; ADepth: Integer): TColumn;
  488.     procedure ColEnter; dynamic;
  489.     procedure ColExit; dynamic;
  490.     procedure ColWidthsChanged; override;
  491.     function  CreateColumns: TDBGridColumns; dynamic;
  492.     function  CreateEditor: TInplaceEdit; override;
  493.     procedure CreateWnd; override;
  494.     procedure CMBiDiModeChanged(var Message: TMessage); message CM_BIDIMODECHANGED;
  495.     procedure CMExit(var Message: TMessage); message CM_EXIT;
  496.     procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  497.     procedure CMParentFontChanged(var Message: TMessage); message CM_PARENTFONTCHANGED;
  498.     procedure CMDeferLayout(var Message); message CM_DEFERLAYOUT;
  499.     procedure CMDesignHitTest(var Msg: TCMDesignHitTest); message CM_DESIGNHITTEST;
  500.     procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
  501.     procedure WMSetCursor(var Msg: TWMSetCursor); message WM_SETCURSOR;
  502.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  503.     procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
  504.     procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL;
  505.     procedure WMIMEStartComp(var Message: TMessage); message WM_IME_STARTCOMPOSITION;
  506.     procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
  507.     procedure WMKillFocus(var Message: TMessage); message WM_KILLFOCUS;
  508.     procedure WMNCLButtonDown(var Message: TWMNCLButtonDown); message WM_NCLBUTTONDOWN;
  509.     procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND;
  510.     procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  511.     procedure CMCancelMode(var Message: TCMCancelMode); message CM_CANCELMODE;
  512.     procedure WMChar(var Msg: TWMChar); message WM_CHAR;
  513.     procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
  514.     procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;
  515.     procedure DeferLayout;
  516.     procedure DefineFieldMap; virtual;
  517.     procedure DefineProperties(Filer: TFiler); override;
  518.     procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override;
  519.     procedure DrawDataCell(const Rect: TRect; Field: TField;
  520.       State: TGridDrawState); dynamic; { obsolete }
  521.     procedure DrawColumnCell(const Rect: TRect; DataCol: Integer;
  522.       Column: TColumn; State: TGridDrawState); dynamic;
  523.     procedure EditButtonClick; dynamic;
  524.     procedure EndLayout; override;
  525.     procedure EndUpdate;
  526.     function  GetColField(DataCol: Integer): TField;
  527.     function  GetEditLimit: Integer; override;
  528.     function  GetEditMask(ACol, ARow: Longint): string; override;
  529.     function  GetEditText(ACol, ARow: Longint): string; override;
  530.     function  GetFieldValue(ACol: Integer): string;
  531.     function  HighlightCell(DataCol, DataRow: Integer; const Value: string;
  532.       AState: TGridDrawState): Boolean; virtual;
  533.     procedure KeyPress(var Key: Char); override;
  534.     procedure InvalidateTitles;
  535.     procedure InvalidateSelected;
  536.     procedure LayoutChanged; virtual;
  537.     procedure LinkActive(Value: Boolean); virtual;
  538.     procedure Loaded; override;
  539.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  540.       X, Y: Integer); override;
  541.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
  542.       X, Y: Integer); override;
  543.     procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  544.     function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; override;
  545.     function DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; override;
  546.     procedure DoColumnComment(Mode: integer; Column: TColumn); virtual;
  547.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  548.     procedure Scroll(Distance: Integer); virtual;
  549.     procedure SetColumnAttributes; virtual;
  550.     procedure SetEditText(ACol, ARow: Longint; const Value: string); override;
  551.     function SelectCell(ACol, ARow: Longint): Boolean; override;
  552.     function  StoreColumns: Boolean;
  553.     function  MouseUpBeforeDblClk: boolean; dynamic;
  554.     procedure TimedScroll(Direction: TGridScrollDirection); override;
  555.     procedure TitleClick(Column: TColumn); dynamic;
  556.     procedure ClipClick; dynamic;
  557.     procedure TopLeftChanged; override;
  558.     function UseRightToLeftAlignmentForField(const AField: TField;
  559.       Alignment: TAlignment): Boolean;
  560.     function BeginColumnDrag(var Origin, Destination: Integer;
  561.       const MousePt: TPoint): Boolean; override;
  562.     function CheckColumnDrag(var Origin, Destination: Integer;
  563.       const MousePt: TPoint): Boolean; override;
  564.     function EndColumnDrag(var Origin, Destination: Integer;
  565.       const MousePt: TPoint): Boolean; override;
  566.     procedure ClipButtonClick(Sender: TObject); virtual;
  567.     function GetPopupMenu: TPopupMenu; override;
  568.     function DataVisible: boolean; virtual;
  569.     function DrawTitleCell(ACanvas: TCanvas; ACol, ARow: Integer; ARect: TRect;
  570.       BorderState: TDrawBorerState; AFillRect, ADraw: boolean): TPoint; override;
  571.     function GetBorderStyle: TEdgeBorderStyle; override;
  572.     function FlatButtons: boolean; override;
  573.     procedure DoColumnClick(Shift: TShiftState; ColIndex: integer); override;
  574.     procedure CreateCellDragImage(ACol, ARow: integer; var DragImages: TImageList); override;
  575.     function CanColResize(ACol: integer): boolean; override;
  576.     property Columns: TDBGridColumns read FColumns write SetColumns;
  577.     property DefaultDrawing: Boolean read FDefaultDrawing write FDefaultDrawing default True;
  578.     property DataSource: TDataSource read GetDataSource write SetDataSource;
  579.     property DataLink: TGridDataLink read FDataLink;
  580.     property IndicatorOffset: Byte read FIndicatorOffset;
  581.     property LayoutLock: Byte read FLayoutLock;
  582.     property Options: TDBGridOptions read FOptions write SetOptions
  583.       default [dgEditing, dgTitles, dgIndicator, dgColumnResize, dgColLines,
  584.       dgRowLines, dgTabs, dgConfirmDelete, dgCancelOnExit];
  585.     property OptionsEx: TDBGridOptionsEx read FOptionsEx write SetOptionsEx
  586.       default [dgeMarkerMenu, dgeShadowSelection, dgeDrawMemoAsText
  587.       {$IFNDEF DELPHI_V5UP}, dgeInsertSelect {$ENDIF}];
  588.     property ParentColor default False;
  589.     property ReadOnly: Boolean read FReadOnly write FReadOnly default False;
  590.     property SelectedRows: TBookmarkList read FBookmarks;
  591.     property TitleFont: TFont read FTitleFont write SetTitleFont;
  592.     property UpdateLock: Byte read FUpdateLock;
  593.     property OnColEnter: TNotifyEvent read FOnColEnter write FOnColEnter;
  594.     property OnColExit: TNotifyEvent read FOnColExit write FOnColExit;
  595.     property OnDrawDataCell: TDrawDataCellEvent read FOnDrawDataCell
  596.       write FOnDrawDataCell; { obsolete }
  597.     property OnDrawColumnCell: TDrawColumnCellEvent read FOnDrawColumnCell
  598.       write FOnDrawColumnCell;
  599.     property OnEditButtonClick: TNotifyEvent read FOnEditButtonClick
  600.       write FOnEditButtonClick;
  601.     property OnColumnMoved: TMovedEvent read FOnColumnMoved write FOnColumnMoved;
  602.     property OnCellClick: TDBGridClickEvent read FOnCellClick write FOnCellClick;
  603.     property OnCellDblClick: TDBGridClickEvent read FOnCellDblClick write FOnCellDblClick;
  604.     property OnTitleClick: TDBGridClickEvent read FOnTitleClick write FOnTitleClick;
  605.     property OnClipClick: TDBGridClipEvent read FOnClipClick write FOnClipClick;
  606.     property Position: TBookMark read GetPosition write SetPosition;
  607.     property FrozenCols: Integer read GetFrozenCols write SetFrozenCols default 0;
  608.     property OnClipButtonClick: TNotifyEvent read FOnClipButtonClick write FOnClipButtonClick;
  609.     property PopupTitle: TPopupMenu read FPopupTitle write SetPopupTitle;
  610.     property DBObject: TDCDBObject read GetDBObject write SetDBObject;
  611.     property OnColumnComment: TDBGridCommentEvent read FOnColumnComment write FOnColumnComment;
  612.     property OnPaintEmptyMessage: TDBGridUpdMessageEvent read FOnPaintEmptyMessage write FOnPaintEmptyMessage;
  613.     property OnDrawCompleteLine: TDBGridDrawCompleteEvent read FOnDrawCompleteLine write FOnDrawCompleteLine;
  614.   public
  615.     constructor Create(AOwner: TComponent); override;
  616.     destructor Destroy; override;
  617.     procedure DefaultDrawDataCell(const Rect: TRect; Field: TField;
  618.       State: TGridDrawState); { obsolete }
  619.     procedure DefaultDrawColumnCell(const Rect: TRect; DataCol: Integer;
  620.       Column: TColumn; State: TGridDrawState);
  621.     procedure DefaultHandler(var Msg); override;
  622.     procedure RowHeightsChanged; override;
  623.     function ExecuteAction(Action: TBasicAction): Boolean; override;
  624.     procedure ShowPopupEditor(Column: TColumn; X: Integer = Low(Integer);
  625.       Y: Integer = Low(Integer)); dynamic;
  626.     function UpdateAction(Action: TBasicAction): Boolean; override;
  627.     function ValidFieldIndex(FieldIndex: Integer): Boolean;
  628.     function GetDataValue(Column: TColumn): string; virtual;
  629.     function ValidBookmark(Bookmark: TBookmark): boolean;
  630.     procedure SavePosition;
  631.     procedure RestPosition;
  632.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  633.     function GroupingEnabled: boolean; override;
  634.     procedure Paint; override;
  635.     property EditorMode;
  636.     property FieldCount: Integer read GetFieldCount;
  637.     property Fields[FieldIndex: Integer]: TField read GetFields;
  638.     property SelectedField: TField read GetSelectedField write SetSelectedField;
  639.     property SelectedIndex: Integer read GetSelectedIndex write SetSelectedIndex;
  640.     property Images: TImageList read FImages write SetImages;
  641.     property ClipDown: boolean read FClipDown write SetClipDown;
  642.     property Col;
  643.     property Row;
  644.     procedure ShowClipPopup;
  645.     procedure HideClipPopup;
  646.     procedure SelectItems(Mode: TSelectMode);
  647.     function CellRect(ACol, ARow: Longint): TRect;
  648.     function MouseCoord(X, Y: Longint): TGridCoord;
  649.     property DataSetVisible: boolean read FDataVisible write SetDataVisible;
  650.   end;
  651.  
  652.   TDCDBGrid = class(TDCCustomDBGrid)
  653.   public
  654.     property Canvas;
  655.     property SelectedRows;
  656.     property Position;
  657.   published
  658.     property Align;
  659.     property Anchors;
  660.     property BiDiMode;
  661.     property BorderStyle;
  662.     property Color;
  663.     property Columns stored False; //StoreColumns;
  664.     property Constraints;
  665.     property Ctl3D;
  666.     property DataSource;
  667.     property DefaultDrawing;
  668.     property DragCursor;
  669.     property DragKind;
  670.     property DragMode;
  671.     property Enabled;
  672.     property FixedColor;
  673.     property Font;
  674.     property ImeMode;
  675.     property ImeName;
  676.     property Options;
  677.     property OptionsEx;
  678.     property ParentBiDiMode;
  679.     property ParentColor;
  680.     property ParentCtl3D;
  681.     property ParentFont;
  682.     property ParentShowHint;
  683.     property PopupMenu;
  684.     property ReadOnly;
  685.     property ShowHint;
  686.     property TabOrder;
  687.     property TabStop;
  688.     property TitleFont;
  689.     property Visible;
  690.     property OnCellClick;
  691.     property OnCellDblClick;
  692.     property OnColEnter;
  693.     property OnColExit;
  694.     property OnColumnMoved;
  695.     property OnDrawDataCell;  { obsolete }
  696.     property OnDrawColumnCell;
  697.     property OnDblClick;
  698.     property OnDragDrop;
  699.     property OnDragOver;
  700.     property OnEditButtonClick;
  701.     property OnEndDock;
  702.     property OnEndDrag;
  703.     property OnEnter;
  704.     property OnExit;
  705.     property OnKeyDown;
  706.     property OnKeyPress;
  707.     property OnKeyUp;
  708.     property OnStartDock;
  709.     property OnStartDrag;
  710.     property OnTitleClick;
  711.     property Images;
  712.     property DefaultRowHeight;
  713.     property OnClipClick;
  714.     property FrozenCols;
  715.     property OnMouseDown;
  716.     property OnMouseMove;
  717.     property OnMouseUp;
  718.     property OnClipButtonClick;
  719.     property PopupTitle;
  720.     property DBObject;
  721.     property OnColumnComment;
  722.     property OnPaintEmptyMessage;
  723.     property OnDrawCompleteLine;
  724.   end;
  725.  
  726. const
  727.   IndicatorWidth  = 12;
  728.   MarkerWidth     = 16;
  729.   IndexTitleWidth = 11;
  730.  
  731. implementation
  732.  
  733. uses DBConsts, Dialogs, DCPopupWindow, DCEditButton, DCChoice;
  734.  
  735. {$R *.RES}
  736.  
  737. const
  738.   MaxMapSize = (MaxInt div 2) div SizeOf(Integer);  { 250 million }
  739.  
  740. type
  741.   TSelection = record
  742.     StartPos, EndPos: Integer;
  743.   end;
  744.  
  745.   TPrivateDataSet = class(TDataSet)
  746.   end;
  747.  
  748. var
  749.   DrawBitmap, TempBitmap: TBitmap;
  750.   UserCount: Integer;
  751.  
  752. { Error reporting }
  753.  
  754. procedure RaiseGridError(const S: string);
  755. begin
  756.   raise EInvalidGridOperation.Create(S);
  757. end;
  758.  
  759. procedure KillMessage(Wnd: HWnd; Msg: Integer);
  760. // Delete the requested message from the queue, but throw back
  761. // any WM_QUIT msgs that PeekMessage may also return
  762. var
  763.   M: TMsg;
  764. begin
  765.   M.Message := 0;
  766.   if PeekMessage(M, Wnd, Msg, Msg, pm_Remove) and (M.Message = WM_QUIT) then
  767.     PostQuitMessage(M.wparam);
  768. end;
  769.  
  770. function GetTextHeight(DC: HDC; Value: string): integer;
  771.  var
  772.   R: TRect;
  773. begin
  774.   R := Rect(0, 0, 500, 0);
  775.   DrawText(DC, PChar(Value), -1, R, DT_CALCRECT or DT_LEFT or
  776.       DT_WORDBREAK or DT_NOPREFIX);
  777.   Result := R.Bottom;
  778. end;
  779.  
  780. function GetTextHeightEx(Canvas: TCanvas; Value: string): integer;
  781.  var
  782.   R: TRect;
  783.   P: TPoint;
  784. begin
  785.   R := Rect(0, 0, MaxInt, MaxInt);
  786.   P := DrawHighLightText(Canvas, PChar(Value), R, 0, DT_LEFT);
  787.   Result := P.Y;
  788. end;
  789.  
  790. function GetTextWidth(DC: HDC; Value: string): integer;
  791.  var
  792.   R: TRect;
  793. begin
  794.   R := Rect(0, 0, 500, 0);
  795.   DrawText(DC, PChar(Value), -1, R, DT_CALCRECT or DT_LEFT or
  796.       DT_WORDBREAK or DT_NOPREFIX);
  797.   Result := R.Right;
  798. end;
  799.  
  800. function GetTextWidthEx(Canvas: TCanvas; Value: string): integer;
  801.  var
  802.   R: TRect;
  803.   P: TPoint;
  804. begin
  805.   R := Rect(0, 0, 500, 0);
  806.   P := DrawHighLightText(Canvas, PChar(Value), R, 0, DT_LEFT or DT_WORDBREAK or DT_NOPREFIX);
  807.   Result := P.X;
  808. end;
  809.  
  810. function GetMultiLineHeight(Font: TFont; Value: string;
  811.                             ACanvas: TCanvas = nil) : Longint;
  812. var
  813.  Canvas: TCanvas;
  814. begin
  815.   if ACanvas = nil then
  816.   begin
  817.     Canvas := nil;
  818.     try
  819.       Canvas := TCanvas.Create;
  820.       Canvas.Handle := GetDC(0);
  821.       Canvas.Font := Font;
  822.       Result := _intMax(GetTextHeightEx(Canvas, Value), GetTextHeightEx(Canvas, 'Wg')) + 4;
  823.     finally
  824.       ReleaseDC(0, Canvas.Handle);
  825.       Canvas.Handle := 0;
  826.       Canvas.Free;
  827.     end
  828.   end
  829.   else
  830.     Result := _intMax(GetTextHeightEx(ACanvas, Value), GetTextHeightEx(ACanvas, 'Wg')) + 4;
  831. end;
  832.  
  833. { TDBGridInplaceEdit }
  834.  
  835. { TDBGridInplaceEdit adds support for a button on the in-place editor,
  836.   which can be used to drop down a table-based lookup list, a stringlist-based
  837.   pick list, or (if button style is esEllipsis) fire the grid event
  838.   OnEditButtonClick.  }
  839.  
  840. type
  841.   TEditStyle = (esSimple, esEllipsis, esPickList, esDataList);
  842.   TPopupListbox = class;
  843.  
  844.   TDBGridInplaceEdit = class(TInplaceEdit)
  845.   private
  846.     FButtonWidth: Integer;
  847.     FDataList: TDBLookupListBox;
  848.     FPickList: TPopupListbox;
  849.     FActiveList: TWinControl;
  850.     FLookupSource: TDatasource;
  851.     FEditStyle: TEditStyle;
  852.     FListVisible: Boolean;
  853.     FTracking: Boolean;
  854.     FPressed: Boolean;
  855.     procedure ListMouseUp(Sender: TObject; Button: TMouseButton;
  856.       Shift: TShiftState; X, Y: Integer);
  857.     procedure SetEditStyle(Value: TEditStyle);
  858.     procedure StopTracking;
  859.     procedure TrackButton(X,Y: Integer);
  860.     procedure CMCancelMode(var Message: TCMCancelMode); message CM_CancelMode;
  861.     procedure WMCancelMode(var Message: TMessage); message WM_CancelMode;
  862.     procedure WMKillFocus(var Message: TMessage); message WM_KillFocus;
  863.     procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message wm_LButtonDblClk;
  864.     procedure WMPaint(var Message: TWMPaint); message wm_Paint;
  865.     procedure WMSetCursor(var Message: TWMSetCursor); message WM_SetCursor;
  866.     function OverButton(const P: TPoint): Boolean;
  867.     function ButtonRect: TRect;
  868.   protected
  869.     procedure BoundsChanged; override;
  870.     procedure CloseUp(Accept: Boolean);
  871.     procedure DoDropDownKeys(var Key: Word; Shift: TShiftState);
  872.     procedure DropDown;
  873.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  874.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  875.       X, Y: Integer); override;
  876.     procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  877.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
  878.       X, Y: Integer); override;
  879.     procedure PaintWindow(DC: HDC); override;
  880.     procedure UpdateContents; override;
  881.     procedure WndProc(var Message: TMessage); override;
  882.     property  EditStyle: TEditStyle read FEditStyle write SetEditStyle;
  883.     property  ActiveList: TWinControl read FActiveList write FActiveList;
  884.     property  DataList: TDBLookupListBox read FDataList;
  885.     property  PickList: TPopupListbox read FPickList;
  886.   public
  887.     constructor Create(Owner: TComponent); override;
  888.   end;
  889.  
  890. { TPopupListbox }
  891.  
  892.   TPopupListbox = class(TCustomListbox)
  893.   private
  894.     FSearchText: String;
  895.     FSearchTickCount: Longint;
  896.   protected
  897.     procedure CreateParams(var Params: TCreateParams); override;
  898.     procedure CreateWnd; override;
  899.     procedure KeyPress(var Key: Char); override;
  900.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  901.   end;
  902.  
  903. procedure TPopupListBox.CreateParams(var Params: TCreateParams);
  904. begin
  905.   inherited CreateParams(Params);
  906.   with Params do
  907.   begin
  908.     Style := Style or WS_BORDER;
  909.     ExStyle := WS_EX_TOOLWINDOW or WS_EX_TOPMOST;
  910.     AddBiDiModeExStyle(ExStyle);
  911.     WindowClass.Style := CS_SAVEBITS;
  912.   end;
  913. end;
  914.  
  915. procedure TPopupListbox.CreateWnd;
  916. begin
  917.   inherited CreateWnd;
  918.   Windows.SetParent(Handle, 0);
  919.   CallWindowProc(DefWndProc, Handle, wm_SetFocus, 0, 0);
  920. end;
  921.  
  922. procedure TPopupListbox.Keypress(var Key: Char);
  923. var
  924.   TickCount: Integer;
  925. begin
  926.   case Key of
  927.     #8, #27: FSearchText := '';
  928.     #32..#255:
  929.       begin
  930.         TickCount := GetTickCount;
  931.         if TickCount - FSearchTickCount > 2000 then FSearchText := '';
  932.         FSearchTickCount := TickCount;
  933.         if Length(FSearchText) < 32 then FSearchText := FSearchText + Key;
  934.         SendMessage(Handle, LB_SelectString, WORD(-1), Longint(PChar(FSearchText)));
  935.         Key := #0;
  936.       end;
  937.   end;
  938.   inherited Keypress(Key);
  939. end;
  940.  
  941. procedure TPopupListbox.MouseUp(Button: TMouseButton; Shift: TShiftState;
  942.   X, Y: Integer);
  943. begin
  944.   inherited MouseUp(Button, Shift, X, Y);
  945.   TDBGridInPlaceEdit(Owner).CloseUp((X >= 0) and (Y >= 0) and
  946.       (X < Width) and (Y < Height));
  947. end;
  948.  
  949.  
  950. constructor TDBGridInplaceEdit.Create(Owner: TComponent);
  951. begin
  952.   inherited Create(Owner);
  953.   FLookupSource := TDataSource.Create(Self);
  954.   FButtonWidth := GetSystemMetrics(SM_CXVSCROLL);
  955.   FEditStyle := esSimple;
  956. end;
  957.  
  958. procedure TDBGridInplaceEdit.BoundsChanged;
  959. var
  960.   R: TRect;
  961. begin
  962.   SetRect(R, 2, 2, Width - 2, Height);
  963.   if FEditStyle <> esSimple then
  964.     if not TDCCustomDBGrid(Owner).UseRightToLeftAlignment then
  965.       Dec(R.Right, FButtonWidth)
  966.     else
  967.       Inc(R.Left, FButtonWidth - 2);
  968.   SendMessage(Handle, EM_SETRECTNP, 0, LongInt(@R));
  969.   SendMessage(Handle, EM_SCROLLCARET, 0, 0);
  970.   if SysLocale.FarEast then
  971.     SetImeCompositionWindow(Font, R.Left, R.Top);
  972. end;
  973.  
  974. procedure TDBGridInplaceEdit.CloseUp(Accept: Boolean);
  975. var
  976.   MasterField: TField;
  977.   ListValue: Variant;
  978. begin
  979.   if FListVisible then
  980.   begin
  981.     if GetCapture <> 0 then SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
  982.     if FActiveList = FDataList then
  983.       ListValue := FDataList.KeyValue
  984.     else
  985.       if FPickList.ItemIndex <> -1 then
  986.         ListValue := FPickList.Items[FPicklist.ItemIndex];
  987.     SetWindowPos(FActiveList.Handle, 0, 0, 0, 0, 0, SWP_NOZORDER or
  988.       SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_HIDEWINDOW);
  989.     FListVisible := False;
  990.     if Assigned(FDataList) then
  991.       FDataList.ListSource := nil;
  992.     FLookupSource.Dataset := nil;
  993.     Invalidate;
  994.     if Accept then
  995.       if FActiveList = FDataList then
  996.         with TDCCustomDBGrid(Grid), Columns[SelectedIndex].Field do
  997.         begin
  998.           MasterField := DataSet.FieldByName(KeyFields);
  999.           if MasterField.CanModify then
  1000.           begin
  1001.             DataSet.Edit;
  1002.             MasterField.Value := ListValue;
  1003.           end;
  1004.         end
  1005.       else
  1006.         if (not VarIsNull(ListValue)) and EditCanModify then
  1007.           with TDCCustomDBGrid(Grid), Columns[SelectedIndex].Field do
  1008.             Text := ListValue;
  1009.   end;
  1010. end;
  1011.  
  1012. procedure TDBGridInplaceEdit.DoDropDownKeys(var Key: Word; Shift: TShiftState);
  1013. begin
  1014.   case Key of
  1015.     VK_UP, VK_DOWN:
  1016.       if ssAlt in Shift then
  1017.       begin
  1018.         if FListVisible then CloseUp(True) else DropDown;
  1019.         Key := 0;
  1020.       end;
  1021.     VK_RETURN, VK_ESCAPE:
  1022.       if FListVisible and not (ssAlt in Shift) then
  1023.       begin
  1024.         CloseUp(Key = VK_RETURN);
  1025.         Key := 0;
  1026.       end;
  1027.   end;
  1028. end;
  1029.  
  1030. procedure TDBGridInplaceEdit.DropDown;
  1031. var
  1032.   P: TPoint;
  1033.   I,J,Y: Integer;
  1034.   Column: TColumn;
  1035. begin
  1036.   if not FListVisible and Assigned(FActiveList) then
  1037.   begin
  1038.     FActiveList.Width := Width;
  1039.     with TDCCustomDBGrid(Grid) do
  1040.       Column := Columns[SelectedIndex];
  1041.     if FActiveList = FDataList then
  1042.     with Column.Field do
  1043.     begin
  1044.       FDataList.Color := Color;
  1045.       FDataList.Font := Font;
  1046.       FDataList.RowCount := Column.DropDownRows;
  1047.       FLookupSource.DataSet := LookupDataSet;
  1048.       FDataList.KeyField := LookupKeyFields;
  1049.       FDataList.ListField := LookupResultField;
  1050.       FDataList.ListSource := FLookupSource;
  1051.       FDataList.KeyValue := DataSet.FieldByName(KeyFields).Value;
  1052. {      J := Column.DefaultWidth;
  1053.       if J > FDataList.ClientWidth then
  1054.         FDataList.ClientWidth := J;
  1055. }    end
  1056.     else
  1057.     begin
  1058.       FPickList.Color := Color;
  1059.       FPickList.Font := Font;
  1060.       FPickList.Items := Column.Picklist;
  1061.       if FPickList.Items.Count >= Integer(Column.DropDownRows) then
  1062.         FPickList.Height := Integer(Column.DropDownRows) * FPickList.ItemHeight + 4
  1063.       else
  1064.         FPickList.Height := FPickList.Items.Count * FPickList.ItemHeight + 4;
  1065.       if Column.Field.IsNull then
  1066.         FPickList.ItemIndex := -1
  1067.       else
  1068.         FPickList.ItemIndex := FPickList.Items.IndexOf(Column.Field.Text);
  1069.       J := FPickList.ClientWidth;
  1070.       for I := 0 to FPickList.Items.Count - 1 do
  1071.       begin
  1072.         Y := FPickList.Canvas.TextWidth(FPickList.Items[I]);
  1073.         if Y > J then J := Y;
  1074.       end;
  1075.       FPickList.ClientWidth := J;
  1076.     end;
  1077.     P := Parent.ClientToScreen(Point(Left, Top));
  1078.     Y := P.Y + Height;
  1079.     if Y + FActiveList.Height > Screen.Height then Y := P.Y - FActiveList.Height;
  1080.     SetWindowPos(FActiveList.Handle, HWND_TOP, P.X, Y, 0, 0,
  1081.       SWP_NOSIZE or SWP_NOACTIVATE or SWP_SHOWWINDOW);
  1082.     FListVisible := True;
  1083.     Invalidate;
  1084.     Windows.SetFocus(Handle);
  1085.   end;
  1086. end;
  1087.  
  1088. type
  1089.   TWinControlCracker = class(TWinControl) end;
  1090.  
  1091. procedure TDBGridInplaceEdit.KeyDown(var Key: Word; Shift: TShiftState);
  1092. begin
  1093.   if (EditStyle = esEllipsis) and (Key = VK_RETURN) and (Shift = [ssCtrl]) then
  1094.   begin
  1095.     TDCCustomDBGrid(Grid).EditButtonClick;
  1096.     KillMessage(Handle, WM_CHAR);
  1097.   end
  1098.   else
  1099.     inherited KeyDown(Key, Shift);
  1100. end;
  1101.  
  1102. procedure TDBGridInplaceEdit.ListMouseUp(Sender: TObject; Button: TMouseButton;
  1103.   Shift: TShiftState; X, Y: Integer);
  1104. begin
  1105.   if Button = mbLeft then
  1106.     CloseUp(PtInRect(FActiveList.ClientRect, Point(X, Y)));
  1107. end;
  1108.  
  1109. procedure TDBGridInplaceEdit.MouseDown(Button: TMouseButton; Shift: TShiftState;
  1110.   X, Y: Integer);
  1111. begin
  1112.   if (Button = mbLeft) and (FEditStyle <> esSimple) and
  1113.     OverButton(Point(X,Y)) then
  1114.   begin
  1115.     if FListVisible then
  1116.       CloseUp(False)
  1117.     else
  1118.     begin
  1119.       MouseCapture := True;
  1120.       FTracking := True;
  1121.       TrackButton(X, Y);
  1122.       if Assigned(FActiveList) then
  1123.         DropDown;
  1124.     end;
  1125.   end;
  1126.   inherited MouseDown(Button, Shift, X, Y);
  1127. end;
  1128.  
  1129. procedure TDBGridInplaceEdit.MouseMove(Shift: TShiftState; X, Y: Integer);
  1130. var
  1131.   ListPos: TPoint;
  1132.   MousePos: TSmallPoint;
  1133. begin
  1134.   if FTracking then
  1135.   begin
  1136.     TrackButton(X, Y);
  1137.     if FListVisible then
  1138.     begin
  1139.       ListPos := FActiveList.ScreenToClient(ClientToScreen(Point(X, Y)));
  1140.       if PtInRect(FActiveList.ClientRect, ListPos) then
  1141.       begin
  1142.         StopTracking;
  1143.         MousePos := PointToSmallPoint(ListPos);
  1144.         SendMessage(FActiveList.Handle, WM_LBUTTONDOWN, 0, Integer(MousePos));
  1145.         Exit;
  1146.       end;
  1147.     end;
  1148.   end;
  1149.   inherited MouseMove(Shift, X, Y);
  1150. end;
  1151.  
  1152. procedure TDBGridInplaceEdit.MouseUp(Button: TMouseButton; Shift: TShiftState;
  1153.   X, Y: Integer);
  1154. var
  1155.   WasPressed: Boolean;
  1156. begin
  1157.   WasPressed := FPressed;
  1158.   StopTracking;
  1159.   if (Button = mbLeft) and (FEditStyle = esEllipsis) and WasPressed then
  1160.     TDCCustomDBGrid(Grid).EditButtonClick;
  1161.   inherited MouseUp(Button, Shift, X, Y);
  1162. end;
  1163.  
  1164. procedure TDBGridInplaceEdit.PaintWindow(DC: HDC);
  1165. var
  1166.   R: TRect;
  1167.   Flags: Integer;
  1168.   W, X, Y: Integer;
  1169. begin
  1170.   if FEditStyle <> esSimple then
  1171.   begin
  1172.     R := ButtonRect;
  1173.     Flags := 0;
  1174.     if FEditStyle in [esDataList, esPickList] then
  1175.     begin
  1176.       if FActiveList = nil then
  1177.         Flags := DFCS_INACTIVE
  1178.       else if FPressed then
  1179.         Flags := DFCS_FLAT or DFCS_PUSHED;
  1180.       DrawFrameControl(DC, R, DFC_SCROLL, Flags or DFCS_SCROLLCOMBOBOX);
  1181.     end
  1182.     else   { esEllipsis }
  1183.     begin
  1184.       if FPressed then Flags := BF_FLAT;
  1185.       DrawEdge(DC, R, EDGE_RAISED, BF_RECT or BF_MIDDLE or Flags);
  1186.       X := R.Left + ((R.Right - R.Left) shr 1) - 1 + Ord(FPressed);
  1187.       Y := R.Top + ((R.Bottom - R.Top) shr 1) - 1 + Ord(FPressed);
  1188.       W := FButtonWidth shr 3;
  1189.       if W = 0 then W := 1;
  1190.       PatBlt(DC, X, Y, W, W, BLACKNESS);
  1191.       PatBlt(DC, X - (W * 2), Y, W, W, BLACKNESS);
  1192.       PatBlt(DC, X + (W * 2), Y, W, W, BLACKNESS);
  1193.     end;
  1194.     ExcludeClipRect(DC, R.Left, R.Top, R.Right, R.Bottom);
  1195.   end;
  1196.   inherited PaintWindow(DC);
  1197. end;
  1198.  
  1199. procedure TDBGridInplaceEdit.SetEditStyle(Value: TEditStyle);
  1200. begin
  1201.   if Value = FEditStyle then Exit;
  1202.   FEditStyle := Value;
  1203.   case Value of
  1204.     esPickList:
  1205.       begin
  1206.         if FPickList = nil then
  1207.         begin
  1208.           FPickList := TPopupListbox.Create(Self);
  1209.           FPickList.Visible := False;
  1210.           FPickList.Parent := Self;
  1211.           FPickList.OnMouseUp := ListMouseUp;
  1212.           FPickList.IntegralHeight := True;
  1213.           FPickList.ItemHeight := 11;
  1214.         end;
  1215.         FActiveList := FPickList;
  1216.       end;
  1217.     esDataList:
  1218.       begin
  1219.         if FDataList = nil then
  1220.         begin
  1221.           FDataList := TPopupDataList.Create(Self);
  1222.           FDataList.Visible := False;
  1223.           FDataList.Parent := Self;
  1224.           FDataList.OnMouseUp := ListMouseUp;
  1225.         end;
  1226.         FActiveList := FDataList;
  1227.       end;
  1228.   else  { cbsNone, cbsEllipsis, or read only field }
  1229.     FActiveList := nil;
  1230.   end;
  1231.   with TDCCustomDBGrid(Grid) do
  1232.     Self.ReadOnly := Columns[SelectedIndex].ReadOnly;
  1233.   Repaint;
  1234. end;
  1235.  
  1236. procedure TDBGridInplaceEdit.StopTracking;
  1237. begin
  1238.   if FTracking then
  1239.   begin
  1240.     TrackButton(-1, -1);
  1241.     FTracking := False;
  1242.     MouseCapture := False;
  1243.   end;
  1244. end;
  1245.  
  1246. procedure TDBGridInplaceEdit.TrackButton(X,Y: Integer);
  1247. var
  1248.   NewState: Boolean;
  1249.   R: TRect;
  1250. begin
  1251.   R := ButtonRect;
  1252.   NewState := PtInRect(R, Point(X, Y));
  1253.   if FPressed <> NewState then
  1254.   begin
  1255.     FPressed := NewState;
  1256.     InvalidateRect(Handle, @R, False);
  1257.   end;
  1258. end;
  1259.  
  1260. procedure TDBGridInplaceEdit.UpdateContents;
  1261. var
  1262.   Column: TColumn;
  1263.   NewStyle: TEditStyle;
  1264.   MasterField: TField;
  1265. begin
  1266.   with TDCCustomDBGrid(Grid) do
  1267.   begin
  1268.     if Columns.Count <= SelectedIndex then Exit;
  1269.     Column := Columns[SelectedIndex];
  1270.   end;
  1271.   NewStyle := esSimple;
  1272.   case Column.ButtonStyle of
  1273.    cbsEllipsis: NewStyle := esEllipsis;
  1274.    cbsAuto:
  1275.      if Assigned(Column.Field) then
  1276.      with Column.Field do
  1277.      begin
  1278.        { Show the dropdown button only if the field is editable }
  1279.        if FieldKind = fkLookup then
  1280.        begin
  1281.          MasterField := Dataset.FieldByName(KeyFields);
  1282.          { Column.DefaultReadonly will always be True for a lookup field.
  1283.            Test if Column.ReadOnly has been assigned a value of True }
  1284.          if Assigned(MasterField) and MasterField.CanModify and
  1285.            not ((cvReadOnly in Column.AssignedValues) and Column.ReadOnly) then
  1286.            with TDCCustomDBGrid(Grid) do
  1287.              if not ReadOnly and DataLink.Active and not Datalink.ReadOnly then
  1288.                NewStyle := esDataList
  1289.        end
  1290.        else
  1291.        if Assigned(Column.Picklist) and (Column.PickList.Count > 0) and
  1292.          not Column.Readonly then
  1293.          NewStyle := esPickList
  1294.        else if DataType in [ftDataset, ftReference] then
  1295.          NewStyle := esEllipsis;
  1296.      end;
  1297.   end;
  1298.   EditStyle := NewStyle;
  1299.   inherited UpdateContents;
  1300.   Font.Assign(Column.Font);
  1301. end;
  1302.  
  1303. procedure TDBGridInplaceEdit.CMCancelMode(var Message: TCMCancelMode);
  1304. begin
  1305.   if (Message.Sender <> Self) and (Message.Sender <> FActiveList) then
  1306.     CloseUp(False);
  1307. end;
  1308.  
  1309. procedure TDBGridInplaceEdit.WMCancelMode(var Message: TMessage);
  1310. begin
  1311.   StopTracking;
  1312.   inherited;
  1313. end;
  1314.  
  1315. procedure TDBGridInplaceEdit.WMKillFocus(var Message: TMessage);
  1316.  var
  1317.   ARect: TRect;
  1318. begin
  1319.   if not SysLocale.FarEast then inherited
  1320.   else
  1321.   begin
  1322.     ImeName := Screen.DefaultIme;
  1323.     ImeMode := imDontCare;
  1324.     inherited;
  1325.     if HWND(Message.WParam) <> TDCCustomDBGrid(Grid).Handle then
  1326.       ActivateKeyboardLayout(Screen.DefaultKbLayout, KLF_ACTIVATE);
  1327.   end;
  1328.   CloseUp(False);
  1329.   with TDCCustomDBGrid(Grid) do
  1330.   begin
  1331.     if dgHighlightRow in Options then
  1332.     begin
  1333.       ARect := BoxRectEx(0 , Row , ColCount-1, Row );
  1334.       ValidateRect(Handle, @ARect);
  1335.       InvalidateRect(Handle, @ARect, False);
  1336.     end;
  1337.   end;
  1338. end;
  1339.  
  1340. function TDBGridInplaceEdit.ButtonRect: TRect;
  1341. begin
  1342.   if not TDCCustomDBGrid(Owner).UseRightToLeftAlignment then
  1343.     Result := Rect(Width - FButtonWidth, 0, Width, Height)
  1344.   else
  1345.     Result := Rect(0, 0, FButtonWidth, Height);
  1346. end;
  1347.  
  1348. function TDBGridInplaceEdit.OverButton(const P: TPoint): Boolean;
  1349. begin
  1350.   Result := PtInRect(ButtonRect, P);
  1351. end;
  1352.  
  1353. procedure TDBGridInplaceEdit.WMLButtonDblClk(var Message: TWMLButtonDblClk);
  1354. begin
  1355.   with Message do
  1356.   if (FEditStyle <> esSimple) and OverButton(Point(XPos, YPos)) then
  1357.     Exit;
  1358.   inherited;
  1359. end;
  1360.  
  1361. procedure TDBGridInplaceEdit.WMPaint(var Message: TWMPaint);
  1362. begin
  1363.   PaintHandler(Message);
  1364. end;
  1365.  
  1366. procedure TDBGridInplaceEdit.WMSetCursor(var Message: TWMSetCursor);
  1367. var
  1368.   P: TPoint;
  1369. begin
  1370.   GetCursorPos(P);
  1371.   P := ScreenToClient(P);
  1372.   if (FEditStyle <> esSimple) and OverButton(P) then
  1373.     Windows.SetCursor(LoadCursor(0, idc_Arrow))
  1374.   else
  1375.     inherited;
  1376. end;
  1377.  
  1378. procedure TDBGridInplaceEdit.WndProc(var Message: TMessage);
  1379. begin
  1380.   case Message.Msg of
  1381.     WM_KEYDOWN, WM_SYSKEYDOWN, WM_CHAR:
  1382.       if EditStyle in [esPickList, esDataList] then
  1383.       with TWMKey(Message) do
  1384.       begin
  1385.         DoDropDownKeys(CharCode, KeyDataToShiftState(KeyData));
  1386.         if (CharCode <> 0) and FListVisible then
  1387.         begin
  1388.           with TMessage(Message) do
  1389.             SendMessage(FActiveList.Handle, Msg, WParam, LParam);
  1390.           Exit;
  1391.         end;
  1392.       end
  1393.   end;
  1394.   inherited;
  1395. end;
  1396.  
  1397.  
  1398. { TGridDataLink }
  1399.  
  1400. type
  1401.   TIntArray = array[0..MaxMapSize] of Integer;
  1402.   PIntArray = ^TIntArray;
  1403.  
  1404. constructor TGridDataLink.Create(AGrid: TDCCustomDBGrid);
  1405. begin
  1406.   inherited Create;
  1407.   FGrid := AGrid;
  1408.   VisualControl := True;
  1409. end;
  1410.  
  1411. destructor TGridDataLink.Destroy;
  1412. begin
  1413.   ClearMapping;
  1414.   inherited Destroy;
  1415. end;
  1416.  
  1417. function TGridDataLink.GetDefaultFields: Boolean;
  1418. var
  1419.   I: Integer;
  1420. begin
  1421.   Result := True;
  1422.   if DataSet <> nil then Result := DataSet.DefaultFields;
  1423.   if Result and SparseMap then
  1424.   for I := 0 to FFieldCount-1 do
  1425.     if FFieldMap[I] < 0 then
  1426.     begin
  1427.       Result := False;
  1428.       Exit;
  1429.     end;
  1430. end;
  1431.  
  1432. function TGridDataLink.GetFields(I: Integer): TField;
  1433. begin
  1434.   if (0 <= I) and (I < FFieldCount) and (FFieldMap[I] >= 0) and (FFieldMap[I] < DataSet.FieldList.Count) then
  1435.     Result := DataSet.FieldList[FFieldMap[I]]
  1436.   else
  1437.     Result := nil;
  1438. end;
  1439.  
  1440. function TGridDataLink.AddMapping(const FieldName: string): Boolean;
  1441. var
  1442.   Field: TField;
  1443.   NewSize: Integer;
  1444. begin
  1445.   Result := True;
  1446.   if FFieldCount >= MaxMapSize then RaiseGridError(STooManyColumns);
  1447.   if SparseMap then
  1448.     Field := DataSet.FindField(FieldName)
  1449.   else
  1450.     Field := DataSet.FieldByName(FieldName);
  1451.  
  1452.   if FFieldCount = Length(FFieldMap) then
  1453.   begin
  1454.     NewSize := Length(FFieldMap);
  1455.     if NewSize = 0 then
  1456.       NewSize := 8
  1457.     else
  1458.       Inc(NewSize, NewSize);
  1459.     if (NewSize < FFieldCount) then
  1460.       NewSize := FFieldCount + 1;
  1461.     if (NewSize > MaxMapSize) then
  1462.       NewSize := MaxMapSize;
  1463.     SetLength(FFieldMap, NewSize);
  1464.   end;
  1465.   if Assigned(Field) then
  1466.   begin
  1467.     FFieldMap[FFieldCount] := Dataset.FieldList.IndexOfObject(Field);
  1468.     Field.FreeNotification(FGrid);
  1469.   end
  1470.   else
  1471.     FFieldMap[FFieldCount] := -1;
  1472.   Inc(FFieldCount);
  1473. end;
  1474.  
  1475. procedure TGridDataLink.ActiveChanged;
  1476. begin
  1477.   FGrid.LinkActive(Active);
  1478.   FModified := False;
  1479. end;
  1480.  
  1481. procedure TGridDataLink.ClearMapping;
  1482. begin
  1483.   FFieldMap := nil;
  1484.   FFieldCount := 0;
  1485. end;
  1486.  
  1487. procedure TGridDataLink.Modified;
  1488. begin
  1489.   FModified := True;
  1490. end;
  1491.  
  1492. procedure TGridDataLink.DataSetChanged;
  1493. begin
  1494.   FGrid.DataChanged;
  1495.   FModified := False;
  1496. end;
  1497.  
  1498. procedure TGridDataLink.DataSetScrolled(Distance: Integer);
  1499. begin
  1500.   FGrid.Scroll(Distance);
  1501. end;
  1502.  
  1503. procedure TGridDataLink.LayoutChanged;
  1504. var
  1505.   SaveState: Boolean;
  1506. begin
  1507.   { FLayoutFromDataset determines whether default column width is forced to
  1508.     be at least wide enough for the column title.  }
  1509.   SaveState := FGrid.FLayoutFromDataset;
  1510.   FGrid.FLayoutFromDataset := True;
  1511.   try
  1512.     FGrid.LayoutChanged;
  1513.   finally
  1514.     FGrid.FLayoutFromDataset := SaveState;
  1515.   end;
  1516.   inherited LayoutChanged;
  1517. end;
  1518.  
  1519. procedure TGridDataLink.FocusControl(Field: TFieldRef);
  1520. begin
  1521.   if Assigned(Field) and Assigned(Field^) then
  1522.   begin
  1523.     FGrid.SelectedField := Field^;
  1524.     if (FGrid.SelectedField = Field^) and FGrid.AcquireFocus then
  1525.     begin
  1526.       Field^ := nil;
  1527.       FGrid.ShowEditor;
  1528.     end;
  1529.   end;
  1530. end;
  1531.  
  1532. procedure TGridDataLink.EditingChanged;
  1533. begin
  1534.   FGrid.EditingChanged;
  1535. end;
  1536.  
  1537. procedure TGridDataLink.RecordChanged(Field: TField);
  1538. begin
  1539.   FGrid.RecordChanged(Field);
  1540.   FModified := False;
  1541. end;
  1542.  
  1543. procedure TGridDataLink.UpdateData;
  1544. begin
  1545.   FInUpdateData := True;
  1546.   try
  1547.     if FModified then FGrid.UpdateData;
  1548.     FModified := False;
  1549.   finally
  1550.     FInUpdateData := False;
  1551.   end;
  1552. end;
  1553.  
  1554. function TGridDataLink.GetMappedIndex(ColIndex: Integer): Integer;
  1555. begin
  1556.   if (0 <= ColIndex) and (ColIndex < FFieldCount) then
  1557.     Result := FFieldMap[ColIndex]
  1558.   else
  1559.     Result := -1;
  1560. end;
  1561.  
  1562. procedure TGridDataLink.Reset;
  1563. begin
  1564.   if FModified then RecordChanged(nil) else Dataset.Cancel;
  1565. end;
  1566.  
  1567. function TGridDataLink.IsAggRow(Value: Integer): Boolean;
  1568. begin
  1569.   Result := False;
  1570. end;
  1571.  
  1572. procedure TGridDataLink.BuildAggMap;
  1573. begin
  1574. end;
  1575.  
  1576. { TColumnTitle }
  1577. constructor TColumnTitle.Create(Column: TColumn);
  1578. begin
  1579.   inherited Create;
  1580.   FColumn := Column;
  1581.   FFont := TFont.Create;
  1582.   FFont.Assign(DefaultFont);
  1583.   FFont.OnChange := FontChanged;
  1584. end;
  1585.  
  1586. destructor TColumnTitle.Destroy;
  1587. begin
  1588.   FFont.Free;
  1589.   inherited Destroy;
  1590. end;
  1591.  
  1592. procedure TColumnTitle.Assign(Source: TPersistent);
  1593. begin
  1594.   if Source is TColumnTitle then
  1595.   begin
  1596.     if cvTitleAlignment in TColumnTitle(Source).FColumn.FAssignedValues then
  1597.       Alignment := TColumnTitle(Source).Alignment;
  1598.     if cvTitleColor in TColumnTitle(Source).FColumn.FAssignedValues then
  1599.       Color := TColumnTitle(Source).Color;
  1600.     if cvTitleCaption in TColumnTitle(Source).FColumn.FAssignedValues then
  1601.       Caption := TColumnTitle(Source).Caption;
  1602.     if cvTitleFont in TColumnTitle(Source).FColumn.FAssignedValues then
  1603.       Font := TColumnTitle(Source).Font;
  1604.   end
  1605.   else
  1606.     inherited Assign(Source);
  1607. end;
  1608.  
  1609. function TColumnTitle.DefaultAlignment: TAlignment;
  1610. begin
  1611.   Result := taLeftJustify;
  1612. end;
  1613.  
  1614. function TColumnTitle.DefaultColor: TColor;
  1615. var
  1616.   Grid: TDCCustomDBGrid;
  1617. begin
  1618.   Grid := FColumn.GetGrid;
  1619.   if Assigned(Grid) then
  1620.     Result := Grid.FixedColor
  1621.   else
  1622.     Result := clBtnFace;
  1623. end;
  1624.  
  1625. function TColumnTitle.DefaultFont: TFont;
  1626. var
  1627.   Grid: TDCCustomDBGrid;
  1628. begin
  1629.   Grid := FColumn.GetGrid;
  1630.   if Assigned(Grid) then
  1631.     Result := Grid.TitleFont
  1632.   else
  1633.     Result := FColumn.Font;
  1634. end;
  1635.  
  1636. function TColumnTitle.DefaultCaption: string;
  1637. var
  1638.   Field: TField;
  1639. begin
  1640.   Field := FColumn.Field;
  1641.   if Assigned(Field) then
  1642.     Result := Field.DisplayName
  1643.   else
  1644.     Result := FColumn.FieldName;
  1645. end;
  1646.  
  1647. procedure TColumnTitle.FontChanged(Sender: TObject);
  1648. begin
  1649.   Include(FColumn.FAssignedValues, cvTitleFont);
  1650.   FColumn.Changed(True);
  1651. end;
  1652.  
  1653. function TColumnTitle.GetAlignment: TAlignment;
  1654. begin
  1655.   if cvTitleAlignment in FColumn.FAssignedValues then
  1656.     Result := FAlignment
  1657.   else
  1658.     Result := DefaultAlignment;
  1659. end;
  1660.  
  1661. function TColumnTitle.GetColor: TColor;
  1662. begin
  1663.   if cvTitleColor in FColumn.FAssignedValues then
  1664.     Result := FColor
  1665.   else
  1666.     Result := DefaultColor;
  1667. end;
  1668.  
  1669. function TColumnTitle.GetCaption: string;
  1670. begin
  1671.   if cvTitleCaption in FColumn.FAssignedValues then
  1672.     Result := FCaption
  1673.   else
  1674.     Result := DefaultCaption;
  1675. end;
  1676.  
  1677. function TColumnTitle.GetFont: TFont;
  1678. var
  1679.   Save: TNotifyEvent;
  1680.   Def: TFont;
  1681. begin
  1682.   if not (cvTitleFont in FColumn.FAssignedValues) then
  1683.   begin
  1684.     Def := DefaultFont;
  1685.     if (FFont.Handle <> Def.Handle) or (FFont.Color <> Def.Color) then
  1686.     begin
  1687.       Save := FFont.OnChange;
  1688.       FFont.OnChange := nil;
  1689.       FFont.Assign(DefaultFont);
  1690.       FFont.OnChange := Save;
  1691.     end;
  1692.   end;
  1693.   Result := FFont;
  1694. end;
  1695.  
  1696. function TColumnTitle.IsAlignmentStored: Boolean;
  1697. begin
  1698.   Result := (cvTitleAlignment in FColumn.FAssignedValues) and
  1699.     (FAlignment <> DefaultAlignment);
  1700. end;
  1701.  
  1702. function TColumnTitle.IsColorStored: Boolean;
  1703. begin
  1704.   Result := (cvTitleColor in FColumn.FAssignedValues) and
  1705.     (FColor <> DefaultColor);
  1706. end;
  1707.  
  1708. function TColumnTitle.IsFontStored: Boolean;
  1709. begin
  1710.   Result := (cvTitleFont in FColumn.FAssignedValues);
  1711. end;
  1712.  
  1713. function TColumnTitle.IsCaptionStored: Boolean;
  1714. begin
  1715.   Result := (cvTitleCaption in FColumn.FAssignedValues) and
  1716.     (FCaption <> DefaultCaption);
  1717. end;
  1718.  
  1719. procedure TColumnTitle.RefreshDefaultFont;
  1720. var
  1721.   Save: TNotifyEvent;
  1722. begin
  1723.   if (cvTitleFont in FColumn.FAssignedValues) then Exit;
  1724.   Save := FFont.OnChange;
  1725.   FFont.OnChange := nil;
  1726.   try
  1727.     FFont.Assign(DefaultFont);
  1728.   finally
  1729.     FFont.OnChange := Save;
  1730.   end;
  1731. end;
  1732.  
  1733. procedure TColumnTitle.RestoreDefaults;
  1734. var
  1735.   FontAssigned: Boolean;
  1736. begin
  1737.   FontAssigned := cvTitleFont in FColumn.FAssignedValues;
  1738.   FColumn.FAssignedValues := FColumn.FAssignedValues - ColumnTitleValues;
  1739.   FCaption := '';
  1740.   RefreshDefaultFont;
  1741.   { If font was assigned, changing it back to default may affect grid title
  1742.     height, and title height changes require layout and redraw of the grid. }
  1743.   FColumn.Changed(FontAssigned);
  1744. end;
  1745.  
  1746. procedure TColumnTitle.SetAlignment(Value: TAlignment);
  1747. begin
  1748.   if (cvTitleAlignment in FColumn.FAssignedValues) and (Value = FAlignment) then Exit;
  1749.   FAlignment := Value;
  1750.   Include(FColumn.FAssignedValues, cvTitleAlignment);
  1751.   FColumn.Changed(False);
  1752. end;
  1753.  
  1754. procedure TColumnTitle.SetColor(Value: TColor);
  1755. begin
  1756.   if (cvTitleColor in FColumn.FAssignedValues) and (Value = FColor) then Exit;
  1757.   FColor := Value;
  1758.   Include(FColumn.FAssignedValues, cvTitleColor);
  1759.   FColumn.Changed(False);
  1760. end;
  1761.  
  1762. procedure TColumnTitle.SetFont(Value: TFont);
  1763. begin
  1764.   FFont.Assign(Value);
  1765. end;
  1766.  
  1767. procedure TColumnTitle.SetCaption(const Value: string);
  1768. var
  1769.   Grid: TDCCustomDBGrid;
  1770. begin
  1771.   Grid := Column.GetGrid;
  1772.   if Column.IsStored then
  1773.   begin
  1774.     if (cvTitleCaption in FColumn.FAssignedValues) and (Value = FCaption) then Exit;
  1775.     FCaption := Value;
  1776.     Include(Column.FAssignedValues, cvTitleCaption);
  1777.     Column.Changed(False);
  1778.   end
  1779.   else
  1780.   begin
  1781.     if Assigned(Grid) and (Grid.Datalink.Active) and Assigned(Column.Field) then
  1782.       Column.Field.DisplayLabel := Value;
  1783.   end;
  1784.   if Assigned(Grid) and (Grid.LayoutLock = 0) then Grid.InternalLayout;
  1785. end;
  1786.  
  1787. { TColumn }
  1788.  
  1789. constructor TColumn.Create(Collection: TCollection);
  1790. var
  1791.   Grid: TDCCustomDBGrid;
  1792. begin
  1793.   Grid := nil;
  1794.   if Assigned(Collection) and (Collection is TDBGridColumns) then
  1795.     Grid := TDBGridColumns(Collection).Grid;
  1796.   if Assigned(Grid) then Grid.BeginLayout;
  1797.   try
  1798.     inherited Create(Collection);
  1799.     FDropDownRows := 7;
  1800.     FButtonStyle := cbsAuto;
  1801.     FFont := TFont.Create;
  1802.     FFont.Assign(DefaultFont);
  1803.     FFont.OnChange := FontChanged;
  1804.     FImeMode := imDontCare;
  1805.     FImeName := Screen.DefaultIme;
  1806.     FTitle := CreateTitle;
  1807.     FVisible := True;
  1808.     FExpanded := True;
  1809.     FStored := True;
  1810.     FItemIndex := -1;
  1811.     FTag := 0;
  1812.     FResize  := True;
  1813.     FComment := '';
  1814.     FWordBreak := False;
  1815.   finally
  1816.     if Assigned(Grid) then Grid.EndLayout;
  1817.   end;
  1818. end;
  1819.  
  1820. destructor TColumn.Destroy;
  1821. begin
  1822.   FTitle.Free;
  1823.   FFont.Free;
  1824.   FPickList.Free;
  1825.   inherited Destroy;
  1826. end;
  1827.  
  1828. procedure TColumn.Assign(Source: TPersistent);
  1829. begin
  1830.   if Source is TColumn then
  1831.   begin
  1832.     if Assigned(Collection) then Collection.BeginUpdate;
  1833.     try
  1834.       RestoreDefaults;
  1835.       FieldName := TColumn(Source).FieldName;
  1836.       if cvColor in TColumn(Source).AssignedValues then
  1837.         Color := TColumn(Source).Color;
  1838.       if cvWidth in TColumn(Source).AssignedValues then
  1839.       begin
  1840.         FWidth := TColumn(Source).FWidth;
  1841.         FAssignedValues := FAssignedValues + [cvWidth];
  1842.       end;
  1843.       if cvFont in TColumn(Source).AssignedValues then
  1844.         Font := TColumn(Source).Font;
  1845.       if cvImeMode in TColumn(Source).AssignedValues then
  1846.         ImeMode := TColumn(Source).ImeMode;
  1847.       if cvImeName in TColumn(Source).AssignedValues then
  1848.         ImeName := TColumn(Source).ImeName;
  1849.       if cvAlignment in TColumn(Source).AssignedValues then
  1850.         Alignment := TColumn(Source).Alignment;
  1851.       if cvReadOnly in TColumn(Source).AssignedValues then
  1852.         ReadOnly := TColumn(Source).ReadOnly;
  1853.       Title := TColumn(Source).Title;
  1854.       DropDownRows   := TColumn(Source).DropDownRows;
  1855.       ButtonStyle    := TColumn(Source).ButtonStyle;
  1856.       PickList       := TColumn(Source).PickList;
  1857.       PopupMenu      := TColumn(Source).PopupMenu;
  1858.       FVisible       := TColumn(Source).FVisible;
  1859.       FExpanded      := TColumn(Source).FExpanded;
  1860.       FItemIndex     := TColumn(Source).FItemIndex;
  1861.       FIndexed       := TColumn(Source).FIndexed;
  1862.       FIndexStyle    := TColumn(Source).FIndexStyle;
  1863.       FDisplayFormat := TColumn(Source).FDisplayFormat;
  1864.       FTag           := TColumn(Source).FTag;
  1865.       FResize        := TColumn(Source).FResize;
  1866.       FComment       := TColumn(Source).FComment;
  1867.       FWordBreak     := TColumn(Source).FWordBreak;
  1868.     finally
  1869.       if Assigned(Collection) then Collection.EndUpdate;
  1870.     end;
  1871.   end
  1872.   else
  1873.     inherited Assign(Source);
  1874. end;
  1875.  
  1876. function TColumn.CreateTitle: TColumnTitle;
  1877. begin
  1878.   Result := TColumnTitle.Create(Self);
  1879. end;
  1880.  
  1881. function TColumn.DefaultAlignment: TAlignment;
  1882. begin
  1883.   if Assigned(Field) then
  1884.     Result := FField.Alignment
  1885.   else
  1886.     Result := taLeftJustify;
  1887. end;
  1888.  
  1889. function TColumn.DefaultColor: TColor;
  1890. var
  1891.   Grid: TDCCustomDBGrid;
  1892. begin
  1893.   Grid := GetGrid;
  1894.   if Assigned(Grid) then
  1895.     Result := Grid.Color
  1896.   else
  1897.     Result := clWindow;
  1898. end;
  1899.  
  1900. function TColumn.DefaultFont: TFont;
  1901. var
  1902.   Grid: TDCCustomDBGrid;
  1903. begin
  1904.   Grid := GetGrid;
  1905.   if Assigned(Grid) then
  1906.     Result := Grid.Font
  1907.   else
  1908.     Result := FFont;
  1909. end;
  1910.  
  1911. function TColumn.DefaultImeMode: TImeMode;
  1912. var
  1913.   Grid: TDCCustomDBGrid;
  1914. begin
  1915.   Grid := GetGrid;
  1916.   if Assigned(Grid) then
  1917.     Result := Grid.ImeMode
  1918.   else
  1919.     Result := FImeMode;
  1920. end;
  1921.  
  1922. function TColumn.DefaultImeName: TImeName;
  1923. var
  1924.   Grid: TDCCustomDBGrid;
  1925. begin
  1926.   Grid := GetGrid;
  1927.   if Assigned(Grid) then
  1928.     Result := Grid.ImeName
  1929.   else
  1930.     Result := FImeName;
  1931. end;
  1932.  
  1933. function TColumn.DefaultReadOnly: Boolean;
  1934.  var
  1935.   Grid: TDCCustomDBGrid;
  1936. begin
  1937.   Grid := GetGrid;
  1938.   Result := (Assigned(Grid) and Grid.ReadOnly) or
  1939.     (Assigned(Field) and FField.ReadOnly);
  1940. end;
  1941.  
  1942. function TColumn.DefaultWidth: Integer;
  1943.  var
  1944.   W: Integer;
  1945.   RestoreCanvas: Boolean;
  1946.   TM: TTextMetric;
  1947.   BitmapsOffset: Integer;
  1948. begin
  1949.   if GetGrid = nil then
  1950.   begin
  1951.     Result := 64;
  1952.     Exit;
  1953.   end;
  1954.   with GetGrid do
  1955.   begin
  1956.     if Assigned(Field) then
  1957.     begin
  1958.       RestoreCanvas := not HandleAllocated or not GetTextMetrics(Canvas.Handle, TM);
  1959.       if RestoreCanvas then Canvas.Handle := GetDC(0);
  1960.       try
  1961.         Canvas.Font := Self.Font;
  1962.         GetTextMetrics(Canvas.Handle, TM);
  1963.         Result := Field.DisplayWidth * (Canvas.TextWidth('0') - TM.tmOverhang)
  1964.           + TM.tmOverhang + 4;
  1965.         if dgTitles in Options then
  1966.         begin
  1967.           Canvas.Font := Title.Font;
  1968.           if (Grid <> nil) and (dgTitleClicked in Grid.Options) and FIndexed
  1969.           then BitmapsOffset := IndexTitleWidth  else BitmapsOffset := 0;
  1970.  
  1971.           if (Grid.Images <> nil) and (FItemIndex <> -1)
  1972.           then Inc(BitmapsOffset,Grid.Images.Width+2);
  1973.  
  1974.           W := GetTextWidthEx(Canvas, Title.Caption) +
  1975.                4 + BitmapsOffset+ TM.tmOverhang + 4;
  1976.           if Result < W then
  1977.             Result := W;
  1978.         end;
  1979.       finally
  1980.         if RestoreCanvas then
  1981.         begin
  1982.           ReleaseDC(0, Canvas.Handle);
  1983.           Canvas.Handle := 0;
  1984.         end;
  1985.       end;
  1986.     end
  1987.     else
  1988.       Result := DefaultColWidth;
  1989.   end;
  1990. end;
  1991.  
  1992. procedure TColumn.FontChanged;
  1993. begin
  1994.   Include(FAssignedValues, cvFont);
  1995.   Title.RefreshDefaultFont;
  1996.   Changed(False);
  1997. end;
  1998.  
  1999. function TColumn.GetAlignment: TAlignment;
  2000. begin
  2001.   if cvAlignment in FAssignedValues then
  2002.     Result := FAlignment
  2003.   else
  2004.     Result := DefaultAlignment;
  2005. end;
  2006.  
  2007. function TColumn.GetColor: TColor;
  2008. begin
  2009.   if cvColor in FAssignedValues then
  2010.     Result := FColor
  2011.   else
  2012.     Result := DefaultColor;
  2013. end;
  2014.  
  2015. function TColumn.GetExpanded: Boolean;
  2016. begin
  2017.   Result := FExpanded and Expandable;
  2018. end;
  2019.  
  2020. function TColumn.GetField: TField;
  2021. var
  2022.   Grid: TDCCustomDBGrid;
  2023. begin    { Returns Nil if FieldName can't be found in dataset }
  2024.   Grid := GetGrid;
  2025.   if (FField = nil) and (Length(FFieldName) > 0) and Assigned(Grid) and
  2026.     Assigned(Grid.DataLink.DataSet) then
  2027.   with Grid.Datalink.Dataset do
  2028.     if Active or (not DefaultFields) then
  2029.       SetField(FindField(FieldName));
  2030.   Result := FField;
  2031. end;
  2032.  
  2033. function TColumn.GetFont: TFont;
  2034. var
  2035.   Save: TNotifyEvent;
  2036. begin
  2037.   if not (cvFont in FAssignedValues) and (FFont.Handle <> DefaultFont.Handle) then
  2038.   begin
  2039.     Save := FFont.OnChange;
  2040.     FFont.OnChange := nil;
  2041.     FFont.Assign(DefaultFont);
  2042.     FFont.OnChange := Save;
  2043.   end;
  2044.   Result := FFont;
  2045. end;
  2046.  
  2047. function TColumn.GetGrid: TDCCustomDBGrid;
  2048. begin
  2049.   if Assigned(Collection) and (Collection is TDBGridColumns) then
  2050.     Result := TDBGridColumns(Collection).Grid
  2051.   else
  2052.     Result := nil;
  2053. end;
  2054.  
  2055. function TColumn.GetDisplayName: string;
  2056. begin
  2057.   Result := FFieldName;
  2058.   if Result = '' then Result := inherited GetDisplayName;
  2059. end;
  2060.  
  2061. function TColumn.GetImeMode: TImeMode;
  2062. begin
  2063.   if cvImeMode in FAssignedValues then
  2064.     Result := FImeMode
  2065.   else
  2066.     Result := DefaultImeMode;
  2067. end;
  2068.  
  2069. function TColumn.GetImeName: TImeName;
  2070. begin
  2071.   if cvImeName in FAssignedValues then
  2072.     Result := FImeName
  2073.   else
  2074.     Result := DefaultImeName;
  2075. end;
  2076.  
  2077. function TColumn.GetParentColumn: TColumn;
  2078. var
  2079.   Col: TColumn;
  2080.   Fld: TField;
  2081.   I: Integer;
  2082. begin
  2083.   Result := nil;
  2084.   Fld := Field;
  2085.   if (Fld <> nil) and (Fld.ParentField <> nil) and (Collection <> nil) then
  2086.     for I := Index - 1 downto 0 do
  2087.     begin
  2088.       Col := TColumn(Collection.Items[I]);
  2089.       if Fld.ParentField = Col.Field then
  2090.       begin
  2091.         Result := Col;
  2092.         Exit;
  2093.       end;
  2094.     end;
  2095. end;
  2096.  
  2097. function TColumn.GetPickList: TStrings;
  2098. begin
  2099.   if FPickList = nil then
  2100.     FPickList := TStringList.Create;
  2101.   Result := FPickList;
  2102. end;
  2103.  
  2104. function TColumn.GetReadOnly: Boolean;
  2105. begin
  2106.   if cvReadOnly in FAssignedValues then
  2107.     Result := FReadOnly
  2108.   else
  2109.     Result := DefaultReadOnly;
  2110. end;
  2111.  
  2112. function TColumn.GetShowing: Boolean;
  2113. var
  2114.   Col: TColumn;
  2115. begin
  2116.   Result := not Expanded and Visible;
  2117.   if Result then
  2118.   begin
  2119.     Col := Self;
  2120.     repeat
  2121.       Col := Col.ParentColumn;
  2122.     until (Col = nil) or not Col.Expanded;
  2123.     Result := Col = nil;
  2124.   end;
  2125. end;
  2126.  
  2127. function TColumn.GetVisible: Boolean;
  2128. var
  2129.   Col: TColumn;
  2130. begin
  2131.   Result := FVisible;
  2132.   if Result then
  2133.   begin
  2134.     Col := ParentColumn;
  2135.     Result := Result and ((Col = nil) or Col.Visible);
  2136.   end;
  2137. end;
  2138.  
  2139. function TColumn.GetWidth: Integer;
  2140. begin
  2141.   if not( Showing or
  2142.       ((Grid <> nil) and (csWriting in Grid.ComponentState) )) then
  2143.   begin
  2144.     if (Grid <> nil) and not (dgColLines in Grid.Options) then
  2145.       Result := 0
  2146.     else
  2147.       Result := -1
  2148.   end
  2149.   else if cvWidth in FAssignedValues then
  2150.     Result := FWidth
  2151.   else
  2152.     Result := DefaultWidth;
  2153. end;
  2154.  
  2155. function TColumn.IsAlignmentStored: Boolean;
  2156. begin
  2157.   Result := (cvAlignment in FAssignedValues) and (FAlignment <> DefaultAlignment);
  2158. end;
  2159.  
  2160. function TColumn.IsColorStored: Boolean;
  2161. begin
  2162.   Result := (cvColor in FAssignedValues) and (FColor <> DefaultColor);
  2163. end;
  2164.  
  2165. function TColumn.IsFontStored: Boolean;
  2166. begin
  2167.   Result := (cvFont in FAssignedValues);
  2168. end;
  2169.  
  2170. function TColumn.IsImeModeStored: Boolean;
  2171. begin
  2172.   Result := (cvImeMode in FAssignedValues) and (FImeMode <> DefaultImeMode);
  2173. end;
  2174.  
  2175. function TColumn.IsImeNameStored: Boolean;
  2176. begin
  2177.   Result := (cvImeName in FAssignedValues) and (FImeName <> DefaultImeName);
  2178. end;
  2179.  
  2180. function TColumn.IsReadOnlyStored: Boolean;
  2181. begin
  2182.   Result := (cvReadOnly in FAssignedValues) and (FReadOnly <> DefaultReadOnly);
  2183. end;
  2184.  
  2185. function TColumn.IsWidthStored: Boolean;
  2186. begin
  2187.   Result := (cvWidth in FAssignedValues) and (FWidth <> DefaultWidth);
  2188. end;
  2189.  
  2190. procedure TColumn.RefreshDefaultFont;
  2191. var
  2192.   Save: TNotifyEvent;
  2193. begin
  2194.   if cvFont in FAssignedValues then Exit;
  2195.   Save := FFont.OnChange;
  2196.   FFont.OnChange := nil;
  2197.   try
  2198.     FFont.Assign(DefaultFont);
  2199.   finally
  2200.     FFont.OnChange := Save;
  2201.   end;
  2202. end;
  2203.  
  2204. procedure TColumn.RestoreDefaults;
  2205. var
  2206.   FontAssigned: Boolean;
  2207. begin
  2208.   FontAssigned := cvFont in FAssignedValues;
  2209.   FTitle.RestoreDefaults;
  2210.   FAssignedValues := [];
  2211.   RefreshDefaultFont;
  2212.   FPickList.Free;
  2213.   FPickList := nil;
  2214.   ButtonStyle := cbsAuto;
  2215.   Changed(FontAssigned);
  2216. end;
  2217.  
  2218. procedure TColumn.SetAlignment(Value: TAlignment);
  2219. var
  2220.   Grid: TDCCustomDBGrid;
  2221. begin
  2222.   if IsStored then
  2223.   begin
  2224.     if (cvAlignment in FAssignedValues) and (Value = FAlignment) then Exit;
  2225.     FAlignment := Value;
  2226.     Include(FAssignedValues, cvAlignment);
  2227.     Changed(False);
  2228.   end
  2229.   else
  2230.   begin
  2231.     Grid := GetGrid;
  2232.     if Assigned(Grid) and (Grid.Datalink.Active) and Assigned(Field) then
  2233.       Field.Alignment := Value;
  2234.   end;
  2235. end;
  2236.  
  2237. procedure TColumn.SetButtonStyle(Value: TColumnButtonStyle);
  2238. begin
  2239.   if Value = FButtonStyle then Exit;
  2240.   FButtonStyle := Value;
  2241.   Changed(False);
  2242. end;
  2243.  
  2244. procedure TColumn.SetColor(Value: TColor);
  2245. begin
  2246.   if (cvColor in FAssignedValues) and (Value = FColor) then Exit;
  2247.   FColor := Value;
  2248.   Include(FAssignedValues, cvColor);
  2249.   Changed(False);
  2250. end;
  2251.  
  2252. procedure TColumn.SetField(Value: TField);
  2253. begin
  2254.   if FField = Value then Exit;
  2255.   FField := Value;
  2256.   if Assigned(Value) then
  2257.     FFieldName := Value.FullName;
  2258.   if not IsStored then
  2259.   begin
  2260.     if Value = nil then
  2261.       FFieldName := '';
  2262.     RestoreDefaults;
  2263.   end;
  2264.   Changed(False);
  2265. end;
  2266.  
  2267. procedure TColumn.SetFieldName(const Value: String);
  2268. var
  2269.   AField: TField;
  2270.   Grid: TDCCustomDBGrid;
  2271. begin
  2272.   AField := nil;
  2273.   Grid := GetGrid;
  2274.   if Assigned(Grid) and Assigned(Grid.DataLink.DataSet) and
  2275.     not (csLoading in Grid.ComponentState) and (Length(Value) > 0) then
  2276.       AField := Grid.DataLink.DataSet.FindField(Value); { no exceptions }
  2277.   FFieldName := Value;
  2278.   SetField(AField);
  2279.   Changed(False);
  2280. end;
  2281.  
  2282. procedure TColumn.SetFont(Value: TFont);
  2283. begin
  2284.   FFont.Assign(Value);
  2285.   Include(FAssignedValues, cvFont);
  2286.   Changed(False);
  2287. end;
  2288.  
  2289. procedure TColumn.SetImeMode(Value: TImeMode);
  2290. begin
  2291.   if (cvImeMode in FAssignedValues) or (Value <> DefaultImeMode) then
  2292.   begin
  2293.     FImeMode := Value;
  2294.     Include(FAssignedValues, cvImeMode);
  2295.   end;
  2296.   Changed(False);
  2297. end;
  2298.  
  2299. procedure TColumn.SetImeName(Value: TImeName);
  2300. begin
  2301.   if (cvImeName in FAssignedValues) or (Value <> DefaultImeName) then
  2302.   begin
  2303.     FImeName := Value;
  2304.     Include(FAssignedValues, cvImeName);
  2305.   end;
  2306.   Changed(False);
  2307. end;
  2308.  
  2309. procedure TColumn.SetIndex(Value: Integer);
  2310. var
  2311.   Grid: TDCCustomDBGrid;
  2312.   Fld: TField;
  2313.   I, OldIndex: Integer;
  2314.   Col: TColumn;
  2315. begin
  2316.   OldIndex := Index;
  2317.   Grid := GetGrid;
  2318.  
  2319.   if IsStored then
  2320.   begin
  2321.     Grid.BeginLayout;
  2322.     try
  2323.       I := OldIndex + 1;  // move child columns along with parent
  2324.       while (I < Collection.Count) and (TColumn(Collection.Items[I]).ParentColumn = Self) do
  2325.         Inc(I);
  2326.       Dec(I);
  2327.       if OldIndex > Value then   // column moving left
  2328.       begin
  2329.         while I > OldIndex do
  2330.         begin
  2331.           Collection.Items[I].Index := Value;
  2332.           Inc(OldIndex);
  2333.         end;
  2334.         inherited SetIndex(Value);
  2335.       end
  2336.       else
  2337.       begin
  2338.         inherited SetIndex(Value);
  2339.         while I > OldIndex do
  2340.         begin
  2341.           Collection.Items[OldIndex].Index := Value;
  2342.           Dec(I);
  2343.         end;
  2344.       end;
  2345.     finally
  2346.       Grid.EndLayout;
  2347.     end;
  2348.   end
  2349.   else
  2350.   begin
  2351.     if (Grid <> nil) and Grid.Datalink.Active then
  2352.     begin
  2353.       if Grid.AcquireLayoutLock then
  2354.       try
  2355.         Col := Grid.ColumnAtDepth(Grid.Columns[Value], Depth);
  2356.         if (Col <> nil) then
  2357.         begin
  2358.           Fld := Col.Field;
  2359.           if Assigned(Fld) then
  2360.             Field.Index := Fld.Index;
  2361.         end;
  2362.       finally
  2363.         Grid.EndLayout;
  2364.       end;
  2365.     end;
  2366.     inherited SetIndex(Value);
  2367.   end;
  2368. end;
  2369.  
  2370. procedure TColumn.SetPickList(Value: TStrings);
  2371. begin
  2372.   if Value = nil then
  2373.   begin
  2374.     FPickList.Free;
  2375.     FPickList := nil;
  2376.     Exit;
  2377.   end;
  2378.   PickList.Assign(Value);
  2379. end;
  2380.  
  2381. procedure TColumn.SetPopupMenu(Value: TPopupMenu);
  2382. begin
  2383.   FPopupMenu := Value;
  2384.   if Value <> nil then Value.FreeNotification(GetGrid);
  2385. end;
  2386.  
  2387. procedure TColumn.SetReadOnly(Value: Boolean);
  2388. var
  2389.   Grid: TDCCustomDBGrid;
  2390. begin
  2391.   Grid := GetGrid;
  2392.   if not IsStored and Assigned(Grid) and Grid.Datalink.Active and Assigned(Field) then
  2393.     Field.ReadOnly := Value
  2394.   else
  2395.   begin
  2396.     if (cvReadOnly in FAssignedValues) and (Value = FReadOnly) then Exit;
  2397.     FReadOnly := Value;
  2398.     Include(FAssignedValues, cvReadOnly);
  2399.     Changed(False);
  2400.   end;
  2401. end;
  2402.  
  2403. procedure TColumn.SetTitle(Value: TColumnTitle);
  2404. begin
  2405.   FTitle.Assign(Value);
  2406. end;
  2407.  
  2408. procedure TColumn.SetWidth(Value: Integer);
  2409. var
  2410.   Grid: TDCCustomDBGrid;
  2411.   TM: TTextMetric;
  2412.   DoSetWidth: Boolean;
  2413. begin
  2414.   DoSetWidth := IsStored;
  2415.   if not DoSetWidth then
  2416.   begin
  2417.     Grid := GetGrid;
  2418.     if Assigned(Grid) then
  2419.     begin
  2420.       if Grid.HandleAllocated and Assigned(Field) and Grid.FUpdateFields then
  2421.       with Grid do
  2422.       begin
  2423.         Canvas.Font := Self.Font;
  2424.         GetTextMetrics(Canvas.Handle, TM);
  2425.         Field.DisplayWidth := (Value + (TM.tmAveCharWidth div 2) - TM.tmOverhang - 3)
  2426.           div TM.tmAveCharWidth;
  2427.       end;
  2428.       if (not Grid.FLayoutFromDataset) or (cvWidth in FAssignedValues) then
  2429.         DoSetWidth := True;
  2430.     end
  2431.     else
  2432.       DoSetWidth := True;
  2433.   end;
  2434.   if DoSetWidth then
  2435.   begin
  2436.     if ((cvWidth in FAssignedValues) or (Value <> DefaultWidth))
  2437.       and (Value <> -1) and (Value <> 0) then
  2438.     begin
  2439.       FWidth := Value;
  2440.       Include(FAssignedValues, cvWidth);
  2441.     end;
  2442.     Changed(False);
  2443.   end;
  2444. end;
  2445.  
  2446. procedure TColumn.SetVisible(Value: Boolean);
  2447. begin
  2448.   if Value <> FVisible then
  2449.   begin
  2450.     FVisible := Value;
  2451.     Width    := Width;
  2452. //    Changed(True);
  2453.   end;
  2454. end;
  2455.  
  2456. procedure TColumn.SetExpanded(Value: Boolean);
  2457. const
  2458.   Direction: array [Boolean] of ShortInt = (-1,1);
  2459. var
  2460.   Grid: TDCCustomDBGrid;
  2461.   WasShowing: Boolean;
  2462. begin
  2463.   if Value <> FExpanded then
  2464.   begin
  2465.     Grid := GetGrid;
  2466.     WasShowing := (Grid <> nil) and Grid.Columns[Grid.SelectedIndex].Showing;
  2467.     FExpanded := Value;
  2468.     Changed(True);
  2469.     if (Grid <> nil) and WasShowing then
  2470.     begin
  2471.       if not Grid.Columns[Grid.SelectedIndex].Showing then
  2472.         // The selected cell was hidden by this expand operation
  2473.         // Select 1st child (next col = 1) when parent is expanded
  2474.         // Select child's parent (prev col = -1) when parent is collapsed
  2475.         Grid.MoveCol(Grid.Col, Direction[FExpanded]);
  2476.     end;
  2477.   end;
  2478. end;
  2479.  
  2480. function TColumn.Depth: Integer;
  2481. var
  2482.   Col: TColumn;
  2483. begin
  2484.   Result := 0;
  2485.   Col := ParentColumn;
  2486.   if Col <> nil then Result := Col.Depth + 1;
  2487. end;
  2488.  
  2489. function TColumn.GetExpandable: Boolean;
  2490. var
  2491.   Fld: TField;
  2492. begin
  2493.   Fld := Field;
  2494.   Result := (Fld <> nil) and (Fld.DataType in [ftADT, ftArray]);
  2495. end;
  2496.  
  2497. procedure TColumn.SetIndexed(Value: Boolean);
  2498. begin
  2499.   if Value = FIndexed then Exit;
  2500.   FIndexed := Value;
  2501.   Changed(False);
  2502. end;
  2503.  
  2504. procedure TColumn.SetItemIndex(Value: Integer);
  2505. begin
  2506.   if Value <> FItemIndex then
  2507.   begin
  2508.     FItemIndex := Value;
  2509.     Changed(False);
  2510.   end;
  2511. end;
  2512.  
  2513.  
  2514. procedure TColumn.SetIndexStyle(const Value: TColumnIndexStyle);
  2515. begin
  2516.   if Value <> FIndexStyle then
  2517.   begin
  2518.     FIndexStyle := Value;
  2519.     Changed(False);
  2520.   end;
  2521. end;
  2522.  
  2523. procedure TColumn.SetDisplayFormat(const Value: string);
  2524. begin
  2525.   if Value <> FDisplayFormat then
  2526.   begin
  2527.     FDisplayFormat := Value;
  2528.     Changed(False);
  2529.   end;
  2530. end;
  2531.  
  2532. procedure TColumn.SetComment(const Value: string);
  2533. begin
  2534.   FComment := Value;
  2535. end;
  2536.  
  2537. procedure TColumn.SetWordBreak(const Value: boolean);
  2538. begin
  2539.   if Value <> FWordBreak then
  2540.   begin
  2541.     FWordBreak := Value;
  2542.     Changed(False);
  2543.   end;
  2544. end;
  2545.  
  2546. { TDBGridColumns }
  2547.  
  2548. constructor TDBGridColumns.Create(Grid: TDCCustomDBGrid; ColumnClass: TColumnClass);
  2549. begin
  2550.   inherited Create(ColumnClass);
  2551.   FGrid := Grid;
  2552. end;
  2553.  
  2554. function TDBGridColumns.Add: TColumn;
  2555. begin
  2556.   Result := TColumn(inherited Add);
  2557. end;
  2558.  
  2559. function TDBGridColumns.GetColumn(Index: Integer): TColumn;
  2560. begin
  2561.   Result := TColumn(inherited Items[Index]);
  2562. end;
  2563.  
  2564. function TDBGridColumns.GetOwner: TPersistent;
  2565. begin
  2566.   Result := FGrid;
  2567. end;
  2568.  
  2569. procedure TDBGridColumns.LoadFromFile(const Filename: string);
  2570. var
  2571.   S: TFileStream;
  2572. begin
  2573.   S := TFileStream.Create(Filename, fmOpenRead);
  2574.   try
  2575.     LoadFromStream(S);
  2576.   finally
  2577.     S.Free;
  2578.   end;
  2579. end;
  2580.  
  2581. type
  2582.   TColumnsWrapper = class(TComponent)
  2583.   private
  2584.     FColumns: TDBGridColumns;
  2585.   published
  2586.     property Columns: TDBGridColumns read FColumns write FColumns;
  2587.   end;
  2588.  
  2589. procedure TDBGridColumns.LoadFromStream(S: TStream);
  2590. var
  2591.   Wrapper: TColumnsWrapper;
  2592. begin
  2593.   Wrapper := TColumnsWrapper.Create(nil);
  2594.   try
  2595.     Wrapper.Columns := FGrid.CreateColumns;
  2596.     S.ReadComponent(Wrapper);
  2597.     Assign(Wrapper.Columns);
  2598.   finally
  2599.     Wrapper.Columns.Free;
  2600.     Wrapper.Free;
  2601.   end;
  2602. end;
  2603.  
  2604. procedure TDBGridColumns.RestoreDefaults;
  2605. var
  2606.   I: Integer;
  2607. begin
  2608.   BeginUpdate;
  2609.   try
  2610.     for I := 0 to Count-1 do
  2611.       Items[I].RestoreDefaults;
  2612.   finally
  2613.     EndUpdate;
  2614.   end;
  2615. end;
  2616.  
  2617. procedure TDBGridColumns.RebuildColumns;
  2618.  
  2619.   procedure AddFields(Fields: TFields; Depth: Integer);
  2620.   var
  2621.     I: Integer;
  2622.   begin
  2623.     Inc(Depth);
  2624.     for I := 0 to Fields.Count-1 do
  2625.     begin
  2626.       Add.FieldName := Fields[I].FullName;
  2627.       if Fields[I].DataType in [ftADT, ftArray] then
  2628.         AddFields((Fields[I] as TObjectField).Fields, Depth);
  2629.     end;
  2630.   end;
  2631.  
  2632. begin
  2633.   if Assigned(FGrid) and Assigned(FGrid.DataSource) and
  2634.     Assigned(FGrid.Datasource.Dataset) then
  2635.   begin
  2636.     FGrid.BeginLayout;
  2637.     try
  2638.       Clear;
  2639.       AddFields(FGrid.Datasource.Dataset.Fields, 0);
  2640.     finally
  2641.       FGrid.EndLayout;
  2642.     end
  2643.   end
  2644.   else
  2645.     Clear;
  2646. end;
  2647.  
  2648. procedure TDBGridColumns.SaveToFile(const Filename: string);
  2649. var
  2650.   S: TStream;
  2651. begin
  2652.   S := TFileStream.Create(Filename, fmCreate);
  2653.   try
  2654.     SaveToStream(S);
  2655.   finally
  2656.     S.Free;
  2657.   end;
  2658. end;
  2659.  
  2660. procedure TDBGridColumns.SaveToStream(S: TStream);
  2661. var
  2662.   Wrapper: TColumnsWrapper;
  2663. begin
  2664.   Wrapper := TColumnsWrapper.Create(nil);
  2665.   try
  2666.     Wrapper.Columns := Self;
  2667.     S.WriteComponent(Wrapper);
  2668.   finally
  2669.     Wrapper.Free;
  2670.   end;
  2671. end;
  2672.  
  2673. procedure TDBGridColumns.SetColumn(Index: Integer; Value: TColumn);
  2674. begin
  2675.   Items[Index].Assign(Value);
  2676. end;
  2677.  
  2678. procedure TDBGridColumns.SetState(NewState: TDBGridColumnsState);
  2679. begin
  2680.   if NewState = State then Exit;
  2681.   if NewState = csDefault then
  2682.     Clear
  2683.   else
  2684.     RebuildColumns;
  2685. end;
  2686.  
  2687. procedure TDBGridColumns.Update(Item: TCollectionItem);
  2688. var
  2689.   Raw: Integer;
  2690. begin
  2691.   if (Grid = nil) or (csLoading in Grid.ComponentState) then Exit;
  2692.   if Item = nil then
  2693.   begin
  2694.     Grid.LayoutChanged;
  2695.     Grid.UpdateColWidths(-1, True)
  2696.   end
  2697.   else begin
  2698.     Raw := FGrid.DataToRawColumn(Item.Index);
  2699.     Grid.InvalidateCol(Raw);
  2700.     if TColumn(Item).Resize then
  2701.       Grid.FSizingIndex := Raw
  2702.     else
  2703.       Grid.FSizingIndex := -1;
  2704.     Grid.ColWidths[Raw] := TColumn(Item).Width;
  2705.   end;
  2706. end;
  2707.  
  2708. function TDBGridColumns.InternalAdd: TColumn;
  2709. begin
  2710.   Result := Add;
  2711.   Result.IsStored := False;
  2712. end;
  2713.  
  2714. function TDBGridColumns.GetState: TDBGridColumnsState;
  2715. begin
  2716.   Result := TDBGridColumnsState((Count > 0) and Items[0].IsStored);
  2717. end;
  2718.  
  2719. { TBookmarkList }
  2720.  
  2721. constructor TBookmarkList.Create(AGrid: TDCCustomDBGrid);
  2722. begin
  2723.   inherited Create;
  2724.   FList := TStringList.Create;
  2725.   FList.OnChange := StringsChanged;
  2726.   FGrid := AGrid;
  2727. end;
  2728.  
  2729. destructor TBookmarkList.Destroy;
  2730. begin
  2731.   Clear;
  2732.   FList.Free;
  2733.   inherited Destroy;
  2734. end;
  2735.  
  2736. procedure TBookmarkList.Clear;
  2737. begin
  2738.   if FList.Count = 0 then Exit;
  2739.   FList.Clear;
  2740.   FGrid.FSelecting := False;
  2741.   FGrid.Invalidate;
  2742. end;
  2743.  
  2744. function TBookmarkList.Compare(const Item1, Item2: TBookmarkStr): Integer;
  2745. begin
  2746.   with FGrid.Datalink.Datasource.Dataset do
  2747.     Result := CompareBookmarks(TBookmark(Item1), TBookmark(Item2));
  2748. end;
  2749.  
  2750. function TBookmarkList.CurrentRow: TBookmarkStr;
  2751. begin
  2752.   if not FLinkActive then RaiseGridError(sDataSetClosed);
  2753.   Result := FGrid.Datalink.Datasource.Dataset.Bookmark;
  2754. end;
  2755.  
  2756. function TBookmarkList.GetCurrentRowSelected: Boolean;
  2757. var
  2758.   Index: Integer;
  2759. begin
  2760.   Result := Find(CurrentRow, Index);
  2761. end;
  2762.  
  2763. function TBookmarkList.Find(const Item: TBookmarkStr; var Index: Integer): Boolean;
  2764. var
  2765.   L, H, I, C: Integer;
  2766. begin
  2767.   if (Item = FCache) and (FCacheIndex >= 0) then
  2768.   begin
  2769.     Index := FCacheIndex;
  2770.     Result := FCacheFind;
  2771.     Exit;
  2772.   end;
  2773.   Result := False;
  2774.   L := 0;
  2775.   H := FList.Count - 1;
  2776. {
  2777.   while L <= H do
  2778.   begin
  2779.     I := (L + H) shr 1;
  2780.     C := Compare(FList[I], Item);
  2781.     if C < 0 then L := I + 1 else
  2782.     begin
  2783.       H := I - 1;
  2784.       if C = 0 then
  2785.       begin
  2786.         Result := True;
  2787.         L := I;
  2788.       end;
  2789.     end;
  2790.   end;
  2791. }
  2792.   for I := 0 to H do
  2793.   begin
  2794.     C := Compare(FList[I], Item);
  2795.     if C = 0 then
  2796.     begin
  2797.       Result := True;
  2798.       L := I;
  2799.       Break;
  2800.     end;
  2801.   end;
  2802.   Index := L;
  2803.   FCache := Item;
  2804.   FCacheIndex := Index;
  2805.   FCacheFind := Result;
  2806. end;
  2807.  
  2808. function TBookmarkList.GetCount: Integer;
  2809. begin
  2810.   Result := FList.Count;
  2811. end;
  2812.  
  2813. function TBookmarkList.GetItem(Index: Integer): TBookmarkStr;
  2814. begin
  2815.   Result := FList[Index];
  2816. end;
  2817.  
  2818. function TBookmarkList.IndexOf(const Item: TBookmarkStr): Integer;
  2819. begin
  2820.   if not Find(Item, Result) then
  2821.     Result := -1;
  2822. end;
  2823.  
  2824. procedure TBookmarkList.LinkActive(Value: Boolean);
  2825. begin
  2826.   Clear;
  2827.   FLinkActive := Value;
  2828. end;
  2829.  
  2830. procedure TBookmarkList.Delete;
  2831. var
  2832.   I: Integer;
  2833. begin
  2834.   with FGrid.Datalink.Datasource.Dataset do
  2835.   begin
  2836.     DisableControls;
  2837.     try
  2838.       for I := FList.Count-1 downto 0 do
  2839.       begin
  2840.         Bookmark := FList[I];
  2841.         Delete;
  2842.         FList.Delete(I);
  2843.       end;
  2844.     finally
  2845.       EnableControls;
  2846.     end;
  2847.   end;
  2848. end;
  2849.  
  2850. function TBookmarkList.Refresh: Boolean;
  2851. var
  2852.   I: Integer;
  2853.   Valid: boolean;
  2854. begin
  2855.   Result := False;
  2856.   if FGrid.DataLink.Dataset = nil then Exit;
  2857.  
  2858.   with FGrid.DataLink.Dataset do
  2859.   try
  2860.     CheckBrowseMode;
  2861.     for I := FList.Count - 1 downto 0 do
  2862.     begin
  2863.       try
  2864.         Valid := BookmarkValid(TBookmark(FList[I]));
  2865.       except
  2866.         Valid := False;
  2867.       end;
  2868.       if not Valid then
  2869.       begin
  2870.         Result := True;
  2871.         FList.Delete(I);
  2872.       end;
  2873.     end;  
  2874.   finally
  2875.     UpdateCursorPos;
  2876.     if Result then FGrid.Invalidate;
  2877.   end;
  2878. end;
  2879.  
  2880. procedure TBookmarkList.SetCurrentRowSelected(Value: Boolean);
  2881. var
  2882.   Index: Integer;
  2883.   Current: TBookmarkStr;
  2884. begin
  2885.   Current := CurrentRow;
  2886.   if (Length(Current) = 0) or (Find(Current, Index) = Value) then Exit;
  2887.   if Value then
  2888.   begin
  2889.     FList.Insert(Index, Current);
  2890.   end
  2891.   else
  2892.     FList.Delete(Index);
  2893.   with FGrid.Datalink do
  2894.     if (DataSet <> nil) and DataSet.ControlsDisabled then Exit;
  2895.   FGrid.InvalidateRow(FGrid.Row);
  2896. end;
  2897.  
  2898. procedure TBookmarkList.StringsChanged(Sender: TObject);
  2899. begin
  2900.   FCache := '';
  2901.   FCacheIndex := -1;
  2902. end;
  2903.  
  2904. procedure TBookmarkList.Load(List: TStringList);
  2905. begin
  2906.   FList.Assign(List);
  2907.   InvalidateRect(FGrid.Handle, nil, False);
  2908. end;
  2909.  
  2910. procedure TBookmarkList.Save(List: TStringList);
  2911. var
  2912.   I: Integer;
  2913. begin
  2914.   List.BeginUpdate;
  2915.   try
  2916.     List.Clear;
  2917.     for I := 0 to FList.Count - 1 do
  2918.       List.Add(FList.Strings[I])
  2919.   finally
  2920.     List.EndUpdate;
  2921.   end;
  2922. end;
  2923.  
  2924. procedure TBookmarkList.SelectAll;
  2925.  var
  2926.   AList: TStringList;
  2927. begin
  2928.   if FGrid.DataLink.DataSet <> nil then with FGrid.DataLink.DataSet do
  2929.   begin
  2930.     FGrid.SavePosition;
  2931.     AList := TStringList.Create;
  2932.     DisableControls;
  2933.     try
  2934.       First;
  2935.       while not Eof do
  2936.       begin
  2937.         AList.Add(CurrentRow);
  2938.         Next;
  2939.       end;
  2940.       Load(AList);
  2941.     finally
  2942.       AList.Free;
  2943.       FGrid.RestPosition;
  2944.       EnableControls;
  2945.     end;
  2946.   end;
  2947. end;
  2948.  
  2949. { TDCCustomDBGrid }
  2950.  
  2951. procedure UsesBitmap;
  2952. begin
  2953.   if UserCount = 0 then
  2954.   begin
  2955.     DrawBitmap := TBitmap.Create;
  2956.     TempBitmap := TBitmap.Create;
  2957.   end;
  2958.   Inc(UserCount);
  2959. end;
  2960.  
  2961. procedure ReleaseBitmap;
  2962. begin
  2963.   Dec(UserCount);
  2964.   if UserCount = 0 then
  2965.   begin
  2966.     DrawBitmap.Free;
  2967.     TempBitmap.Free;
  2968.   end;
  2969. end;
  2970.  
  2971. procedure WriteText(ACanvas: TCanvas; ARect: TRect; DX, DY: Integer;
  2972.   const Text: string; Alignment: TAlignment; ARightToLeft: Boolean; AWordBreak: boolean);
  2973. const
  2974.   AlignFlags : array [TAlignment] of Integer =
  2975.     ( DT_LEFT or DT_EXPANDTABS or DT_NOPREFIX,
  2976.       DT_RIGHT or DT_EXPANDTABS or DT_NOPREFIX,
  2977.       DT_CENTER or DT_EXPANDTABS or DT_NOPREFIX );
  2978.   RTL: array [Boolean] of Integer = (0, DT_RTLREADING);
  2979. var
  2980.   B, R: TRect;
  2981.   Hold, Left: Integer;
  2982.   I: TColorRef;
  2983. begin
  2984.   I := ColorToRGB(ACanvas.Brush.Color);
  2985.   if (GetNearestColor(ACanvas.Handle, I) = I) and not AWordBreak then
  2986.   begin                       { Use ExtTextOut for solid colors }
  2987.     { In BiDi, because we changed the window origin, the text that does not
  2988.       change alignment, actually gets its alignment changed. }
  2989.     if (ACanvas.CanvasOrientation = coRightToLeft) and (not ARightToLeft) then
  2990.       ChangeBiDiModeAlignment(Alignment);
  2991.     case Alignment of
  2992.       taLeftJustify:
  2993.         Left := ARect.Left + DX;
  2994.       taRightJustify:
  2995.         Left := ARect.Right - ACanvas.TextWidth(Text) - 3;
  2996.     else { taCenter }
  2997.       Left := ARect.Left + (ARect.Right - ARect.Left) shr 1
  2998.         - (ACanvas.TextWidth(Text) shr 1);
  2999.     end;
  3000.     ACanvas.TextRect(ARect, Left, ARect.Top + DY, Text);
  3001.   end
  3002.   else
  3003.   begin                  { Use FillRect and Drawtext for dithered colors }
  3004.     DrawBitmap.Canvas.Lock;
  3005.     try
  3006.       with DrawBitmap, ARect do { Use offscreen bitmap to eliminate flicker and }
  3007.       begin                     { brush origin tics in painting / scrolling.    }
  3008.         Width  := _intMax(Width, Right - Left);
  3009.         Height := _intMax(Height, Bottom - Top);
  3010.         R := Rect(DX, DY, Right - Left - 1, Bottom - Top - 1);
  3011.         B := Rect(0, 0, Right - Left, Bottom - Top);
  3012.       end;
  3013.       with DrawBitmap.Canvas do
  3014.       begin
  3015.         Font := ACanvas.Font;
  3016.         Font.Color := ACanvas.Font.Color;
  3017.         Brush := ACanvas.Brush;
  3018.         Brush.Style := bsSolid;
  3019.         FillRect(B);
  3020.         SetBkMode(Handle, TRANSPARENT);
  3021.         if (ACanvas.CanvasOrientation = coRightToLeft) then
  3022.           ChangeBiDiModeAlignment(Alignment);
  3023.         if AWordBreak then
  3024.           DrawText(Handle, PChar(Text), Length(Text), R,
  3025.             AlignFlags[Alignment] or RTL[ARightToLeft] or DT_WORDBREAK)
  3026.         else
  3027.           DrawText(Handle, PChar(Text), Length(Text), R,
  3028.             AlignFlags[Alignment] or RTL[ARightToLeft])
  3029.       end;
  3030.       if (ACanvas.CanvasOrientation = coRightToLeft) then
  3031.       begin
  3032.         Hold := ARect.Left;
  3033.         ARect.Left := ARect.Right;
  3034.         ARect.Right := Hold;
  3035.       end;
  3036.       ACanvas.CopyRect(ARect, DrawBitmap.Canvas, B);
  3037.     finally
  3038.       DrawBitmap.Canvas.Unlock;
  3039.     end;
  3040.   end;
  3041. end;
  3042.  
  3043. constructor TDCCustomDBGrid.Create(AOwner: TComponent);
  3044. begin
  3045.   inherited Create(AOwner);
  3046.   inherited DefaultDrawing := False;
  3047.  
  3048.   FAcquireFocus := True;
  3049.   FTitleOffset := 1;
  3050.   FIndicatorOffset := 1;
  3051.   FUpdateFields := True;
  3052.   FOptions := [dgEditing, dgTitles, dgIndicator, dgColumnResize,
  3053.     dgColLines, dgRowLines, dgTabs, dgConfirmDelete, dgCancelOnExit];
  3054.   FOptionsEx := [dgeMarkerMenu, dgeShadowSelection, dgeDrawMemoAsText
  3055.     {$IFNDEF DELPHI_V5UP}, dgeInsertSelect {$ENDIF}];
  3056.   if SysLocale.PriLangID = LANG_KOREAN then Include(FOptions, dgAlwaysShowEditor);
  3057.   DesignOptionsBoost := [goColSizing];
  3058.   VirtualView := True;
  3059.   UsesBitmap;
  3060.   ScrollBars := ssHorizontal;
  3061.   inherited Options := [goFixedHorzLine, goFixedVertLine, goHorzLine,
  3062.     goVertLine, goColSizing, goColMoving, goTabs, goEditing];
  3063.   FColumns := CreateColumns;
  3064.   FVisibleColumns := TList.Create;
  3065.   inherited RowCount := 2;
  3066.   inherited ColCount := 2;
  3067.   FDataLink := TGridDataLink.Create(Self);
  3068.   Color := clWindow;
  3069.   ParentColor := False;
  3070.   FTitleFont := TFont.Create;
  3071.   FTitleFont.OnChange := TitleFontChanged;
  3072.   FSaveCellExtents := False;
  3073.   FUserChange := True;
  3074.   FDefaultDrawing := True;
  3075.   FBookmarks := TBookmarkList.Create(Self);
  3076.   ClickedCol := -1;
  3077.   FCurrentCol := -1;
  3078.   FMousePoint := Point(-1,-1);
  3079.   FFrozenCols := 0;
  3080.   FClipDown   := False;
  3081.   FFirstGridCell := 0;
  3082.   FDBObject := TDCDBObject.Create;
  3083.  
  3084.   FImageChangeLink :=  TChangeLink.Create;
  3085.   FImageChangeLink.OnChange := ImageListChange;
  3086.  
  3087.   HideEditor;
  3088.   FDataVisible := True;
  3089.   FColumnCell  := -1;
  3090.   FSizingIndex := -1;
  3091. end;
  3092.  
  3093. destructor TDCCustomDBGrid.Destroy;
  3094. begin
  3095.   if Assigned(FClipPopup) then
  3096.     TDBClipPopup(FClipPopup).Free;
  3097.  
  3098.   if Assigned(FCurrentPos[1].Bookmark) then FreeMem(FCurrentPos[1].Bookmark);
  3099.   if Assigned(FCurrentPos[2].Bookmark) then FreeMem(FCurrentPos[2].Bookmark);
  3100.  
  3101.   FImageChangeLink.Free;
  3102.  
  3103.   FColumns.Free;
  3104.   FColumns := nil;
  3105.   FVisibleColumns.Free;
  3106.   FVisibleColumns := nil;
  3107.   FDataLink.Free;
  3108.   FDataLink := nil;
  3109.   FTitleFont.Free;
  3110.   FTitleFont := nil;
  3111.   FBookmarks.Free;
  3112.   FBookmarks := nil;
  3113.   ReleaseBitmap;
  3114.  
  3115.   FDBObject.Free;
  3116.   FDBObject := nil;
  3117.  
  3118.   inherited Destroy;
  3119. end;
  3120.  
  3121. function TDCCustomDBGrid.AcquireFocus: Boolean;
  3122. begin
  3123.   Result := True;
  3124.   if FAcquireFocus and CanFocus and not (csDesigning in ComponentState) then
  3125.   begin
  3126.     SetFocus;
  3127.     Result := Focused or (InplaceEditor <> nil) and InplaceEditor.Focused;
  3128.   end;
  3129. end;
  3130.  
  3131. function TDCCustomDBGrid.RawToDataColumn(ACol: Integer): Integer;
  3132. begin
  3133.   Result := ACol - FIndicatorOffset;
  3134. end;
  3135.  
  3136. function TDCCustomDBGrid.DataToRawColumn(ACol: Integer): Integer;
  3137. begin
  3138.   Result := ACol + FIndicatorOffset;
  3139. end;
  3140.  
  3141. function TDCCustomDBGrid.AcquireLayoutLock: Boolean;
  3142. begin
  3143.   Result := (FUpdateLock = 0) and (FLayoutLock = 0);
  3144.   if Result then BeginLayout;
  3145. end;
  3146.  
  3147. procedure TDCCustomDBGrid.BeginLayout;
  3148. begin
  3149.   BeginUpdate;
  3150.   if (FLayoutLock = 0) and Assigned(Columns) then Columns.BeginUpdate;
  3151.   Inc(FLayoutLock);
  3152. end;
  3153.  
  3154. procedure TDCCustomDBGrid.BeginUpdate;
  3155. begin
  3156.   Inc(FUpdateLock);
  3157. end;
  3158.  
  3159. procedure TDCCustomDBGrid.CancelLayout;
  3160. begin
  3161.   if FLayoutLock > 0 then
  3162.   begin
  3163.     if FLayoutLock = 1 then
  3164.       Columns.EndUpdate;
  3165.     Dec(FLayoutLock);
  3166.     EndUpdate;
  3167.   end;
  3168. end;
  3169.  
  3170. function TDCCustomDBGrid.CanEditAcceptKey(Key: Char): Boolean;
  3171. begin
  3172.   with Columns[SelectedIndex] do
  3173.     Result := FDatalink.Active and Assigned(Field) and Field.IsValidChar(Key);
  3174. end;
  3175.  
  3176. function TDCCustomDBGrid.CanEditModify: Boolean;
  3177. begin
  3178.   Result := False;
  3179.   if not ReadOnly and FDatalink.Active and not FDatalink.Readonly then
  3180.   with Columns[SelectedIndex] do
  3181.     if not ReadOnly and Assigned(Field) and Field.CanModify
  3182.       and (not (Field.DataType in ftNonTextTypes) or Assigned(Field.OnSetText)) then
  3183.     begin
  3184.       FDatalink.Edit;
  3185.       Result := FDatalink.Editing;
  3186.       if Result then FDatalink.Modified;
  3187.     end;
  3188. end;
  3189.  
  3190. function TDCCustomDBGrid.CanEditShow: Boolean;
  3191. begin
  3192.   Result := (LayoutLock = 0) and inherited CanEditShow;
  3193. end;
  3194.  
  3195. procedure TDCCustomDBGrid.CellClick(Column: TColumn);
  3196. begin
  3197.   if Assigned(FOnCellClick) then FOnCellClick(Column);
  3198. end;
  3199.  
  3200. procedure TDCCustomDBGrid.ColEnter;
  3201. begin
  3202.   UpdateIme;
  3203.   if Assigned(FOnColEnter) then FOnColEnter(Self);
  3204. end;
  3205.  
  3206. procedure TDCCustomDBGrid.ColExit;
  3207. begin
  3208.   if Assigned(FOnColExit) then FOnColExit(Self);
  3209. end;
  3210.  
  3211. procedure TDCCustomDBGrid.ColumnMoved(FromIndex, ToIndex: Longint);
  3212. begin
  3213.   inherited;
  3214.   FromIndex := RawToDataColumn(FromIndex);
  3215.   ToIndex := RawToDataColumn(ToIndex);
  3216.   Columns[FromIndex].Index := ToIndex;
  3217.   if Assigned(FOnColumnMoved) then FOnColumnMoved(Self, FromIndex, ToIndex);
  3218. end;
  3219.  
  3220. procedure TDCCustomDBGrid.ColWidthsChanged;
  3221.  var
  3222.   I: Integer;
  3223. begin
  3224.   if not UpdateLocked and (FDatalink.Active or (FColumns.State = csCustomized)) and
  3225.     AcquireLayoutLock then
  3226.   try
  3227.     inherited ColWidthsChanged;
  3228.     for I := FIndicatorOffset to ColCount - 1 do
  3229.       FColumns[I - FIndicatorOffset].Width := ColWidths[I];
  3230.   finally
  3231.     EndLayout;
  3232.   end;
  3233. end;
  3234.  
  3235. function TDCCustomDBGrid.CreateColumns: TDBGridColumns;
  3236. begin
  3237.   Result := TDBGridColumns.Create(Self, TColumn);
  3238. end;
  3239.  
  3240. function TDCCustomDBGrid.CreateEditor: TInplaceEdit;
  3241. begin
  3242.   Result := TDBGridInplaceEdit.Create(Self);
  3243. end;
  3244.  
  3245. procedure TDCCustomDBGrid.CreateWnd;
  3246. begin
  3247.   BeginUpdate;   { prevent updates in WMSize message that follows WMCreate }
  3248.   try
  3249.     inherited CreateWnd;
  3250.   finally
  3251.     EndUpdate;
  3252.   end;
  3253.   UpdateRowCount;
  3254.   UpdateActive;
  3255.   UpdateScrollBar;
  3256.   FOriginalImeName := ImeName;
  3257.   FOriginalImeMode := ImeMode;
  3258.  
  3259.   FClipPopup := TDBClipPopup.Create(Self);
  3260. end;
  3261.  
  3262. procedure TDCCustomDBGrid.DataChanged;
  3263. begin
  3264.   if not HandleAllocated then Exit;
  3265.   SelectedRows.StringsChanged(nil);
  3266.   UpdateRowCount;
  3267.   UpdateScrollBar;
  3268.   UpdateActive;
  3269.   invalidate;
  3270. end;
  3271.  
  3272. procedure TDCCustomDBGrid.DefaultHandler(var Msg);
  3273. var
  3274.   P: TPopupMenu;
  3275.   Cell: TGridCoord;
  3276. begin
  3277.   inherited DefaultHandler(Msg);
  3278.   if TMessage(Msg).Msg = wm_RButtonUp then
  3279.     with TWMRButtonUp(Msg) do
  3280.     begin
  3281.       Cell := MouseCoord(XPos, YPos);
  3282.       if (Cell.X < FIndicatorOffset) or (Cell.Y < 0) then Exit;
  3283.       P := Columns[RawToDataColumn(Cell.X)].PopupMenu;
  3284.       if (P <> nil) and P.AutoPopup then
  3285.       begin
  3286.         SendCancelMode(nil);
  3287.         P.PopupComponent := Self;
  3288.         with ClientToScreen(SmallPointToPoint(Pos)) do
  3289.           P.Popup(X, Y);
  3290.         Result := 1;
  3291.       end;
  3292.     end;
  3293. end;
  3294.  
  3295. procedure TDCCustomDBGrid.DeferLayout;
  3296. var
  3297.   M: TMsg;
  3298. begin
  3299.   if HandleAllocated and
  3300.     not PeekMessage(M, Handle, CM_DEFERLAYOUT, CM_DEFERLAYOUT, pm_NoRemove) then
  3301.     PostMessage(Handle, CM_DEFERLAYOUT, 0, 0);
  3302.   CancelLayout;
  3303. end;
  3304.  
  3305. procedure TDCCustomDBGrid.DefineFieldMap;
  3306. var
  3307.   I: Integer;
  3308. begin
  3309.   if FColumns.State = csCustomized then
  3310.   begin   { Build the column/field map from the column attributes }
  3311.     DataLink.SparseMap := True;
  3312.     for I := 0 to FColumns.Count-1 do
  3313.       FDataLink.AddMapping(FColumns[I].FieldName);
  3314.   end
  3315.   else   { Build the column/field map from the field list order }
  3316.   begin
  3317.     FDataLink.SparseMap := False;
  3318.     with Datalink.Dataset do
  3319.       for I := 0 to FieldList.Count - 1 do
  3320.         with FieldList[I] do if Visible then Datalink.AddMapping(FullName);
  3321.   end;
  3322. end;
  3323.  
  3324. function TDCCustomDBGrid.UseRightToLeftAlignmentForField(const AField: TField;
  3325.   Alignment: TAlignment): Boolean;
  3326. begin
  3327.   Result := False;
  3328.   if IsRightToLeft then
  3329.     Result := OkToChangeFieldAlignment(AField, Alignment);
  3330. end;
  3331.  
  3332. procedure TDCCustomDBGrid.DefaultDrawDataCell(const Rect: TRect; Field: TField;
  3333.   State: TGridDrawState);
  3334. var
  3335.   Alignment: TAlignment;
  3336.   Value: string;
  3337.   AWordBreak: boolean;
  3338. begin
  3339.   Alignment := taLeftJustify;
  3340.   Value := '';
  3341.   AWordBreak := False;
  3342.   if Assigned(Field) then
  3343.   begin
  3344.     Alignment := Field.Alignment;
  3345.     if Assigned(FDrawColumn) then
  3346.     begin
  3347.       Value := GetDataValue(FDrawColumn);
  3348.       AWordBreak := FDrawColumn.WordBreak;
  3349.     end
  3350.     else
  3351.       Value := Field.DisplayText;
  3352.   end;
  3353.   WriteText(Canvas, Rect, 2, 2, Value, Alignment,
  3354.     UseRightToLeftAlignmentForField(Field, Alignment), AWordBreak);
  3355. end;
  3356.  
  3357. procedure TDCCustomDBGrid.DefaultDrawColumnCell(const Rect: TRect;
  3358.   DataCol: Integer; Column: TColumn; State: TGridDrawState);
  3359. var
  3360.   Value: string;
  3361. begin
  3362.   Value := GetDataValue(Column);
  3363.   with Column do
  3364.     WriteText(Canvas, Rect, 2, 2, Value, Alignment,
  3365.       UseRightToLeftAlignmentForField(Field, Alignment), WordBreak);
  3366. end;
  3367.  
  3368. procedure TDCCustomDBGrid.ReadColumns(Reader: TReader);
  3369. begin
  3370.   Columns.Clear;
  3371.   Reader.ReadValue;
  3372.   Reader.ReadCollection(Columns);
  3373. end;
  3374.  
  3375. procedure TDCCustomDBGrid.WriteColumns(Writer: TWriter);
  3376. begin
  3377.   Writer.WriteCollection(Columns);
  3378. end;
  3379.  
  3380. procedure TDCCustomDBGrid.DefineProperties(Filer: TFiler);
  3381. begin
  3382.   Filer.DefineProperty('Columns', ReadColumns, WriteColumns,
  3383.     ((Columns.State = csCustomized) and (Filer.Ancestor = nil)) or
  3384.     ((Filer.Ancestor <> nil) and
  3385.      ((Columns.State <> TDCCustomDBGrid(Filer.Ancestor).Columns.State) or
  3386.   {$IFDEF DELPHI_V6}
  3387.     (not CollectionsEqual(Columns, TDCCustomDBGrid(Filer.Ancestor).Columns,
  3388.       Self, TDCCustomDBGrid(Filer.Ancestor)))
  3389.   {$ELSE}
  3390.     (not CollectionsEqual(Columns, TDCCustomDBGrid(Filer.Ancestor).Columns))
  3391.   {$ENDIF}
  3392.      )));
  3393. end;
  3394.  
  3395. function TDCCustomDBGrid.ColumnAtDepth(Col: TColumn; ADepth: Integer): TColumn;
  3396. begin
  3397.   Result := Col;
  3398.   while (Result <> nil) and (Result.Depth > ADepth) do
  3399.     Result := Result.ParentColumn;
  3400. end;
  3401.  
  3402. function TDCCustomDBGrid.CalcTitleRect(Col: TColumn; ARow: Integer;
  3403.   var MasterCol: TColumn): TRect;
  3404. var
  3405.   I,J: Integer;
  3406.   InBiDiMode: Boolean;
  3407.   DrawInfo: TGridDrawInfo;
  3408. begin
  3409.   MasterCol := ColumnAtDepth(Col, ARow);
  3410.   if MasterCol = nil then Exit;
  3411.  
  3412.   I := DataToRawColumn(MasterCol.Index);
  3413.   if (I >= LeftCol) or (I < FixedCols) then
  3414.     J := MasterCol.Depth
  3415.   else
  3416.   begin
  3417.     I := LeftCol;
  3418.     if Col.Depth > ARow then
  3419.       J := ARow
  3420.     else
  3421.       J := Col.Depth;
  3422.   end;
  3423.  
  3424.   Result := CellRect(I, J);
  3425.  
  3426.   InBiDiMode := UseRightToLeftAlignment and
  3427.                 (Canvas.CanvasOrientation = coLeftToRight);
  3428.  
  3429.   for I := Col.Index to Columns.Count-1 do
  3430.   begin
  3431.     if ColumnAtDepth(Columns[I], ARow) <> MasterCol then Break;
  3432.     if not InBiDiMode then
  3433.     begin
  3434.       J := CellRect(DataToRawColumn(I), ARow).Right;
  3435.       if J = 0 then Break;
  3436.       Result.Right := _intMax(Result.Right, J);
  3437.     end
  3438.     else
  3439.     begin
  3440.       J := CellRect(DataToRawColumn(I), ARow).Left;
  3441.       if J >= ClientWidth then Break;
  3442.       Result.Left := J;
  3443.     end;
  3444.   end;
  3445.   J := Col.Depth;
  3446.   if (J <= ARow) and (J < FixedRows-1) then
  3447.   begin
  3448.     CalcFixedInfo(DrawInfo);
  3449.     Result.Bottom := DrawInfo.Vert.FixedBoundary - DrawInfo.Vert.EffectiveLineWidth;
  3450.   end;
  3451. end;
  3452.  
  3453. function TDCCustomDBGrid.DrawTitleCell(ACanvas: TCanvas; ACol,
  3454.   ARow: Integer; ARect: TRect; BorderState: TDrawBorerState; AFillRect, ADraw: boolean): TPoint;
  3455.   const
  3456.     ScrollArrows: array [Boolean, Boolean] of Integer =
  3457.       ((DFCS_SCROLLRIGHT, DFCS_SCROLLLEFT), (DFCS_SCROLLLEFT, DFCS_SCROLLRIGHT));
  3458.     ColumnIndexStyle : array [TColumnIndexStyle] of Integer =
  3459.      (nbmIndexNone,nbmIndexAsc,nbmIndexDesc);
  3460.     AlignFlags : array [TAlignment] of Integer =
  3461.       ( DT_LEFT   or DT_NOPREFIX,
  3462.         DT_RIGHT  or DT_NOPREFIX,
  3463.         DT_CENTER or DT_NOPREFIX );
  3464.  
  3465.   var
  3466.     Column, MasterCol: TColumn;
  3467.     TextRect, ButtonRect, DrawRect: TRect;
  3468.     I: Integer;
  3469.     InBiDiMode: Boolean;
  3470.  
  3471.   function DoPaint(Canvas: TCanvas; DrawRect: TRect): TPoint;
  3472.     var
  3473.      P: TPoint;
  3474.   begin
  3475.     TextRect := DrawRect;
  3476.  
  3477.     Canvas.Font := MasterCol.Title.Font;
  3478.     Canvas.Font.Color := ColorToRGB(MasterCol.Title.Font.Color);
  3479.  
  3480.     Canvas.Brush.Color := MasterCol.Title.Color;
  3481.     I := GetSystemMetrics(SM_CXHSCROLL);
  3482.     if ((DrawRect.Right - DrawRect.Left) > I) and MasterCol.Expandable and ADraw then
  3483.     begin
  3484.       Dec(TextRect.Right, I);
  3485.       ButtonRect := DrawRect;
  3486.       ButtonRect.Left := TextRect.Right;
  3487.       I := SaveDC(Canvas.Handle);
  3488.       try
  3489.         if AFillRect then Canvas.FillRect(ButtonRect);
  3490.         InflateRect(ButtonRect, -1, -1);
  3491.         IntersectClipRect(Canvas.Handle, ButtonRect.Left,
  3492.           ButtonRect.Top, ButtonRect.Right, ButtonRect.Bottom);
  3493.         InflateRect(ButtonRect, 1, 1);
  3494.         { DrawFrameControl doesn't draw properly when orienatation has changed.
  3495.           It draws as ExtTextOut does. }
  3496.         InBiDiMode := Canvas.CanvasOrientation = coRightToLeft;
  3497.         if InBiDiMode then { stretch the arrows box }
  3498.           Inc(ButtonRect.Right, GetSystemMetrics(SM_CXHSCROLL) + 4);
  3499.         DrawFrameControl(Canvas.Handle, ButtonRect, DFC_SCROLL,
  3500.           ScrollArrows[InBiDiMode, MasterCol.Expanded] or DFCS_FLAT);
  3501.       finally
  3502.         RestoreDC(Canvas.Handle, I);
  3503.       end;
  3504.     end;
  3505.  
  3506.     if AFillRect then FillRect(Canvas.Handle, TextRect, Canvas.Brush.Handle);
  3507.  
  3508.     if BorderState = dsDown then
  3509.     begin
  3510.        TextRect.Left   := TextRect.Left + 3;
  3511.        TextRect.Top    := TextRect.Top  + 1;
  3512.     end
  3513.     else
  3514.       TextRect.Left := TextRect.Left + 2;
  3515.  
  3516.     if (MasterCol.Grid.Images <> nil) and (MasterCol.ItemIndex <> -1) and
  3517.        ((TextRect.Right - TextRect.Left) > 0)
  3518.     then begin
  3519.       Column.Grid.Images.Draw(Canvas, TextRect.Left, TextRect.Top, Column.ItemIndex);
  3520.       TextRect.Left := TextRect.Left + Column.Grid.Images.Width+2;
  3521.     end;
  3522.  
  3523.     if TextRect.Left < TextRect.Right then
  3524.     begin
  3525.       SetTextColor(Canvas.Handle, Canvas.Font.Color);
  3526.       case MasterCol.Title.Alignment of
  3527.         taLeftJustify:
  3528.           if ADraw then
  3529.             P := DrawHighLightText(Canvas, PChar(MasterCol.Title.Caption),
  3530.               TextRect, 1, DT_NOPREFIX)
  3531.           else
  3532.             P := DrawHighLightText(Canvas, PChar(MasterCol.Title.Caption),
  3533.               TextRect, 0, DT_NOPREFIX);
  3534.         taCenter, taRightJustify:
  3535.           begin
  3536.             if MasterCol.Indexed and (MasterCol.IndexStyle <> idxNone) then
  3537.               Dec(TextRect.Right, IndexTitleWidth + 2);
  3538.             P := DrawTitleRect(Canvas, TextRect, MasterCol.Title.Caption,
  3539.               MasterCol.Title.Alignment, ADraw);
  3540.           end;
  3541.       end;
  3542.       Result.Y := P.Y;
  3543.       Result.X := TextRect.Left - DrawRect.Left + P.X + 2;
  3544.       if MasterCol.Indexed and ((MasterCol.IndexStyle <> idxNone) and
  3545.         ((P.X + IndexTitleWidth) < (TextRect.Right - TextRect.Left)) or not ADraw)
  3546.       then begin
  3547.         if ADraw then begin
  3548.           if MasterCol.Title.Alignment = taCenter then
  3549.             P.X := (TextRect.Right + TextRect.Left - P.X) div 2 + P.X - 1;
  3550.           GDGetImages.Draw(Canvas, TextRect.Left + P.X, TextRect.Top, ColumnIndexStyle[Column.IndexStyle]);
  3551.         end;
  3552.         Inc(Result.X, IndexTitleWidth);
  3553.       end
  3554.       else
  3555.         Inc(Result.X, 2);
  3556.     end;
  3557.   end;
  3558.  
  3559. begin
  3560.   Column := Columns[ACol];
  3561.   MasterCol := ColumnAtDepth(Column, ARow);
  3562.  
  3563.   with ARect do
  3564.     if Right-Left = 0 then Exit;
  3565.  
  3566.   if MasterCol = nil then
  3567.   begin
  3568.     if AFillRect and ADraw then Canvas.FillRect(ARect);
  3569.     with ARect do Result := Point(Right-Left, Bottom-Top);
  3570.     Exit;
  3571.   end;
  3572.  
  3573.   if AFillRect then
  3574.   begin
  3575.     DrawBitmap.Width  := ARect.Right  - ARect.Left;
  3576.     DrawBitmap.Height := ARect.Bottom - ARect.Top;
  3577.  
  3578.     with DrawBitmap do
  3579.     begin
  3580.       DrawRect := Rect(0,0, Width, Height);
  3581.       Result := DoPaint(Canvas, DrawRect);
  3582.     end;
  3583.     if ADraw then ACanvas.Draw(ARect.Left, ARect.Top, DrawBitmap);
  3584.   end
  3585.   else
  3586.     Result := DoPaint(ACanvas, ARect);
  3587. end;
  3588.  
  3589. procedure TDCCustomDBGrid.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
  3590.  
  3591. var
  3592.   FrameOffs: Byte;
  3593.   BorderState: TDrawBorerState;
  3594.   BorderStyle: TEdgeBorderStyle;
  3595.   TitleRect: TRect;
  3596.   MasterCol: TColumn;
  3597.   Indicators: TImageList;
  3598.  
  3599.   function RowIsMultiSelected: Boolean;
  3600.   var
  3601.     Index: Integer;
  3602.   begin
  3603.     Result := (dgMultiSelect in Options) and Datalink.Active and
  3604.       FBookmarks.Find(Datalink.Datasource.Dataset.Bookmark, Index);
  3605.   end;
  3606.  
  3607. var
  3608.   OldActive: Integer;
  3609.   Indicator: Integer;
  3610.   Highlight: Boolean;
  3611.   Value: string;
  3612.   MultiSelected, FrozenCol: Boolean;
  3613.   ALeft, ATop: Integer;
  3614.   BRect: TRect;
  3615.  
  3616.   function IsColFirstVisible(ACol: integer): boolean;
  3617.    var
  3618.     AFirst: Integer;
  3619.   begin
  3620.     AFirst := 0;
  3621.     while (AFirst < Columns.Count-1) and (Columns[AFirst].Visible = False) do
  3622.       Inc(AFirst);
  3623.     if LeftCol - FIndicatorOffset > AFirst then AFirst := 0;
  3624.  
  3625.     Result := Assigned(DataLink) and DataLink.Active and (dgMarker in Options) and
  3626.       (ACol = LeftCol - FIndicatorOffset + AFirst);
  3627.   end;
  3628.  
  3629.   procedure DrawMarker(BRect: TRect);
  3630.   begin
  3631.     Canvas.Brush.Color := FixedColor;
  3632.     Canvas.FillRect(BRect);
  3633.     if FBookMarks.CurrentRowSelected then
  3634.     begin
  3635.       Indicators.Draw(Canvas, BRect.Right - (MarkerWidth div 2)-4,
  3636.           (BRect.Top + BRect.Bottom - Indicators.Height) shr 1, nbmCheck);
  3637.     end;
  3638.     if BorderStyle <> ebsNone then
  3639.     begin
  3640.       if BorderStyle = ebsShadowFlat then
  3641.       begin
  3642.         if not (dgColLines in Options) then
  3643.           BRect.Left  := BRect.Left - 2
  3644.         else begin
  3645.           BRect.Left  := BRect.Left - 1;
  3646.           BRect.Right := BRect.Right + 1;
  3647.         end;
  3648.         BRect.Top    := BRect.Top    - 1;
  3649.         BRect.Bottom := BRect.Bottom + 1;
  3650.       end;
  3651.       if FrozenCol then InflateRect(BRect, -1, -1);
  3652.       DrawGridFrameBorder(Canvas, BRect, BorderStyle, dsUp, FixedColor);
  3653.     end;
  3654.   end;
  3655.  
  3656. begin
  3657.   if [csDestroying, csLoading] * ComponentState  <> [] then
  3658.   begin
  3659.     Canvas.Brush.Color := Color;
  3660.     Canvas.FillRect(ARect);
  3661.     Exit;
  3662.   end;
  3663.   Indicators := GDGetImages;
  3664.  
  3665.   BorderStyle := GetBorderStyle;
  3666.  
  3667.   if (ClickedCol <> -1) and (ACol= ClickedCol) and (ARow < FTitleOffset) then
  3668.     BorderState := dsDown
  3669.   else
  3670.     BorderState := dsUp;
  3671.  
  3672.   Dec(ARow, FTitleOffset);
  3673.   Dec(ACol, FIndicatorOffset);
  3674.  
  3675.   if (gdFixed in AState) and (ACol >= 0) and (ACol < FFrozenCols) and (ARow >= 0) then
  3676.     FrozenCol := True
  3677.   else
  3678.     FrozenCol := False;
  3679.  
  3680.   if (gdFixed in AState) and ([dgRowLines, dgColLines] * Options =
  3681.     [dgRowLines, dgColLines]) and not FrozenCol
  3682.   then begin
  3683.     InflateRect(ARect, -1, -1);
  3684.     FrameOffs := 1;
  3685.   end
  3686.   else
  3687.     FrameOffs := 2;
  3688.  
  3689.   if (gdFixed in AState) and (ACol < 0)
  3690.   then begin
  3691.     if (dgMarker in Options) and (ACol = -1) and (ARow >= 0) and
  3692.       Assigned(DataLink) and DataLink.Active then
  3693.     begin
  3694.       if not RectVisible(Canvas.Handle, CellRect(LeftCol, ARow + FTitleOffset)) then
  3695.       begin
  3696.         OldActive := FDataLink.ActiveRecord;
  3697.         try
  3698.           FDataLink.ActiveRecord := ARow;
  3699.           InflateRect(ARect, 1, 1);
  3700.           DrawMarker(ARect);
  3701.         finally
  3702.           FDataLink.ActiveRecord := OldActive;
  3703.         end;
  3704.       end;
  3705.       Exit;
  3706.     end;
  3707.     Canvas.Brush.Color := FixedColor;
  3708.     Canvas.FillRect(ARect);
  3709.     if ([dgIndicator, dgMarker] * Options = [dgIndicator, dgMarker]) and (ACol = -2)
  3710.        or
  3711.        ([dgIndicator, dgMarker] * Options = [dgIndicator])  and (ACol = -1)
  3712.     then begin
  3713.       if Assigned(DataLink) and DataLink.Active  then
  3714.       begin
  3715.         MultiSelected := False;
  3716.         if ARow >= 0 then
  3717.         begin
  3718.           OldActive := FDataLink.ActiveRecord;
  3719.           try
  3720.             FDatalink.ActiveRecord := ARow;
  3721.             MultiSelected := RowIsMultiselected;
  3722.           finally
  3723.             FDatalink.ActiveRecord := OldActive;
  3724.           end;
  3725.         end;
  3726.         if (ARow = FDataLink.ActiveRecord) or MultiSelected
  3727.         then begin
  3728.           Indicator := nbmArrow;
  3729.           if FDataLink.DataSet <> nil then
  3730.             case FDataLink.DataSet.State of
  3731.               dsEdit  : Indicator := nbmEdit;
  3732.               dsInsert: Indicator := nbmInsert;
  3733.               dsBrowse:
  3734.                 if MultiSelected then
  3735.                   if (ARow <> FDatalink.ActiveRecord) then
  3736.                     Indicator := nbmMultiDot
  3737.                   else
  3738.                     Indicator := nbmMultiArrow;  // multiselected and current row
  3739.             end;
  3740.           ALeft := ARect.Right - Indicators.Width - FrameOffs;
  3741.           if Canvas.CanvasOrientation = coRightToLeft then Inc(ALeft);
  3742.           Indicators.Draw(Canvas, ALeft,
  3743.             (ARect.Top + ARect.Bottom - Indicators.Height) shr 1, Indicator, True);
  3744.           if ARow = FDatalink.ActiveRecord then
  3745.             FSelRow := ARow + FTitleOffset;
  3746.         end;
  3747.       end;
  3748.     end;
  3749.     if (ARow < 0) and (dgeMarkerMenu in OptionsEx) and
  3750.        ( ((ACol = -1) and  (dgIndicator in Options) and not (dgMarker in Options) ) or
  3751.          ((ACol = -2) and  (dgIndicator in Options) and     (dgMarker in Options) ) )
  3752.     then begin
  3753.        ALeft := (ARect.Right + ARect.Left - Indicators.Width - FrameOffs) shr 1 + 1;
  3754.        ATop  := (ARect.Top + ARect.Bottom - Indicators.Height) shr 1;
  3755.        if FClipDown then
  3756.        begin
  3757.          if [dgRowLines, dgColLines] * Options =  [dgRowLines, dgColLines] then
  3758.            Indicators.Draw(Canvas, ALeft, ATop+1, nbmMain)
  3759.          else
  3760.            Indicators.Draw(Canvas, ALeft-1, ATop, nbmMain);
  3761.          InflateRect(ARect, 1, 1);
  3762.          DrawGridFrameBorder(Canvas, ARect, BorderStyle, dsDown, FixedColor);
  3763.        end
  3764.        else begin
  3765.          Indicators.Draw(Canvas, ALeft-1, ATop, nbmMain);
  3766.          InflateRect(ARect, 1, 1);
  3767.          DrawGridFrameBorder(Canvas, ARect, BorderStyle, dsUp, FixedColor);
  3768.        end;
  3769.        Exit;
  3770.     end;
  3771.     if (ARow < 0) and (ACol = -1) and (dgMarker in Options)
  3772.     then begin
  3773.        ALeft := (ARect.Right + ARect.Left - Indicators.Width - FrameOffs) shr 1 + 1;
  3774.        ATop  := (ARect.Top + ARect.Bottom - Indicators.Height) shr 1 - 1;
  3775.        Indicators.Draw(Canvas, ALeft-1, ATop, nbmCheckHrd);
  3776.        InflateRect(ARect, 1, 1);
  3777.        DrawGridFrameBorder(Canvas, ARect, BorderStyle, dsUp, FixedColor);
  3778.        Exit;
  3779.     end;
  3780.   end
  3781.   else with Canvas do
  3782.   begin
  3783.     FDrawColumn := Columns[ACol];
  3784.     if not (gdFixed in AState) or FrozenCol then
  3785.     begin
  3786.       Font := FDrawColumn.Font;
  3787.       Brush.Color := FDrawColumn.Color;
  3788.     end;
  3789.     if (ARow < 0) then
  3790.     begin
  3791.       if not FDrawColumn.Showing then Exit;
  3792.       TitleRect := CalcTitleRect(FDrawColumn, ARow + FTitleOffset, MasterCol);
  3793.       TitleRect.Right := ARect.Right;
  3794.       DrawTitleCell(Canvas, ACol, ARow + FTitleOffset, TitleRect, BorderState, True, True);
  3795.     end
  3796.     else if (FDataLink = nil) or not FDataLink.Active then
  3797.     begin
  3798.       if not FDrawColumn.Showing then Exit;
  3799.       FillRect(ARect);
  3800.     end
  3801.     else
  3802.     begin
  3803.       OldActive := FDataLink.ActiveRecord;
  3804.       try
  3805.         FDataLink.ActiveRecord := ARow;
  3806.  
  3807.         if IsColFirstVisible(ACol) then
  3808.         begin
  3809.           BRect := ARect;
  3810.           if (dgIndicator in Options)
  3811.              then BRect.Left  := IndicatorWidth + 1
  3812.              else BRect.Left  := 0;
  3813.           BRect.Right := BRect.Left + MarkerWidth;
  3814.           if ACol < (FixedCols - FIndicatorOffset) then InflateRect(BRect, 1, 1);
  3815.           DrawMarker(BRect);
  3816.         end;
  3817.  
  3818.         if not FDrawColumn.Showing then Exit;
  3819.  
  3820.         if (gdFixed in AState) and not FrozenCol then
  3821.         begin
  3822.            Font := FDrawColumn.Title.Font;
  3823.            Brush.Color := FDrawColumn.Title.Color;
  3824.         end
  3825.         else
  3826.         begin
  3827.           Font := FDrawColumn.Font;
  3828.           Brush.Color := FDrawColumn.Color;
  3829.         end;
  3830.  
  3831.         Value := GetDataValue(FDrawColumn);
  3832.         if FrozenCol and (ARow = Row - FTitleOffset) and
  3833.           (dgRowSelect in Options) then
  3834.           AState := AState + [gdSelected];
  3835.         Highlight := HighlightCell(ACol, ARow, Value, AState);
  3836.  
  3837.         if (dgHighlightRow in Options) and
  3838.            ((dgAlwaysShowSelection in Options) or Focused)
  3839.         then begin
  3840.           if OldActive = ARow then
  3841.           begin
  3842.             if ACol >= 0 then
  3843.             begin
  3844.               if not Focused and (dgeShadowSelection in OptionsEx) then
  3845.                 Brush.Color := clShadowed
  3846.               else begin
  3847.                 Brush.Color := clHighlight;
  3848.                 Font.Color := clHighlightText;
  3849.               end;
  3850.             end;
  3851.             AState := AState + [gdSelected];
  3852.           end;
  3853.           if Highlight then
  3854.           begin
  3855.             if not Focused and (dgeShadowSelection in OptionsEx) then
  3856.               Brush.Color := clShadowed
  3857.             else begin
  3858.               Brush.Color := clRowHighlight;
  3859.               Font.Color  := clTextHighlight;
  3860.             end;
  3861.             AState := AState + [gdFocused];
  3862.           end;
  3863.         end
  3864.         else if Highlight then
  3865.         begin
  3866.           if not Focused and (dgeShadowSelection in OptionsEx) then
  3867.             Brush.Color := clShadowed
  3868.           else begin
  3869.             Brush.Color := clHighlight;
  3870.             Font.Color := clHighlightText;
  3871.           end;
  3872.             AState := AState + [gdSelected];
  3873.         end;
  3874.         if not Enabled then
  3875.            Font.Color := clGrayText;
  3876.  
  3877.         if FDefaultDrawing and (ARect.Right - ARect.Left > 0) then
  3878.         begin
  3879.            WriteText(Canvas, ARect, 2, 2, Value, FDrawColumn.Alignment,
  3880.               UseRightToLeftAlignmentForField(FDrawColumn.Field, FDrawColumn.Alignment), FDrawColumn.WordBreak);
  3881.         end;
  3882.  
  3883.         if Columns.State = csDefault then
  3884.           DrawDataCell(ARect, FDrawColumn.Field, AState);
  3885.         DrawColumnCell(ARect, ACol, FDrawColumn, AState);
  3886.  
  3887.       finally
  3888.         FDataLink.ActiveRecord := OldActive;
  3889.       end;
  3890.       if FDefaultDrawing and (gdSelected in AState)
  3891.         and ((dgAlwaysShowSelection in Options) or Focused)
  3892.         and not (csDesigning in ComponentState)
  3893.         and not (dgRowSelect in Options)
  3894.         and (UpdateLock = 0)
  3895.         and (ValidParentForm(Self).ActiveControl = Self)
  3896.         and not (dgHighlightRow in Options) then
  3897.         Windows.DrawFocusRect(Handle, ARect);
  3898.     end;
  3899.   end;
  3900.   if (gdFixed in AState) and (([dgRowLines, dgColLines] * Options =
  3901.     [dgRowLines, dgColLines]) or (dgFlatButtons in Options)) and
  3902.     not FrozenCol then
  3903.   begin
  3904.     InflateRect(ARect, 1, 1);
  3905.     DrawGridFrameBorder(Canvas, ARect, BorderStyle, BorderState, FixedColor);
  3906.   end;
  3907. end;
  3908.  
  3909. procedure TDCCustomDBGrid.DrawDataCell(const Rect: TRect; Field: TField;
  3910.   State: TGridDrawState);
  3911. begin
  3912.   if Assigned(FOnDrawDataCell) then FOnDrawDataCell(Self, Rect, Field, State);
  3913. end;
  3914.  
  3915. procedure TDCCustomDBGrid.DrawColumnCell(const Rect: TRect; DataCol: Integer;
  3916.   Column: TColumn; State: TGridDrawState);
  3917. begin
  3918.   if Assigned(OnDrawColumnCell) then
  3919.     OnDrawColumnCell(Self, Rect, DataCol, Column, State);
  3920. end;
  3921.  
  3922. procedure TDCCustomDBGrid.EditButtonClick;
  3923. begin
  3924.   if Assigned(FOnEditButtonClick) then
  3925.     FOnEditButtonClick(Self)
  3926.   else
  3927.     ShowPopupEditor(Columns[SelectedIndex]);
  3928. end;
  3929.  
  3930. procedure TDCCustomDBGrid.EditingChanged;
  3931. begin
  3932.   if dgIndicator in Options then InvalidateCell(0, FSelRow);
  3933. end;
  3934.  
  3935. procedure TDCCustomDBGrid.EndLayout;
  3936. begin
  3937.   if FLayoutLock > 0 then
  3938.   begin
  3939.     try
  3940.       try
  3941.         if FLayoutLock = 1 then
  3942.           InternalLayout;
  3943.       finally
  3944.         if FLayoutLock = 1 then
  3945.           FColumns.EndUpdate;
  3946.       end;
  3947.     finally
  3948.       Dec(FLayoutLock);
  3949.       EndUpdate;
  3950.     end;
  3951.   end;
  3952. end;
  3953.  
  3954. procedure TDCCustomDBGrid.EndUpdate;
  3955. begin
  3956.   if FUpdateLock > 0 then
  3957.     Dec(FUpdateLock);
  3958. end;
  3959.  
  3960. function TDCCustomDBGrid.GetColField(DataCol: Integer): TField;
  3961. begin
  3962.   Result := nil;
  3963.   if (DataCol >= 0) and FDatalink.Active and (DataCol < Columns.Count) then
  3964.     Result := Columns[DataCol].Field;
  3965. end;
  3966.  
  3967. function TDCCustomDBGrid.GetDataSource: TDataSource;
  3968. begin
  3969.   Result := FDataLink.DataSource;
  3970. end;
  3971.  
  3972. function TDCCustomDBGrid.GetEditLimit: Integer;
  3973. begin
  3974.   Result := 0;
  3975.   if Assigned(SelectedField) and (SelectedField.DataType = ftString) then
  3976.     Result := SelectedField.Size;
  3977. end;
  3978.  
  3979. function TDCCustomDBGrid.GetEditMask(ACol, ARow: Longint): string;
  3980. begin
  3981.   Result := '';
  3982.   if FDatalink.Active then
  3983.   with Columns[RawToDataColumn(ACol)] do
  3984.     if Assigned(Field) then
  3985.       Result := Field.EditMask;
  3986. end;
  3987.  
  3988. function TDCCustomDBGrid.GetEditText(ACol, ARow: Longint): string;
  3989. begin
  3990.   Result := '';
  3991.   if FDatalink.Active then
  3992.   with Columns[RawToDataColumn(ACol)] do
  3993.     if Assigned(Field) then
  3994.       Result := Field.Text;
  3995.   FEditText := Result;
  3996. end;
  3997.  
  3998. function TDCCustomDBGrid.GetFieldCount: Integer;
  3999. begin
  4000.   Result := FDatalink.FieldCount;
  4001. end;
  4002.  
  4003. function TDCCustomDBGrid.GetFields(FieldIndex: Integer): TField;
  4004. begin
  4005.   Result := FDatalink.Fields[FieldIndex];
  4006. end;
  4007.  
  4008. function TDCCustomDBGrid.GetFieldValue(ACol: Integer): string;
  4009. var
  4010.   Field: TField;
  4011. begin
  4012.   Result := '';
  4013.   Field := GetColField(ACol);
  4014.   if Field <> nil then Result := Field.DisplayText;
  4015. end;
  4016.  
  4017. function TDCCustomDBGrid.GetSelectedField: TField;
  4018. var
  4019.   Index: Integer;
  4020. begin
  4021.   Index := SelectedIndex;
  4022.   if Index <> -1 then
  4023.     Result := Columns[Index].Field
  4024.   else
  4025.     Result := nil;
  4026. end;
  4027.  
  4028. function TDCCustomDBGrid.GetSelectedIndex: Integer;
  4029. begin
  4030.   Result := RawToDataColumn(Col);
  4031. end;
  4032.  
  4033. function TDCCustomDBGrid.HighlightCell(DataCol, DataRow: Integer;
  4034.   const Value: string; AState: TGridDrawState): Boolean;
  4035. var
  4036.   Index: Integer;
  4037. begin
  4038.   Result := False;
  4039.   if (dgMultiSelect in Options) and Datalink.Active then
  4040.     Result := FBookmarks.Find(Datalink.Datasource.Dataset.Bookmark, Index);
  4041.   if not Result then
  4042.     Result := (gdSelected in AState)
  4043.       and ((dgAlwaysShowSelection in Options) or Focused or
  4044.           ((InplaceEditor <> nil) and InplaceEditor.Focused))
  4045.         { updatelock eliminates flicker when tabbing between rows }
  4046.       and ((UpdateLock = 0) or (dgRowSelect in Options));
  4047. end;
  4048.  
  4049. procedure TDCCustomDBGrid.KeyDown(var Key: Word; Shift: TShiftState);
  4050. var
  4051.   KeyDownEvent: TKeyEvent;
  4052.  
  4053.   procedure Tab(GoForward: Boolean);
  4054.   var
  4055.     ACol, Original: Integer;
  4056.   begin
  4057.     ACol := Col;
  4058.     Original := ACol;
  4059.     BeginUpdate;    { Prevent highlight flicker on tab to next/prior row }
  4060.     try
  4061.       while True do
  4062.       begin
  4063.         if GoForward then
  4064.           Inc(ACol) else
  4065.           Dec(ACol);
  4066.         if ACol >= ColCount then
  4067.         begin
  4068.           NextRow(False);
  4069.           ACol := FIndicatorOffset;
  4070.         end
  4071.         else if ACol < FIndicatorOffset then
  4072.         begin
  4073.           PriorRow(False);
  4074.           ACol := ColCount - FIndicatorOffset;
  4075.         end;
  4076.         if ACol = Original then Exit;
  4077.         if TabStops[ACol] then
  4078.         begin
  4079.           MoveCol(ACol, 0);
  4080.           Exit;
  4081.         end;
  4082.       end;
  4083.     finally
  4084.       EndUpdate;
  4085.     end;
  4086.   end;
  4087.  
  4088.   function DeletePrompt: Boolean;
  4089.   var
  4090.     Msg: string;
  4091.   begin
  4092.     if (FBookmarks.Count > 1) then
  4093.       Msg := SDeleteMultipleRecordsQuestion
  4094.     else
  4095.       Msg := SDeleteRecordQuestion;
  4096.     Result := not (dgConfirmDelete in Options) or
  4097.       (MessageDlg(Msg, mtConfirmation, mbOKCancel, 0) <> idCancel);
  4098.   end;
  4099.  
  4100. const
  4101.   RowMovementKeys = [VK_UP, VK_PRIOR, VK_DOWN, VK_NEXT, VK_HOME, VK_END];
  4102.  
  4103. begin
  4104.   if not DataVisible then Exit;
  4105.  
  4106.   if FClipPopupVisible then
  4107.   begin
  4108.     if Key = VK_ESCAPE then
  4109.       HideClipPopup
  4110.     else
  4111.       TDBClipPopup(FClipPopup).KeyDown(Key, Shift);
  4112.     Key := 0;
  4113.     Exit;
  4114.   end;
  4115.  
  4116.   KeyDownEvent := OnKeyDown;
  4117.   if Assigned(KeyDownEvent) then KeyDownEvent(Self, Key, Shift);
  4118.   if not FDatalink.Active or not CanGridAcceptKey(Key, Shift) then Exit;
  4119.   if UseRightToLeftAlignment then
  4120.     if Key = VK_LEFT then
  4121.       Key := VK_RIGHT
  4122.     else if Key = VK_RIGHT then
  4123.       Key := VK_LEFT;
  4124.   with FDatalink.DataSet do
  4125.     if ssCtrl in Shift then
  4126.     begin
  4127.       if (Key in RowMovementKeys) then ClearSelection;
  4128.       case Key of
  4129.         VK_UP, VK_PRIOR: FDataLink.MoveBy(-FDatalink.ActiveRecord);
  4130.         VK_DOWN, VK_NEXT: FDataLink.MoveBy(FDatalink.BufferCount - FDatalink.ActiveRecord - 1);
  4131.         VK_LEFT: MoveCol(FIndicatorOffset, 1);
  4132.         VK_RIGHT: MoveCol(ColCount - 1, -1);
  4133.         VK_HOME: First;
  4134.         VK_END: Last;
  4135.         VK_DELETE:
  4136.           if not ReadOnly and not IsEmpty and CanModify and DeletePrompt then
  4137.             if FBookmarks.Count > 0 then
  4138.               FBookmarks.Delete
  4139.             else
  4140.               Delete;
  4141.         65:{A} SelectItems(smSelect);
  4142.       end
  4143.     end
  4144.     else
  4145.       case Key of
  4146.         VK_UP: PriorRow(True);
  4147.         VK_DOWN: NextRow(True);
  4148.         VK_LEFT:
  4149.           if (dgRowSelect in Options) then
  4150.             PriorRow(False) else
  4151.             MoveCol(Col - 1, -1);
  4152.         VK_RIGHT:
  4153.           if (dgRowSelect in Options) then
  4154.             NextRow(False) else
  4155.             MoveCol(Col + 1, 1);
  4156.         VK_HOME:
  4157.           if (ColCount = FIndicatorOffset+1)
  4158.              or (dgRowSelect in Options) then
  4159.           begin
  4160.             ClearSelection;
  4161.             First;
  4162.           end
  4163.           else
  4164.             MoveCol(FIndicatorOffset, 1);
  4165.         VK_END:
  4166.           if (ColCount = FIndicatorOffset+1)
  4167.              or (dgRowSelect in Options) then
  4168.           begin
  4169.             ClearSelection;
  4170.             Last;
  4171.           end
  4172.           else
  4173.             MoveCol(ColCount - 1, -1);
  4174.         VK_NEXT:
  4175.           begin
  4176.             ClearSelection;
  4177.             FDataLink.MoveBy(VisibleRowCount);
  4178.           end;
  4179.         VK_PRIOR:
  4180.           begin
  4181.             ClearSelection;
  4182.             FDataLink.MoveBy(-VisibleRowCount);
  4183.           end;
  4184.         VK_INSERT:
  4185.           if (dgeInsertSelect in OptionsEx) and
  4186.              (dgMarker in Options) and FDatalink.Active then
  4187.           begin
  4188.             try
  4189.               BeginUpdate;
  4190.               FSelectionAnchor := FBookmarks.CurrentRow;
  4191.               FBookmarks.CurrentRowSelected := not FBookmarks.CurrentRowSelected;
  4192.               FSelecting := True;
  4193.               NextRow(True);
  4194.             finally
  4195.               EndUpdate;
  4196.             end
  4197.           end
  4198.           else
  4199.             if CanModify and not ReadOnly and (dgEditing in Options) then
  4200.             begin
  4201.               ClearSelection;
  4202.               Insert;
  4203.             end;
  4204.         VK_TAB: if not (ssAlt in Shift) then Tab(not (ssShift in Shift));
  4205.         VK_ESCAPE:
  4206.           begin
  4207.             inherited;
  4208.             if Key = VK_ESCAPE then
  4209.             begin
  4210.               if SysLocale.PriLangID = LANG_KOREAN then
  4211.                 FIsESCKey := True;
  4212.               FDatalink.Reset;
  4213.               ClearSelection;
  4214.               if not (dgAlwaysShowEditor in Options) then HideEditor;
  4215.             end;
  4216.           end;
  4217.         VK_F2: EditorMode := True;
  4218.       end;
  4219. end;
  4220.  
  4221. procedure TDCCustomDBGrid.KeyPress(var Key: Char);
  4222. begin
  4223.   if not DataVisible then Exit;
  4224.   if (DragState <> dsNone) then
  4225.   begin
  4226.     inherited;
  4227.     Exit;
  4228.   end;
  4229.  
  4230.   FIsESCKey := False;
  4231.   if not (dgAlwaysShowEditor in Options) and (Key = Char(VK_RETURN)) then
  4232.     FDatalink.UpdateData;
  4233.   inherited KeyPress(Key);
  4234. end;
  4235.  
  4236. procedure TDCCustomDBGrid.SetTitleHeight;
  4237. var
  4238.   I, D, B: Integer;
  4239.   Heights: array of Integer;
  4240.   P: TPoint;
  4241. begin
  4242.   Canvas.Font := Font;
  4243.   B := GetSystemMetrics(SM_CYHSCROLL);
  4244.   if dgTitles in Options then
  4245.   begin
  4246.     SetLength(Heights, FTitleOffset+1);
  4247.     for I := 0 to FColumns.Count-1 do
  4248.     begin
  4249.       Canvas.Font := FColumns[I].Title.Font;
  4250.       D := FColumns[I].Depth;
  4251.       if D <= High(Heights) then
  4252.       begin
  4253.         P.Y := GetTextHeightEx(Canvas, FColumns[I].Title.Caption);
  4254.         if P.Y > 0 then Inc(P.Y, 4);
  4255.         if (Images <> nil) and (FColumns[I].ItemIndex <> -1) then
  4256.            if P.Y < (Images.Height + 3) then P.Y := Images.Height + 3;
  4257.  
  4258.         if FColumns[I].Expandable and (B > P.Y) then  P.Y := B;
  4259.         Heights[D] := _intMax(P.Y, Heights[D]);
  4260.       end;
  4261.     end;
  4262.     if Heights[0] = 0 then
  4263.     begin
  4264.       Canvas.Font := FTitleFont;
  4265.       Heights[0] := Canvas.TextHeight('Wg') + 4;
  4266.     end;
  4267.  
  4268.     for I := 0 to High(Heights)-1 do
  4269.       RowHeights[I] := Heights[I];
  4270.   end;
  4271. end;
  4272.  
  4273. { InternalLayout is called with layout locks and column locks in effect }
  4274. procedure TDCCustomDBGrid.InternalLayout;
  4275.  
  4276.   function FieldIsMapped(F: TField): Boolean;
  4277.   var
  4278.     X: Integer;
  4279.   begin
  4280.     Result := False;
  4281.     if F = nil then Exit;
  4282.     for X := 0 to FDatalink.FieldCount-1 do
  4283.       if FDatalink.Fields[X] = F then
  4284.       begin
  4285.         Result := True;
  4286.         Exit;
  4287.       end;
  4288.   end;
  4289.  
  4290.   procedure CheckForPassthroughs;  // check for Columns.State flip-flop
  4291.   var
  4292.     SeenPassthrough: Boolean;
  4293.     I, J: Integer;
  4294.     Column: TColumn;
  4295.   begin
  4296.     SeenPassthrough := False;
  4297.     for I := 0 to FColumns.Count-1 do
  4298.       if not FColumns[I].IsStored then
  4299.         SeenPassthrough := True
  4300.       else if SeenPassthrough then
  4301.       begin  // we have both persistent and non-persistent columns.  Kill the latter
  4302.         for J := FColumns.Count-1 downto 0 do
  4303.         begin
  4304.           Column := FColumns[J];
  4305.           if not Column.IsStored then
  4306.             Column.Free;
  4307.         end;
  4308.         Exit;
  4309.       end;
  4310.   end;
  4311.  
  4312.   procedure ResetColumnFieldBindings;
  4313.   var
  4314.     I, J, K: Integer;
  4315.     Fld: TField;
  4316.     Column: TColumn;
  4317.   begin
  4318.     if FColumns.State = csDefault then
  4319.     begin
  4320.        { Destroy columns whose fields have been destroyed or are no longer
  4321.          in field map }
  4322.       if (not FDataLink.Active) and (FDatalink.DefaultFields) then
  4323.         FColumns.Clear
  4324.       else
  4325.         for J := FColumns.Count-1 downto 0 do
  4326.           with FColumns[J] do
  4327.           if not Assigned(Field)
  4328.             or not FieldIsMapped(Field) then Free;
  4329.       I := FDataLink.FieldCount;
  4330.       if (I = 0) and (FColumns.Count = 0) then Inc(I);
  4331.       for J := 0 to I-1 do
  4332.       begin
  4333.         Fld := FDatalink.Fields[J];
  4334.         if Assigned(Fld) then
  4335.         begin
  4336.           K := J;
  4337.            { Pointer compare is valid here because the grid sets matching
  4338.              column.field properties to nil in response to field object
  4339.              free notifications.  Closing a dataset that has only default
  4340.              field objects will destroy all the fields and set associated
  4341.              column.field props to nil. }
  4342.           while (K < FColumns.Count) and (FColumns[K].Field <> Fld) do
  4343.             Inc(K);
  4344.           if K < FColumns.Count then
  4345.             Column := FColumns[K]
  4346.           else
  4347.           begin
  4348.             Column := FColumns.InternalAdd;
  4349.             Column.Field := Fld;
  4350.             if Column.Field.Tag = -1 then Column.Visible := False;
  4351.           end;
  4352.         end
  4353.         else
  4354.           Column := FColumns.InternalAdd;
  4355.         Column.Index := J;
  4356.       end;
  4357.     end
  4358.     else
  4359.     begin
  4360.       { Force columns to reaquire fields (in case dataset has changed) }
  4361.       for I := 0 to FColumns.Count-1 do
  4362.         FColumns[I].Field := nil;
  4363.     end;
  4364.   end;
  4365.  
  4366.   procedure MeasureTitleHeights;
  4367.   var
  4368.     K: Integer;
  4369.     RestoreCanvas: Boolean;
  4370.   begin
  4371.     RestoreCanvas := not HandleAllocated;
  4372.     if RestoreCanvas then Canvas.Handle := GetDC(0);
  4373.     try
  4374.       Canvas.Font := Font;
  4375.       K := Canvas.TextHeight('Wg') + 3;
  4376.       if dgRowLines in Options then
  4377.         Inc(K, GridLineWidth);
  4378.  
  4379.       // DefaultRowHeight := K;
  4380.       // New 29/09/1998
  4381.       if not (dgUserRowHeight in Options) then DefaultRowHeight := K;
  4382.       SetTitleHeight;
  4383.     finally
  4384.       if RestoreCanvas then
  4385.       begin
  4386.         ReleaseDC(0, Canvas.Handle);
  4387.         Canvas.Handle := 0;
  4388.       end;
  4389.     end;
  4390.   end;
  4391.  
  4392. var
  4393.   I, J: Integer;
  4394. begin
  4395.   if ([csLoading, csDestroying] * ComponentState) <> [] then Exit;
  4396.  
  4397.   if HandleAllocated then KillMessage(Handle, CM_DEFERLAYOUT);
  4398.  
  4399.   CheckForPassthroughs;
  4400.   FIndicatorOffset := 0;
  4401.  
  4402.   if dgIndicator in Options then Inc(FIndicatorOffset);
  4403.   if dgMarker in Options then Inc(FIndicatorOffset);
  4404.  
  4405.   FDatalink.ClearMapping;
  4406.   if FDatalink.Active then DefineFieldMap;
  4407.   DoubleBuffered := (FDatalink.Dataset <> nil) and FDatalink.Dataset.ObjectView;
  4408.   ResetColumnFieldBindings;
  4409.   FVisibleColumns.Clear;
  4410.   for I := 0 to FColumns.Count-1 do
  4411.     if FColumns[I].Showing then FVisibleColumns.Add(FColumns[I]);
  4412.   ColCount := FColumns.Count + FIndicatorOffset;
  4413.   FTitleOffset := 0;
  4414.   if dgTitles in Options then
  4415.   begin
  4416.     FTitleOffset := 1;
  4417.     if (FDatalink <> nil) and (FDatalink.Dataset <> nil)
  4418.       and FDatalink.Dataset.ObjectView then
  4419.     begin
  4420.       for I := 0 to FColumns.Count-1 do
  4421.       begin
  4422.         if FColumns[I].Showing then
  4423.         begin
  4424.           J := FColumns[I].Depth;
  4425.           if J >= FTitleOffset then FTitleOffset := J+1;
  4426.         end;
  4427.       end;
  4428.     end;
  4429.   end;
  4430.   MeasureTitleHeights;
  4431.   SetColumnAttributes;
  4432.   UpdateRowCount;
  4433.   UpdateActive;
  4434.  
  4435.   if dgAutoSize in Options then
  4436.   begin
  4437.     if FSizingIndex > -1 then
  4438.     begin
  4439.       I := FSizingIndex;
  4440.       FSizingIndex := -1;
  4441.       UpdateColWidths(I, i <> ColCount - 1);
  4442.     end
  4443.     else
  4444.       UpdateColWidths(-1, True);
  4445.  
  4446.     if FColumns.Count  > 0 then
  4447.       for I := FIndicatorOffset to ColCount - 1 do
  4448.         FColumns[I - FIndicatorOffset].Width := ColWidths[I];
  4449.   end
  4450.   else
  4451.    invalidate;
  4452. end;
  4453.  
  4454. procedure TDCCustomDBGrid.LayoutChanged;
  4455. begin
  4456.   if AcquireLayoutLock then
  4457.     EndLayout;
  4458. end;
  4459.  
  4460. procedure TDCCustomDBGrid.LinkActive(Value: Boolean);
  4461. var
  4462.   Comp: TComponent;
  4463.   I: Integer;
  4464. begin
  4465.   if not Value then HideEditor;
  4466.   FBookmarks.LinkActive(Value);
  4467.   try
  4468.     LayoutChanged;
  4469.   finally
  4470.     for I := ComponentCount-1 downto 0 do
  4471.     begin
  4472.       Comp := Components[I];   // Free all the popped-up subgrids
  4473.       if (Comp is TDCCustomDBGrid)
  4474.         and (TDCCustomDBGrid(Comp).DragKind = dkDock) then
  4475.         Comp.Free;
  4476.     end;
  4477.     UpdateScrollBar;
  4478.     if Value and (dgAlwaysShowEditor in Options) then ShowEditor;
  4479.   end;
  4480. end;
  4481.  
  4482. procedure TDCCustomDBGrid.Loaded;
  4483. begin
  4484.   inherited Loaded;
  4485.   if FColumns.Count > 0 then
  4486.     ColCount := FColumns.Count;
  4487.   LayoutChanged;
  4488. end;
  4489.  
  4490. function TDCCustomDBGrid.PtInExpandButton(X,Y: Integer; var MasterCol: TColumn): Boolean;
  4491. var
  4492.   Cell: TGridCoord;
  4493.   R: TRect;
  4494. begin
  4495.   MasterCol := nil;
  4496.   Result := False;
  4497.   Cell := MouseCoord(X,Y);
  4498.   if (Cell.Y < FTitleOffset) and FDatalink.Active
  4499.     and (Cell.X >= FIndicatorOffset)
  4500.     and (RawToDataColumn(Cell.X) < Columns.Count) then
  4501.   begin
  4502.     R := CalcTitleRect(Columns[RawToDataColumn(Cell.X)], Cell.Y, MasterCol);
  4503.     if not UseRightToLeftAlignment then
  4504.       R.Left := R.Right - GetSystemMetrics(SM_CXHSCROLL)
  4505.     else
  4506.       R.Right := R.Left + GetSystemMetrics(SM_CXHSCROLL);
  4507.     Result := MasterCol.Expandable and PtInRect(R, Point(X,Y));
  4508.   end;
  4509. end;
  4510.  
  4511. function TDCCustomDBGrid.LeftTitleButton(Row, Col: integer): boolean;
  4512. begin
  4513.   Result := ([dgIndicator, dgTitles]*Options=[dgIndicator, dgTitles]) and
  4514.             (Row=0) and (Col=0);
  4515. end;
  4516.  
  4517. procedure TDCCustomDBGrid.MouseDown(Button: TMouseButton; Shift: TShiftState;
  4518.   X, Y: Integer);
  4519. var
  4520.   Cell: TGridCoord;
  4521.   OldCol,OldRow: Integer;
  4522.   MasterCol: TColumn;
  4523.   GridOptions: TGridOptions;
  4524.   AX, AY: integer;
  4525.   AOnMouseDown: TMouseEvent;
  4526.   Msg: TMsg;
  4527.   R: TRect;
  4528. begin
  4529.   if not AcquireFocus or not DataVisible then Exit;
  4530.  
  4531.   AX := X; AY := Y;
  4532.  
  4533.   if (X > 0) and (Y > 0) then
  4534.     Cell := MouseCoord(X, Y)
  4535.   else begin
  4536.     Cell.X := 0;
  4537.     Cell.Y := -1;
  4538.   end;
  4539.  
  4540.   R := CellRect(Cell.X, Cell.Y);
  4541.   if IsRectEmpty(R) then Exit;
  4542.  
  4543.   if (ssDouble in Shift) and (Button = mbLeft) then
  4544.   begin
  4545.     if (Cell.X >=  FIndicatorOffset) and
  4546.        (Cell.Y >=  FTitleOffset)     then
  4547.     begin
  4548.       if MouseUpBeforeDblClk then
  4549.       begin
  4550.         {WM_LBUTTONUP}
  4551.         case Integer(GetMessage(Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST)) of
  4552.           -1:;
  4553.           0 :
  4554.             begin
  4555.               PostQuitMessage(Msg.WParam);
  4556.             end;
  4557.           else
  4558.             DispatchMessage(Msg);
  4559.         end;
  4560.       end;
  4561.       DblClick;
  4562.       if Cell.Y >= FTitleOffset then CellDblClick(Columns[SelectedIndex]);
  4563.       Exit;
  4564.     end;
  4565.     Shift := Shift - [ssDouble];
  4566.   end;
  4567.  
  4568.   FMousePoint := Point(X,Y);
  4569.  
  4570.   if (dgTitleClicked in Options) and (Button = mbLeft) and not Sizing(X, Y)
  4571.       and (Cell.Y=0) and FDatalink.Active and
  4572.       not ( ([dgMarker,dgIndicator]*Options=[dgMarker,dgIndicator]) and (Cell.X = 1) or
  4573.             ([dgMarker,dgIndicator]*Options=[dgMarker]            ) and (Cell.X = 0))
  4574.   then begin
  4575.     ClickedCol := Cell.X;
  4576.   end;
  4577.  
  4578.   if (Button = mbLeft) and LeftTitleButton(Cell.X,Cell.Y) and
  4579.      (dgeMarkerMenu in OptionsEx) then
  4580.   begin
  4581.     ClipClick;
  4582.     Exit;
  4583.   end;
  4584.  
  4585.   if FClipPopupVisible then HideClipPopup;
  4586.  
  4587.   if Sizing(X, Y) then
  4588.   begin
  4589.     FDatalink.UpdateData;
  4590.     HideEditor;
  4591.     inherited MouseDown(Button, Shift, X, Y);
  4592.     Exit;
  4593.   end
  4594.   else
  4595.    FSizingIndex := -1;
  4596.  
  4597.   if (Cell.X < 0) and (Cell.Y < 0) then
  4598.   begin
  4599.     inherited MouseDown(Button, Shift, X, Y);
  4600.     Exit;
  4601.   end;
  4602.  
  4603.   if (DragKind = dkDock) and (Cell.X < FIndicatorOffset) and
  4604.     (Cell.Y < FTitleOffset) and (not (csDesigning in ComponentState)) then
  4605.   begin
  4606.     BeginDrag(False);
  4607.     Exit;
  4608.   end;
  4609.  
  4610.   if PtInExpandButton(X,Y, MasterCol) then
  4611.   begin
  4612.     MasterCol.Expanded := not MasterCol.Expanded;
  4613.     ReleaseCapture;
  4614.     UpdateDesigner;
  4615.     Exit;
  4616.   end;
  4617.  
  4618.   if ((csDesigning in ComponentState) or (dgColumnResize in Options)) and
  4619.     (Cell.Y < FTitleOffset) then
  4620.   begin
  4621.     FDataLink.UpdateData;
  4622.     HideEditor;
  4623.     //inherited MouseDown(Button, Shift, X, Y);
  4624.  
  4625.     if (dgTitleClicked in Options) and FDatalink.Active and (Button = mbLeft) and
  4626.        ( ([dgMarker,dgIndicator]*Options=[dgMarker,dgIndicator]) and (Cell.X > 1) or
  4627.          ([dgMarker,dgIndicator]*Options=[dgIndicator]         ) and (Cell.X > 0) or
  4628.          ([dgMarker,dgIndicator]*Options=[dgMarker]            ) and (Cell.X > 0) or
  4629.          ([dgMarker,dgIndicator]*Options=[]                    ) )
  4630.     then begin
  4631.       GridOptions := inherited Options;
  4632.       inherited Options := inherited Options - [goColMoving];
  4633.       inherited MouseDown(Button, Shift, X, Y);
  4634.       inherited Options := GridOptions;
  4635.     end
  4636.     else inherited MouseDown(Button, Shift, X, Y);
  4637.     Exit;
  4638.   end;
  4639.  
  4640.   if FDatalink.Active then
  4641.     with Cell do
  4642.     begin
  4643.       BeginUpdate;   { eliminates highlight flicker when selection moves }
  4644.       try
  4645.         FDatalink.UpdateData; // validate before moving
  4646.         HideEditor;
  4647.         OldCol := Col;
  4648.         OldRow := Row;
  4649.         if (Y >= FTitleOffset) and (Y - Row <> 0) then
  4650.           FDatalink.MoveBy(Y - Row);
  4651.         //if (X >= FIndicatorOffset) then
  4652.         //New 29091998
  4653.         if (X >= (FixedCols - FrozenCols)) then
  4654.           MoveCol(X, 0);
  4655.         if (dgMultiSelect in Options) and FDatalink.Active then
  4656.           with FBookmarks do
  4657.           begin
  4658.             FSelecting := False;
  4659.             if ssCtrl in Shift then
  4660.               CurrentRowSelected := not CurrentRowSelected
  4661.             else
  4662.             begin
  4663.               Clear;
  4664.               CurrentRowSelected := True;
  4665.             end;
  4666.           end;
  4667.         if (dgMarker in Options)  and FDatalink.Active and
  4668.            (X < FIndicatorOffset) and
  4669.            ( ((dgIndicator in Options)   and  (X=1))   or
  4670.              (not(dgIndicator in Options) and (X=0)) ) and
  4671.            (Button = mbLeft)
  4672.         then
  4673.           with FBookmarks do
  4674.           begin
  4675.             FSelecting := False;
  4676.             CurrentRowSelected := not CurrentRowSelected;
  4677.             InvalidateCell(Cell.X, Cell.Y);
  4678.           end;
  4679.         if (Button = mbLeft) and
  4680.           (((X = OldCol) and (Y = OldRow)) or (dgAlwaysShowEditor in Options)) then
  4681.           ShowEditor         { put grid in edit mode }
  4682.         else
  4683.           InvalidateEditor;  { draw editor, if needed }
  4684.       finally
  4685.         EndUpdate;
  4686.         AOnMouseDown := OnMouseDown;
  4687.         if Assigned(AOnMouseDown) then AOnMouseDown(Self, Button, Shift, AX, AY);
  4688.       end;
  4689.     end;
  4690. end;
  4691.  
  4692. procedure TDCCustomDBGrid.MouseMove(Shift: TShiftState; X, Y: Integer);
  4693. var
  4694.   Cell: TGridCoord;
  4695.   OldCurrentCol: integer;
  4696. begin
  4697.   if not DataVisible then Exit;
  4698.   Cell := MouseCoord(X,Y);
  4699.   OldCurrentCol := FCurrentCol;
  4700.   if Cell.Y = 0 then FCurrentCol := Cell.X else FCurrentCol := -1;
  4701.  
  4702.   if (DragState = dsNone) and
  4703.      (Cell.X >= FixedCols) and (ClickedCol=FCurrentCol) and (ClickedCol <> -1) and
  4704.      (FGridState <> gsColMoving) and
  4705.      ((Abs(FMousePoint.X - X) > 5) or (Abs(FMousePoint.Y - Y) > 5) ) then
  4706.   begin
  4707.      FGridState := gsColMoving;
  4708.      inherited MouseDown(mbLeft, Shift, FMousePoint.X, FMousePoint.Y);
  4709.      if (FGridState = gsColMoving) or (DragState = dsColMoving) then Exit;
  4710.   end;
  4711.  
  4712.   inherited MouseMove(Shift, X, Y);
  4713.  
  4714.   if (ClickedCol <> -1) and (FCurrentCol <> OldCurrentCol) and
  4715.      (FGridState <> gsColMoving) and (DragState = dsNone)
  4716.      and not
  4717.       ((ClickedCol = 0) and  not(dgIndicator in Options) and (dgMarker in Options)) or
  4718.       ((ClickedCol = 1) and     (dgIndicator in Options) and (dgMarker in Options))
  4719.   then begin
  4720.     InvalidateCell(ClickedCol, 0);
  4721.   end;
  4722.  
  4723.   if (Cell.Y < FTitleOffset) and (RawToDataColumn(Cell.X)>=0) and (Columns.Count > 0) then
  4724.   begin
  4725.     FColumnCell := RawToDataColumn(Cell.X);
  4726.     DoColumnComment(MODE_SHOWWINDOW, Columns[FColumnCell]);
  4727.   end
  4728.   else begin
  4729.     DoColumnComment(MODE_HIDEWINDOW, nil);
  4730.     {Γ±≥αΓΦ≥ⁿ ∩≡εΓσ≡Ω≤ φα ∩εΣ±Γσ≥Ω≤ hinta σ±δΦ ≥σΩ±≥ φσ ∩ε∞σ∙ασ≥±  Γ  ≈σΘΩσ}
  4731.   end;
  4732.  
  4733. end;
  4734.  
  4735. procedure TDCCustomDBGrid.MouseUp(Button: TMouseButton; Shift: TShiftState;
  4736.   X, Y: Integer);
  4737. var
  4738.   Cell  : TGridCoord;
  4739.   SaveState: TGridState;
  4740.   SaveDragState: TDragGridState;
  4741.   MouseClick: boolean;
  4742.   OldClickedCol, NewSize: integer;
  4743.   R: TRect;
  4744. begin
  4745.   SaveState := FGridState;
  4746.   SaveDragState := DragState;
  4747.  
  4748.   MouseClick := (ClickedCol <> -1) and (ClickedCol=FCurrentCol);
  4749.   Cell := MouseCoord(X,Y);
  4750.  
  4751.   inherited MouseUp(Button, Shift, X, Y);
  4752.  
  4753.   if (SaveState = gsColSizing) and (FSizingIndex < FixedCols) then
  4754.   begin
  4755.     R := CellRect(FSizingIndex, Cell.Y);
  4756.     NewSize := X - R.Left + FSizingOff;
  4757.     if NewSize < 5 then  NewSize := 5;
  4758.     ColWidths[FSizingIndex] := NewSize;
  4759.     UpdateDesigner;
  4760.   end;
  4761.  
  4762.   if (Button = mbLeft) and (ClickedCol <> -1) then
  4763.   begin
  4764.     OldClickedCol := ClickedCol;
  4765.     ClickedCol := -1;
  4766.     InvalidateCell(OldClickedCol, 0);
  4767.   end;
  4768.  
  4769.   if (SaveState = gsRowSizing) or (SaveState = gsColSizing) or
  4770.     ((InplaceEditor <> nil) and (InplaceEditor.Visible) and
  4771.      (PtInRect(InplaceEditor.BoundsRect, Point(X,Y)))) then Exit;
  4772.  
  4773.   if (Button = mbLeft) and (Cell.X >= FIndicatorOffset) and(Cell.Y >= 0) and
  4774.      (SaveState <> gsColMoving) and (RawToDataColumn(Cell.X) < Columns.Count) and
  4775.      (SaveDragState <> dsColMoving) and (SaveDragState <>dsHeaderMoving)
  4776.   then begin
  4777.     if (Cell.Y <  FTitleOffset) and MouseClick then
  4778.       DoColumnClick(Shift, Cell.X)
  4779.     else
  4780.       CellClick(Columns[SelectedIndex]);
  4781.   end;
  4782.  
  4783. end;
  4784.  
  4785. procedure TDCCustomDBGrid.MoveCol(RawCol, Direction: Integer);
  4786. var
  4787.   OldCol: Integer;
  4788. begin
  4789.   FDatalink.UpdateData;
  4790.   if RawCol >= ColCount then
  4791.     RawCol := ColCount - 1;
  4792.   //if RawCol < FIndicatorOffset then RawCol := FIndicatorOffset;
  4793.   //30/09/1998
  4794.   if RawCol < FixedCols - FrozenCols then RawCol := FixedCols- FrozenCols;
  4795.   if Direction <> 0 then
  4796.   begin
  4797.     while (RawCol < ColCount) and (RawCol >= FIndicatorOffset) and
  4798.       (ColWidths[RawCol] <= 0) do
  4799.       Inc(RawCol, Direction);
  4800.     if (RawCol >= ColCount) or (RawCol < FIndicatorOffset) then Exit;
  4801.   end;
  4802.   OldCol := Col;
  4803.   if RawCol <> OldCol then
  4804.   begin
  4805.     if not FInColExit then
  4806.     begin
  4807.       FInColExit := True;
  4808.       try
  4809.         ColExit;
  4810.       finally
  4811.         FInColExit := False;
  4812.       end;
  4813.       if Col <> OldCol then Exit;
  4814.     end;
  4815.     if not (dgAlwaysShowEditor in Options) then HideEditor;
  4816.     LockWindowUpdate(Handle);
  4817.     Col := RawCol;
  4818.     LockWindowUpdate(0);
  4819.     ColEnter;
  4820.   end;
  4821. end;
  4822.  
  4823. procedure TDCCustomDBGrid.Notification(AComponent: TComponent;
  4824.   Operation: TOperation);
  4825. var
  4826.   I: Integer;
  4827.   NeedLayout: Boolean;
  4828. begin
  4829.   inherited Notification(AComponent, Operation);
  4830.   if (Operation = opRemove) then
  4831.   begin
  4832.     if (AComponent is TPopupMenu) then
  4833.     begin
  4834.       for I := 0 to Columns.Count-1 do
  4835.         if Columns[I].PopupMenu = AComponent then
  4836.           Columns[I].PopupMenu := nil;
  4837.     end
  4838.     else if (FDataLink <> nil) then
  4839.       if (AComponent = DataSource)  then
  4840.         DataSource := nil
  4841.       else if (AComponent is TField) then
  4842.       begin
  4843.         NeedLayout := False;
  4844.         BeginLayout;
  4845.         try
  4846.           for I := 0 to Columns.Count-1 do
  4847.             with Columns[I] do
  4848.               if Field = AComponent then
  4849.               begin
  4850.                 Field := nil;
  4851.                 NeedLayout := True;
  4852.               end;
  4853.         finally
  4854.           if NeedLayout and Assigned(FDatalink.Dataset)
  4855.             and not FDatalink.Dataset.ControlsDisabled then
  4856.             EndLayout
  4857.           else
  4858.             DeferLayout;
  4859.         end;
  4860.       end;
  4861.   end;
  4862.   if (Operation = opRemove) and (AComponent = FImages) then FImages := nil;
  4863. end;
  4864.  
  4865. procedure TDCCustomDBGrid.RecordChanged(Field: TField);
  4866. var
  4867.   I: Integer;
  4868.   CField: TField;
  4869. begin
  4870.   if not HandleAllocated then Exit;
  4871.   if Field = nil then
  4872.     Invalidate
  4873.   else
  4874.   begin
  4875.     for I := 0 to Columns.Count - 1 do
  4876.       if Columns[I].Field = Field then
  4877.         InvalidateCol(DataToRawColumn(I));
  4878.   end;
  4879.   CField := SelectedField;
  4880.   if ((Field = nil) or (CField = Field)) and
  4881.     (Assigned(CField) and (CField.Text <> FEditText) and
  4882.     ((SysLocale.PriLangID <> LANG_KOREAN) or FIsESCKey)) then
  4883.   begin
  4884.     InvalidateEditor;
  4885.     if InplaceEditor <> nil then InplaceEditor.Deselect;
  4886.   end;
  4887. end;
  4888.  
  4889. procedure TDCCustomDBGrid.Scroll(Distance: Integer);
  4890. var
  4891.   OldRect, NewRect: TRect;
  4892.   RowHeight: Integer;
  4893. begin
  4894.   if not HandleAllocated then Exit;
  4895.   OldRect := BoxRectEx(0, Row, ColCount - 1, Row);
  4896.   if (FDataLink.ActiveRecord >= RowCount - FTitleOffset) then UpdateRowCount;
  4897.   UpdateScrollBar;
  4898.   UpdateActive;
  4899.   NewRect := BoxRectEx(0, Row, ColCount - 1, Row);
  4900.   ValidateRect(Handle, @OldRect);
  4901.   InvalidateRect(Handle, @OldRect, False);
  4902.   InvalidateRect(Handle, @NewRect, False);
  4903.   if Distance <> 0 then
  4904.   begin
  4905.     HideEditor;
  4906.     try
  4907.       if Abs(Distance) > VisibleRowCount then
  4908.       begin
  4909.         Invalidate;
  4910.         Exit;
  4911.       end
  4912.       else
  4913.       begin
  4914.         RowHeight := DefaultRowHeight;
  4915.         if dgRowLines in Options then Inc(RowHeight, GridLineWidth);
  4916.         if (dgIndicator in Options) or
  4917.            (dgMarker    in Options) then
  4918.         begin
  4919.           OldRect := BoxRectEx(0, FSelRow, ColCount - 1, FSelRow);
  4920.           InvalidateRect(Handle, @OldRect, False);
  4921.         end;
  4922.         NewRect := BoxRectEx(0, FTitleOffset, ColCount - 1, 1000);
  4923.         ScrollWindowEx(Handle, 0, -RowHeight * Distance, @NewRect, @NewRect,
  4924.           0, nil, SW_Invalidate);
  4925.         if (dgIndicator in Options) or
  4926.            (dgMarker    in Options) then
  4927.         begin
  4928.           NewRect := BoxRectEx(0, Row, ColCount - 1, Row);
  4929.           InvalidateRect(Handle, @NewRect, False);
  4930.         end;
  4931.       end;
  4932.     finally
  4933.       if dgAlwaysShowEditor in Options then ShowEditor;
  4934.     end;
  4935.   end;
  4936.   if UpdateLock = 0 then Update;
  4937. end;
  4938.  
  4939. procedure TDCCustomDBGrid.SetColumns(Value: TDBGridColumns);
  4940. begin
  4941.   Columns.Assign(Value);
  4942. end;
  4943.  
  4944. function ReadOnlyField(Field: TField): Boolean;
  4945. var
  4946.   MasterField: TField;
  4947. begin
  4948.   Result := Field.ReadOnly;
  4949.   if not Result and (Field.FieldKind = fkLookup) then
  4950.   begin
  4951.     Result := True;
  4952.     if Field.DataSet = nil then Exit;
  4953.     MasterField := Field.Dataset.FindField(Field.KeyFields);
  4954.     if MasterField = nil then Exit;
  4955.     Result := MasterField.ReadOnly;
  4956.   end;
  4957. end;
  4958.  
  4959. procedure TDCCustomDBGrid.SetColumnAttributes;
  4960. var
  4961.   I: Integer;
  4962. begin
  4963.   for I := 0 to FColumns.Count-1 do
  4964.   with FColumns[I] do
  4965.   begin
  4966.     TabStops[I + FIndicatorOffset] := Showing and not ReadOnly and DataLink.Active and
  4967.       Assigned(Field) and not (Field.FieldKind = fkCalculated) and not ReadOnlyField(Field);
  4968.     ColWidths[I + FIndicatorOffset] := Width;
  4969.   end;
  4970.   if (dgIndicator in Options) then
  4971.     ColWidths[0] := IndicatorWidth;
  4972.   if (dgMarker    in Options) then
  4973.      if (dgIndicator in Options) then
  4974.         ColWidths[1] := MarkerWidth
  4975.       else
  4976.         ColWidths[0] := MarkerWidth;
  4977.   SetFrozenCols(FFrozenCols)
  4978. end;
  4979.  
  4980. procedure TDCCustomDBGrid.SetDataSource(Value: TDataSource);
  4981. begin
  4982.   FBookmarks.Clear;
  4983.   if Value = FDatalink.Datasource then Exit;
  4984.   FDataLink.DataSource := Value;
  4985.   if Value <> nil then Value.FreeNotification(Self);
  4986.   LinkActive(FDataLink.Active);
  4987. end;
  4988.  
  4989. procedure TDCCustomDBGrid.SetEditText(ACol, ARow: Longint; const Value: string);
  4990. begin
  4991.   FEditText := Value;
  4992. end;
  4993.  
  4994. procedure TDCCustomDBGrid.SetOptions(Value: TDBGridOptions);
  4995. const
  4996.   LayoutOptions = [dgEditing, dgAlwaysShowEditor, dgTitles, dgIndicator,
  4997.     dgColLines, dgRowLines, dgRowSelect, dgAlwaysShowSelection, dgMarker,
  4998.     dgTitleClicked, dgHighlightRow, dgCompleteLines];
  4999. var
  5000.   NewGridOptions: TGridOptions;
  5001.   ChangedOptions: TDBGridOptions;
  5002. begin
  5003.   if FOptions <> Value then
  5004.   begin
  5005.     NewGridOptions := [];
  5006.     if dgColLines in Value then
  5007.       NewGridOptions := NewGridOptions + [goFixedVertLine, goVertLine];
  5008.     if dgRowLines in Value then
  5009.       NewGridOptions := NewGridOptions + [goFixedHorzLine, goHorzLine];
  5010.     if dgColumnResize in Value then
  5011.       NewGridOptions := NewGridOptions + [goColSizing, goColMoving];
  5012.     if dgTabs in Value then Include(NewGridOptions, goTabs);
  5013.     if dgRowSelect in Value then
  5014.     begin
  5015.       Include(NewGridOptions, goRowSelect);
  5016.       Exclude(Value, dgAlwaysShowEditor);
  5017.       Exclude(Value, dgEditing);
  5018.     end;
  5019.  
  5020.     if dgHighlightRow in Value then
  5021.     begin
  5022.       Exclude(Value, dgRowSelect);
  5023.     end;
  5024.  
  5025.     if dgEditing in Value then Include(NewGridOptions, goEditing);
  5026.     if dgAlwaysShowEditor in Value then Include(NewGridOptions, goAlwaysShowEditor);
  5027.     if dgMultiSelect in (FOptions - Value) then FBookmarks.Clear;
  5028.  
  5029.     if dgMultiSelect in Value then Value := Value - [dgMarker];
  5030.  
  5031.     if dgRowSizing in Value  then
  5032.     begin
  5033.       NewGridOptions := NewGridOptions + [goRowSizing];
  5034.       Value := Value +[dgUserRowHeight];
  5035.     end;
  5036.  
  5037.     if dgFlatButtons in Value then
  5038.       NewGridOptions := NewGridOptions - [goFixedHorzLine, goFixedVertLine];
  5039.  
  5040.     inherited Options := NewGridOptions;
  5041.  
  5042.     ChangedOptions := (FOptions + Value) - (FOptions * Value);
  5043.     FOptions := Value;
  5044.  
  5045.     GridOptions := [];
  5046.     if dgAutoSize in Value then GridOptions := GridOptions + [goAutoSize];
  5047.  
  5048.     if ChangedOptions * LayoutOptions <> [] then LayoutChanged;
  5049.     if [dgFlatButtons, dgAutoSize] * ChangedOptions  <> [] then
  5050.     begin
  5051.       LockUpdate;
  5052.       if dgAutoSize in ChangedOptions then ScrollBars := ScrollBars;
  5053.       RecreateWnd;
  5054.       UnlockUpdate;
  5055.       if dgAutoSize in ChangedOptions then LayoutChanged;
  5056.     end;
  5057.  
  5058.   end;
  5059. end;
  5060.  
  5061. procedure TDCCustomDBGrid.SetSelectedField(Value: TField);
  5062. var
  5063.   I: Integer;
  5064. begin
  5065.   if Value = nil then Exit;
  5066.   for I := 0 to Columns.Count - 1 do
  5067.     if Columns[I].Field = Value then
  5068.       MoveCol(DataToRawColumn(I), 0);
  5069. end;
  5070.  
  5071. procedure TDCCustomDBGrid.SetSelectedIndex(Value: Integer);
  5072. begin
  5073.   MoveCol(DataToRawColumn(Value), 0);
  5074. end;
  5075.  
  5076. procedure TDCCustomDBGrid.SetTitleFont(Value: TFont);
  5077. begin
  5078.   FTitleFont.Assign(Value);
  5079.   if (dgTitles in Options) and HandleAllocated then LayoutChanged;
  5080. end;
  5081.  
  5082. function TDCCustomDBGrid.StoreColumns: Boolean;
  5083. begin
  5084.   Result := Columns.State = csCustomized;
  5085. end;
  5086.  
  5087. procedure TDCCustomDBGrid.TimedScroll(Direction: TGridScrollDirection);
  5088. begin
  5089.   if FDatalink.Active then
  5090.   begin
  5091.     with FDatalink do
  5092.     begin
  5093.       if sdUp in Direction then
  5094.       begin
  5095.         FDataLink.MoveBy(-ActiveRecord - 1);
  5096.         Exclude(Direction, sdUp);
  5097.       end;
  5098.       if sdDown in Direction then
  5099.       begin
  5100.         FDataLink.MoveBy(RecordCount - ActiveRecord);
  5101.         Exclude(Direction, sdDown);
  5102.       end;
  5103.     end;
  5104.     if Direction <> [] then inherited TimedScroll(Direction);
  5105.   end;
  5106. end;
  5107.  
  5108. procedure TDCCustomDBGrid.TitleClick(Column: TColumn);
  5109. begin
  5110.   if Assigned(FOnTitleClick) then FOnTitleClick(Column);
  5111. end;
  5112.  
  5113. procedure TDCCustomDBGrid.ClipClick;
  5114. begin
  5115.   if FClipPopupVisible then
  5116.     HideClipPopup
  5117.   else
  5118.     ShowClipPopup;
  5119. end;
  5120.  
  5121. procedure TDCCustomDBGrid.TitleFontChanged(Sender: TObject);
  5122. begin
  5123.   if (not FSelfChangingTitleFont) and not (csLoading in ComponentState) then
  5124.     ParentFont := False;
  5125.   if dgTitles in Options then LayoutChanged;
  5126. end;
  5127.  
  5128. procedure TDCCustomDBGrid.UpdateActive;
  5129. var
  5130.   NewRow: Integer;
  5131.   Field: TField;
  5132. begin
  5133.   if FDatalink.Active and HandleAllocated and not (csLoading in ComponentState) then
  5134.   begin
  5135.     if FDatalink.DataSet.Active and (FDatalink.ActiveRecord = FDatalink.RecordCount)
  5136.     then begin
  5137.       FDatalink.DataSet.Prior;
  5138.       FDatalink.DataSet.Next;
  5139.     end;
  5140.     NewRow := FDatalink.ActiveRecord + FTitleOffset;
  5141.     if Row <> NewRow then
  5142.     begin
  5143.       if not (dgAlwaysShowEditor in Options) then HideEditor;
  5144.       MoveColRow(Col, NewRow, False, False);
  5145.       InvalidateEditor;
  5146.     end;
  5147.     Field := SelectedField;
  5148.     if Assigned(Field) and (Field.Text <> FEditText) then
  5149.       InvalidateEditor;
  5150.   end;
  5151. end;
  5152.  
  5153. procedure TDCCustomDBGrid.UpdateData;
  5154. var
  5155.   Field: TField;
  5156. begin
  5157.   Field := SelectedField;
  5158.   if Assigned(Field) then
  5159.     Field.Text := FEditText;
  5160. end;
  5161.  
  5162. procedure TDCCustomDBGrid.UpdateRowCount;
  5163. var
  5164.   OldRowCount: Integer;
  5165. begin
  5166.   OldRowCount := RowCount;
  5167.   if RowCount <= FTitleOffset then RowCount := FTitleOffset + 1;
  5168.   FixedRows := FTitleOffset;
  5169.   with FDataLink do
  5170.     if not Active or (RecordCount = 0) or not HandleAllocated then
  5171.       RowCount := 1 + FTitleOffset
  5172.     else
  5173.     begin
  5174.       RowCount := 1000;
  5175.       FDataLink.BufferCount := VisibleRowCount;
  5176.       RowCount := RecordCount + FTitleOffset;
  5177.       if (dgRowSelect in Options) then
  5178.          TopRow := FixedRows;
  5179.       UpdateActive;
  5180.     end;
  5181.   if OldRowCount <> RowCount then UpdateScrollBar;
  5182. end;
  5183.  
  5184. procedure TDCCustomDBGrid.UpdateScrollBar;
  5185. var
  5186.   SIOld, SINew: TScrollInfo;
  5187. begin
  5188.   if FDatalink.Active and HandleAllocated then
  5189.   begin
  5190.     ShowScrollBar(Self.Handle, SB_VERT, True);
  5191.     with FDatalink.DataSet do
  5192.     begin
  5193.       SIOld.cbSize := sizeof(SIOld);
  5194.       SIOld.fMask := SIF_ALL;
  5195.       GetScrollInfo(Self.Handle, SB_VERT, SIOld);
  5196.       SINew := SIOld;
  5197.       if IsSequenced then
  5198.       begin
  5199.         SINew.nMin := 1;
  5200.         SINew.nPage := Self.VisibleRowCount;
  5201.         SINew.nMax := Integer(DWORD(RecordCount) + SINew.nPage - 1);
  5202.         if State in [dsInactive, dsBrowse, dsEdit] then
  5203.           SINew.nPos := RecNo;  // else keep old pos
  5204.       end
  5205.       else
  5206.       begin
  5207.         SINew.nMin := 0;
  5208.         SINew.nPage := 0;
  5209.         SINew.nMax := 4;
  5210.         if FDataLink.BOF then SINew.nPos := 0
  5211.         else if FDataLink.EOF then SINew.nPos := 4
  5212.         else SINew.nPos := 2;
  5213.       end;
  5214.       if (SINew.nMin <> SIOld.nMin) or (SINew.nMax <> SIOld.nMax) or
  5215.         (SINew.nPage <> SIOld.nPage) or (SINew.nPos <> SIOld.nPos) then
  5216.         SetScrollInfo(Self.Handle, SB_VERT, SINew, True);
  5217.     end;
  5218.   end
  5219.   else begin
  5220.     if HandleAllocated then ShowScrollBar(Self.Handle, SB_VERT, False);
  5221.   end;
  5222. end;
  5223.  
  5224. function TDCCustomDBGrid.ValidFieldIndex(FieldIndex: Integer): Boolean;
  5225. begin
  5226.   Result := DataLink.GetMappedIndex(FieldIndex) >= 0;
  5227. end;
  5228.  
  5229. procedure TDCCustomDBGrid.CMParentFontChanged(var Message: TMessage);
  5230. begin
  5231.   inherited;
  5232.   if ParentFont then
  5233.   begin
  5234.     FSelfChangingTitleFont := True;
  5235.     try
  5236.       TitleFont := Font;
  5237.     finally
  5238.       FSelfChangingTitleFont := False;
  5239.     end;
  5240.     LayoutChanged;
  5241.   end;
  5242. end;
  5243.  
  5244. procedure TDCCustomDBGrid.CMBiDiModeChanged(var Message: TMessage);
  5245. var
  5246.   Loop: Integer;
  5247. begin
  5248.   inherited;
  5249.   for Loop := 0 to ComponentCount - 1 do
  5250.     if Components[Loop] is TDCCustomDBGrid then
  5251.       with Components[Loop] as TDCCustomDBGrid do
  5252.         { Changing the window, echos down to the subgrid }
  5253.         if Parent <> nil then
  5254.           Parent.BiDiMode := Self.BiDiMode;
  5255. end;
  5256.  
  5257. procedure TDCCustomDBGrid.CMExit(var Message: TMessage);
  5258. begin
  5259.   try
  5260.     if FDatalink.Active then
  5261.       with FDatalink.Dataset do
  5262.         if (dgCancelOnExit in Options) and (State = dsInsert) and
  5263.           not Modified and not FDatalink.FModified then
  5264.           Cancel else
  5265.           FDataLink.UpdateData;
  5266.     HideClipPopup;
  5267.     DoColumnComment(MODE_HIDEWINDOW, nil);
  5268.   except
  5269.     SetFocus;
  5270.     raise;
  5271.   end;
  5272.   inherited;
  5273. end;
  5274.  
  5275. procedure TDCCustomDBGrid.CMFontChanged(var Message: TMessage);
  5276. var
  5277.   I: Integer;
  5278. begin
  5279.   inherited;
  5280.   BeginLayout;
  5281.   try
  5282.     for I := 0 to Columns.Count-1 do
  5283.       Columns[I].RefreshDefaultFont;
  5284.   finally
  5285.     EndLayout;
  5286.   end;
  5287. end;
  5288.  
  5289. procedure TDCCustomDBGrid.CMDeferLayout(var Message);
  5290. begin
  5291.   if AcquireLayoutLock then
  5292.     EndLayout
  5293.   else
  5294.     DeferLayout;
  5295. end;
  5296.  
  5297. procedure TDCCustomDBGrid.CMDesignHitTest(var Msg: TCMDesignHitTest);
  5298. var
  5299.   MasterCol: TColumn;
  5300. begin
  5301.   inherited;
  5302.   if (Msg.Result = 1) and ((FDataLink = nil) or
  5303.     ((Columns.State = csDefault) and
  5304.      (FDataLink.DefaultFields or (not FDataLink.Active)))) then
  5305.     Msg.Result := 0
  5306.   else if (Msg.Result = 0) and (FDataLink <> nil) and (FDataLink.Active)
  5307.     and (Columns.State = csCustomized)
  5308.     and PtInExpandButton(Msg.XPos, Msg.YPos, MasterCol) then
  5309.     Msg.Result := 1;
  5310. end;
  5311.  
  5312. procedure TDCCustomDBGrid.WMSetCursor(var Msg: TWMSetCursor);
  5313. begin
  5314.   if (csDesigning in ComponentState) and
  5315.       ((FDataLink = nil) or
  5316.        ((Columns.State = csDefault) and
  5317.         (FDataLink.DefaultFields or not FDataLink.Active)))
  5318.   then
  5319.     Windows.SetCursor(LoadCursor(0, IDC_ARROW))
  5320.   else begin
  5321.     if not DataVisible then
  5322.       Windows.SetCursor(LoadCursor(0, IDC_ARROW))
  5323.     else
  5324.       inherited;
  5325.   end;
  5326. end;
  5327.  
  5328. procedure TDCCustomDBGrid.WMSize(var Message: TWMSize);
  5329. begin
  5330.   UpdateColWidths(-1, True);
  5331.   inherited;
  5332.   if UpdateLock = 0 then UpdateRowCount;
  5333.   InvalidateTitles;
  5334.   if not DataVisible or (Footers.Height > 0) then Invalidate;
  5335. end;
  5336.  
  5337. procedure TDCCustomDBGrid.WMVScroll(var Message: TWMVScroll);
  5338. var
  5339.   SI: TScrollInfo;
  5340. begin
  5341.   if not AcquireFocus and not DataVisible then Exit;
  5342.   if FDatalink.Active then
  5343.     with Message, FDataLink.DataSet do
  5344.       case ScrollCode of
  5345.         SB_LINEUP: FDataLink.MoveBy(-FDatalink.ActiveRecord - 1);
  5346.         SB_LINEDOWN: FDataLink.MoveBy(FDatalink.RecordCount - FDatalink.ActiveRecord);
  5347.         SB_PAGEUP: FDataLink.MoveBy(-VisibleRowCount);
  5348.         SB_PAGEDOWN: FDataLink.MoveBy(VisibleRowCount);
  5349.         SB_THUMBPOSITION:
  5350.           begin
  5351.             if IsSequenced then
  5352.             begin
  5353.               SI.cbSize := sizeof(SI);
  5354.               SI.fMask := SIF_ALL;
  5355.               GetScrollInfo(Self.Handle, SB_VERT, SI);
  5356.               if SI.nTrackPos <= 1 then First
  5357.               else if SI.nTrackPos >= RecordCount then Last
  5358.               else RecNo := SI.nTrackPos;
  5359.             end
  5360.             else
  5361.               case Pos of
  5362.                 0: First;
  5363.                 1: FDataLink.MoveBy(-VisibleRowCount);
  5364.                 2: Exit;
  5365.                 3: FDataLink.MoveBy(VisibleRowCount);
  5366.                 4: Last;
  5367.               end;
  5368.           end;
  5369.         SB_BOTTOM: Last;
  5370.         SB_TOP: First;
  5371.       end;
  5372. end;
  5373.  
  5374. procedure TDCCustomDBGrid.SetIme;
  5375. var
  5376.   Column: TColumn;
  5377. begin
  5378.   if not SysLocale.FarEast then Exit;
  5379.  
  5380.   ImeName := FOriginalImeName;
  5381.   ImeMode := FOriginalImeMode;
  5382.   Column := Columns[SelectedIndex];
  5383.   if Column.IsImeNameStored then ImeName := Column.ImeName;
  5384.   if Column.IsImeModeStored then ImeMode := Column.ImeMode;
  5385.  
  5386.   if InplaceEditor <> nil then
  5387.   begin
  5388.     TDBGridInplaceEdit(Self).ImeName := ImeName;
  5389.     TDBGridInplaceEdit(Self).ImeMode := ImeMode;
  5390.   end;
  5391. end;
  5392.  
  5393. procedure TDCCustomDBGrid.UpdateIme;
  5394. begin
  5395.   if not SysLocale.FarEast then Exit;
  5396.   SetIme;
  5397.   SetImeName(ImeName);
  5398.   SetImeMode(Handle, ImeMode);
  5399. end;
  5400.  
  5401. procedure TDCCustomDBGrid.WMIMEStartComp(var Message: TMessage);
  5402. begin
  5403.   inherited;
  5404.   ShowEditor;
  5405. end;
  5406.  
  5407. procedure TDCCustomDBGrid.WMSetFocus(var Message: TWMSetFocus);
  5408. begin
  5409.   if not ((InplaceEditor <> nil) and
  5410.     (Message.FocusedWnd = InplaceEditor.Handle)) then SetIme;
  5411.   inherited;
  5412.   if InplaceEditor = nil then
  5413.   begin
  5414.     MoveCol(Col, 1);
  5415.     InvalidateSelected;
  5416.   end;
  5417. end;
  5418.  
  5419. procedure TDCCustomDBGrid.WMKillFocus(var Message: TMessage);
  5420. begin
  5421.   if not SysLocale.FarEast then inherited
  5422.   else
  5423.   begin
  5424.     ImeName := Screen.DefaultIme;
  5425.     ImeMode := imDontCare;
  5426.     inherited;
  5427.     if not ((InplaceEditor <> nil) and
  5428.       (HWND(Message.WParam) = InplaceEditor.Handle)) then
  5429.       ActivateKeyboardLayout(Screen.DefaultKbLayout, KLF_ACTIVATE);
  5430.   end;
  5431.   if FClipPopupVisible then HideClipPopup;
  5432.   InvalidateSelected;
  5433. end;
  5434.  
  5435. { Defer action processing to datalink }
  5436.  
  5437. function TDCCustomDBGrid.ExecuteAction(Action: TBasicAction): Boolean;
  5438. begin
  5439.   Result := (DataLink <> nil) and DataLink.ExecuteAction(Action);
  5440. end;
  5441.  
  5442. function TDCCustomDBGrid.UpdateAction(Action: TBasicAction): Boolean;
  5443. begin
  5444.   Result := (DataLink <> nil) and DataLink.UpdateAction(Action);
  5445. end;
  5446.  
  5447. procedure TDCCustomDBGrid.ShowPopupEditor(Column: TColumn; X, Y: Integer);
  5448. var
  5449.   SubGrid: TDCCustomDBGrid;
  5450.   DS: TDataSource;
  5451.   I: Integer;
  5452.   FloatRect: TRect;
  5453.   Cmp: TControl;
  5454. begin
  5455.   if not ((Column.Field <> nil) and (Column.Field is TDataSetField)) then  Exit;
  5456.  
  5457.   // find existing popup for this column field, if any, and show it
  5458.   for I := 0 to ComponentCount-1 do
  5459.     if Components[I] is TDCCustomDBGrid then
  5460.     begin
  5461.       SubGrid := TDCCustomDBGrid(Components[I]);
  5462.       if (SubGrid.DataSource <> nil) and
  5463.         (SubGrid.DataSource.DataSet = (Column.Field as TDatasetField).NestedDataset) then
  5464.       begin
  5465.         SubGrid.Parent.Show;
  5466.         SubGrid.SetFocus;
  5467.         Exit;
  5468.       end;
  5469.     end;
  5470.  
  5471.   // create another instance of this kind of grid
  5472.   SubGrid := TDCCustomDBGrid(TComponentClass(Self.ClassType).Create(Self));
  5473.   try
  5474.     DS := TDataSource.Create(SubGrid); // incestuous, but easy cleanup
  5475.     DS.Dataset := (Column.Field as TDatasetField).NestedDataset;
  5476.     SubGrid.DataSource := DS;
  5477.     SubGrid.Columns.State := Columns.State;
  5478.     SubGrid.Columns[0].Expanded := True;
  5479.     SubGrid.Visible := False;
  5480.     SubGrid.FloatingDockSiteClass := TCustomDockForm;
  5481.     FloatRect.TopLeft := ClientToScreen(CellRect(Col, Row).BottomRight);
  5482.     if X > Low(Integer) then FloatRect.Left := X;
  5483.     if Y > Low(Integer) then FloatRect.Top := Y;
  5484.     FloatRect.Right := FloatRect.Left + Width;
  5485.     FloatRect.Bottom := FloatRect.Top + Height;
  5486.     SubGrid.ManualFloat(FloatRect);
  5487. //    SubGrid.ManualDock(nil,nil,alClient);
  5488.     SubGrid.Parent.BiDiMode := Self.BiDiMode; { This carries the BiDi setting }
  5489.     I := SubGrid.CellRect(SubGrid.ColCount-1, 0).Right;
  5490.     if (I > 0) and (I < Screen.Width div 2) then
  5491.       SubGrid.Parent.ClientWidth := I
  5492.     else
  5493.       SubGrid.Parent.Width := Screen.Width div 4;
  5494.     SubGrid.Parent.Height := Screen.Height div 4;
  5495.     SubGrid.Align := alClient;
  5496.     SubGrid.DragKind := dkDock;
  5497.     SubGrid.Color := Color;
  5498.     SubGrid.Ctl3D := Ctl3D;
  5499.     SubGrid.Cursor := Cursor;
  5500.     SubGrid.Enabled := Enabled;
  5501.     SubGrid.FixedColor := FixedColor;
  5502.     SubGrid.Font := Font;
  5503.     SubGrid.HelpContext := HelpContext;
  5504.     SubGrid.IMEMode := IMEMode;
  5505.     SubGrid.IMEName := IMEName;
  5506.     SubGrid.Options := Options;
  5507.     Cmp := Self;
  5508.     while (Cmp <> nil) and (TDCCustomDBGrid(Cmp).PopupMenu = nil) do
  5509.       Cmp := Cmp.Parent;
  5510.     if Cmp <> nil then
  5511.       SubGrid.PopupMenu := TDCCustomDBGrid(Cmp).PopupMenu;
  5512.     SubGrid.TitleFont := TitleFont;
  5513.     SubGrid.Visible := True;
  5514.     SubGrid.Parent.Show;
  5515.   except
  5516.     SubGrid.Free;
  5517.     raise;
  5518.   end;
  5519. end;
  5520.  
  5521. procedure TDCCustomDBGrid.CalcSizingState(X, Y: Integer;
  5522.   var State: TGridState; var Index, SizingPos, SizingOfs: Integer;
  5523.   var FixedInfo: TGridDrawInfo);
  5524.  var
  5525.   R: TGridCoord;
  5526.   EffectiveOptions: TGridOptions;
  5527.   AWidth, i, j: integer;
  5528.  
  5529.   procedure CalcAxisState(const AxisInfo: TGridAxisDrawInfo; Pos: Integer;
  5530.     NewState: TGridState);
  5531.   var
  5532.     I, Line, Back, Range, J: Integer;
  5533.   begin
  5534.     if UseRightToLeftAlignment then
  5535.       Pos := ClientWidth - Pos;
  5536.     with AxisInfo do
  5537.     begin
  5538.       Range := EffectiveLineWidth;
  5539.       Back := 0;
  5540.       if Range < 7 then
  5541.       begin
  5542.         Range := 7;
  5543.         Back := (Range - EffectiveLineWidth) shr 1;
  5544.       end;
  5545.  
  5546.       Line := FixedBoundary - AWidth;
  5547.       J := FixedCols - FrozenCols;
  5548.       for I := J to GridCellCount - 1 do
  5549.       begin
  5550.         if (I < FixedCols) or (I >= FirstGridCell) then
  5551.           Inc(Line, GetExtent(I));
  5552.         if Line > (GridBoundary  - Back + Range)  then Break;
  5553.         if (Pos >= Line - Back) and (Pos <= Line - Back + Range) then
  5554.         begin
  5555.           State := NewState;
  5556.           SizingPos := Line;
  5557.           SizingOfs := Line - Pos;
  5558.           Index := I;
  5559.           Exit;
  5560.         end;
  5561.         if (I < FixedCols) or (I >= FirstGridCell) then
  5562.           Inc(Line, EffectiveLineWidth);
  5563.       end;
  5564.       if (GridBoundary = GridExtent) and (Pos >= GridExtent - Back)
  5565.         and (Pos <= GridExtent) then
  5566.       begin
  5567.         State := NewState;
  5568.         SizingPos := GridExtent;
  5569.         SizingOfs := GridExtent - Pos;
  5570.         Index := I;
  5571.       end;
  5572.     end;
  5573.   end;
  5574.  
  5575.   function XOutsideHorzFixedBoundary: Boolean;
  5576.   begin
  5577.     with FixedInfo do
  5578.       if not UseRightToLeftAlignment then
  5579.         Result := X > (Horz.FixedBoundary-AWidth)
  5580.       else
  5581.         Result := X < ClientWidth - (Horz.FixedBoundary-AWidth);
  5582.   end;
  5583.  
  5584.   function XOutsideOrEqualHorzFixedBoundary: Boolean;
  5585.   begin
  5586.     with FixedInfo do
  5587.       if not UseRightToLeftAlignment then
  5588.         Result := X >= (Horz.FixedBoundary-AWidth)
  5589.       else
  5590.         Result := X <= ClientWidth - (Horz.FixedBoundary-AWidth);
  5591.   end;
  5592.  
  5593.  
  5594. begin
  5595.   if FrozenCols = 0 then
  5596.     inherited CalcSizingState(X, Y, State, Index, SizingPos, SizingOfs, FixedInfo)
  5597.   else begin
  5598.     AWidth := 0;
  5599.     State := gsNormal;
  5600.     Index := -1;
  5601.     EffectiveOptions := inherited Options;
  5602.     if csDesigning in ComponentState then
  5603.       EffectiveOptions := EffectiveOptions + DesignOptionsBoost;
  5604.     if [goColSizing, goRowSizing] * EffectiveOptions <> [] then
  5605.       with FixedInfo do
  5606.       begin
  5607.         Vert.GridExtent := ClientHeight;
  5608.         Horz.GridExtent := ClientWidth;
  5609.         with Horz do
  5610.         begin
  5611.           j := FixedCols - FrozenCols;
  5612.           for i := j to FixedCols - 1 do Inc(AWidth, GetExtent(i));
  5613.         end;
  5614.         if (XOutsideHorzFixedBoundary) and (goColSizing in EffectiveOptions) then
  5615.         begin
  5616.           if Y >= Vert.FixedBoundary then Exit;
  5617.           CalcAxisState(Horz, X, gsColSizing);
  5618.         end
  5619.         else if (Y > Vert.FixedBoundary) and (goRowSizing in EffectiveOptions) then
  5620.         begin
  5621.           if XOutsideOrEqualHorzFixedBoundary then Exit;
  5622.           CalcAxisState(Vert, Y, gsRowSizing);
  5623.         end;
  5624.       end;
  5625.   end;
  5626.  
  5627.   with FixedInfo.Horz do
  5628.   begin
  5629.     if (State = gsColSizing) and ((FixedCols - FrozenCols) < Index) and
  5630.        (Index = LastFullVisibleCell+1) and (LeftCol >= FindicatorOffset) and
  5631.        ((Columns[LeftCol - FIndicatorOffset].Width + FixedBoundary) > GridBoundary) then
  5632.     Index := LeftCol;
  5633.   end;
  5634.  
  5635.   R := MouseCoord(X, Y);
  5636.   R.X := RawToDataColumn(R.X);
  5637.  
  5638.   if (State = gsColSizing) and (FDataLink <> nil)
  5639.     and (FDatalink.Dataset <> nil) and FDataLink.Dataset.ObjectView then
  5640.   begin
  5641.     if (R.X >= 0) and (R.X < Columns.Count) and (Columns[R.X].Depth > R.Y) then
  5642.       State := gsNormal;
  5643.   end;
  5644.  
  5645.   if (State = gsColSizing) and not(csDesigning in ComponentState) then
  5646.   begin
  5647.     R.X := RawToDataColumn(Index);
  5648.     if (R.X >= 0) and (R.X < Columns.Count) and not Columns[R.X].Resize then
  5649.       State := gsNormal;
  5650.   end;
  5651.   if State <> gsNormal then
  5652.   begin
  5653.     FSizingIndex := Index;
  5654.     FSizingOff := SizingOfs;
  5655.   end;
  5656. end;
  5657.  
  5658. function TDCCustomDBGrid.CheckColumnDrag(var Origin, Destination: Integer;
  5659.   const MousePt: TPoint): Boolean;
  5660. var
  5661.   I, ARow: Integer;
  5662.   DestCol: TColumn;
  5663. begin
  5664.   Result := inherited CheckColumnDrag(Origin, Destination, MousePt);
  5665.   if Result and (FDatalink.Dataset <> nil) and FDatalink.Dataset.ObjectView then
  5666.   begin
  5667.     assert(FDragCol <> nil);
  5668.     ARow := FDragCol.Depth;
  5669.     if Destination <> Origin then
  5670.     begin
  5671.       DestCol := ColumnAtDepth(Columns[RawToDataColumn(Destination)], ARow);
  5672.       if DestCol.ParentColumn <> FDragCol.ParentColumn then
  5673.         if Destination < Origin then
  5674.           DestCol := Columns[FDragCol.ParentColumn.Index+1]
  5675.         else
  5676.         begin
  5677.           I := DestCol.Index;
  5678.           while DestCol.ParentColumn <> FDragCol.ParentColumn do
  5679.           begin
  5680.             Dec(I);
  5681.             DestCol := Columns[I];
  5682.           end;
  5683.         end;
  5684.       if (DestCol.Index > FDragCol.Index) then
  5685.       begin
  5686.         I := DestCol.Index + 1;
  5687.         while (I < Columns.Count) and (ColumnAtDepth(Columns[I],ARow) = DestCol) do
  5688.           Inc(I);
  5689.         DestCol := Columns[I-1];
  5690.       end;
  5691.       Destination := DataToRawColumn(DestCol.Index);
  5692.     end;
  5693.   end;
  5694. end;
  5695.  
  5696. function TDCCustomDBGrid.BeginColumnDrag(var Origin, Destination: Integer;
  5697.   const MousePt: TPoint): Boolean;
  5698. var
  5699.   I, ARow: Integer;
  5700. begin
  5701.   Result := inherited BeginColumnDrag(Origin, Destination, MousePt);
  5702.   if Result and (FDatalink.Dataset <> nil) and FDatalink.Dataset.ObjectView then
  5703.   begin
  5704.     ARow := MouseCoord(MousePt.X, MousePt.Y).Y;
  5705.     FDragCol := ColumnAtDepth(Columns[RawToDataColumn(Origin)], ARow);
  5706.     if FDragCol = nil then Exit;
  5707.     I := DataToRawColumn(FDragCol.Index);
  5708.     if Origin <> I then Origin := I;
  5709.     Destination := Origin;
  5710.   end;
  5711. end;
  5712.  
  5713. function TDCCustomDBGrid.EndColumnDrag(var Origin, Destination: Integer;
  5714.   const MousePt: TPoint): Boolean;
  5715. begin
  5716.   Result := inherited EndColumnDrag(Origin, Destination, MousePt);
  5717.   FDragCol := nil;
  5718. end;
  5719.  
  5720. procedure TDCCustomDBGrid.InvalidateTitles;
  5721. var
  5722.   R, R1: TRect;
  5723.   DrawInfo: TGridDrawInfo;
  5724. begin
  5725.   if HandleAllocated and (dgTitles in Options) and (FDatalink <> nil) and
  5726.     (FDatalink.Dataset <> nil) then
  5727.   begin
  5728.     CalcDrawInfo(DrawInfo);
  5729.     with DrawInfo.Horz do
  5730.     begin
  5731.       R1 := CellRect(LeftCol + VisibleColCount, 0);
  5732.       if not IsRectEmpty(R1) and (FFirstGridCell > FirstGridCell) then
  5733.       begin
  5734.         R  := Rect(R1.Left, 0, R1.Right, DrawInfo.Vert.FixedBoundary);
  5735.         InvalidateRect(Handle, @R, False);
  5736.       end;
  5737.       FFirstGridCell := FirstGridCell;
  5738.     end;
  5739.   end;
  5740. end;
  5741.  
  5742. procedure TDCCustomDBGrid.TopLeftChanged;
  5743. begin
  5744.   if LeftCol < FixedCols then LeftCol := FixedCols;
  5745.   InvalidateTitles;
  5746.   inherited TopLeftChanged;
  5747. end;
  5748.  
  5749. procedure TDCCustomDBGrid.RowHeightsChanged;
  5750. var
  5751.   i, HeightChanged, DefaultHeight : Integer;
  5752. begin
  5753.   HeightChanged := -1;
  5754.   DefaultHeight := DefaultRowHeight;
  5755.   for i := Ord(dgTitles in Options) to RowCount do
  5756.     if RowHeights[i] <> DefaultHeight then
  5757.     begin
  5758.       HeightChanged := i;
  5759.       Break;
  5760.     end;
  5761.   if HeightChanged <> -1 then
  5762.   begin
  5763.     DefaultRowHeight := RowHeights[i];
  5764.     //New 03031999
  5765.     //RecreateWnd;
  5766.     if FLayoutLock = 0 then InternalLayout;
  5767.   end;
  5768.   SetTitleHeight;
  5769.   inherited;
  5770. end;
  5771.  
  5772. procedure TDCCustomDBGrid.SetFrozenCols(Value: integer);
  5773. var
  5774.   FixCount, I: Integer;
  5775.   Changed: boolean;
  5776. begin
  5777.   Changed := False;
  5778.   FixCount := _intMax(Value, 0) + IndicatorOffset;
  5779.   if DataLink.Active and not (csLoading in ComponentState) and
  5780.     (ColCount > IndicatorOffset + 1) then
  5781.   begin
  5782.     FixCount := _intMin(FixCount, ColCount-1);
  5783.     if (FFrozenCols <> Value) or (FixCount <> FixedCols) then
  5784.     begin
  5785.       LockWindowUpdate(Handle);
  5786.       FixedCols := FixCount;
  5787.       Col := FixedCols - FrozenCols;
  5788.       LockWindowUpdate(0);
  5789.       for I := 1 to _intMin(FixedCols, ColCount-1) do TabStops[I] := False;
  5790.       Changed := True;
  5791.     end
  5792.   end;
  5793.   if not Changed then  FixedCols := _intMin(ColCount -1, FixCount);
  5794.   FFrozenCols := FixCount - IndicatorOffset;
  5795. end;
  5796.  
  5797. function  TDCCustomDBGrid.GetFrozenCols: integer;
  5798. begin
  5799.   if DataLink.Active then Result := FixedCols - IndicatorOffset
  5800.   else Result := FFrozenCols;
  5801. end;
  5802.  
  5803. procedure TDCCustomDBGrid.SavePosition;
  5804. begin
  5805.   if Assigned(DataSource) and Assigned(DataSource.DataSet) and
  5806.      Datasource.DataSet.Active and (TPrivateDataSet(DataSource.DataSet).BookmarkSize > 0)
  5807.   then begin
  5808.     with Datasource.DataSet do
  5809.     begin
  5810.       if Assigned(FCurrentPos[1].Bookmark) then FreeBookmark(FCurrentPos[1].Bookmark);
  5811.       if Assigned(FCurrentPos[2].Bookmark) then FreeBookmark(FCurrentPos[2].Bookmark);
  5812.  
  5813.       DisableControls;
  5814.       Prior;
  5815.       if not Bof then
  5816.       begin
  5817.         FCurrentPos[1].Row      := Row;
  5818.         FCurrentPos[1].Bookmark := GetBookmark;
  5819.         FCurrentPos[1].ActiveRecord := DataLink.ActiveRecord;
  5820.         Next;
  5821.       end
  5822.       else
  5823.         FCurrentPos[1].Bookmark := nil;
  5824.  
  5825.       FCurrentPos[2].Row      := Row;
  5826.       FCurrentPos[2].Bookmark := GetBookmark;
  5827.       FCurrentPos[2].ActiveRecord := DataLink.ActiveRecord;
  5828.       EnableControls;
  5829.     end;
  5830.   end;
  5831. end;
  5832.  
  5833. function TDCCustomDBGrid.GetPosition: TBookmark;
  5834. begin
  5835.   Result := FCurrentPos[2].Bookmark;
  5836. end;
  5837.  
  5838. procedure TDCCustomDBGrid.RestPosition;
  5839.  
  5840.  procedure LocateBookmark(BookamarkInfo: TBookmarkInfo);
  5841.   var
  5842.    ARow, BRow, i, j: integer;
  5843.  begin
  5844.  
  5845.    with TPrivateDataSet(DataSource.DataSet) do
  5846.    begin
  5847.      CheckBrowseMode;
  5848.      DoBeforeScroll;
  5849.      DataLink.ActiveRecord := BookamarkInfo.ActiveRecord;
  5850.      InternalGotoBookmark(BookamarkInfo.Bookmark);
  5851.      Resync([rmExact]);
  5852.  
  5853.      ARow := Row;
  5854.      BRow := BookamarkInfo.Row;
  5855.  
  5856.      if BRow > ARow then
  5857.      begin
  5858.        i := BRow - FTitleOffset; j := 0;
  5859.        while (i>0) and not FDatalink.DataSet.Bof do
  5860.        begin
  5861.          FDatalink.MoveBy(-1); inc(j); dec(i);
  5862.        end;
  5863.        if FDatalink.DataSet.Bof then Dec(j);
  5864.        FDatalink.MoveBy(j);
  5865.      end
  5866.      else begin
  5867.        if BRow < ARow then
  5868.        begin
  5869.          i := RowCount - BRow - 1; j := 0;
  5870.          while (i>0) and not FDatalink.DataSet.Eof do
  5871.          begin
  5872.            FDatalink.MoveBy(1); inc(j); dec(i);
  5873.          end;
  5874.          if FDatalink.DataSet.Eof then Dec(j);
  5875.          FDatalink.MoveBy(-j);
  5876.        end
  5877.        else begin
  5878.          FDatalink.MoveBy(-ARow + 1);
  5879.          FDatalink.MoveBy(ARow - 1);
  5880.        end;
  5881.      end;
  5882.      DoAfterScroll;
  5883.    end;
  5884.  end;
  5885. begin
  5886.   if Assigned(DataSource) and Assigned(DataSource.DataSet) and
  5887.      Datasource.DataSet.Active and (TPrivateDataSet(DataSource.DataSet).BookmarkSize > 0)
  5888.   then begin
  5889.     Datasource.DataSet.DisableControls;
  5890.     if not(Assigned(FCurrentPos[2].Bookmark) and ValidBookmark(FCurrentPos[2].Bookmark))
  5891.     then begin
  5892.       if Assigned(FCurrentPos[1].Bookmark) and ValidBookmark(FCurrentPos[1].Bookmark) then
  5893.         LocateBookmark(FCurrentPos[1])
  5894.       else
  5895.         DataSource.DataSet.First;
  5896.     end
  5897.     else LocateBookmark(FCurrentPos[2]);
  5898.     Datasource.DataSet.EnableControls;
  5899.   end;
  5900. end;
  5901.  
  5902. procedure TDCCustomDBGrid.SetPosition(const Value: TBookmark);
  5903. begin
  5904.   FCurrentPos[2].Bookmark := Value;
  5905. end;
  5906.  
  5907. procedure TDCCustomDBGrid.SetClipDown(const Value: boolean);
  5908. begin
  5909.   if FClipDown <> Value then
  5910.   begin
  5911.     FClipDown := Value;
  5912.     if (dgIndicator in Options) then  InvalidateCell(0, 0);
  5913.   end;
  5914. end;
  5915.  
  5916. procedure TDCCustomDBGrid.HideClipPopup;
  5917. begin
  5918.   FClipPopupVisible := False;
  5919.   TDCClipPopup(FClipPopup).Hide;
  5920.   ClickedCol := -1;
  5921.   SetClipDown(False);
  5922. end;
  5923.  
  5924. procedure TDCCustomDBGrid.ShowClipPopup;
  5925.  var
  5926.   Show: boolean;
  5927.   R: TRect;
  5928. begin
  5929.   Show := True;
  5930.   FClipPopupVisible := True;
  5931.  
  5932.   R := CellRect(0,0);
  5933.  
  5934.   TDBClipPopup(FClipPopup).Hide;
  5935.   TDBClipPopup(FClipPopup).AddButtons;
  5936.   TDBClipPopup(FClipPopup).SetBoundsEx(R.Left, R.Bottom,
  5937.     TDBClipPopup(FClipPopup).Width, TDBClipPopup(FClipPopup).Height);
  5938.  
  5939.   if Assigned(FOnClipClick) then
  5940.     FOnClipClick(FClipPopup, TDBClipPopup(FClipPopup).Left,
  5941.       TDBClipPopup(FClipPopup).Top, Show);
  5942.   if Show then
  5943.   begin
  5944.     ClipDown := not ClipDown;
  5945.     TDBClipPopup(FClipPopup).OnButtonClick := ClipButtonClick;
  5946.     TDBClipPopup(FClipPopup).Show;
  5947.   end
  5948.   else
  5949.     HideClipPopup;
  5950. end;
  5951.  
  5952. procedure TDCCustomDBGrid.CMCancelMode(var Message: TCMCancelMode);
  5953. begin
  5954.   inherited;
  5955.   if (Message.Sender <> Self) and FClipPopupVisible and
  5956.      (Message.Sender <> FClipPopup)
  5957.   then HideClipPopup;
  5958. end;
  5959.  
  5960. procedure TDCCustomDBGrid.WMNCLButtonDown(var Message: TWMNCLButtonDown);
  5961. begin
  5962.   inherited;
  5963.   if FClipPopupVisible then HideClipPopup;
  5964. end;
  5965.  
  5966. procedure TDCCustomDBGrid.CreateParams(var Params: TCreateParams);
  5967. begin
  5968.   inherited CreateParams(Params);
  5969.   if (BorderStyle = bsSingle) and (dgFlatButtons in Options) then
  5970.   with Params do
  5971.   begin
  5972.     if NewStyleControls and Ctl3D then
  5973.       ExStyle := ExStyle and not WS_EX_CLIENTEDGE
  5974.     else
  5975.       Style := Style and not WS_BORDER;
  5976.   end;
  5977. end;
  5978.  
  5979. procedure TDCCustomDBGrid.InvalidateSelected;
  5980.  var
  5981.   Rect: TRect;
  5982. begin
  5983.   if not HandleAllocated then Exit;
  5984.   Rect := BoxRectEx(0, Row , ColCount-1, Row );
  5985.   InvalidateRect(Handle, @Rect, False);
  5986.   ProcessPaintMessages;
  5987. end;
  5988.  
  5989. procedure TDCCustomDBGrid.SetImages(const Value: TImageList);
  5990. begin
  5991.   FImages := Value;
  5992.   Invalidate;
  5993. end;
  5994.  
  5995. procedure TDCCustomDBGrid.ClipButtonClick(Sender: TObject);
  5996. begin
  5997.   HideClipPopup;
  5998.   if Assigned(FOnClipButtonClick) then FOnClipButtonClick(Sender);
  5999. end;
  6000.  
  6001. function TDCCustomDBGrid.SelectCell(ACol, ARow: Integer): Boolean;
  6002.  var
  6003.   OldRect, NewRect: TRect;
  6004. begin
  6005.   Result := inherited SelectCell(ACol, ARow);
  6006.   if Result and (ARow<>Row) then
  6007.   begin
  6008.     OldRect := BoxRectEx(0 , Row , ColCount-1, Row );
  6009.     NewRect := BoxRectEx(0 , ARow, ColCount-1, ARow);
  6010.     ValidateRect(Handle, @OldRect);
  6011.     InvalidateRect(Handle, @OldRect, False);
  6012.     InvalidateRect(Handle, @NewRect, False);
  6013.   end;
  6014. end;
  6015.  
  6016. function TDCCustomDBGrid.GetPopupMenu: TPopupMenu;
  6017.  var
  6018.   P: TPoint;
  6019.   Cell: TGridCoord;
  6020. begin
  6021.   GetCursorPos(P);
  6022.   P := ScreenToClient(P);
  6023.   Cell := MouseCoord(P.X, P.Y);
  6024.   with Cell do
  6025.     if (Y < FTitleOffset) and (X > 0) and (X >= FIndicatorOffset) and
  6026.        Assigned(FPopupTitle) then
  6027.       Result := FPopupTitle
  6028.     else
  6029.       Result := inherited GetPopupMenu;
  6030. end;
  6031.  
  6032. procedure TDCCustomDBGrid.SetPopupTitle(const Value: TPopupMenu);
  6033. begin
  6034.   FPopupTitle := Value;
  6035. end;
  6036.  
  6037. function TDCCustomDBGrid.DoMouseWheelDown(Shift: TShiftState;
  6038.   MousePos: TPoint): Boolean;
  6039.  var
  6040.   MouseWheelDownEvent: TMouseWheelUpDownEvent;
  6041. begin
  6042.   Result := False;
  6043.   MouseWheelDownEvent := OnMouseWheelDown;
  6044.   if Assigned(MouseWheelDownEvent) then
  6045.     MouseWheelDownEvent(Self, Shift, MousePos, Result);
  6046.  
  6047.   if not Result and (DragState = dsNone) and (DataSource <> nil) and
  6048.      (DataSource.DataSet <> nil) and PtInRect(ClientRect, ScreenToClient(MousePos)) then
  6049.   begin
  6050.     NextRow(True);
  6051.     Result := True;
  6052.   end;
  6053. end;
  6054.  
  6055. function TDCCustomDBGrid.DoMouseWheelUp(Shift: TShiftState;
  6056.   MousePos: TPoint): Boolean;
  6057.  var
  6058.   MouseWheelUpEvent: TMouseWheelUpDownEvent;
  6059. begin
  6060.   Result := False;
  6061.   MouseWheelUpEvent := OnMouseWheelDown;
  6062.   if Assigned(MouseWheelUpEvent) then
  6063.     MouseWheelUpEvent(Self, Shift, MousePos, Result);
  6064.  
  6065.   if not Result and (DragState = dsNone) and (DataSource <> nil) and
  6066.      (DataSource.DataSet <> nil) and PtInRect(ClientRect, ScreenToClient(MousePos)) then
  6067.   begin
  6068.     PriorRow(True);
  6069.     Result := True;
  6070.   end;
  6071. end;
  6072.  
  6073. procedure TDCCustomDBGrid.DoSelection(Select: Boolean; Direction: Integer;
  6074.  Shift: TShiftState);
  6075.  var
  6076.   AddAfter: Boolean;
  6077. begin
  6078.   AddAfter := False;
  6079.   BeginUpdate;
  6080.   try
  6081.     if (dgMultiSelect in Options) and FDatalink.Active then
  6082.     begin
  6083.       if Select and (ssShift in Shift) then
  6084.       begin
  6085.         if not FSelecting then
  6086.         begin
  6087.           FSelectionAnchor := FBookmarks.CurrentRow;
  6088.           FBookmarks.CurrentRowSelected := True;
  6089.           FSelecting := True;
  6090.           AddAfter := True;
  6091.         end
  6092.         else
  6093.         with FBookmarks do
  6094.         begin
  6095.           AddAfter := Compare(CurrentRow, FSelectionAnchor) <> -Direction;
  6096.           if not AddAfter then
  6097.             CurrentRowSelected := False;
  6098.         end
  6099.       end
  6100.       else
  6101.         ClearSelection;
  6102.     end
  6103.     else if (dgMarker in Options) and FDatalink.Active then
  6104.     begin
  6105.       if Select and (ssShift in Shift) then
  6106.       begin
  6107.          FSelectionAnchor := FBookmarks.CurrentRow;
  6108.          FBookmarks.CurrentRowSelected := not FBookmarks.CurrentRowSelected;
  6109.          FSelecting := True;
  6110.          AddAfter   := False;
  6111.       end;
  6112.     end;
  6113.     FDatalink.MoveBy(Direction);
  6114.     if AddAfter then FBookmarks.CurrentRowSelected := True;
  6115.   finally
  6116.     EndUpdate;
  6117.   end;
  6118. end;
  6119.  
  6120. procedure TDCCustomDBGrid.NextRow(Select: Boolean);
  6121. begin
  6122.   with FDatalink.Dataset do
  6123.   begin
  6124.     if (State = dsInsert) and not Modified and not FDatalink.FModified then
  6125.       if FDataLink.Eof then Exit else Cancel
  6126.     else
  6127.       DoSelection(Select, 1, []);
  6128.     if FDataLink.Eof and CanModify and not ReadOnly and (dgEditing in Options) then
  6129.       Append;
  6130.   end;
  6131. end;
  6132.  
  6133. procedure TDCCustomDBGrid.PriorRow(Select: Boolean);
  6134. begin
  6135.   with FDatalink.Dataset do
  6136.     if (State = dsInsert) and not Modified and FDataLink.EOF and
  6137.       not FDatalink.FModified then
  6138.       Cancel
  6139.     else
  6140.       DoSelection(Select, -1, []);
  6141. end;
  6142.  
  6143. procedure TDCCustomDBGrid.ClearSelection;
  6144. begin
  6145.   if (dgMultiSelect in Options) then
  6146.   begin
  6147.     FBookmarks.Clear;
  6148.     FSelecting := False;
  6149.   end;
  6150. end;
  6151.  
  6152. function TDCCustomDBGrid.GetDBObject: TDCDBObject;
  6153. begin
  6154.   Result := FDBObject;
  6155. end;
  6156.  
  6157. procedure TDCCustomDBGrid.SetDBObject(const Value: TDCDBObject);
  6158. begin
  6159.   FDBObject.Assign(Value);
  6160. end;
  6161.  
  6162. function TDCCustomDBGrid.GetDataValue(Column: TColumn): string;
  6163. begin
  6164.   if Assigned(Column.Field) then
  6165.     with Column do
  6166.     begin
  6167.       if DisplayFormat = '' then
  6168.       begin
  6169.         case Field.DataType of
  6170.           ftMemo:
  6171.             if dgeDrawMemoAsText in OptionsEx then
  6172.               Result := Field.AsString
  6173.             else
  6174.               Result := Field.DisplayText
  6175.           else
  6176.             Result := Field.DisplayText
  6177.         end
  6178.       end
  6179.       else
  6180.         try
  6181.           case Field.DataType of
  6182.             ftFloat:
  6183.               Result := Format(DisplayFormat, [Field.AsFloat]);
  6184.             ftCurrency:
  6185.               Result := Format(DisplayFormat, [Field.AsCurrency]);
  6186.             ftBCD:
  6187.               Result := Format(DisplayFormat, [Field.AsFloat]);
  6188.             ftMemo:
  6189.               if dgeDrawMemoAsText in OptionsEx then
  6190.                 Result := Field.AsString
  6191.               else
  6192.                 Result := Field.DisplayText;
  6193.             ftDate, ftTime, ftDateTime:
  6194.               DateTimeToString(Result, DisplayFormat, Field.AsDateTime);
  6195.             else
  6196.               Result := Format(DisplayFormat, [Field.DisplayText]);
  6197.           end;
  6198.         except
  6199.           Result := Field.DisplayText
  6200.         end;
  6201.     end
  6202.   else
  6203.     Result := '';
  6204. end;
  6205.  
  6206. procedure TDCCustomDBGrid.DoColumnComment(Mode: integer; Column: TColumn);
  6207. begin
  6208.   if (FColumnCell <> -1) and (Mode = MODE_HIDEWINDOW) then
  6209.   begin
  6210.     if Assigned(FOnColumnComment) then FOnColumnComment(Self, Mode, Column);
  6211.     FColumnCell := -1;
  6212.   end
  6213.   else
  6214.     if Assigned(FOnColumnComment) then FOnColumnComment(Self, Mode, Column);
  6215. end;
  6216.  
  6217. procedure TDCCustomDBGrid.CMMouseLeave(var Message: TMessage);
  6218. begin
  6219.   inherited;
  6220.   DoColumnComment(MODE_HIDEWINDOW, nil);
  6221. end;
  6222.  
  6223. procedure TDCCustomDBGrid.Paint;
  6224.  var
  6225.   DrawInfo: TGridDrawInfo;
  6226.   ARow, CurRow: integer;
  6227.   ARect, BRect: TRect;
  6228.   BorderStyle: TEdgeBorderStyle;
  6229.   LineColor: TColor;
  6230.   UpdateRect, FooterRect: TRect;
  6231.   DefaultDrawing: boolean;
  6232.   SaveIndex: integer;
  6233. begin
  6234.   if (dgCompleteLines in Options) and not(dgAutoSize in Options) then
  6235.   begin
  6236.     CalcDrawInfo(DrawInfo);
  6237.  
  6238.     SaveIndex := SaveDC(Canvas.Handle);
  6239.     UpdateRect := Canvas.ClipRect;
  6240.     FooterRect := Footers.BoundsRect;
  6241.     with UpdateRect do
  6242.     begin
  6243.       Bottom := FooterRect.Top;
  6244.       Left  := DrawInfo.Horz.GridBoundary;
  6245.       Right := DrawInfo.Horz.GridExtent;
  6246.       ExcludeClipRect(Canvas.Handle, Left, Top, Right, Bottom);
  6247.     end;
  6248.     inherited;
  6249.     RestoreDC(Canvas.Handle, SaveIndex);
  6250.  
  6251.     if not IsRectEmpty(FooterRect) then
  6252.       with FooterRect do
  6253.         ExcludeClipRect(Canvas.Handle, Left, Top, Right, Bottom);
  6254.         
  6255.     with DrawInfo do
  6256.     begin
  6257.       if Horz.GridBoundary < Horz.GridExtent then
  6258.       begin
  6259.         CurRow := 0;
  6260.  
  6261.         if ColorToRGB(Color) = clSilver then
  6262.           LineColor := clGray
  6263.         else
  6264.           LineColor := clSilver;
  6265.  
  6266.         BorderStyle := GetBorderStyle;
  6267.  
  6268.         if FTitleOffset > 0 then
  6269.         begin
  6270.           if Columns.Count > 0 then
  6271.             Canvas.Brush.Color := Columns[Columns.Count-1].Title.Color
  6272.           else
  6273.             Canvas.Brush.Color := FixedColor;
  6274.           ARect := Rect(Horz.GridBoundary, 0, Horz.GridExtent, 0);
  6275.           while CurRow < FTitleOffset do
  6276.           begin
  6277.             ARect.Bottom := ARect.Bottom + RowHeights[CurRow];
  6278.             BRect := ARect;
  6279.             InflateRect(BRect, 1, 1);
  6280.             if RectVisible(Canvas.Handle, BRect) then
  6281.             begin
  6282.               if RectVisible(Canvas.Handle, ARect) then
  6283.               begin
  6284.                 Canvas.FillRect(ARect);
  6285.                 if BorderStyle <> ebsNone then
  6286.                 begin
  6287.                   ARect.Right := ARect.Right + 1;
  6288.                   if BorderStyle = ebsShadowFlat then
  6289.                   begin
  6290.                     InflateRect(ARect, 1, 1);
  6291.                     DrawGridFrameBorder(Canvas, ARect, BorderStyle, dsUp, FixedColor);
  6292.                     InflateRect(ARect, -1, -1);
  6293.                   end
  6294.                   else
  6295.                     DrawGridFrameBorder(Canvas, ARect, BorderStyle, dsUp, FixedColor);
  6296.                   ARect.Right := ARect.Right - 1;
  6297.                 end;
  6298.               end;  
  6299.  
  6300.               if dgRowLines in FOptions then
  6301.               begin
  6302.                 if dgFlatButtons in FOptions then
  6303.                   Canvas.Pen.Color := FixedColor
  6304.                 else
  6305.                   Canvas.Pen.Color := clBlack;
  6306.  
  6307.                 Canvas.MoveTo(ARect.Left, ARect.Bottom);
  6308.                 Canvas.LineTo(ARect.Right, ARect.Bottom);
  6309.               end;
  6310.             end;
  6311.             Inc(CurRow);
  6312.             ARect.Top := ARect.Bottom;
  6313.           end;
  6314.  
  6315.         end;
  6316.  
  6317.         while (CurRow < Vert.GridCellCount) and
  6318.               (ARect.Top < UpdateRect.Bottom) do
  6319.         begin
  6320.           if dgRowLines in FOptions then
  6321.           begin
  6322.             ARect.Bottom := ARect.Bottom + RowHeights[CurRow] +1;
  6323.             ARect.Top    := ARect.Top    + 1;
  6324.           end
  6325.           else begin
  6326.             ARect.Bottom := ARect.Bottom + RowHeights[CurRow];
  6327.             ARect.Top    := ARect.Top;
  6328.           end;
  6329.  
  6330.           if RectVisible(Canvas.Handle, ARect) and
  6331.              ((dgRowSelect in Options) or (dgHighlightRow in Options)) and
  6332.              ((dgAlwaysShowSelection in Options) or Focused) and
  6333.              FDataLink.Active then
  6334.           begin
  6335.             if (FDataLink.ActiveRecord = (CurRow-FTitleOffset)) then
  6336.             begin
  6337.               if Focused or not(dgeShadowSelection in OptionsEx) then
  6338.               begin
  6339.                 Canvas.Brush.Color := clHighlight
  6340.               end
  6341.               else begin
  6342.                 if dgAlwaysShowSelection in Options then
  6343.                   Canvas.Brush.Color := clShadowed;
  6344.               end;
  6345.             end
  6346.             else
  6347.               Canvas.Brush.Color := Self.Color;
  6348.           end
  6349.           else
  6350.             Canvas.Brush.Color := Self.Color;
  6351.  
  6352.           Canvas.Pen.Color := FixedColor;
  6353.           if Assigned(FOnDrawCompleteLine) then
  6354.           begin
  6355.             DefaultDrawing := True;
  6356.             ARow := CurRow-FTitleOffset;
  6357.             FOnDrawCompleteLine(Self, Canvas, ARect, Focused, ARow, DefaultDrawing);
  6358.             if DefaultDrawing then Canvas.FillRect(ARect);
  6359.           end
  6360.           else
  6361.             Canvas.FillRect(ARect);
  6362.  
  6363.           ARect.Top    := ARect.Top - 1;
  6364.           ARect.Bottom := ARect.Bottom;
  6365.  
  6366.           if (dgRowLines in FOptions) and RectVisible(Canvas.Handle, ARect) then
  6367.           begin
  6368.             Canvas.Pen.Color := LineColor;
  6369.             Canvas.MoveTo(ARect.Left, ARect.Bottom);
  6370.             Canvas.LineTo(ARect.Right, ARect.Bottom);
  6371.           end;
  6372.           Inc(CurRow);
  6373.           ARect.Top := ARect.Bottom;
  6374.         end;
  6375.       end;
  6376.       if ARect.Top < UpdateRect.Bottom then
  6377.       begin
  6378.         BRect := ClientRect;
  6379.         if Vert.GridBoundary < Vert.GridExtent   then
  6380.         begin
  6381.           ARect.Top    := Vert.GridBoundary;
  6382.           ARect.Bottom := Vert.GridExtent;
  6383.           Canvas.Brush.Color := Self.Color;
  6384.           Canvas.FillRect(ARect);
  6385.         end;
  6386.       end;
  6387.     end;
  6388.   end
  6389.   else
  6390.     inherited;
  6391. end;
  6392.  
  6393. function TDCCustomDBGrid.BoxRectEx(ALeft, ATop, ARight,
  6394.   ABottom: Integer): TRect;
  6395. begin
  6396.   Result := BoxRect(ALeft, ATop, ARight, ABottom);
  6397.   if dgCompleteLines in Options then Result.Right := Width;
  6398. end;
  6399.  
  6400. function TDCCustomDBGrid.CellRect(ACol, ARow: Integer): TRect;
  6401. begin
  6402.   Result := inherited CellRect(ACol, ARow);
  6403. end;
  6404.  
  6405. function TDCCustomDBGrid.MouseCoord(X, Y: Integer): TGridCoord;
  6406. begin
  6407.   Result := inherited MouseCoord(X, Y); 
  6408. end;
  6409.  
  6410. function TDCCustomDBGrid.DataVisible: boolean;
  6411. begin
  6412.   Result := (csDesigning in ComponentState) or
  6413.             (FDataVisible and (FColumns.Count <> 0) and
  6414.             (((DataSource <> nil) and (DataSource.DataSet <> nil) and (FDatalink.Fields[0] <> nil)) or
  6415.              (FColumns[0].FFieldName <> '')));
  6416. end;
  6417.  
  6418. procedure TDCCustomDBGrid.WMEraseBkgnd(var Message: TWmEraseBkgnd);
  6419. begin
  6420. {  inherited;  }
  6421. end;
  6422.  
  6423. procedure TDCCustomDBGrid.WMPaint(var Message: TWMPaint);
  6424.  var
  6425.   PS: TPaintStruct;
  6426.   EmptyMessage: string;
  6427.   R, R1: TRect;
  6428.   MBitmap, OBitmap: HBITMAP;
  6429.   MDC, DC: HDC;
  6430.   Flags: integer;
  6431. begin
  6432.   if not DataVisible then
  6433.   begin
  6434.     if Message.DC <> 0 then
  6435.     begin
  6436.       if not (csCustomPaint in ControlState) and (ControlCount = 0) then
  6437.         inherited
  6438.       else
  6439.         PaintHandler(Message);
  6440.     end
  6441.     else
  6442.     begin
  6443.       ShowScrollBar(Handle, SB_HORZ, False);
  6444.       ShowScrollBar(Handle, SB_VERT, False);
  6445.       GetWindowRect(Handle, R);  OffsetRect(R, -R.Left, -R.Top); R1 := R;
  6446.       DC := GetDC(0);
  6447.       MBitmap := CreateCompatibleBitmap(DC, R.Right, R.Bottom);
  6448.       ReleaseDC(0, DC);
  6449.       MDC := CreateCompatibleDC(0);
  6450.       OBitmap := SelectObject(MDC, MBitmap);
  6451.  
  6452.       try
  6453.         DC := BeginPaint(Handle, PS);
  6454.         Canvas.Handle := MDC;
  6455.         Canvas.Brush.Color := Self.Color;
  6456.         Canvas.Font := Self.Font;
  6457.  
  6458.         EmptyMessage := LoadStr(RES_STRN_MSG_DBGCEM);
  6459.         Flags        := DT_END_ELLIPSIS or DT_CENTER;
  6460.  
  6461.         if Assigned(FOnPaintEmptyMessage) then
  6462.           FOnPaintEmptyMessage(Self, Canvas, R, EmptyMessage)
  6463.         else begin
  6464.           Canvas.Lock;
  6465.           Canvas.FillRect(R);
  6466.           InflateRect(R, -5, -5);
  6467.           DrawHighLightText(Canvas, PChar(EmptyMessage), R, 1, Flags or DT_WORDBREAK);
  6468.           Canvas.UnLock;
  6469.         end;
  6470.         BitBlt(DC, 0, 0, R1.Right, R1.Bottom, MDC, 0, 0, SRCCOPY);
  6471.         EndPaint(Handle, PS);
  6472.       finally
  6473.         SelectObject(MDC, OBitmap);
  6474.         DeleteDC(MDC);
  6475.         DeleteObject(MBitmap);
  6476.         Canvas.Handle := 0;
  6477.       end;
  6478.     end;
  6479.   end
  6480.   else
  6481.    inherited;
  6482. end;
  6483.  
  6484. function TDCCustomDBGrid.MouseUpBeforeDblClk: boolean;
  6485. begin
  6486.   Result := True;
  6487. end;
  6488.  
  6489. procedure TDCCustomDBGrid.WMChar(var Msg: TWMChar);
  6490. begin
  6491.   if not DataVisible then
  6492.     Exit
  6493.   else
  6494.     inherited;
  6495. end;
  6496.  
  6497. procedure TDCCustomDBGrid.ImageListChange(Sender: TObject);
  6498. begin
  6499.   invalidate;
  6500. end;
  6501.  
  6502. procedure TDCCustomDBGrid.SetDataVisible(const Value: boolean);
  6503. begin
  6504.   if FDataVisible <> Value then
  6505.   begin
  6506.     FDataVisible := Value;
  6507.     invalidate;
  6508.   end;
  6509. end;
  6510.  
  6511. procedure TDCCustomDBGrid.WMNCCalcSize(var Message: TWMNCCalcSize);
  6512. begin
  6513.   inherited;
  6514.   if (BorderStyle = bsSingle) and (dgFlatButtons in Options) then
  6515.    InflateRect(Message.CalcSize_Params^.rgrc[0], -1, -1);
  6516. end;
  6517.  
  6518. procedure TDCCustomDBGrid.WMNCPaint(var Message: TMessage);
  6519.  var
  6520.   R, R1: TRect;
  6521.   DC: HDC;
  6522.   ScrollW, ScrollH: integer;
  6523.   Brush: HBRUSH;
  6524.   ScrollInfo: TScrollInfo;
  6525.   IScroll, VScroll, HScroll: boolean;
  6526. begin
  6527.   inherited;
  6528.   if (BorderStyle = bsSingle) and (dgFlatButtons in Options) then
  6529.   begin
  6530.     DC := GetWindowDC(Handle);
  6531.     Brush := CreateSolidBrush(ColorToRGB(clBtnFace));
  6532.     try
  6533.       GetWindowRect(Handle, R);  OffsetRect(R, -R.Left, -R.Top);
  6534.  
  6535.       ScrollInfo.cbSize := SizeOf(ScrollInfo);
  6536.       ScrollInfo.fMask := SIF_ALL;
  6537.       IScroll := GetScrollInfo(Self.Handle, SB_HORZ, ScrollInfo);
  6538.       HScroll := IScroll and (ScrollInfo.nMin <> ScrollInfo.nMax);
  6539.       IScroll := GetScrollInfo(Self.Handle, SB_VERT, ScrollInfo);
  6540.       VScroll := IScroll and (ScrollInfo.nMin <> ScrollInfo.nMax);
  6541.  
  6542.       if DataVisible and HScroll and VScroll then
  6543.       begin
  6544.         ScrollW := GetSystemMetrics(SM_CXVSCROLL);
  6545.         ScrollH := GetSystemMetrics(SM_CYVSCROLL);
  6546.         R1 := Rect(R.Right - ScrollW-1, R.Bottom - ScrollH-1, R.Right-1, R.Bottom-1);
  6547.         FrameRect(DC, R1, Brush);
  6548.       end;
  6549.  
  6550.       DrawEdge(DC, R, BDR_SUNKENOUTER, BF_TOPLEFT);
  6551.       DrawEdge(DC, R, BDR_RAISEDINNER, BF_BOTTOMRIGHT);
  6552.     finally
  6553.       DeleteObject(Brush);
  6554.       ReleaseDC(Handle, DC);
  6555.     end;
  6556.   end;
  6557. end;
  6558.  
  6559. procedure TDCCustomDBGrid.WMHScroll(var Message: TWMHScroll);
  6560. begin
  6561.   if not DataVisible then Exit;
  6562.   inherited;
  6563. end;
  6564.  
  6565. function TDCCustomDBGrid.ValidBookmark(Bookmark: TBookmark): boolean;
  6566. begin
  6567.  try
  6568.    with TPrivateDataSet(DataSource.DataSet) do
  6569.      Result := not(Eof and Bof) and (BookmarkSize > 0);
  6570.    Result := Result and DataSource.Dataset.BookmarkValid(Bookmark)
  6571.  except
  6572.    Result := False;
  6573.  end;
  6574. end;
  6575.  
  6576. function TDCCustomDBGrid.GetBorderStyle: TEdgeBorderStyle;
  6577. begin
  6578.   if not((dgColLines in Options) and (dgRowLines in Options)) then
  6579.   begin
  6580.     if dgFlatButtons in Options then
  6581.       Result := ebsShadowFlat
  6582.     else
  6583.       Result := ebsNone
  6584.   end
  6585.   else begin
  6586.     if ColorToRGB(Color) = ColorToRGB(FixedColor) then
  6587.       Result := ebsNone
  6588.     else
  6589.     begin
  6590.       if dgFlatButtons in Options then
  6591.         Result := ebsFlat
  6592.       else
  6593.         Result := ebsNormal;
  6594.     end;
  6595.   end;
  6596. end;
  6597.  
  6598. function TDCCustomDBGrid.GroupingEnabled: boolean;
  6599. begin
  6600.   Result := False;
  6601. end;
  6602.  
  6603. function TDCCustomDBGrid.FlatButtons: boolean;
  6604. begin
  6605.   Result := dgFlatButtons in Options;
  6606. end;
  6607.  
  6608. procedure TDCCustomDBGrid.DoColumnClick(Shift: TShiftState;
  6609.   ColIndex: integer);
  6610.  var
  6611.   i: integer;
  6612. begin
  6613.   inherited;
  6614.   if (RawToDataColumn(ColIndex) < Columns.Count) then
  6615.   begin
  6616.     if Columns[RawToDataColumn(ColIndex)].Indexed then
  6617.     for i := 0 to Columns.Count-1 do
  6618.     begin
  6619.       if i = RawToDataColumn(ColIndex) then
  6620.       begin
  6621.         if Columns[i].IndexStyle < High(TColumnIndexStyle)
  6622.           then Columns[i].IndexStyle := Succ(Columns[i].IndexStyle)
  6623.           else Columns[i].IndexStyle := Pred(Columns[i].IndexStyle);
  6624.         InvalidateCell(DataToRawColumn(i),0);
  6625.       end
  6626.       else
  6627.         if not(ssShift in Shift) then
  6628.         begin
  6629.           if Columns[i].Indexed and
  6630.              (Columns[i].IndexStyle <> Low(TColumnIndexStyle))
  6631.           then begin
  6632.             Columns[i].IndexStyle := Low(TColumnIndexStyle);
  6633.             InvalidateCell(DataToRawColumn(i),0);
  6634.           end;
  6635.         end;
  6636.     end;
  6637.     TitleClick(Columns[RawToDataColumn(ColIndex)])
  6638.   end;
  6639. end;
  6640.  
  6641. procedure TDCCustomDBGrid.CreateCellDragImage(ACol, ARow: integer;
  6642.   var DragImages: TImageList);
  6643.  const
  6644.    DragTextOffset = 5;
  6645.  var
  6646.   ABitmap: TBitmap;
  6647.   AText: string;
  6648.   P: TPoint;
  6649.   R, ARect: TRect;
  6650. begin
  6651.   inherited;
  6652.   exit;
  6653.   if Columns.Count > 0 then
  6654.   begin
  6655.     AText := GetDataValue(Columns[0]);
  6656.     ABitmap := TBitmap.Create;
  6657.  
  6658.     R := Rect(0, 0, 500, 0);
  6659.     P := DrawHighLightText(Canvas, PChar(AText), R, 0, DT_LEFT);
  6660.  
  6661.     P.X := Columns[0].Width;
  6662.     Inc(P.X, DragTextOffset + DragTextOffset div 2);
  6663.  
  6664.     with ABitmap do
  6665.     begin
  6666.       Width  := _intMin(P.X, 200);
  6667.       Height := _intMax(P.Y, DefaultRowHeight);
  6668.       ARect  := Rect(0, 0, Width, Height);
  6669.       Canvas.Brush.Color := FixedColor;
  6670.       Canvas.Font.Assign(Font);
  6671.       Canvas.FillRect(ARect);
  6672.       DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_RECT);
  6673.       ARect.Top   := (ARect.Top + ARect.Bottom - P.Y) div 2;
  6674.       ARect.Left  := DragTextOffset;
  6675.       ARect.Right := ARect.Right - DragTextOffset;
  6676.       DrawHighLightText(Canvas, PChar(AText), ARect, 1, DT_LEFT or DT_END_ELLIPSIS);
  6677.     end;
  6678.  
  6679.     if DragImages = nil then
  6680.     begin
  6681.       DragImages := TImageList.CreateSize(ABitmap.Width, ABitmap.Height);
  6682.       DragImages.AddMasked(ABitmap, clNone);
  6683.     end;
  6684.   end;
  6685. end;
  6686.  
  6687. procedure TDCCustomDBGrid.SelectItems(Mode: TSelectMode);
  6688. begin
  6689.   case Mode of
  6690.     smSelect: FBookmarks.SelectAll;
  6691.     smDeselect: FBookmarks.Clear;
  6692.   end;
  6693. end;
  6694.  
  6695. function TDCCustomDBGrid.CanColResize(ACol: integer): boolean;
  6696.  var
  6697.   i: integer;
  6698. begin
  6699.   Result := inherited CanColResize(ACol);
  6700.   i := RawToDataColumn(ACol);
  6701.   if Result and (i >= 0) then
  6702.     with Columns[i] do Result := Visible and (Resize or (csDesigning in ComponentState));
  6703. end;
  6704.  
  6705. procedure TDCCustomDBGrid.SetOptionsEx(const Value: TDBGridOptionsEx);
  6706.  var
  6707.   ChangedOptions: TDBGridOptionsEx;
  6708. begin
  6709.   if FOptionsEx <> Value then
  6710.   begin
  6711.     ChangedOptions := (FOptionsEx + Value) - (FOptionsEx * Value);
  6712.     FOptionsEx := Value;
  6713.     if [dgeMarkerMenu, dgeShadowSelection, dgeDrawMemoAsText] * ChangedOptions  <> [] then
  6714.     begin
  6715.       invalidate;
  6716.     end;
  6717.   end;
  6718. end;
  6719.  
  6720. procedure TDCCustomDBGrid.CellDblClick(Column: TColumn);
  6721. begin
  6722.   if Assigned(FOnCellDblClick) then FOnCellDblClick(Column);
  6723. end;
  6724.  
  6725. end.
  6726.