Rxdbctrl.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:106k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 1995, 1996 AO ROSNO             }
  6. {         Copyright (c) 1997, 1998 Master-Bank          }
  7. {                                                       }
  8. {*******************************************************}
  9. unit RXDBCtrl;
  10. {$I RX.INC}
  11. {$R-}
  12. interface
  13. uses
  14.   Windows, Registry, Variants,
  15.   Messages, Classes, Controls, Forms, Grids, Graphics, Buttons, Menus,
  16.   StdCtrls, Mask, IniFiles, ToolEdit, DB, DBGrids, 
  17.   {$IFNDEF RX_D3} DBTables, {$ENDIF}
  18.   Placemnt, DateUtil, DBCtrls, RxCtrls, CurrEdit;
  19. { TRxDBGrid }
  20. const
  21.   DefRxGridOptions = [dgEditing, dgTitles, dgIndicator, dgColumnResize,
  22.     dgColLines, dgRowLines, dgConfirmDelete, dgCancelOnExit];
  23. {$IFDEF RX_V110}
  24.  {$IFDEF CBUILDER}
  25.   {$NODEFINE DefRxGridOptions}
  26.  {$ENDIF}
  27. {$ENDIF}
  28. type
  29.   TTitleClickEvent = procedure (Sender: TObject; ACol: Longint;
  30.     Field: TField) of object;
  31.   TCheckTitleBtnEvent = procedure (Sender: TObject; ACol: Longint;
  32.     Field: TField; var Enabled: Boolean) of object;
  33.   TGetCellParamsEvent = procedure (Sender: TObject; Field: TField;
  34.     AFont: TFont; var Background: TColor; Highlight: Boolean) of object;
  35.   TSortMarker = (smNone, smDown, smUp);
  36.   TGetBtnParamsEvent = procedure (Sender: TObject; Field: TField;
  37.     AFont: TFont; var Background: TColor; var SortMarker: TSortMarker;
  38.     IsDown: Boolean) of object;
  39.   TGetCellPropsEvent = procedure (Sender: TObject; Field: TField;
  40.     AFont: TFont; var Background: TColor) of object; { obsolete }
  41.   TDBEditShowEvent = procedure (Sender: TObject; Field: TField;
  42.     var AllowEdit: Boolean) of object;
  43. {$IFNDEF WIN32}
  44.   TBookmarkList = class
  45.   private
  46.     FList: THugeList;
  47.     FGrid: TCustomDBGrid;
  48.     FCache: TBookmark;
  49.     FCacheIndex: Longint;
  50.     FCacheFind: Boolean;
  51.     FLinkActive: Boolean;
  52.     function GetCount: Longint;
  53.     function GetCurrentRowSelected: Boolean;
  54.     function GetItem(Index: Longint): TBookmark;
  55.     procedure SetCurrentRowSelected(Value: Boolean);
  56.     procedure ListChanged;
  57.   protected
  58.     function CurrentRow: TBookmark;
  59.     function Compare(const Item1, Item2: TBookmark): Longint;
  60.     procedure LinkActive(Value: Boolean);
  61.   public
  62.     constructor Create(AGrid: TCustomDBGrid);
  63.     destructor Destroy; override;
  64.     procedure Clear;  { free all bookmarks }
  65.     procedure Delete; { delete all selected rows from dataset }
  66.     function Find(const Item: TBookmark; var Index: Longint): Boolean;
  67.     function IndexOf(const Item: TBookmark): Longint;
  68.     function Refresh: Boolean; { drop orphaned bookmarks; True = orphans found }
  69.     property Count: Longint read GetCount;
  70.     property CurrentRowSelected: Boolean read GetCurrentRowSelected
  71.       write SetCurrentRowSelected;
  72.     property Items[Index: Longint]: TBookmark read GetItem; default;
  73.   end;
  74. {$ENDIF}
  75.   TRxDBGrid = class(TDBGrid)
  76.   private
  77.     FShowGlyphs: Boolean;
  78.     FDefaultDrawing: Boolean;
  79.     FMultiSelect: Boolean;
  80.     FSelecting: Boolean;
  81.     FClearSelection: Boolean;
  82.     FTitleButtons: Boolean;
  83. {$IFDEF WIN32}
  84.     FPressedCol: TColumn;
  85. {$ELSE}
  86.     FPressedCol: Longint;
  87. {$ENDIF}
  88.     FPressed: Boolean;
  89.     FTracking: Boolean;
  90.     FSwapButtons: Boolean;
  91.     FIniLink: TIniLink;
  92.     FDisableCount: Integer;
  93.     FFixedCols: Integer;
  94.     FMsIndicators: TImageList;
  95.     FOnCheckButton: TCheckTitleBtnEvent;
  96.     FOnGetCellProps: TGetCellPropsEvent;
  97.     FOnGetCellParams: TGetCellParamsEvent;
  98.     FOnGetBtnParams: TGetBtnParamsEvent;
  99.     FOnEditChange: TNotifyEvent;
  100.     FOnKeyPress: TKeyPressEvent;
  101.     FOnTitleBtnClick: TTitleClickEvent;
  102.     FOnShowEditor: TDbEditShowEvent;
  103.     FOnTopLeftChanged: TNotifyEvent;
  104. {$IFDEF WIN32}
  105.     FSelectionAnchor: TBookmarkStr;
  106. {$ELSE}
  107.     FSelectionAnchor: TBookmark;
  108.     FBookmarks: TBookmarkList;
  109.     FOnColumnMoved: TMovedEvent;
  110. {$ENDIF}
  111.     function GetImageIndex(Field: TField): Integer;
  112.     procedure SetShowGlyphs(Value: Boolean);
  113.     procedure SetRowsHeight(Value: Integer);
  114.     function GetRowsHeight: Integer;
  115.     function GetStorage: TFormPlacement;
  116.     procedure SetStorage(Value: TFormPlacement);
  117.     procedure IniSave(Sender: TObject);
  118.     procedure IniLoad(Sender: TObject);
  119.     procedure SetMultiSelect(Value: Boolean);
  120.     procedure SetTitleButtons(Value: Boolean);
  121.     procedure StopTracking;
  122.     procedure TrackButton(X, Y: Integer);
  123.     function ActiveRowSelected: Boolean;
  124.     function GetSelCount: Longint;
  125.     procedure InternalSaveLayout(IniFile: TObject; const Section: string);
  126.     procedure InternalRestoreLayout(IniFile: TObject; const Section: string);
  127. {$IFDEF WIN32}
  128.     procedure SaveColumnsLayout(IniFile: TObject; const Section: string);
  129.     procedure RestoreColumnsLayout(IniFile: TObject; const Section: string);
  130.     function GetOptions: TDBGridOptions;
  131.     procedure SetOptions(Value: TDBGridOptions);
  132.     function GetMasterColumn(ACol, ARow: Longint): TColumn;
  133. {$ELSE}
  134.     function GetFixedColor: TColor;
  135.     procedure SetFixedColor(Value: TColor);
  136.     function GetIndicatorOffset: Byte;
  137. {$ENDIF}
  138.     function GetTitleOffset: Byte;
  139.     procedure SetFixedCols(Value: Integer);
  140.     function GetFixedCols: Integer;
  141. {$IFDEF RX_D4}
  142.     function CalcLeftColumn: Integer;
  143. {$ENDIF}
  144.     procedure WMChar(var Msg: TWMChar); message WM_CHAR;
  145.     procedure WMCancelMode(var Message: TMessage); message WM_CANCELMODE;
  146. {$IFDEF WIN32}
  147.     procedure WMRButtonUp(var Message: TWMMouse); message WM_RBUTTONUP;
  148. {$ENDIF}
  149.   protected
  150.     function AcquireFocus: Boolean;
  151.     function CanEditShow: Boolean; override;
  152.     function CreateEditor: TInplaceEdit; override;
  153.     procedure DoTitleClick(ACol: Longint; AField: TField); dynamic;
  154.     procedure CheckTitleButton(ACol, ARow: Longint; var Enabled: Boolean); dynamic;
  155.     procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override;
  156.     procedure DrawDataCell(const Rect: TRect; Field: TField;
  157.       State: TGridDrawState); override; { obsolete from Delphi 2.0 }
  158.     procedure EditChanged(Sender: TObject); dynamic;
  159.     procedure GetCellProps(Field: TField; AFont: TFont; var Background: TColor;
  160.       Highlight: Boolean); dynamic;
  161.     function HighlightCell(DataCol, DataRow: Integer; const Value: string;
  162.       AState: TGridDrawState): Boolean; override;
  163.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  164.     procedure KeyPress(var Key: Char); override;
  165.     procedure SetColumnAttributes; override;
  166.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  167.       X, Y: Integer); override;
  168.     procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  169.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
  170.       X, Y: Integer); override;
  171. {$IFDEF RX_D4}
  172.     function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; override;
  173.     function DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; override;
  174. {$ENDIF}
  175.     procedure Scroll(Distance: Integer); override;
  176.     procedure LayoutChanged; override;
  177.     procedure TopLeftChanged; override;
  178. {$IFDEF WIN32}
  179.     procedure DrawColumnCell(const Rect: TRect; DataCol: Integer;
  180.       Column: TColumn; State: TGridDrawState); override;
  181.     procedure ColWidthsChanged; override;
  182. {$ELSE}
  183.     procedure ColumnMoved(FromIndex, ToIndex: Longint); override;
  184.     procedure LinkActive(Value: Boolean); override;
  185. {$ENDIF}
  186.     procedure Paint; override;
  187.   public
  188.     constructor Create(AOwner: TComponent); override;
  189.     destructor Destroy; override;
  190.     procedure DefaultDataCellDraw(const Rect: TRect; Field: TField;
  191.       State: TGridDrawState);
  192.     procedure DisableScroll;
  193.     procedure EnableScroll;
  194.     function ScrollDisabled: Boolean;
  195.     procedure MouseToCell(X, Y: Integer; var ACol, ARow: Longint);
  196.     procedure SaveLayout(IniFile: TIniFile);
  197.     procedure RestoreLayout(IniFile: TIniFile);
  198.     procedure SelectAll;
  199.     procedure UnselectAll;
  200.     procedure ToggleRowSelection;
  201.     procedure GotoSelection(Index: Longint);
  202. {$IFDEF WIN32}
  203.     procedure SaveLayoutReg(IniFile: TRegIniFile);
  204.     procedure RestoreLayoutReg(IniFile: TRegIniFile);
  205.     property SelectedRows;
  206. {$ELSE}
  207.     property SelectedRows: TBookmarkList read FBookmarks;
  208. {$ENDIF WIN32}
  209.     property SelCount: Longint read GetSelCount;
  210.     property Canvas;
  211.     property Col;
  212.     property InplaceEditor;
  213.     property LeftCol;
  214.     property Row;
  215.     property VisibleRowCount;
  216.     property VisibleColCount;
  217.     property IndicatorOffset {$IFNDEF WIN32}: Byte read GetIndicatorOffset {$ENDIF};
  218.     property TitleOffset: Byte read GetTitleOffset;
  219.   published
  220. {$IFDEF WIN32}
  221.     property Options: TDBGridOptions read GetOptions write SetOptions
  222.       default DefRxGridOptions;
  223. {$ELSE}
  224.     property FixedColor: TColor read GetFixedColor write SetFixedColor
  225.       default clBtnFace; { fix Delphi 1.0 bug }
  226.     property Options default DefRxGridOptions;
  227. {$ENDIF}
  228.     property FixedCols: Integer read GetFixedCols write SetFixedCols default 0;
  229.     property ClearSelection: Boolean read FClearSelection write FClearSelection
  230.       default True;
  231.     property DefaultDrawing: Boolean read FDefaultDrawing write FDefaultDrawing
  232.       default True;
  233.     property IniStorage: TFormPlacement read GetStorage write SetStorage;
  234.     property MultiSelect: Boolean read FMultiSelect write SetMultiSelect
  235.       default False;
  236.     property ShowGlyphs: Boolean read FShowGlyphs write SetShowGlyphs
  237.       default True;
  238.     property TitleButtons: Boolean read FTitleButtons write SetTitleButtons
  239.       default False;
  240.     property RowsHeight: Integer read GetRowsHeight write SetRowsHeight
  241.       stored False; { obsolete, for backward compatibility only }
  242.     property OnCheckButton: TCheckTitleBtnEvent read FOnCheckButton write FOnCheckButton;
  243.     property OnGetCellProps: TGetCellPropsEvent read FOnGetCellProps
  244.       write FOnGetCellProps; { obsolete }
  245.     property OnGetCellParams: TGetCellParamsEvent read FOnGetCellParams write FOnGetCellParams;
  246.     property OnGetBtnParams: TGetBtnParamsEvent read FOnGetBtnParams write FOnGetBtnParams;
  247.     property OnEditChange: TNotifyEvent read FOnEditChange write FOnEditChange;
  248.     property OnShowEditor: TDBEditShowEvent read FOnShowEditor write FOnShowEditor;
  249.     property OnTitleBtnClick: TTitleClickEvent read FOnTitleBtnClick write FOnTitleBtnClick;
  250.     property OnKeyPress: TKeyPressEvent read FOnKeyPress write FOnKeyPress;
  251.     property OnTopLeftChanged: TNotifyEvent read FOnTopLeftChanged write FOnTopLeftChanged;
  252. {$IFNDEF WIN32}
  253.     property OnColumnMoved: TMovedEvent read FOnColumnMoved write FOnColumnMoved;
  254. {$ENDIF}
  255. {$IFDEF RX_D5}
  256.     property OnContextPopup;
  257. {$ENDIF}
  258.     property OnMouseDown;
  259.     property OnMouseMove;
  260.     property OnMouseUp;
  261. {$IFDEF RX_D4}
  262.     property OnMouseWheelDown;
  263.     property OnMouseWheelUp;
  264. {$ENDIF}
  265.   end;
  266. { TRxDBComboEdit }
  267.   TRxDBComboEdit = class(TCustomComboEdit)
  268.   private
  269.     FDataLink: TFieldDataLink;
  270. {$IFDEF WIN32}
  271.     FCanvas: TControlCanvas;
  272. {$ENDIF}
  273.     FFocused: Boolean;
  274.     procedure DataChange(Sender: TObject);
  275.     procedure EditingChange(Sender: TObject);
  276.     function GetDataField: string;
  277.     function GetDataSource: TDataSource;
  278.     function GetField: TField;
  279.     procedure SetDataField(const Value: string);
  280.     procedure SetDataSource(Value: TDataSource);
  281.     procedure SetFocused(Value: Boolean);
  282.     procedure SetReadOnly(Value: Boolean);
  283.     procedure UpdateData(Sender: TObject);
  284.     procedure WMCut(var Message: TMessage); message WM_CUT;
  285.     procedure WMPaste(var Message: TMessage); message WM_PASTE;
  286.     procedure CMEnter(var Message: TCMEnter); message CM_ENTER;
  287.     procedure CMExit(var Message: TCMExit); message CM_EXIT;
  288. {$IFDEF WIN32}
  289.     procedure CMGetDataLink(var Message: TMessage); message CM_GETDATALINK;
  290.     procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  291. {$ENDIF}
  292.   protected
  293.     procedure Change; override;
  294.     function EditCanModify: Boolean; override;
  295.     function GetReadOnly: Boolean; override;
  296.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  297.     procedure KeyPress(var Key: Char); override;
  298.     procedure Loaded; override;
  299.     procedure Notification(AComponent: TComponent;
  300.       Operation: TOperation); override;
  301.     procedure Reset; override;
  302.   public
  303.     constructor Create(AOwner: TComponent); override;
  304.     destructor Destroy; override;
  305. {$IFDEF RX_D4}
  306.     function ExecuteAction(Action: TBasicAction): Boolean; override;
  307.     function UpdateAction(Action: TBasicAction): Boolean; override;
  308.     function UseRightToLeftAlignment: Boolean; override;
  309. {$ENDIF}
  310.     property Button;
  311.     property Field: TField read GetField;
  312.   published
  313.     property AutoSelect;
  314.     property BorderStyle;
  315.     property ButtonHint;
  316.     property CharCase;
  317.     property ClickKey;
  318.     property Color;
  319.     property Ctl3D;
  320.     property DataField: string read GetDataField write SetDataField;
  321.     property DataSource: TDataSource read GetDataSource write SetDataSource;
  322.     property DirectInput;
  323.     property DragCursor;
  324.     property DragMode;
  325.     property Enabled;
  326.     property Font;
  327.     property GlyphKind;
  328.     { Ensure GlyphKind is published before Glyph and ButtonWidth }
  329.     property Glyph;
  330.     property ButtonWidth;
  331.     property HideSelection;
  332. {$IFDEF RX_D4}
  333.     property Anchors;
  334.     property BiDiMode;
  335.     property Constraints;
  336.     property DragKind;
  337.     property ParentBiDiMode;
  338. {$ENDIF}
  339. {$IFDEF WIN32}
  340.   {$IFNDEF VER90}
  341.     property ImeMode;
  342.     property ImeName;
  343.   {$ENDIF}
  344. {$ENDIF}
  345.     property MaxLength;
  346.     property NumGlyphs;
  347.     property ParentColor;
  348.     property ParentCtl3D;
  349.     property ParentFont;
  350.     property ParentShowHint;
  351.     property PopupMenu;
  352.     property ReadOnly: Boolean read GetReadOnly write SetReadOnly default False;
  353.     property ShowHint;
  354.     property TabOrder;
  355.     property TabStop;
  356.     property Visible;
  357.     property OnButtonClick;
  358.     property OnChange;
  359.     property OnClick;
  360.     property OnDblClick;
  361.     property OnDragDrop;
  362.     property OnDragOver;
  363.     property OnEndDrag;
  364.     property OnEnter;
  365.     property OnExit;
  366.     property OnKeyDown;
  367.     property OnKeyPress;
  368.     property OnKeyUp;
  369.     property OnMouseDown;
  370.     property OnMouseMove;
  371.     property OnMouseUp;
  372. {$IFDEF WIN32}
  373.     property OnStartDrag;
  374. {$ENDIF}
  375. {$IFDEF RX_D5}
  376.     property OnContextPopup;
  377. {$ENDIF}
  378. {$IFDEF RX_D4}
  379.     property OnEndDock;
  380.     property OnStartDock;
  381. {$ENDIF}
  382.   end;
  383. { TDBDateEdit }
  384.   TDBDateEdit = class(TCustomDateEdit)
  385.   private
  386.     FDataLink: TFieldDataLink;
  387. {$IFDEF WIN32}
  388.     FCanvas: TControlCanvas;
  389. {$ENDIF}
  390.     procedure DataChange(Sender: TObject);
  391.     procedure EditingChange(Sender: TObject);
  392.     function GetDataField: string;
  393.     function GetDataSource: TDataSource;
  394.     function GetField: TField;
  395.     procedure SetDataField(const Value: string);
  396.     procedure SetDataSource(Value: TDataSource);
  397.     procedure SetReadOnly(Value: Boolean);
  398.     procedure UpdateData(Sender: TObject);
  399.     procedure AfterPopup(Sender: TObject; var Date: TDateTime; var Action: Boolean);
  400.     procedure WMCut(var Message: TMessage); message WM_CUT;
  401.     procedure WMPaste(var Message: TMessage); message WM_PASTE;
  402.     procedure CMEnter(var Message: TCMEnter); message CM_ENTER;
  403.     procedure CMExit(var Message: TCMExit); message CM_EXIT;
  404. {$IFDEF WIN32}
  405.     procedure CMGetDataLink(var Message: TMessage); message CM_GETDATALINK;
  406.     procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  407. {$ENDIF}
  408.   protected
  409. {$IFDEF WIN32}
  410.     procedure AcceptValue(const Value: Variant); override;
  411. {$ENDIF}
  412.     procedure ApplyDate(Value: TDateTime); override;
  413.     function GetReadOnly: Boolean; override;
  414.     procedure Change; override;
  415.     function EditCanModify: Boolean; override;
  416.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  417.     procedure KeyPress(var Key: Char); override;
  418.     procedure Notification(AComponent: TComponent;
  419.       Operation: TOperation); override;
  420.     procedure Reset; override;
  421.   public
  422.     constructor Create(AOwner: TComponent); override;
  423.     destructor Destroy; override;
  424.     procedure UpdateMask; override;
  425. {$IFDEF RX_D4}
  426.     function ExecuteAction(Action: TBasicAction): Boolean; override;
  427.     function UpdateAction(Action: TBasicAction): Boolean; override;
  428.     function UseRightToLeftAlignment: Boolean; override;
  429. {$ENDIF}
  430.     property Field: TField read GetField;
  431.   published
  432.     property CalendarHints;
  433.     property DataField: string read GetDataField write SetDataField;
  434.     property DataSource: TDataSource read GetDataSource write SetDataSource;
  435.     property ReadOnly: Boolean read GetReadOnly write SetReadOnly default False;
  436.     property AutoSelect;
  437.     property BlanksChar;
  438.     property BorderStyle;
  439.     property ButtonHint;
  440.     property CheckOnExit;
  441.     property ClickKey;
  442.     property Color;
  443.     property Ctl3D;
  444.     property DefaultToday;
  445.     property DialogTitle;
  446.     property DirectInput;
  447.     property DragCursor;
  448.     property DragMode;
  449.     property Enabled;
  450.     property Font;
  451.     property GlyphKind;
  452.     { Ensure GlyphKind is declared before Glyph and ButtonWidth }
  453.     property Glyph;
  454.     property ButtonWidth;
  455.     property HideSelection;
  456. {$IFDEF RX_D4}
  457.     property Anchors;
  458.     property BiDiMode;
  459.     property Constraints;
  460.     property DragKind;
  461.     property ParentBiDiMode;
  462. {$ENDIF}
  463. {$IFDEF WIN32}
  464.   {$IFNDEF VER90}
  465.     property ImeMode;
  466.     property ImeName;
  467.   {$ENDIF}
  468. {$ENDIF}
  469.     property MaxLength;
  470.     property NumGlyphs;
  471.     property ParentColor;
  472.     property ParentCtl3D;
  473.     property ParentFont;
  474.     property ParentShowHint;
  475.     property PopupAlign;
  476.     property PopupColor;
  477.     property PopupMenu;
  478.     property ShowHint;
  479.     property CalendarStyle;
  480.     property TabOrder;
  481.     property TabStop;
  482.     property StartOfWeek;
  483.     property Weekends;
  484.     property WeekendColor;
  485.     property YearDigits;
  486.     property Visible;
  487.     property OnButtonClick;
  488.     property OnChange;
  489.     property OnClick;
  490.     property OnDblClick;
  491.     property OnDragDrop;
  492.     property OnDragOver;
  493.     property OnEndDrag;
  494.     property OnEnter;
  495.     property OnExit;
  496.     property OnKeyDown;
  497.     property OnKeyPress;
  498.     property OnKeyUp;
  499.     property OnMouseDown;
  500.     property OnMouseMove;
  501.     property OnMouseUp;
  502. {$IFDEF WIN32}
  503.     property OnStartDrag;
  504. {$ENDIF}
  505. {$IFDEF RX_D5}
  506.     property OnContextPopup;
  507. {$ENDIF}
  508. {$IFDEF RX_D4}
  509.     property OnEndDock;
  510.     property OnStartDock;
  511. {$ENDIF}
  512.   end;
  513. { TRxDBCalcEdit }
  514.   TRxDBCalcEdit = class(TRxCustomCalcEdit)
  515.   private
  516.     FDataLink: TFieldDataLink;
  517.     FDefaultParams: Boolean;
  518.     procedure DataChange(Sender: TObject);
  519.     procedure EditingChange(Sender: TObject);
  520.     function GetDataField: string;
  521.     function GetDataSource: TDataSource;
  522.     function GetField: TField;
  523.     procedure SetDataField(const Value: string);
  524.     procedure SetDataSource(Value: TDataSource);
  525.     procedure SetDefaultParams(Value: Boolean);
  526.     procedure SetReadOnly(Value: Boolean);
  527.     procedure UpdateFieldData(Sender: TObject);
  528.     procedure WMCut(var Message: TMessage); message WM_CUT;
  529.     procedure WMPaste(var Message: TMessage); message WM_PASTE;
  530.     procedure CMEnter(var Message: TCMEnter); message CM_ENTER;
  531.     procedure CMExit(var Message: TCMExit); message CM_EXIT;
  532. {$IFDEF WIN32}
  533.     procedure CMGetDataLink(var Message: TMessage); message CM_GETDATALINK;
  534. {$ENDIF}
  535.   protected
  536. {$IFDEF WIN32}
  537.     procedure AcceptValue(const Value: Variant); override;
  538.     function GetDisplayText: string; override;
  539. {$ENDIF}
  540.     function GetReadOnly: Boolean; override;
  541.     procedure Change; override;
  542.     function EditCanModify: Boolean; override;
  543.     function IsValidChar(Key: Char): Boolean; override;
  544.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  545.     procedure KeyPress(var Key: Char); override;
  546.     procedure Notification(AComponent: TComponent;
  547.       Operation: TOperation); override;
  548.     procedure Reset; override;
  549.     procedure UpdatePopup; override;
  550.   public
  551.     constructor Create(AOwner: TComponent); override;
  552.     destructor Destroy; override;
  553.     procedure UpdateFieldParams;
  554. {$IFDEF RX_D4}
  555.     function ExecuteAction(Action: TBasicAction): Boolean; override;
  556.     function UpdateAction(Action: TBasicAction): Boolean; override;
  557.     function UseRightToLeftAlignment: Boolean; override;
  558. {$ENDIF}
  559.     property Field: TField read GetField;
  560.     property Value;
  561.   published
  562.     property DataField: string read GetDataField write SetDataField;
  563.     property DataSource: TDataSource read GetDataSource write SetDataSource;
  564.     property DefaultParams: Boolean read FDefaultParams write SetDefaultParams default False;
  565.     property ReadOnly: Boolean read GetReadOnly write SetReadOnly default False;
  566.     property Alignment;
  567.     property AutoSelect;
  568.     property BeepOnError;
  569.     property BorderStyle;
  570.     property ButtonHint;
  571.     property CheckOnExit;
  572.     property ClickKey;
  573.     property Color;
  574.     property Ctl3D;
  575.     property DecimalPlaces;
  576.     property DirectInput;
  577.     property DisplayFormat;
  578.     property DragCursor;
  579.     property DragMode;
  580.     property Enabled;
  581.     property Font;
  582.     property FormatOnEditing;
  583.     property GlyphKind;
  584.     { Ensure GlyphKind is declared before Glyph and ButtonWidth }
  585.     property Glyph;
  586.     property ButtonWidth;
  587.     property HideSelection;
  588. {$IFDEF RX_D4}
  589.     property Anchors;
  590.     property BiDiMode;
  591.     property Constraints;
  592.     property DragKind;
  593.     property ParentBiDiMode;
  594. {$ENDIF}
  595. {$IFDEF WIN32}
  596.   {$IFNDEF VER90}
  597.     property ImeMode;
  598.     property ImeName;
  599.   {$ENDIF}
  600. {$ENDIF}
  601.     property MaxLength;
  602.     property MaxValue;
  603.     property MinValue;
  604.     property NumGlyphs;
  605.     property ParentColor;
  606.     property ParentCtl3D;
  607.     property ParentFont;
  608.     property ParentShowHint;
  609.     property PopupAlign;
  610.     property PopupMenu;
  611.     property ShowHint;
  612.     property TabOrder;
  613.     property TabStop;
  614.     property Visible;
  615.     property ZeroEmpty;
  616.     property OnButtonClick;
  617.     property OnChange;
  618.     property OnClick;
  619.     property OnDblClick;
  620.     property OnDragDrop;
  621.     property OnDragOver;
  622.     property OnEndDrag;
  623.     property OnEnter;
  624.     property OnExit;
  625.     property OnKeyDown;
  626.     property OnKeyPress;
  627.     property OnKeyUp;
  628.     property OnMouseDown;
  629.     property OnMouseMove;
  630.     property OnMouseUp;
  631. {$IFDEF WIN32}
  632.     property OnStartDrag;
  633. {$ENDIF}
  634. {$IFDEF RX_D5}
  635.     property OnContextPopup;
  636. {$ENDIF}
  637. {$IFDEF RX_D4}
  638.     property OnEndDock;
  639.     property OnStartDock;
  640. {$ENDIF}
  641.   end;
  642. { TDBStatusLabel }
  643.   TGetStringEvent = function(Sender: TObject): string of object;
  644.   TDataValueEvent = procedure(Sender: TObject; DataSet: TDataSet;
  645.     var Value: Longint) of object;
  646.   TDBLabelStyle = (lsState, lsRecordNo, lsRecordSize);
  647.   TGlyphAlign = glGlyphLeft..glGlyphRight;
  648.   TDBStatusKind = dsInactive..dsCalcFields;
  649.   TDBLabelOptions = (doCaption, doGlyph, doBoth);
  650.   TDBStatusLabel = class(TRxCustomLabel)
  651.   private
  652.     FDataLink: TDataLink;
  653.     FDataSetName: PString;
  654.     FStyle: TDBLabelStyle;
  655.     FEditColor: TColor;
  656.     FCalcCount: Boolean;
  657.     FCaptions: TStrings;
  658.     FGlyph: TBitmap;
  659.     FCell: TBitmap;
  660.     FGlyphAlign: TGlyphAlign;
  661.     FRecordCount: Longint;
  662.     FRecordNo: Longint;
  663.     FShowOptions: TDBLabelOptions;
  664.     FOnGetDataName: TGetStringEvent;
  665.     FOnGetRecNo: TDataValueEvent;
  666.     FOnGetRecordCount: TDataValueEvent;
  667.     function GetStatusKind(State: TDataSetState): TDBStatusKind;
  668.     procedure CaptionsChanged(Sender: TObject);
  669.     function GetDataSetName: string;
  670.     procedure SetDataSetName(Value: string);
  671.     function GetDataSource: TDataSource;
  672.     procedure SetDataSource(Value: TDataSource);
  673.     function GetDatasetState: TDataSetState;
  674.     procedure SetEditColor(Value: TColor);
  675.     procedure SetStyle(Value: TDBLabelStyle);
  676.     procedure SetShowOptions(Value: TDBLabelOptions);
  677.     procedure SetGlyphAlign(Value: TGlyphAlign);
  678.     procedure SetCaptions(Value: TStrings);
  679.     procedure SetCalcCount(Value: Boolean);
  680.   protected
  681.     procedure Loaded; override;
  682.     function GetDefaultFontColor: TColor; override;
  683.     function GetLabelCaption: string; override;
  684.     function GetCaption(State: TDataSetState): string; virtual;
  685.     procedure Notification(AComponent: TComponent;
  686.       Operation: TOperation); override;
  687.     procedure Paint; override;
  688.     procedure SetName(const Value: TComponentName); override;
  689.   public
  690.     constructor Create(AOwner: TComponent); override;
  691.     destructor Destroy; override;
  692.     procedure UpdateData; virtual;
  693.     procedure UpdateStatus; virtual;
  694.     property Caption;
  695.     property DatasetState: TDataSetState read GetDatasetState;
  696.   published
  697.     property DatasetName: string read GetDataSetName write SetDataSetName;
  698.     property DataSource: TDataSource read GetDataSource write SetDataSource;
  699.     property EditColor: TColor read FEditColor write SetEditColor default clRed;
  700.     property Captions: TStrings read FCaptions write SetCaptions;
  701.     property Style: TDBLabelStyle read FStyle write SetStyle default lsState;
  702.     property CalcRecCount: Boolean read FCalcCount write SetCalcCount default False;
  703.     property ShowOptions: TDBLabelOptions read FShowOptions write SetShowOptions
  704.       default doCaption;
  705.     property GlyphAlign: TGlyphAlign read FGlyphAlign write SetGlyphAlign
  706.       default glGlyphLeft;
  707.     property Layout default tlCenter;
  708.     property ShadowSize default 0;
  709.     property Align;
  710.     property Alignment;
  711.     property AutoSize;
  712.     property Color;
  713.     property DragCursor;
  714.     property DragMode;
  715.     property Font;
  716. {$IFDEF RX_D4}
  717.     property Anchors;
  718.     property BiDiMode;
  719.     property Constraints;
  720.     property DragKind;
  721.     property ParentBiDiMode;
  722. {$ENDIF}
  723.     property ParentColor;
  724.     property ParentFont;
  725.     property ParentShowHint;
  726.     property PopupMenu;
  727.     property ShadowColor;
  728.     property ShadowPos;
  729.     property ShowHint;
  730.     property Transparent;
  731.     property Visible;
  732.     property WordWrap;
  733.     property OnGetDataName: TGetStringEvent read FOnGetDataName write FOnGetDataName;
  734.     property OnGetRecordCount: TDataValueEvent read FOnGetRecordCount
  735.       write FOnGetRecordCount;
  736.     property OnGetRecNo: TDataValueEvent read FOnGetRecNo write FOnGetRecNo;
  737.     property OnClick;
  738.     property OnDblClick;
  739.     property OnDragDrop;
  740.     property OnDragOver;
  741.     property OnEndDrag;
  742.     property OnMouseDown;
  743.     property OnMouseMove;
  744.     property OnMouseUp;
  745.     property OnMouseEnter;
  746.     property OnMouseLeave;
  747. {$IFDEF WIN32}
  748.     property OnStartDrag;
  749. {$ENDIF}
  750. {$IFDEF RX_D5}
  751.     property OnContextPopup;
  752. {$ENDIF}
  753. {$IFDEF RX_D4}
  754.     property OnEndDock;
  755.     property OnStartDock;
  756. {$ENDIF}
  757.   end;
  758. implementation
  759. uses SysUtils, rxStrUtils, Dialogs, ExtCtrls, DbConsts, AppUtils, VCLUtils,
  760.   DbUtils, {$IFNDEF RX_D3} BdeUtils, {$ENDIF} PickDate, RxCalc, MaxMin,
  761.   RxDConst;
  762. {$IFDEF WIN32}
  763.   {$R *.R32}
  764. {$ELSE}
  765.   {$R *.R16}
  766. {$ENDIF}
  767. type
  768.   TGridPicture = (gpBlob, gpMemo, gpPicture, gpOle, gpObject, gpData,
  769.     gpNotEmpty, gpMarkDown, gpMarkUp);
  770. const
  771.   GridBmpNames: array[TGridPicture] of PChar =
  772.     ('DBG_BLOB', 'DBG_MEMO', 'DBG_PICT', 'DBG_OLE', 'DBG_OBJECT', 'DBG_DATA',
  773.      'DBG_NOTEMPTY', 'DBG_SMDOWN', 'DBG_SMUP');
  774.   GridBitmaps: array[TGridPicture] of TBitmap =
  775.     (nil, nil, nil, nil, nil, nil, nil, nil, nil);
  776.   bmMultiDot = 'DBG_MSDOT';
  777.   bmMultiArrow = 'DBG_MSARROW';
  778. function GetGridBitmap(BmpType: TGridPicture): TBitmap;
  779. begin
  780.   if GridBitmaps[BmpType] = nil then begin
  781.     GridBitmaps[BmpType] := TBitmap.Create;
  782.     GridBitmaps[BmpType].Handle := LoadBitmap(HInstance, GridBmpNames[BmpType]);
  783.   end;
  784.   Result := GridBitmaps[BmpType];
  785. end;
  786. procedure DestroyLocals; far;
  787. var
  788.   I: TGridPicture;
  789. begin
  790.   for I := Low(TGridPicture) to High(TGridPicture) do GridBitmaps[I].Free;
  791. end;
  792. procedure GridInvalidateRow(Grid: TRxDBGrid; Row: Longint);
  793. var
  794.   I: Longint;
  795. begin
  796.   for I := 0 to Grid.ColCount - 1 do Grid.InvalidateCell(I, Row);
  797. end;
  798. {$IFNDEF WIN32}
  799. { TBookmarkList }
  800. constructor TBookmarkList.Create(AGrid: TCustomDBGrid);
  801. begin
  802.   inherited Create;
  803.   FList := THugeList.Create;
  804.   FGrid := AGrid;
  805. end;
  806. destructor TBookmarkList.Destroy;
  807. begin
  808.   Clear;
  809.   FList.Free;
  810.   inherited Destroy;
  811. end;
  812. procedure TBookmarkList.Clear;
  813. var
  814.   I: Longint;
  815. begin
  816.   if FList.Count = 0 then Exit;
  817.   for I := FList.Count - 1 downto 0 do StrDispose(FList[I]);
  818.   FList.Clear;
  819.   ListChanged;
  820.   FGrid.Invalidate;
  821. end;
  822. function TBookmarkList.Compare(const Item1, Item2: TBookmark): Longint;
  823. begin
  824.   Result := BookmarksCompare(TRxDBGrid(FGrid).Datalink.Dataset,
  825.     Item1, Item2);
  826. end;
  827. function TBookmarkList.CurrentRow: TBookmark;
  828. begin
  829.   if not FLinkActive then _DBError(sDataSetClosed);
  830.   Result := TRxDBGrid(FGrid).Datalink.Dataset.GetBookmark;
  831. end;
  832. function TBookmarkList.GetCurrentRowSelected: Boolean;
  833. var
  834.   Index: Longint;
  835.   Row: TBookmark;
  836. begin
  837.   Row := CurrentRow;
  838.   try
  839.     Result := Find(Row, Index);
  840.   finally
  841.     StrDispose(Row);
  842.   end;
  843. end;
  844. function TBookmarkList.Find(const Item: TBookmark; var Index: Longint): Boolean;
  845. var
  846.   L, H, I, C: Longint;
  847.   P: PChar;
  848. begin
  849.   if (Compare(Item, FCache) = 0) and (FCacheIndex >= 0) then begin
  850.     Index := FCacheIndex;
  851.     Result := FCacheFind;
  852.     Exit;
  853.   end;
  854.   Result := False;
  855.   L := 0;
  856.   H := FList.Count - 1;
  857.   while L <= H do begin
  858.     I := (L + H) shr 1;
  859.     C := Compare(TBookmark(FList[I]), Item);
  860.     if C < 0 then L := I + 1
  861.     else begin
  862.       H := I - 1;
  863.       if C = 0 then begin
  864.         Result := True;
  865.         L := I;
  866.       end;
  867.     end;
  868.   end;
  869.   Index := L;
  870.   StrDispose(FCache);
  871.   FCache := nil;
  872.   P := PChar(Item);
  873.   if P <> nil then begin
  874.     Dec(P, 2);
  875.     FCache := StrAlloc(Word(Pointer(P)^));
  876.     Move(Item^, FCache^, Word(Pointer(P)^));
  877.   end;
  878.   FCacheIndex := Index;
  879.   FCacheFind := Result;
  880. end;
  881. function TBookmarkList.GetCount: Longint;
  882. begin
  883.   Result := FList.Count;
  884. end;
  885. function TBookmarkList.GetItem(Index: Longint): TBookmark;
  886. begin
  887.   Result := TBookmark(FList[Index]);
  888. end;
  889. function TBookmarkList.IndexOf(const Item: TBookmark): Longint;
  890. begin
  891.   if not Find(Item, Result) then Result := -1;
  892. end;
  893. procedure TBookmarkList.LinkActive(Value: Boolean);
  894. begin
  895.   Clear;
  896.   FLinkActive := Value;
  897. end;
  898. procedure TBookmarkList.Delete;
  899. var
  900.   I: Longint;
  901. begin
  902.   with TRxDBGrid(FGrid).Datalink.Dataset do begin
  903.     DisableControls;
  904.     try
  905.       for I := FList.Count - 1 downto 0 do begin
  906.         if FList[I] <> nil then begin
  907.           GotoBookmark(TBookmark(FList[I]));
  908.           Delete;
  909.           StrDispose(FList[I]);
  910.         end;
  911.         FList.Delete(I);
  912.       end;
  913.       ListChanged;
  914.     finally
  915.       EnableControls;
  916.     end;
  917.   end;
  918. end;
  919. function TBookmarkList.Refresh: Boolean;
  920. var
  921.   I: Longint;
  922. begin
  923.   Result := False;
  924.   with TRxDBGrid(FGrid).DataLink.Dataset do
  925.   try
  926.     CheckBrowseMode;
  927.     for I := FList.Count - 1 downto 0 do
  928.       if DbiSetToBookmark(Handle, Pointer(FList[I])) <> 0 then begin
  929.         Result := True;
  930.         StrDispose(FList[I]);
  931.         FList.Delete(I);
  932.       end;
  933.     ListChanged;
  934.   finally
  935.     UpdateCursorPos;
  936.     if Result then FGrid.Invalidate;
  937.   end;
  938. end;
  939. procedure TBookmarkList.SetCurrentRowSelected(Value: Boolean);
  940. var
  941.   Index: Longint;
  942.   Current: TBookmark;
  943. begin
  944.   Current := CurrentRow;
  945.   Index := 0;
  946.   if (Current = nil) or (Find(Current, Index) = Value) then begin
  947.     if Current <> nil then StrDispose(Current);
  948.     Exit;
  949.   end;
  950.   if Value then begin
  951.     try
  952.       FList.Insert(Index, Current);
  953.     except
  954.       StrDispose(Current);
  955.       raise;
  956.     end;
  957.   end
  958.   else begin
  959.     if (Index < FList.Count) and (Index >= 0) then begin
  960.       StrDispose(FList[Index]);
  961.       FList.Delete(Index);
  962.     end;
  963.     StrDispose(Current);
  964.   end;
  965.   ListChanged;
  966.   TRxDBGrid(FGrid).InvalidateRow(TRxDBGrid(FGrid).Row);
  967.   GridInvalidateRow(TRxDBGrid(FGrid), TRxDBGrid(FGrid).Row);
  968. end;
  969. procedure TBookmarkList.ListChanged;
  970. begin
  971.   if FCache <> nil then StrDispose(FCache);
  972.   FCache := nil;
  973.   FCacheIndex := -1;
  974. end;
  975. {$ENDIF WIN32}
  976. type
  977.   TBookmarks = class(TBookmarkList);
  978. { TRxDBGrid }
  979. constructor TRxDBGrid.Create(AOwner: TComponent);
  980. var
  981.   Bmp: TBitmap;
  982. begin
  983.   inherited Create(AOwner);
  984.   inherited DefaultDrawing := False;
  985.   Options := DefRxGridOptions;
  986.   Bmp := TBitmap.Create;
  987.   try
  988.     Bmp.Handle := LoadBitmap(hInstance, bmMultiDot);
  989. {$IFDEF WIN32}
  990.     FMsIndicators := TImageList.CreateSize(Bmp.Width, Bmp.Height);
  991. {$ELSE}
  992.     FMsIndicators := TImageList.Create(Bmp.Width, Bmp.Height);
  993.     Bmp.Monochrome := False;
  994. {$ENDIF}
  995.     FMsIndicators.AddMasked(Bmp, clWhite);
  996.     Bmp.Handle := LoadBitmap(hInstance, bmMultiArrow);
  997. {$IFNDEF WIN32}
  998.     Bmp.Monochrome := False;
  999. {$ENDIF}
  1000.     FMsIndicators.AddMasked(Bmp, clWhite);
  1001.   finally
  1002.     Bmp.Free;
  1003.   end;
  1004.   FIniLink := TIniLink.Create;
  1005.   FIniLink.OnSave := IniSave;
  1006.   FIniLink.OnLoad := IniLoad;
  1007.   FShowGlyphs := True;
  1008.   FDefaultDrawing := True;
  1009.   FClearSelection := True;
  1010. {$IFNDEF WIN32}
  1011.   FBookmarks := TBookmarkList.Create(Self);
  1012.   FPressedCol := -1;
  1013. {$ENDIF}
  1014. end;
  1015. destructor TRxDBGrid.Destroy;
  1016. begin
  1017.   FIniLink.Free;
  1018. {$IFNDEF WIN32}
  1019.   if FSelectionAnchor <> nil then StrDispose(FSelectionAnchor);
  1020.   FSelectionAnchor := nil;
  1021.   FBookmarks.Free;
  1022.   FBookmarks := nil;
  1023. {$ENDIF}
  1024.   FMsIndicators.Free;
  1025.   inherited Destroy;
  1026. end;
  1027. function TRxDBGrid.GetImageIndex(Field: TField): Integer;
  1028. var
  1029.   AOnGetText: TFieldGetTextEvent;
  1030.   AOnSetText: TFieldSetTextEvent;
  1031. begin
  1032.   Result := -1;
  1033.   if FShowGlyphs and Assigned(Field) then begin
  1034.     if (not ReadOnly) and Field.CanModify then begin
  1035.       { Allow editing of memo fields if OnSetText and OnGetText
  1036.         events are assigned }
  1037.       AOnGetText := Field.OnGetText;
  1038.       AOnSetText := Field.OnSetText;
  1039.       if Assigned(AOnSetText) and Assigned(AOnGetText) then Exit;
  1040.     end;
  1041.     case Field.DataType of
  1042.       ftBytes, ftVarBytes, ftBlob: Result := Ord(gpBlob);
  1043.       ftMemo: Result := Ord(gpMemo);
  1044.       ftGraphic: Result := Ord(gpPicture);
  1045. {$IFDEF WIN32}
  1046.       ftTypedBinary: Result := Ord(gpBlob);
  1047.       ftFmtMemo: Result := Ord(gpMemo);
  1048.       ftParadoxOle, ftDBaseOle: Result := Ord(gpOle);
  1049. {$ENDIF}
  1050. {$IFDEF RX_D3}
  1051.       ftCursor: Result := Ord(gpData);
  1052. {$ENDIF}
  1053. {$IFDEF RX_D4}
  1054.       ftReference, ftDataSet: Result := Ord(gpData);
  1055. {$ENDIF}
  1056. {$IFDEF RX_D5}
  1057.       ftOraClob: Result := Ord(gpMemo);
  1058.       ftOraBlob: Result := Ord(gpBlob);
  1059. {$ENDIF}
  1060.     end;
  1061.   end;
  1062. end;
  1063. function TRxDBGrid.ActiveRowSelected: Boolean;
  1064. var
  1065. {$IFDEF WIN32}
  1066.   Index: Integer;
  1067. {$ELSE}
  1068.   Index: Longint;
  1069.   Bookmark: TBookmark;
  1070. {$ENDIF}
  1071. begin
  1072.   Result := False;
  1073.   if MultiSelect and Datalink.Active then begin
  1074. {$IFDEF WIN32}
  1075.     Result := SelectedRows.Find(Datalink.DataSet.Bookmark, Index);
  1076. {$ELSE}
  1077.     Bookmark := Datalink.Dataset.GetBookmark;
  1078.     try
  1079.       Result := SelectedRows.Find(Bookmark, Index);
  1080.     finally
  1081.       StrDispose(Bookmark);
  1082.     end;
  1083. {$ENDIF}
  1084.   end;
  1085. end;
  1086. function TRxDBGrid.HighlightCell(DataCol, DataRow: Integer;
  1087.   const Value: string; AState: TGridDrawState): Boolean;
  1088. begin
  1089.   Result := ActiveRowSelected;
  1090.   if not Result then
  1091.     Result := inherited HighlightCell(DataCol, DataRow, Value, AState);
  1092. end;
  1093. procedure TRxDBGrid.ToggleRowSelection;
  1094. begin
  1095.   if MultiSelect and Datalink.Active then
  1096.     with SelectedRows do CurrentRowSelected := not CurrentRowSelected;
  1097. end;
  1098. function TRxDBGrid.GetSelCount: Longint;
  1099. begin
  1100.   if MultiSelect and (Datalink <> nil) and Datalink.Active then
  1101.     Result := SelectedRows.Count
  1102.   else Result := 0;
  1103. end;
  1104. procedure TRxDBGrid.SelectAll;
  1105. var
  1106.   ABookmark: TBookmark;
  1107. begin
  1108.   if MultiSelect and DataLink.Active then begin
  1109.     with Datalink.Dataset do begin
  1110.       if (BOF and EOF) then Exit;
  1111.       DisableControls;
  1112.       try
  1113.         ABookmark := GetBookmark;
  1114.         try
  1115.           First;
  1116.           while not EOF do begin
  1117.             SelectedRows.CurrentRowSelected := True;
  1118.             Next;
  1119.           end;
  1120.         finally
  1121.           try
  1122.             GotoBookmark(ABookmark);
  1123.           except
  1124.           end;
  1125.           FreeBookmark(ABookmark);
  1126.         end;
  1127.       finally
  1128.         EnableControls;
  1129.       end;
  1130.     end;
  1131.   end;
  1132. end;
  1133. procedure TRxDBGrid.UnselectAll;
  1134. begin
  1135.   if MultiSelect then begin
  1136.     SelectedRows.Clear;
  1137.     FSelecting := False;
  1138.   end;
  1139. end;
  1140. procedure TRxDBGrid.GotoSelection(Index: Longint);
  1141. begin
  1142.   if MultiSelect and DataLink.Active and (Index < SelectedRows.Count) and
  1143.     (Index >= 0) then
  1144.     Datalink.DataSet.GotoBookmark(Pointer(SelectedRows[Index]));
  1145. end;
  1146. {$IFNDEF WIN32}
  1147. function TRxDBGrid.GetIndicatorOffset: Byte;
  1148. begin
  1149.   Result := 0;
  1150.   if dgIndicator in Options then Inc(Result);
  1151. end;
  1152. {$ENDIF WIN32}
  1153. procedure TRxDBGrid.LayoutChanged;
  1154. var
  1155.   ACol: Longint;
  1156. begin
  1157.   ACol := Col;
  1158.   inherited LayoutChanged;
  1159.   if Datalink.Active and (FixedCols > 0) then
  1160. {$IFDEF RX_D4}
  1161.     Col := Min(Max(CalcLeftColumn, ACol), ColCount - 1);
  1162. {$ELSE}
  1163.     Col := Min(Max(inherited FixedCols, ACol), ColCount - 1);
  1164. {$ENDIF}
  1165. end;
  1166. {$IFDEF WIN32}
  1167. procedure TRxDBGrid.ColWidthsChanged;
  1168. var
  1169.   ACol: Longint;
  1170. begin
  1171.   ACol := Col;
  1172.   inherited ColWidthsChanged;
  1173.   if Datalink.Active and (FixedCols > 0) then
  1174. {$IFDEF RX_D4}
  1175.     Col := Min(Max(CalcLeftColumn, ACol), ColCount - 1);
  1176. {$ELSE}
  1177.     Col := Min(Max(inherited FixedCols, ACol), ColCount - 1);
  1178. {$ENDIF}
  1179. end;
  1180. {$ENDIF}
  1181. function TRxDBGrid.CreateEditor: TInplaceEdit;
  1182. begin
  1183.   Result := inherited CreateEditor;
  1184.   TEdit(Result).OnChange := EditChanged;
  1185. end;
  1186. function TRxDBGrid.GetTitleOffset: Byte;
  1187. {$IFDEF RX_D4}
  1188. var
  1189.   I, J: Integer;
  1190. {$ENDIF}
  1191. begin
  1192.   Result := 0;
  1193.   if dgTitles in Options then begin
  1194.     Result := 1;
  1195. {$IFDEF RX_D4}
  1196.     if (Datalink <> nil) and (Datalink.Dataset <> nil) and
  1197.       Datalink.Dataset.ObjectView then
  1198.     begin
  1199.       for I := 0 to Columns.Count - 1 do begin
  1200.         if Columns[I].Showing then begin
  1201.           J := Columns[I].Depth;
  1202.           if J >= Result then Result := J + 1;
  1203.         end;
  1204.       end;
  1205.     end;
  1206. {$ENDIF}
  1207.   end;
  1208. end;
  1209. procedure TRxDBGrid.SetColumnAttributes;
  1210. begin
  1211.   inherited SetColumnAttributes;
  1212.   SetFixedCols(FFixedCols);
  1213. end;
  1214. procedure TRxDBGrid.SetFixedCols(Value: Integer);
  1215. var
  1216.   FixCount, I: Integer;
  1217. begin
  1218.   FixCount := Max(Value, 0) + IndicatorOffset;
  1219.   if DataLink.Active and not (csLoading in ComponentState) and
  1220.     (ColCount > IndicatorOffset + 1) then
  1221.   begin
  1222.     FixCount := Min(FixCount, ColCount - 1);
  1223.     inherited FixedCols := FixCount;
  1224.     for I := 1 to Min(FixedCols, ColCount - 1) do
  1225.       TabStops[I] := False;
  1226.   end;
  1227.   FFixedCols := FixCount - IndicatorOffset;
  1228. end;
  1229. function TRxDBGrid.GetFixedCols: Integer;
  1230. begin
  1231.   if DataLink.Active then Result := inherited FixedCols - IndicatorOffset
  1232.   else Result := FFixedCols;
  1233. end;
  1234. {$IFDEF RX_D4}
  1235. function TRxDBGrid.CalcLeftColumn: Integer;
  1236. begin
  1237.   Result := FixedCols + IndicatorOffset;
  1238.   while (Result < ColCount) and (ColWidths[Result] <= 0) do
  1239.     Inc(Result);
  1240. end;
  1241. {$ENDIF}
  1242. procedure TRxDBGrid.KeyDown(var Key: Word; Shift: TShiftState);
  1243. var
  1244.   KeyDownEvent: TKeyEvent;
  1245.   procedure ClearSelections;
  1246.   begin
  1247.     if FMultiSelect then begin
  1248.       if FClearSelection then SelectedRows.Clear;
  1249.       FSelecting := False;
  1250.     end;
  1251.   end;
  1252.   procedure DoSelection(Select: Boolean; Direction: Integer);
  1253.   var
  1254.     AddAfter: Boolean;
  1255. {$IFNDEF WIN32}
  1256.     CurRow: TBookmark;
  1257. {$ENDIF}
  1258.   begin
  1259.     AddAfter := False;
  1260. {$IFDEF WIN32}
  1261.     BeginUpdate;
  1262.     try
  1263. {$ENDIF}
  1264.       if MultiSelect and DataLink.Active then
  1265.         if Select and (ssShift in Shift) then begin
  1266.           if not FSelecting then begin
  1267. {$IFNDEF WIN32}
  1268.             if FSelectionAnchor <> nil then StrDispose(FSelectionAnchor);
  1269. {$ENDIF}
  1270.             FSelectionAnchor := TBookmarks(SelectedRows).CurrentRow;
  1271.             SelectedRows.CurrentRowSelected := True;
  1272.             FSelecting := True;
  1273.             AddAfter := True;
  1274.           end
  1275.           else with TBookmarks(SelectedRows) do begin
  1276. {$IFDEF WIN32}
  1277.             AddAfter := Compare(CurrentRow, FSelectionAnchor) <> -Direction;
  1278. {$ELSE}
  1279.             CurRow := CurrentRow;
  1280.             try
  1281.               AddAfter := Compare(CurRow, FSelectionAnchor) <> -Direction;
  1282.             finally
  1283.               StrDispose(CurRow);
  1284.             end;
  1285. {$ENDIF}
  1286.             if not AddAfter then CurrentRowSelected := False;
  1287.           end
  1288.         end
  1289.         else ClearSelections;
  1290.       if Direction <> 0 then Datalink.DataSet.MoveBy(Direction);
  1291.       if AddAfter then SelectedRows.CurrentRowSelected := True;
  1292. {$IFDEF WIN32}
  1293.     finally
  1294.       EndUpdate;
  1295.     end;
  1296. {$ENDIF}
  1297.   end;
  1298.   procedure NextRow(Select: Boolean);
  1299.   begin
  1300.     with Datalink.Dataset do begin
  1301.       DoSelection(Select, 1);
  1302.       if EOF and CanModify and (not ReadOnly) and (dgEditing in Options) then
  1303.         Append;
  1304.     end;
  1305.   end;
  1306.   procedure PriorRow(Select: Boolean);
  1307.   begin
  1308.     DoSelection(Select, -1);
  1309.   end;
  1310.   procedure CheckTab(GoForward: Boolean);
  1311.   var
  1312.     ACol, Original: Integer;
  1313.   begin
  1314.     ACol := Col;
  1315.     Original := ACol;
  1316.     if MultiSelect and DataLink.Active then
  1317.       while True do begin
  1318.         if GoForward then Inc(ACol) else Dec(ACol);
  1319.         if ACol >= ColCount then begin
  1320.           ClearSelections;
  1321.           ACol := IndicatorOffset;
  1322.         end
  1323.         else if ACol < IndicatorOffset then begin
  1324.           ClearSelections;
  1325.           ACol := ColCount;
  1326.         end;
  1327.         if ACol = Original then Exit;
  1328.         if TabStops[ACol] then Exit;
  1329.       end;
  1330.   end;
  1331.   function DeletePrompt: Boolean;
  1332.   var
  1333.     S: string;
  1334.   begin
  1335.     if (SelectedRows.Count > 1) then
  1336. {$IFDEF WIN32}
  1337.       S := ResStr(SDeleteMultipleRecordsQuestion)
  1338. {$ELSE}
  1339.       S := LoadStr(SDeleteMultipleRecords)
  1340. {$ENDIF}
  1341.     else S := ResStr(SDeleteRecordQuestion);
  1342.     Result := not (dgConfirmDelete in Options) or
  1343.       (MessageDlg(S, mtConfirmation, [mbYes, mbNo], 0) = mrYes);
  1344.   end;
  1345. begin
  1346.   KeyDownEvent := OnKeyDown;
  1347.   if Assigned(KeyDownEvent) then KeyDownEvent(Self, Key, Shift);
  1348.   if not Datalink.Active or not CanGridAcceptKey(Key, Shift) then Exit;
  1349.   with Datalink.DataSet do
  1350.     if ssCtrl in Shift then begin
  1351.       if (Key in [VK_UP, VK_PRIOR, VK_DOWN, VK_NEXT, VK_HOME, VK_END]) then
  1352.         ClearSelections;
  1353.       case Key of
  1354.         VK_LEFT:
  1355.           if FixedCols > 0 then begin
  1356. {$IFDEF RX_D4}
  1357.             SelectedIndex := CalcLeftColumn - IndicatorOffset;
  1358. {$ELSE}
  1359.             SelectedIndex := FixedCols;
  1360. {$ENDIF}
  1361.             Exit;
  1362.           end;
  1363.         VK_DELETE:
  1364.           if not ReadOnly and CanModify and not
  1365.             IsDataSetEmpty(Datalink.DataSet) then
  1366.           begin
  1367.             if DeletePrompt then begin
  1368.               if SelectedRows.Count > 0 then SelectedRows.Delete
  1369.               else Delete;
  1370.             end;
  1371.             Exit;
  1372.           end;
  1373.       end
  1374.     end
  1375.     else begin
  1376.       case Key of
  1377.         VK_LEFT:
  1378.           if (FixedCols > 0) and not (dgRowSelect in Options) then begin
  1379. {$IFDEF RX_D4}
  1380.             if SelectedIndex <= CalcLeftColumn - IndicatorOffset then
  1381.               Exit;
  1382. {$ELSE}
  1383.             if SelectedIndex <= FFixedCols then Exit;
  1384. {$ENDIF}
  1385.           end;
  1386.         VK_HOME:
  1387.           if (FixedCols > 0) and (ColCount <> IndicatorOffset + 1) and
  1388.             not (dgRowSelect in Options) then
  1389.           begin
  1390. {$IFDEF RX_D4}
  1391.             SelectedIndex := CalcLeftColumn - IndicatorOffset;
  1392. {$ELSE}
  1393.             SelectedIndex := FixedCols;
  1394. {$ENDIF}
  1395.             Exit;
  1396.           end;
  1397.       end;
  1398.       if (Datalink.DataSet.State = dsBrowse) then begin
  1399.         case Key of
  1400.           VK_UP:
  1401.             begin
  1402.               PriorRow(True); Exit;
  1403.             end;
  1404.           VK_DOWN:
  1405.             begin
  1406.               NextRow(True); Exit;
  1407.             end;
  1408.         end;
  1409.       end;
  1410.       if ((Key in [VK_LEFT, VK_RIGHT]) and (dgRowSelect in Options)) or
  1411.         ((Key in [VK_HOME, VK_END]) and ((ColCount = IndicatorOffset + 1)
  1412.           or (dgRowSelect in Options))) or (Key in [VK_ESCAPE, VK_NEXT,
  1413.           VK_PRIOR]) or ((Key = VK_INSERT) and (CanModify and
  1414.           (not ReadOnly) and (dgEditing in Options))) then
  1415.         ClearSelections
  1416.       else if ((Key = VK_TAB) and not (ssAlt in Shift)) then
  1417.         CheckTab(not (ssShift in Shift));
  1418.     end;
  1419.   OnKeyDown := nil;
  1420.   try
  1421.     inherited KeyDown(Key, Shift);
  1422.   finally
  1423.     OnKeyDown := KeyDownEvent;
  1424.   end;
  1425. end;
  1426. procedure TRxDBGrid.SetShowGlyphs(Value: Boolean);
  1427. begin
  1428.   if FShowGlyphs <> Value then begin
  1429.     FShowGlyphs := Value;
  1430.     Invalidate;
  1431.   end;
  1432. end;
  1433. procedure TRxDBGrid.SetRowsHeight(Value: Integer);
  1434. begin
  1435.   if not (csDesigning in ComponentState) and (DefaultRowHeight <> Value) then
  1436.   begin
  1437.     DefaultRowHeight := Value;
  1438.     if dgTitles in Options then RowHeights[0] := Value + 2;
  1439.     if HandleAllocated then
  1440.       Perform(WM_SIZE, SIZE_RESTORED, MakeLong(ClientWidth, ClientHeight));
  1441.   end;
  1442. end;
  1443. function TRxDBGrid.GetRowsHeight: Integer;
  1444. begin
  1445.   Result := DefaultRowHeight;
  1446. end;
  1447. {$IFDEF WIN32}
  1448. function TRxDBGrid.GetOptions: TDBGridOptions;
  1449. begin
  1450.   Result := inherited Options;
  1451.   if FMultiSelect then Result := Result + [dgMultiSelect]
  1452.   else Result := Result - [dgMultiSelect];
  1453. end;
  1454. procedure TRxDBGrid.SetOptions(Value: TDBGridOptions);
  1455. var
  1456.   NewOptions: TGridOptions;
  1457. begin
  1458.   inherited Options := Value - [dgMultiSelect];
  1459.   NewOptions := TDrawGrid(Self).Options;
  1460.   if FTitleButtons then begin
  1461.     TDrawGrid(Self).Options := NewOptions + [goFixedHorzLine, goFixedVertLine];
  1462.   end
  1463.   else begin
  1464.     if not (dgColLines in Value) then
  1465.       NewOptions := NewOptions - [goFixedVertLine];
  1466.     if not (dgRowLines in Value) then
  1467.       NewOptions := NewOptions - [goFixedHorzLine];
  1468.     TDrawGrid(Self).Options := NewOptions;
  1469.   end;
  1470.   SetMultiSelect(dgMultiSelect in Value);
  1471. end;
  1472. {$ELSE}
  1473. procedure TRxDBGrid.LinkActive(Value: Boolean);
  1474. begin
  1475.   SelectedRows.LinkActive(Value);
  1476.   inherited LinkActive(Value);
  1477. end;
  1478. function TRxDBGrid.GetFixedColor: TColor;
  1479. begin
  1480.   Result := inherited TitleColor;
  1481. end;
  1482. procedure TRxDBGrid.SetFixedColor(Value: TColor);
  1483. begin
  1484.   if FixedColor <> Value then begin
  1485.     inherited TitleColor := Value;
  1486.     inherited FixedColor := Value;
  1487.     Invalidate;
  1488.   end;
  1489. end;
  1490. procedure TRxDBGrid.ColumnMoved(FromIndex, ToIndex: Longint);
  1491. begin
  1492.   inherited ColumnMoved(FromIndex, ToIndex);
  1493.   if Assigned(FOnColumnMoved) then FOnColumnMoved(Self, FromIndex, ToIndex);
  1494. end;
  1495. {$ENDIF WIN32}
  1496. procedure TRxDBGrid.Paint;
  1497. begin
  1498.   inherited Paint;
  1499.   if not (csDesigning in ComponentState) and
  1500.     (dgRowSelect in Options) and DefaultDrawing and Focused then
  1501.   begin
  1502.     Canvas.Font.Color := clWindowText;
  1503.     with Selection do
  1504.       DrawFocusRect(Canvas.Handle, BoxRect(Left, Top, Right, Bottom));
  1505.   end;
  1506. end;
  1507. procedure TRxDBGrid.SetTitleButtons(Value: Boolean);
  1508. begin
  1509.   if FTitleButtons <> Value then begin
  1510.     FTitleButtons := Value;
  1511.     Invalidate;
  1512. {$IFDEF WIN32}
  1513.     SetOptions(Options);
  1514. {$ENDIF}
  1515.   end;
  1516. end;
  1517. procedure TRxDBGrid.SetMultiSelect(Value: Boolean);
  1518. begin
  1519.   if FMultiSelect <> Value then begin
  1520.     FMultiSelect := Value;
  1521.     if not Value then SelectedRows.Clear;
  1522.   end;
  1523. end;
  1524. function TRxDBGrid.GetStorage: TFormPlacement;
  1525. begin
  1526.   Result := FIniLink.Storage;
  1527. end;
  1528. procedure TRxDBGrid.SetStorage(Value: TFormPlacement);
  1529. begin
  1530.   FIniLink.Storage := Value;
  1531. end;
  1532. function TRxDBGrid.AcquireFocus: Boolean;
  1533. begin
  1534.   Result := True;
  1535.   if FAcquireFocus and CanFocus and not (csDesigning in ComponentState) then
  1536.   begin
  1537.     SetFocus;
  1538.     Result := Focused or (InplaceEditor <> nil) and InplaceEditor.Focused;
  1539.   end;
  1540. end;
  1541. function TRxDBGrid.CanEditShow: Boolean;
  1542. var
  1543.   F: TField;
  1544. begin
  1545.   Result := inherited CanEditShow;
  1546.   F := nil;
  1547.   if Result and (Datalink <> nil) and Datalink.Active and (FieldCount > 0) and
  1548.     (SelectedIndex < FieldCount) and (SelectedIndex >= 0) and
  1549.     (FieldCount <= DataSource.DataSet.FieldCount) then
  1550.   begin
  1551.     F := Fields[SelectedIndex];
  1552.     if F <> nil then Result := GetImageIndex(F) < 0;
  1553.   end;
  1554.   if Result and Assigned(FOnShowEditor) then
  1555.     FOnShowEditor(Self, F, Result);
  1556. end;
  1557. procedure TRxDBGrid.GetCellProps(Field: TField; AFont: TFont;
  1558.   var Background: TColor; Highlight: Boolean);
  1559. var
  1560.   AColor, ABack: TColor;
  1561. begin
  1562.   if Assigned(FOnGetCellParams) then
  1563.     FOnGetCellParams(Self, Field, AFont, Background, Highlight)
  1564.   else if Assigned(FOnGetCellProps) then begin
  1565.     if Highlight then begin
  1566.       AColor := AFont.Color;
  1567.       FOnGetCellProps(Self, Field, AFont, ABack);
  1568.       AFont.Color := AColor;
  1569.     end
  1570.     else FOnGetCellProps(Self, Field, AFont, Background);
  1571.   end;
  1572. end;
  1573. procedure TRxDBGrid.DoTitleClick(ACol: Longint; AField: TField);
  1574. begin
  1575.   if Assigned(FOnTitleBtnClick) then FOnTitleBtnClick(Self, ACol, AField);
  1576. end;
  1577. procedure TRxDBGrid.CheckTitleButton(ACol, ARow: Longint; var Enabled: Boolean);
  1578. var
  1579.   Field: TField;
  1580. begin
  1581.   if (ACol >= 0) and (ACol < {$IFDEF WIN32} Columns.Count {$ELSE}
  1582.     FieldCount {$ENDIF}) then
  1583.   begin
  1584.     if Assigned(FOnCheckButton) then begin
  1585. {$IFDEF WIN32}
  1586.       Field := Columns[ACol].Field;
  1587.   {$IFDEF RX_D4}
  1588.       if ColumnAtDepth(Columns[ACol], ARow) <> nil then
  1589.         Field := ColumnAtDepth(Columns[ACol], ARow).Field;
  1590.   {$ENDIF}
  1591. {$ELSE}
  1592.       Field := Fields[ACol];
  1593. {$ENDIF}
  1594.       FOnCheckButton(Self, ACol, Field, Enabled);
  1595.     end;
  1596.   end
  1597.   else Enabled := False;
  1598. end;
  1599. procedure TRxDBGrid.DisableScroll;
  1600. begin
  1601.   Inc(FDisableCount);
  1602. end;
  1603. type
  1604.   THackLink = class(TGridDataLink);
  1605. procedure TRxDBGrid.EnableScroll;
  1606. begin
  1607.   if FDisableCount <> 0 then begin
  1608.     Dec(FDisableCount);
  1609.     if FDisableCount = 0 then
  1610.       THackLink(DataLink).DataSetScrolled(0);
  1611.   end;
  1612. end;
  1613. function TRxDBGrid.ScrollDisabled: Boolean;
  1614. begin
  1615.   Result := FDisableCount <> 0;
  1616. end;
  1617. procedure TRxDBGrid.Scroll(Distance: Integer);
  1618. {$IFNDEF RX_D3}
  1619. var
  1620.   IndicatorRect: TRect;
  1621. {$ENDIF}
  1622. begin
  1623.   if FDisableCount = 0 then begin
  1624.     inherited Scroll(Distance);
  1625. {$IFNDEF RX_D3}
  1626.     if (dgIndicator in Options) and HandleAllocated and MultiSelect then
  1627.     begin
  1628.       IndicatorRect := BoxRect(0, 0, 0, RowCount - 1);
  1629.       InvalidateRect(Handle, @IndicatorRect, False);
  1630.     end;
  1631. {$ENDIF}
  1632.   end;
  1633. end;
  1634. {$IFDEF RX_D4}
  1635. function TRxDBGrid.DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean;
  1636. begin
  1637.   Result := False;
  1638.   if Assigned(OnMouseWheelDown) then
  1639.     OnMouseWheelDown(Self, Shift, MousePos, Result);
  1640.   if not Result then begin
  1641.     if not AcquireFocus then Exit;
  1642.     if Datalink.Active then begin
  1643.       Result := Datalink.DataSet.MoveBy(1) <> 0;
  1644.     end;
  1645.   end;
  1646. end;
  1647. function TRxDBGrid.DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean;
  1648. begin
  1649.   Result := False;
  1650.   if Assigned(OnMouseWheelUp) then
  1651.     OnMouseWheelUp(Self, Shift, MousePos, Result);
  1652.   if not Result then begin
  1653.     if not AcquireFocus then Exit;
  1654.     if Datalink.Active then begin
  1655.       Result := Datalink.DataSet.MoveBy(-1) <> 0;
  1656.     end;
  1657.   end;
  1658. end;
  1659. {$ENDIF RX_D4}
  1660. procedure TRxDBGrid.EditChanged(Sender: TObject);
  1661. begin
  1662.   if Assigned(FOnEditChange) then FOnEditChange(Self);
  1663. end;
  1664. procedure TRxDBGrid.TopLeftChanged;
  1665. begin
  1666.   if (dgRowSelect in Options) and DefaultDrawing then
  1667.     GridInvalidateRow(Self, Self.Row);
  1668.   inherited TopLeftChanged;
  1669.   if FTracking then StopTracking;
  1670.   if Assigned(FOnTopLeftChanged) then FOnTopLeftChanged(Self);
  1671. end;
  1672. procedure TRxDBGrid.StopTracking;
  1673. begin
  1674.   if FTracking then begin
  1675.     TrackButton(-1, -1);
  1676.     FTracking := False;
  1677.     MouseCapture := False;
  1678.   end;
  1679. end;
  1680. procedure TRxDBGrid.TrackButton(X, Y: Integer);
  1681. var
  1682.   Cell: TGridCoord;
  1683.   NewPressed: Boolean;
  1684.   I, Offset: Integer;
  1685. begin
  1686.   Cell := MouseCoord(X, Y);
  1687.   Offset := TitleOffset;
  1688.   NewPressed := PtInRect(Rect(0, 0, ClientWidth, ClientHeight), Point(X, Y)) and
  1689.     (FPressedCol = {$IFDEF WIN32} GetMasterColumn(Cell.X, Cell.Y) {$ELSE}
  1690.     Cell.X {$ENDIF}) and (Cell.Y < Offset);
  1691.   if FPressed <> NewPressed then begin
  1692.     FPressed := NewPressed;
  1693.     for I := 0 to Offset - 1 do
  1694.       GridInvalidateRow(Self, I);
  1695.   end;
  1696. end;
  1697. procedure TRxDBGrid.MouseDown(Button: TMouseButton; Shift: TShiftState;
  1698.   X, Y: Integer);
  1699. var
  1700.   Cell: TGridCoord;
  1701.   MouseDownEvent: TMouseEvent;
  1702.   EnableClick: Boolean;
  1703. begin
  1704.   if not AcquireFocus then Exit;
  1705.   if (ssDouble in Shift) and (Button = mbLeft) then begin
  1706.     DblClick;
  1707.     Exit;
  1708.   end;
  1709.   if Sizing(X, Y) then
  1710.     inherited MouseDown(Button, Shift, X, Y)
  1711.   else begin
  1712.     Cell := MouseCoord(X, Y);
  1713. {$IFDEF RX_D4}
  1714.     if (DragKind = dkDock) and (Cell.X < IndicatorOffset) and
  1715.       (Cell.Y < TitleOffset) and (not (csDesigning in ComponentState)) then
  1716.     begin
  1717.       BeginDrag(False);
  1718.       Exit;
  1719.     end;
  1720. {$ENDIF}
  1721.     if FTitleButtons and (Datalink <> nil) and Datalink.Active and
  1722.       (Cell.Y < TitleOffset) and (Cell.X >= IndicatorOffset) and
  1723.       not (csDesigning in ComponentState) then
  1724.     begin
  1725.       if (dgColumnResize in Options) and (Button = mbRight) then begin
  1726.         Button := mbLeft;
  1727.         FSwapButtons := True;
  1728.         MouseCapture := True;
  1729.       end
  1730.       else if Button = mbLeft then begin
  1731.         EnableClick := True;
  1732.         CheckTitleButton(Cell.X - IndicatorOffset, Cell.Y, EnableClick);
  1733.         if EnableClick then begin
  1734.           MouseCapture := True;
  1735.           FTracking := True;
  1736. {$IFDEF WIN32}
  1737.           FPressedCol := GetMasterColumn(Cell.X, Cell.Y);
  1738. {$ELSE}
  1739.           FPressedCol := Cell.X;
  1740. {$ENDIF}
  1741.           TrackButton(X, Y);
  1742.         end else Beep;
  1743.         Exit;
  1744.       end;
  1745.     end;
  1746.     if (Cell.X < FixedCols + IndicatorOffset) and Datalink.Active then begin
  1747.       if (dgIndicator in Options) then
  1748.         inherited MouseDown(Button, Shift, 1, Y)
  1749.       else if Cell.Y >= TitleOffset then
  1750.         if Cell.Y - Row <> 0 then Datalink.Dataset.MoveBy(Cell.Y - Row);
  1751.     end
  1752.     else inherited MouseDown(Button, Shift, X, Y);
  1753.     MouseDownEvent := OnMouseDown;
  1754.     if Assigned(MouseDownEvent) then MouseDownEvent(Self, Button, Shift, X, Y);
  1755.     if not (((csDesigning in ComponentState) or (dgColumnResize in Options)) and
  1756.       (Cell.Y < TitleOffset)) and (Button = mbLeft) then
  1757.     begin
  1758.       if MultiSelect and Datalink.Active then
  1759.         with SelectedRows do begin
  1760.           FSelecting := False;
  1761.           if ssCtrl in Shift then
  1762.             CurrentRowSelected := not CurrentRowSelected
  1763.           else begin
  1764.             Clear;
  1765.             if FClearSelection then CurrentRowSelected := True;
  1766.           end;
  1767.         end;
  1768.     end;
  1769.   end;
  1770. end;
  1771. procedure TRxDBGrid.MouseMove(Shift: TShiftState; X, Y: Integer);
  1772. begin
  1773.   if FTracking then TrackButton(X, Y);
  1774.   inherited MouseMove(Shift, X, Y);
  1775. end;
  1776. procedure TRxDBGrid.MouseUp(Button: TMouseButton; Shift: TShiftState;
  1777.   X, Y: Integer);
  1778. var
  1779.   Cell: TGridCoord;
  1780.   ACol: Longint;
  1781.   DoClick: Boolean;
  1782. begin
  1783.   if FTracking and {$IFDEF WIN32} (FPressedCol <> nil) {$ELSE}
  1784.     (FPressedCol >= 0) {$ENDIF} then
  1785.   begin
  1786.     Cell := MouseCoord(X, Y);
  1787.     DoClick := PtInRect(Rect(0, 0, ClientWidth, ClientHeight), Point(X, Y))
  1788.       and (Cell.Y < TitleOffset) and
  1789. {$IFDEF WIN32}
  1790.       (FPressedCol = GetMasterColumn(Cell.X, Cell.Y));
  1791. {$ELSE}
  1792.       (Cell.X = FPressedCol);
  1793. {$ENDIF}
  1794.     StopTracking;
  1795.     if DoClick then begin
  1796.       ACol := Cell.X;
  1797.       if (dgIndicator in Options) then Dec(ACol);
  1798.       if (DataLink <> nil) and DataLink.Active and (ACol >= 0) and
  1799.         (ACol < {$IFDEF WIN32} Columns.Count {$ELSE} FieldCount {$ENDIF}) then
  1800.       begin
  1801. {$IFDEF WIN32}
  1802.         DoTitleClick(FPressedCol.Index, FPressedCol.Field);
  1803. {$ELSE}
  1804.         DoTitleClick(ACol, Fields[ACol]);
  1805. {$ENDIF}
  1806.       end;
  1807.     end;
  1808.   end
  1809.   else if FSwapButtons then begin
  1810.     FSwapButtons := False;
  1811.     MouseCapture := False;
  1812.     if Button = mbRight then Button := mbLeft;
  1813.   end;
  1814.   inherited MouseUp(Button, Shift, X, Y);
  1815. end;
  1816. {$IFDEF WIN32}
  1817. procedure TRxDBGrid.WMRButtonUp(var Message: TWMMouse);
  1818. begin
  1819.   if not (FGridState in [gsColMoving, gsRowMoving]) then
  1820.     inherited
  1821.   else if not (csNoStdEvents in ControlStyle) then
  1822.     with Message do MouseUp(mbRight, KeysToShiftState(Keys), XPos, YPos);
  1823. end;
  1824. {$ENDIF}
  1825. procedure TRxDBGrid.WMCancelMode(var Message: TMessage);
  1826. begin
  1827.   StopTracking;
  1828.   inherited;
  1829. end;
  1830. type
  1831.   THack = class(TWinControl);
  1832. procedure TRxDBGrid.WMChar(var Msg: TWMChar);
  1833.   function DoKeyPress(var Msg: TWMChar): Boolean;
  1834.   var
  1835.     Form: TCustomForm;
  1836.     Ch: Char;
  1837.   begin
  1838.     Result := True;
  1839.     Form := GetParentForm(Self);
  1840.     if (Form <> nil) and TForm(Form).KeyPreview and
  1841.       THack(Form).DoKeyPress(Msg) then Exit;
  1842.     with Msg do begin
  1843.       if Assigned(FOnKeyPress) then begin
  1844.         Ch := Char(CharCode);
  1845.         FOnKeyPress(Self, Ch);
  1846.         CharCode := Word(Ch);
  1847.       end;
  1848.       if Char(CharCode) = #0 then Exit;
  1849.     end;
  1850.     Result := False;
  1851.   end;
  1852. begin
  1853.   if EditorMode or not DoKeyPress(Msg) then inherited;
  1854. end;
  1855. procedure TRxDBGrid.KeyPress(var Key: Char);
  1856. begin
  1857.   if EditorMode then inherited OnKeyPress := FOnKeyPress;
  1858.   try
  1859.     inherited KeyPress(Key);
  1860.   finally
  1861.     inherited OnKeyPress := nil;
  1862.   end;
  1863. end;
  1864. procedure TRxDBGrid.DefaultDataCellDraw(const Rect: TRect; Field: TField;
  1865.   State: TGridDrawState);
  1866. begin
  1867.   DefaultDrawDataCell(Rect, Field, State);
  1868. end;
  1869. {$IFDEF WIN32}
  1870. function TRxDBGrid.GetMasterColumn(ACol, ARow: Longint): TColumn;
  1871. begin
  1872.   if (dgIndicator in Options) then Dec(ACol, IndicatorOffset);
  1873.   if (Datalink <> nil) and Datalink.Active and (ACol >= 0) and
  1874.     (ACol < Columns.Count) then
  1875.   begin
  1876.     Result := Columns[ACol];
  1877. {$IFDEF RX_D4}
  1878.     Result := ColumnAtDepth(Result, ARow);
  1879. {$ENDIF}
  1880.   end
  1881.   else Result := nil;
  1882. end;
  1883. {$ENDIF}
  1884. procedure TRxDBGrid.DrawCell(ACol, ARow: Longint; ARect: TRect;
  1885.   AState: TGridDrawState);
  1886. {$IFDEF RX_D4}
  1887.   function CalcTitleRect(Col: TColumn; ARow: Integer; var MasterCol: TColumn): TRect;
  1888.     { copied from Inprise's DbGrids.pas }
  1889.   var
  1890.     I,J: Integer;
  1891.     InBiDiMode: Boolean;
  1892.     DrawInfo: TGridDrawInfo;
  1893.   begin
  1894.     MasterCol := ColumnAtDepth(Col, ARow);
  1895.     if MasterCol = nil then Exit;
  1896.     I := DataToRawColumn(MasterCol.Index);
  1897.     if I >= LeftCol then J := MasterCol.Depth
  1898.     else begin
  1899.       if (FixedCols > 0) and (MasterCol.Index < FixedCols) then begin
  1900.         J := MasterCol.Depth;
  1901.       end
  1902.       else begin
  1903.         I := LeftCol;
  1904.         if Col.Depth > ARow then J := ARow
  1905.         else J := Col.Depth;
  1906.       end;
  1907.     end;
  1908.     Result := CellRect(I, J);
  1909.     InBiDiMode := UseRightToLeftAlignment and (Canvas.CanvasOrientation = coLeftToRight);
  1910.     for I := Col.Index to Columns.Count - 1 do begin
  1911.       if ColumnAtDepth(Columns[I], ARow) <> MasterCol then Break;
  1912.       if not InBiDiMode then begin
  1913.         J := CellRect(DataToRawColumn(I), ARow).Right;
  1914.         if J = 0 then Break;
  1915.         Result.Right := Max(Result.Right, J);
  1916.       end
  1917.       else begin
  1918.         J := CellRect(DataToRawColumn(I), ARow).Left;
  1919.         if J >= ClientWidth then Break;
  1920.         Result.Left := J;
  1921.       end;
  1922.     end;
  1923.     J := Col.Depth;
  1924.     if (J <= ARow) and (J < FixedRows - 1) then begin
  1925.       CalcFixedInfo(DrawInfo);
  1926.       Result.Bottom := DrawInfo.Vert.FixedBoundary -
  1927.         DrawInfo.Vert.EffectiveLineWidth;
  1928.     end;
  1929.   end;
  1930.   procedure DrawExpandBtn(var TitleRect, TextRect: TRect; InBiDiMode: Boolean;
  1931.     Expanded: Boolean); { copied from Inprise's DbGrids.pas }
  1932.   const
  1933.     ScrollArrows: array [Boolean, Boolean] of Integer =
  1934.       ((DFCS_SCROLLRIGHT, DFCS_SCROLLLEFT), (DFCS_SCROLLLEFT, DFCS_SCROLLRIGHT));
  1935.   var
  1936.     ButtonRect: TRect;
  1937.     I: Integer;
  1938.   begin
  1939.     I := GetSystemMetrics(SM_CXHSCROLL);
  1940.     if ((TextRect.Right - TextRect.Left) > I) then begin
  1941.       Dec(TextRect.Right, I);
  1942.       ButtonRect := TitleRect;
  1943.       ButtonRect.Left := TextRect.Right;
  1944.       I := SaveDC(Canvas.Handle);
  1945.       try
  1946.         Canvas.FillRect(ButtonRect);
  1947.         InflateRect(ButtonRect, -1, -1);
  1948.         with ButtonRect do
  1949.           IntersectClipRect(Canvas.Handle, Left, Top, Right, Bottom);
  1950.         InflateRect(ButtonRect, 1, 1);
  1951.         { DrawFrameControl doesn't draw properly when orienatation has changed.
  1952.           It draws as ExtTextOut does. }
  1953.         if InBiDiMode then { stretch the arrows box }
  1954.           Inc(ButtonRect.Right, GetSystemMetrics(SM_CXHSCROLL) + 4);
  1955.         DrawFrameControl(Canvas.Handle, ButtonRect, DFC_SCROLL,
  1956.           ScrollArrows[InBiDiMode, Expanded] or DFCS_FLAT);
  1957.       finally
  1958.         RestoreDC(Canvas.Handle, I);
  1959.       end;
  1960.       TitleRect.Right := ButtonRect.Left;
  1961.     end;
  1962.   end;
  1963. {$ENDIF RX_D4}
  1964. var
  1965.   FrameOffs: Byte;
  1966.   BackColor: TColor;
  1967.   SortMarker: TSortMarker;
  1968.   Indicator, ALeft: Integer;
  1969.   Down: Boolean;
  1970.   Bmp: TBitmap;
  1971.   SavePen: TColor;
  1972.   OldActive: Longint;
  1973.   MultiSelected: Boolean;
  1974.   FixRect: TRect;
  1975.   TitleRect, TextRect: TRect;
  1976.   AField: TField;
  1977. {$IFDEF RX_D4}
  1978.   MasterCol: TColumn;
  1979.   InBiDiMode: Boolean;
  1980. {$ENDIF}
  1981. {$IFDEF WIN32}
  1982.   DrawColumn: TColumn;
  1983. const
  1984.   EdgeFlag: array[Boolean] of UINT = (BDR_RAISEDINNER, BDR_SUNKENINNER);
  1985. {$ENDIF}
  1986. begin
  1987.   inherited DrawCell(ACol, ARow, ARect, AState);
  1988. {$IFDEF RX_D4}
  1989.   InBiDiMode := Canvas.CanvasOrientation = coRightToLeft;
  1990. {$ENDIF}
  1991.   if (dgIndicator in Options) and (ACol = 0) and (ARow - TitleOffset >= 0)
  1992.     and MultiSelect and (DataLink <> nil) and DataLink.Active and
  1993.     (Datalink.DataSet.State = dsBrowse) then
  1994.   begin { draw multiselect indicators if needed }
  1995.     FixRect := ARect;
  1996.     if ([dgRowLines, dgColLines] * Options = [dgRowLines, dgColLines]) then
  1997.     begin
  1998.       InflateRect(FixRect, -1, -1);
  1999.       FrameOffs := 1;
  2000.     end
  2001.     else FrameOffs := 2;
  2002.     OldActive := DataLink.ActiveRecord;
  2003.     try
  2004.       Datalink.ActiveRecord := ARow - TitleOffset;
  2005.       MultiSelected := ActiveRowSelected;
  2006.     finally
  2007.       Datalink.ActiveRecord := OldActive;
  2008.     end;
  2009.     if MultiSelected then begin
  2010.       if (ARow - TitleOffset <> Datalink.ActiveRecord) then Indicator := 0
  2011.       else Indicator := 1;  { multiselected and current row }
  2012. {$IFDEF WIN32}
  2013.       FMsIndicators.BkColor := FixedColor;
  2014. {$ELSE}
  2015.       Canvas.Brush.Color := TitleColor;
  2016.       Canvas.FillRect(FixRect);
  2017. {$ENDIF}
  2018.       ALeft := FixRect.Right - FMsIndicators.Width - FrameOffs;
  2019. {$IFDEF RX_D4}
  2020.       if InBiDiMode then Inc(ALeft);
  2021. {$ENDIF}
  2022.       FMsIndicators.Draw(Self.Canvas, ALeft, (FixRect.Top +
  2023.         FixRect.Bottom - FMsIndicators.Height) shr 1, Indicator);
  2024.     end;
  2025.   end
  2026.   else if not (csLoading in ComponentState) and
  2027.     (FTitleButtons {$IFDEF RX_D4} or (FixedCols > 0) {$ENDIF}) and
  2028.     (gdFixed in AState) and (dgTitles in Options) and (ARow < TitleOffset) then
  2029.   begin
  2030.     SavePen := Canvas.Pen.Color;
  2031.     try
  2032.       Canvas.Pen.Color := clWindowFrame;
  2033.       if (dgIndicator in Options) then Dec(ACol, IndicatorOffset);
  2034.       AField := nil;
  2035.       SortMarker := smNone;
  2036. {$IFDEF WIN32}
  2037.       if (Datalink <> nil) and Datalink.Active and (ACol >= 0) and
  2038.         (ACol < Columns.Count) then
  2039.       begin
  2040.         DrawColumn := Columns[ACol];
  2041.         AField := DrawColumn.Field;
  2042.       end
  2043.       else DrawColumn := nil;
  2044. {$IFDEF RX_D4}
  2045.       if Assigned(DrawColumn) and not DrawColumn.Showing then Exit;
  2046.       TitleRect := CalcTitleRect(DrawColumn, ARow, MasterCol);
  2047.       if TitleRect.Right < ARect.Right then
  2048.         TitleRect.Right := ARect.Right;
  2049.       if MasterCol = nil then
  2050.         Exit
  2051.       else if MasterCol <> DrawColumn then
  2052.         AField := MasterCol.Field;
  2053.       DrawColumn := MasterCol;
  2054.       if ((dgColLines in Options) or FTitleButtons) and (ACol = FixedCols - 1) then
  2055.       begin
  2056.         if (ACol < Columns.Count - 1) and not (Columns[ACol + 1].Showing) then
  2057.         begin
  2058.           Canvas.MoveTo(TitleRect.Right, TitleRect.Top);
  2059.           Canvas.LineTo(TitleRect.Right, TitleRect.Bottom);
  2060.         end;
  2061.       end;
  2062.       if ((dgRowLines in Options) or FTitleButtons) and not MasterCol.Showing then
  2063.       begin
  2064.         Canvas.MoveTo(TitleRect.Left, TitleRect.Bottom);
  2065.         Canvas.LineTo(TitleRect.Right, TitleRect.Bottom);
  2066.       end;
  2067. {$ELSE}
  2068.       TitleRect := ARect;
  2069. {$ENDIF RX_D4}
  2070.       Down := FPressed and FTitleButtons and (FPressedCol = DrawColumn);
  2071.       if FTitleButtons or ([dgRowLines, dgColLines] * Options =
  2072.         [dgRowLines, dgColLines]) then
  2073.       begin
  2074.         DrawEdge(Canvas.Handle, TitleRect, EdgeFlag[Down], BF_BOTTOMRIGHT);
  2075.         DrawEdge(Canvas.Handle, TitleRect, EdgeFlag[Down], BF_TOPLEFT);
  2076.         InflateRect(TitleRect, -1, -1);
  2077.       end;
  2078.       Canvas.Font := TitleFont;
  2079.       Canvas.Brush.Color := FixedColor;
  2080.       if (DrawColumn <> nil) then begin
  2081.         Canvas.Font := DrawColumn.Title.Font;
  2082.         Canvas.Brush.Color := DrawColumn.Title.Color;
  2083.       end;
  2084.       if FTitleButtons and (AField <> nil) and Assigned(FOnGetBtnParams) then
  2085.       begin
  2086.         BackColor := Canvas.Brush.Color;
  2087.         FOnGetBtnParams(Self, AField, Canvas.Font, BackColor, SortMarker, Down);
  2088.         Canvas.Brush.Color := BackColor;
  2089.       end;
  2090.       if Down then begin
  2091.         Inc(TitleRect.Left); Inc(TitleRect.Top);
  2092.       end;
  2093.       ARect := TitleRect;
  2094.       if (DataLink = nil) or not DataLink.Active then
  2095.         Canvas.FillRect(TitleRect)
  2096.       else if (DrawColumn <> nil) then begin
  2097.         case SortMarker of
  2098.           smDown: Bmp := GetGridBitmap(gpMarkDown);
  2099.           smUp: Bmp := GetGridBitmap(gpMarkUp);
  2100.           else Bmp := nil;
  2101.         end;
  2102.         if Bmp <> nil then Indicator := Bmp.Width + 6
  2103.         else Indicator := 1;
  2104.         TextRect := TitleRect;
  2105. {$IFDEF RX_D4}
  2106.         if DrawColumn.Expandable then
  2107.           DrawExpandBtn(TitleRect, TextRect, InBiDiMode, DrawColumn.Expanded);
  2108. {$ENDIF}
  2109.         with DrawColumn.Title do
  2110.           DrawCellText(Self, ACol, ARow, MinimizeText(Caption, Canvas,
  2111.             WidthOf(TextRect) - Indicator), TextRect, Alignment, vaCenter
  2112.             {$IFDEF RX_D4}, IsRightToLeft {$ENDIF});
  2113.         if Bmp <> nil then begin
  2114.           ALeft := TitleRect.Right - Bmp.Width - 3;
  2115.           if Down then Inc(ALeft);
  2116. {$IFDEF RX_D4}
  2117.           if IsRightToLeft then ALeft := TitleRect.Left + 3;
  2118. {$ENDIF}
  2119.           if (ALeft > TitleRect.Left) and (ALeft + Bmp.Width < TitleRect.Right) then
  2120.             DrawBitmapTransparent(Canvas, ALeft, (TitleRect.Bottom +
  2121.               TitleRect.Top - Bmp.Height) div 2, Bmp, clFuchsia);
  2122.         end;
  2123.       end
  2124. {$ELSE WIN32}
  2125.       if not (dgColLines in Options) then begin
  2126.         Canvas.MoveTo(ARect.Right - 1, ARect.Top);
  2127.         Canvas.LineTo(ARect.Right - 1, ARect.Bottom);
  2128.         Dec(ARect.Right);
  2129.       end;
  2130.       if not (dgRowLines in Options) then begin
  2131.         Canvas.MoveTo(ARect.Left, ARect.Bottom - 1);
  2132.         Canvas.LineTo(ARect.Right, ARect.Bottom - 1);
  2133.         Dec(ARect.Bottom);
  2134.       end;
  2135.       Down := FPressed and FTitleButtons and (FPressedCol = ACol);
  2136.       if (Datalink <> nil) and Datalink.Active and (ACol >= 0) and
  2137.         (ACol < FieldCount) then
  2138.       begin
  2139.         AField := Fields[ACol];
  2140.       end;
  2141.       if Down then begin
  2142.         with ARect do begin
  2143.           Canvas.Pen.Color := clBtnShadow;
  2144.           Canvas.PolyLine([Point(Left, Bottom - 1), Point(Left, Top),
  2145.             Point(Right, Top)]);
  2146.           Inc(Left, 2); Inc(Top, 2);
  2147.         end;
  2148.       end
  2149.       else Frame3D(Canvas, ARect, clBtnHighlight, clBtnShadow, 1);
  2150.       Canvas.Font := TitleFont;
  2151.       Canvas.Brush.Color := TitleColor;
  2152.       if FTitleButtons and (AField <> nil) and Assigned(FOnGetBtnParams) then
  2153.       begin
  2154.         BackColor := Canvas.Brush.Color;
  2155.         FOnGetBtnParams(Self, AField, Canvas.Font, BackColor, SortMarker, Down);
  2156.         Canvas.Brush.Color := BackColor;
  2157.       end;
  2158.       if (DataLink = nil) or not DataLink.Active then
  2159.         Canvas.FillRect(ARect)
  2160.       else if (AField <> nil) then begin
  2161.         case SortMarker of
  2162.           smDown: Bmp := GetGridBitmap(gpMarkDown);
  2163.           smUp: Bmp := GetGridBitmap(gpMarkUp);
  2164.           else Bmp := nil;
  2165.         end;
  2166.         if Bmp <> nil then Indicator := Bmp.Width + 8
  2167.         else Indicator := 1;
  2168.         DrawCellText(Self, ACol, ARow, MinimizeText(AField.DisplayLabel,
  2169.           Canvas, WidthOf(ARect) - Indicator), ARect, taLeftJustify, vaCenter);
  2170.         if Bmp <> nil then begin
  2171.           ALeft := ARect.Right - Bmp.Width - 4;
  2172.           if Down then Inc(ALeft);
  2173.           DrawBitmapTransparent(Canvas, ALeft,
  2174.             (ARect.Bottom + ARect.Top - Bmp.Height) div 2, Bmp, clFuchsia);
  2175.         end;
  2176.       end
  2177. {$ENDIF WIN32}
  2178.       else DrawCellText(Self, ACol, ARow, '', ARect, taLeftJustify, vaCenter);
  2179.     finally
  2180.       Canvas.Pen.Color := SavePen;
  2181.     end;
  2182.   end
  2183.   else begin
  2184. {$IFDEF RX_D4}
  2185.     Canvas.Font := Self.Font;
  2186.     if (DataLink <> nil) and DataLink.Active and (ACol >= 0) and
  2187.       (ACol < Columns.Count) then
  2188.     begin
  2189.       DrawColumn := Columns[ACol];
  2190.       if DrawColumn <> nil then Canvas.Font := DrawColumn.Font;
  2191.     end;
  2192. {$ENDIF}
  2193.   end;
  2194. end;
  2195. {$IFDEF WIN32}
  2196. procedure TRxDBGrid.DrawColumnCell(const Rect: TRect; DataCol: Integer;
  2197.   Column: TColumn; State: TGridDrawState);
  2198. {$ELSE}
  2199. procedure TRxDBGrid.DrawDataCell(const Rect: TRect; Field: TField;
  2200.   State: TGridDrawState);
  2201. {$ENDIF}
  2202. var
  2203.   I: Integer;
  2204.   NewBackgrnd: TColor;
  2205.   Highlight: Boolean;
  2206.   Bmp: TBitmap;
  2207. {$IFDEF WIN32}
  2208.   Field: TField;
  2209. {$ENDIF}
  2210. begin
  2211. {$IFDEF WIN32}
  2212.   Field := Column.Field;
  2213. {$ENDIF}
  2214.   NewBackgrnd := Canvas.Brush.Color;
  2215.   Highlight := (gdSelected in State) and ((dgAlwaysShowSelection in Options) or
  2216.     Focused);
  2217.   GetCellProps(Field, Canvas.Font, NewBackgrnd, Highlight or ActiveRowSelected);
  2218.   Canvas.Brush.Color := NewBackgrnd;
  2219.   if FDefaultDrawing then begin
  2220.     I := GetImageIndex(Field);
  2221.     if I >= 0 then begin
  2222.       Bmp := GetGridBitmap(TGridPicture(I));
  2223.       Canvas.FillRect(Rect);
  2224.       DrawBitmapTransparent(Canvas, (Rect.Left + Rect.Right - Bmp.Width) div 2,
  2225.         (Rect.Top + Rect.Bottom - Bmp.Height) div 2, Bmp, clOlive);
  2226.     end else
  2227. {$IFDEF WIN32}
  2228.     DefaultDrawColumnCell(Rect, DataCol, Column, State);
  2229. {$ELSE}
  2230.     DefaultDrawDataCell(Rect, Field, State);
  2231. {$ENDIF}
  2232.   end;
  2233. {$IFDEF WIN32}
  2234.   if Columns.State = csDefault then
  2235.     inherited DrawDataCell(Rect, Field, State);
  2236.   inherited DrawColumnCell(Rect, DataCol, Column, State);
  2237. {$ELSE}
  2238.   inherited DrawDataCell(Rect, Field, State);
  2239. {$ENDIF}
  2240.   if FDefaultDrawing and Highlight and not (csDesigning in ComponentState)
  2241.     and not (dgRowSelect in Options)
  2242.     and (ValidParentForm(Self).ActiveControl = Self) then
  2243.     Canvas.DrawFocusRect(Rect);
  2244. end;
  2245. {$IFDEF WIN32}
  2246. procedure TRxDBGrid.DrawDataCell(const Rect: TRect; Field: TField;
  2247.   State: TGridDrawState);
  2248. begin
  2249. end;
  2250. {$ENDIF}
  2251. procedure TRxDBGrid.MouseToCell(X, Y: Integer; var ACol, ARow: Longint);
  2252. var
  2253.   Coord: TGridCoord;
  2254. begin
  2255.   Coord := MouseCoord(X, Y);
  2256.   ACol := Coord.X;
  2257.   ARow := Coord.Y;
  2258. end;
  2259. {$IFDEF WIN32}
  2260. procedure TRxDBGrid.SaveColumnsLayout(IniFile: TObject;
  2261.   const Section: string);
  2262. var
  2263.   I: Integer;
  2264.   S: string;
  2265. begin
  2266.   if Section <> '' then S := Section
  2267.   else S := GetDefaultSection(Self);
  2268.   IniEraseSection(IniFile, S);
  2269.   with Columns do begin
  2270.     for I := 0 to Count - 1 do begin
  2271.       IniWriteString(IniFile, S, Format('%s.%s', [Name, Items[I].FieldName]),
  2272.         Format('%d,%d', [Items[I].Index, Items[I].Width]));
  2273.     end;
  2274.   end;
  2275. end;
  2276. procedure TRxDBGrid.RestoreColumnsLayout(IniFile: TObject;
  2277.   const Section: string);
  2278. type
  2279.   TColumnInfo = record
  2280.     Column: TColumn;
  2281.     EndIndex: Integer;
  2282.   end;
  2283.   PColumnArray = ^TColumnArray;
  2284.   TColumnArray = array[0..0] of TColumnInfo;
  2285. const
  2286.   Delims = [' ',','];
  2287. var
  2288.   I, J: Integer;
  2289.   SectionName, S: string;
  2290.   ColumnArray: PColumnArray;
  2291. begin
  2292.   if Section <> '' then SectionName := Section
  2293.   else SectionName := GetDefaultSection(Self);
  2294.   with Columns do begin
  2295.     ColumnArray := AllocMemo(Count * SizeOf(TColumnInfo));
  2296.     try
  2297.       for I := 0 to Count - 1 do begin
  2298.         S := IniReadString(IniFile, SectionName,
  2299.           Format('%s.%s', [Name, Items[I].FieldName]), '');
  2300.         ColumnArray^[I].Column := Items[I];
  2301.         ColumnArray^[I].EndIndex := Items[I].Index;
  2302.         if S <> '' then begin
  2303.           ColumnArray^[I].EndIndex := StrToIntDef(ExtractWord(1, S, Delims),
  2304.             ColumnArray^[I].EndIndex);
  2305.           Items[I].Width := StrToIntDef(ExtractWord(2, S, Delims),
  2306.             Items[I].Width);
  2307.         end;
  2308.       end;
  2309.       for I := 0 to Count - 1 do begin
  2310.         for J := 0 to Count - 1 do begin
  2311.           if ColumnArray^[J].EndIndex = I then begin
  2312.             ColumnArray^[J].Column.Index := ColumnArray^[J].EndIndex;
  2313.             Break;
  2314.           end;
  2315.         end;
  2316.       end;
  2317.     finally
  2318.       FreeMemo(Pointer(ColumnArray));
  2319.     end;
  2320.   end;
  2321. end;
  2322. procedure TRxDBGrid.SaveLayoutReg(IniFile: TRegIniFile);
  2323. begin
  2324.   InternalSaveLayout(IniFile, '');
  2325. end;
  2326. procedure TRxDBGrid.RestoreLayoutReg(IniFile: TRegIniFile);
  2327. begin
  2328.   InternalRestoreLayout(IniFile, '');
  2329. end;
  2330. {$ENDIF WIN32}
  2331. procedure TRxDBGrid.InternalSaveLayout(IniFile: TObject;
  2332.   const Section: string);
  2333. begin
  2334.   if (DataSource <> nil) and (DataSource.DataSet <> nil) then
  2335. {$IFDEF WIN32}
  2336.     if StoreColumns then SaveColumnsLayout(IniFile, Section) else
  2337. {$ENDIF}
  2338.     InternalSaveFields(DataSource.DataSet, IniFile, Section);
  2339. end;
  2340. procedure TRxDBGrid.InternalRestoreLayout(IniFile: TObject;
  2341.   const Section: string);
  2342. begin
  2343.   if (DataSource <> nil) and (DataSource.DataSet <> nil) then begin
  2344.     HandleNeeded;
  2345. {$IFDEF WIN32}
  2346.     BeginLayout;
  2347.     try
  2348.       if StoreColumns then RestoreColumnsLayout(IniFile, Section) else
  2349. {$ENDIF}
  2350.       InternalRestoreFields(DataSource.DataSet, IniFile, Section, False);
  2351. {$IFDEF WIN32}
  2352.     finally
  2353.       EndLayout;
  2354.     end;
  2355. {$ENDIF}
  2356.   end;
  2357. end;
  2358. procedure TRxDBGrid.SaveLayout(IniFile: TIniFile);
  2359. begin
  2360.   InternalSaveLayout(IniFile, '');
  2361. end;
  2362. procedure TRxDBGrid.RestoreLayout(IniFile: TIniFile);
  2363. begin
  2364.   InternalRestoreLayout(IniFile, '');
  2365. end;
  2366. procedure TRxDBGrid.IniSave(Sender: TObject);
  2367. var
  2368.   Section: string;
  2369. begin
  2370.   if (Name <> '') and (FIniLink.IniObject <> nil) then begin
  2371. {$IFDEF WIN32}
  2372.     if StoreColumns then
  2373.       Section := FIniLink.RootSection + GetDefaultSection(Self) else
  2374. {$ENDIF}
  2375.     if (FIniLink.RootSection <> '') and (DataSource <> nil) and
  2376.       (DataSource.DataSet <> nil) then
  2377.       Section := FIniLink.RootSection + DataSetSectionName(DataSource.DataSet)
  2378.     else Section := '';
  2379.     InternalSaveLayout(FIniLink.IniObject, Section);
  2380.   end;
  2381. end;
  2382. procedure TRxDBGrid.IniLoad(Sender: TObject);
  2383. var
  2384.   Section: string;
  2385. begin
  2386.   if (Name <> '') and (FIniLink.IniObject <> nil) then begin
  2387. {$IFDEF WIN32}
  2388.     if StoreColumns then
  2389.       Section := FIniLink.RootSection + GetDefaultSection(Self) else
  2390. {$ENDIF}
  2391.     if (FIniLink.RootSection <> '') and (DataSource <> nil) and
  2392.       (DataSource.DataSet <> nil) then
  2393.       Section := FIniLink.RootSection + DataSetSectionName(DataSource.DataSet)
  2394.     else Section := '';
  2395.     InternalRestoreLayout(FIniLink.IniObject, Section);
  2396.   end;
  2397. end;
  2398. { TRxDBComboEdit }
  2399. procedure ResetMaxLength(DBEdit: TRxDBComboEdit);
  2400. var
  2401.   F: TField;
  2402. begin
  2403.   with DBEdit do
  2404.     if (MaxLength > 0) and (DataSource <> nil) and
  2405.       (DataSource.DataSet <> nil) then
  2406.     begin
  2407.       F := DataSource.DataSet.FindField(DataField);
  2408.       if Assigned(F) and (F.DataType = ftString) and
  2409.         (F.Size = MaxLength) then MaxLength := 0;
  2410.     end;
  2411. end;
  2412. constructor TRxDBComboEdit.Create(AOwner: TComponent);
  2413. begin
  2414.   inherited Create(AOwner);
  2415. {$IFDEF WIN32}
  2416.   ControlStyle := ControlStyle + [csReplicatable];
  2417. {$ENDIF}
  2418.   inherited ReadOnly := True;
  2419.   FDataLink := TFieldDataLink.Create;
  2420.   FDataLink.Control := Self;
  2421.   FDataLink.OnDataChange := DataChange;
  2422.   FDataLink.OnEditingChange := EditingChange;
  2423.   FDataLink.OnUpdateData := UpdateData;
  2424.   AlwaysEnable := True;
  2425. end;
  2426. destructor TRxDBComboEdit.Destroy;
  2427. begin
  2428.   FDataLink.Free;
  2429.   FDataLink := nil;
  2430. {$IFDEF WIN32}
  2431.   FCanvas.Free;
  2432. {$ENDIF}
  2433.   inherited Destroy;
  2434. end;
  2435. procedure TRxDBComboEdit.Loaded;
  2436. begin
  2437.   inherited Loaded;
  2438.   ResetMaxLength(Self);
  2439.   if (csDesigning in ComponentState) then DataChange(Self);
  2440. end;
  2441. procedure TRxDBComboEdit.Notification(AComponent: TComponent;
  2442.   Operation: TOperation);
  2443. begin
  2444.   inherited Notification(AComponent, Operation);
  2445.   if (Operation = opRemove) and (FDataLink <> nil) and
  2446.     (AComponent = DataSource) then DataSource := nil;
  2447. end;
  2448. procedure TRxDBComboEdit.KeyDown(var Key: Word; Shift: TShiftState);
  2449. begin
  2450.   inherited KeyDown(Key, Shift);
  2451.   if (Key = VK_DELETE) or ((Key = VK_INSERT) and (ssShift in Shift)) then
  2452.     FDataLink.Edit;
  2453. end;
  2454. procedure TRxDBComboEdit.KeyPress(var Key: Char);
  2455. begin
  2456.   inherited KeyPress(Key);
  2457.   if (Key in [#32..#255]) and (FDataLink.Field <> nil) and
  2458.     not FDataLink.Field.IsValidChar(Key) then
  2459.   begin
  2460.     Beep;
  2461.     Key := #0;
  2462.   end;
  2463.   case Key of
  2464.     ^H, ^V, ^X, #32..#255:
  2465.       FDataLink.Edit;
  2466.     #27:
  2467.       begin
  2468.         FDataLink.Reset;
  2469.         SelectAll;
  2470.         Key := #0;
  2471.       end;
  2472.   end;
  2473. end;
  2474. function TRxDBComboEdit.EditCanModify: Boolean;
  2475. begin
  2476.   Result := FDataLink.Edit;
  2477. end;
  2478. procedure TRxDBComboEdit.Reset;
  2479. begin
  2480.   FDataLink.Reset;
  2481.   SelectAll;
  2482. end;
  2483. procedure TRxDBComboEdit.SetFocused(Value: Boolean);
  2484. begin
  2485.   if FFocused <> Value then begin
  2486.     FFocused := Value;
  2487.     if (Alignment <> taLeftJustify) and not IsMasked then Invalidate;
  2488.     FDataLink.Reset;
  2489.   end;
  2490. end;
  2491. procedure TRxDBComboEdit.Change;
  2492. begin
  2493.   FDataLink.Modified;
  2494.   inherited Change;
  2495. end;
  2496. function TRxDBComboEdit.GetDataSource: TDataSource;
  2497. begin
  2498.   Result := FDataLink.DataSource;
  2499. end;
  2500. procedure TRxDBComboEdit.SetDataSource(Value: TDataSource);
  2501. begin
  2502. {$IFDEF RX_D4}
  2503.   if not (FDataLink.DataSourceFixed and (csLoading in ComponentState)) then
  2504. {$ENDIF}
  2505.     FDataLink.DataSource := Value;
  2506. {$IFDEF WIN32}
  2507.   if Value <> nil then Value.FreeNotification(Self);
  2508. {$ENDIF}
  2509. end;
  2510. function TRxDBComboEdit.GetDataField: string;
  2511. begin
  2512.   Result := FDataLink.FieldName;
  2513. end;
  2514. procedure TRxDBComboEdit.SetDataField(const Value: string);
  2515. begin
  2516.   if not (csDesigning in ComponentState) then ResetMaxLength(Self);
  2517.   FDataLink.FieldName := Value;
  2518. end;
  2519. function TRxDBComboEdit.GetReadOnly: Boolean;
  2520. begin
  2521.   Result := FDataLink.ReadOnly;
  2522. end;
  2523. procedure TRxDBComboEdit.SetReadOnly(Value: Boolean);
  2524. begin
  2525.   FDataLink.ReadOnly := Value;
  2526. end;
  2527. function TRxDBComboEdit.GetField: TField;
  2528. begin
  2529.   Result := FDataLink.Field;
  2530. end;
  2531. procedure TRxDBComboEdit.DataChange(Sender: TObject);
  2532. begin
  2533.   if FDataLink.Field <> nil then begin
  2534.     if Alignment <> FDataLink.Field.Alignment then begin
  2535.       EditText := '';  {forces update}
  2536.       Alignment := FDataLink.Field.Alignment;
  2537.     end;
  2538.     EditMask := FDataLink.Field.EditMask;
  2539.     if not (csDesigning in ComponentState) then begin
  2540.       if (FDataLink.Field.DataType = ftString) and (MaxLength = 0) then
  2541.         MaxLength := FDataLink.Field.Size;
  2542.     end;
  2543.     if FFocused and FDataLink.CanModify then
  2544.       Text := FDataLink.Field.Text
  2545.     else begin
  2546.       EditText := FDataLink.Field.DisplayText;
  2547.       {if FDataLink.Editing then Modified := True;}
  2548.     end;
  2549.   end
  2550.   else begin
  2551.     Alignment := taLeftJustify;
  2552.     EditMask := '';
  2553.     if csDesigning in ComponentState then EditText := Name
  2554.     else EditText := '';
  2555.   end;
  2556. end;
  2557. procedure TRxDBComboEdit.EditingChange(Sender: TObject);
  2558. begin
  2559.   inherited ReadOnly := not FDataLink.Editing;
  2560. end;
  2561. procedure TRxDBComboEdit.UpdateData(Sender: TObject);
  2562. begin
  2563.   ValidateEdit;
  2564.   FDataLink.Field.Text := Text;
  2565. end;
  2566. procedure TRxDBComboEdit.WMPaste(var Message: TMessage);
  2567. begin
  2568.   FDataLink.Edit;
  2569.   inherited;
  2570. end;
  2571. procedure TRxDBComboEdit.WMCut(var Message: TMessage);
  2572. begin
  2573.   FDataLink.Edit;
  2574.   inherited;
  2575. end;
  2576. procedure TRxDBComboEdit.CMEnter(var Message: TCMEnter);
  2577. begin
  2578.   SetFocused(True);
  2579.   inherited;
  2580. {$IFDEF RX_D3}
  2581.   if SysLocale.FarEast and FDataLink.CanModify then
  2582.     inherited ReadOnly := False;
  2583. {$ENDIF}
  2584. end;
  2585. procedure TRxDBComboEdit.CMExit(var Message: TCMExit);
  2586. begin
  2587.   try
  2588.     FDataLink.UpdateRecord;
  2589.   except
  2590.     SelectAll;
  2591.     if CanFocus then SetFocus;
  2592.     raise;
  2593.   end;
  2594.   SetFocused(False);
  2595.   CheckCursor;
  2596.   DoExit;
  2597. end;
  2598. {$IFDEF WIN32}
  2599. procedure TRxDBComboEdit.WMPaint(var Message: TWMPaint);
  2600. var
  2601.   S: string;
  2602. begin
  2603.   if (csPaintCopy in ControlState) and (FDataLink.Field <> nil) then
  2604.   begin
  2605.     S := FDataLink.Field.DisplayText;
  2606.     case CharCase of
  2607.       ecUpperCase: S := AnsiUpperCase(S);
  2608.       ecLowerCase: S := AnsiLowerCase(S);
  2609.     end;
  2610.   end
  2611.   else S := EditText;
  2612.   if not PaintComboEdit(Self, S, Alignment, True, FCanvas, Message) then
  2613.     inherited;
  2614. end;
  2615. procedure TRxDBComboEdit.CMGetDataLink(var Message: TMessage);
  2616. begin
  2617.   Message.Result := Integer(FDataLink);
  2618. end;
  2619. {$ENDIF}
  2620. {$IFDEF RX_D4}
  2621. function TRxDBComboEdit.UseRightToLeftAlignment: Boolean;
  2622. begin
  2623.   Result := DBUseRightToLeftAlignment(Self, Field);
  2624. end;
  2625. function TRxDBComboEdit.ExecuteAction(Action: TBasicAction): Boolean;
  2626. begin
  2627.   Result := inherited ExecuteAction(Action) or (FDataLink <> nil) and
  2628.     FDataLink.ExecuteAction(Action);
  2629. end;
  2630. function TRxDBComboEdit.UpdateAction(Action: TBasicAction): Boolean;
  2631. begin
  2632.   Result := inherited UpdateAction(Action) or (FDataLink <> nil) and
  2633.     FDataLink.UpdateAction(Action);
  2634. end;
  2635. {$ENDIF}
  2636. { TDBDateEdit }
  2637. constructor TDBDateEdit.Create(AOwner: TComponent);
  2638. begin
  2639.   inherited Create(AOwner);
  2640. {$IFDEF WIN32}
  2641.   ControlStyle := ControlStyle + [csReplicatable];
  2642. {$ENDIF}
  2643.   inherited ReadOnly := True;
  2644.   FDataLink := TFieldDataLink.Create;
  2645.   FDataLink.Control := Self;
  2646.   FDataLink.OnDataChange := DataChange;
  2647.   FDataLink.OnEditingChange := EditingChange;
  2648.   FDataLink.OnUpdateData := UpdateData;
  2649.   Self.OnAcceptDate := AfterPopup;
  2650.   AlwaysEnable := True;
  2651.   UpdateMask;
  2652. end;
  2653. destructor TDBDateEdit.Destroy;
  2654. begin
  2655.   FDataLink.Free;
  2656.   FDataLink := nil;
  2657. {$IFDEF WIN32}
  2658.   FCanvas.Free;
  2659. {$ENDIF}
  2660.   inherited Destroy;
  2661. end;
  2662. procedure TDBDateEdit.AfterPopup(Sender: TObject; var Date: TDateTime;
  2663.   var Action: Boolean);
  2664. begin
  2665.   Action := Action and (DataSource <> nil) and (DataSource.DataSet <> nil) and
  2666.     DataSource.DataSet.CanModify;
  2667.   if Action then Action := EditCanModify;
  2668. end;
  2669. procedure TDBDateEdit.Notification(AComponent: TComponent;
  2670.   Operation: TOperation);
  2671. begin
  2672.   inherited Notification(AComponent, Operation);
  2673.   if (Operation = opRemove) and (FDataLink <> nil) and
  2674.     (AComponent = DataSource) then DataSource := nil;
  2675. end;
  2676. procedure TDBDateEdit.KeyDown(var Key: Word; Shift: TShiftState);
  2677. begin
  2678.   inherited KeyDown(Key, Shift);
  2679.   if not ReadOnly and ((Key = VK_DELETE) or ((Key = VK_INSERT)
  2680.     and (ssShift in Shift))) then
  2681.     FDataLink.Edit;
  2682. end;
  2683. procedure TDBDateEdit.KeyPress(var Key: Char);
  2684. begin
  2685.   inherited KeyPress(Key);
  2686.   if (Key in [#32..#255]) and (FDataLink.Field <> nil) and
  2687.     not (Key in ['0'..'9']) and (Key <> DateSeparator) then
  2688.   begin
  2689.     Beep;
  2690.     Key := #0;
  2691.   end;
  2692.   case Key of
  2693.     ^H, ^V, ^X, '0'..'9': FDataLink.Edit;
  2694.     #27:
  2695.       begin
  2696.         Reset;
  2697.         Key := #0;
  2698.       end;
  2699.   end;
  2700. end;
  2701. function TDBDateEdit.EditCanModify: Boolean;
  2702. begin
  2703.   Result := FDataLink.Edit;
  2704. end;
  2705. procedure TDBDateEdit.Reset;
  2706. begin
  2707.   FDataLink.Reset;
  2708.   SelectAll;
  2709. end;
  2710. procedure TDBDateEdit.Change;
  2711. begin
  2712.   if not Formatting then FDataLink.Modified;
  2713.   inherited Change;
  2714. end;
  2715. function TDBDateEdit.GetDataSource: TDataSource;
  2716. begin
  2717.   Result := FDataLink.DataSource;
  2718. end;
  2719. procedure TDBDateEdit.SetDataSource(Value: TDataSource);
  2720. begin
  2721. {$IFDEF RX_D4}
  2722.   if not (FDataLink.DataSourceFixed and (csLoading in ComponentState)) then
  2723. {$ENDIF}
  2724.     FDataLink.DataSource := Value;
  2725. {$IFDEF WIN32}
  2726.   if Value <> nil then Value.FreeNotification(Self);
  2727. {$ENDIF}
  2728. end;
  2729. function TDBDateEdit.GetDataField: string;
  2730. begin
  2731.   Result := FDataLink.FieldName;
  2732. end;
  2733. procedure TDBDateEdit.SetDataField(const Value: string);
  2734. begin
  2735.   FDataLink.FieldName := Value;
  2736. end;
  2737. function TDBDateEdit.GetReadOnly: Boolean;
  2738. begin
  2739.   Result := FDataLink.ReadOnly;
  2740. end;
  2741. procedure TDBDateEdit.SetReadOnly(Value: Boolean);
  2742. begin
  2743.   FDataLink.ReadOnly := Value;
  2744. end;
  2745. function TDBDateEdit.GetField: TField;
  2746. begin
  2747.   Result := FDataLink.Field;
  2748. end;
  2749. procedure TDBDateEdit.UpdateMask;
  2750. begin
  2751.   UpdateFormat;
  2752.   UpdatePopup;
  2753.   DataChange(nil);
  2754. end;
  2755. procedure TDBDateEdit.DataChange(Sender: TObject);
  2756. begin
  2757.   if FDataLink.Field <> nil then begin
  2758.     EditMask := GetDateMask;
  2759.     Self.Date := FDataLink.Field.AsDateTime;
  2760.   end
  2761.   else begin
  2762.     if csDesigning in ComponentState then begin
  2763.       EditMask := '';
  2764.       EditText := Name;
  2765.     end
  2766.     else begin
  2767.       EditMask := GetDateMask;
  2768.       if DefaultToday then Date := SysUtils.Date
  2769.       else Date := NullDate;
  2770.     end;
  2771.   end;
  2772. end;
  2773. procedure TDBDateEdit.EditingChange(Sender: TObject);
  2774. begin
  2775.   inherited ReadOnly := not FDataLink.Editing;
  2776.   if FDataLink.Editing and DefaultToday and (FDataLink.Field <> nil) and
  2777.     (FDataLink.Field.AsDateTime = NullDate) then
  2778.     FDataLink.Field.AsDateTime := SysUtils.Now;
  2779. end;
  2780. procedure TDBDateEdit.UpdateData(Sender: TObject);
  2781. var
  2782.   D: TDateTime;
  2783. begin
  2784.   ValidateEdit;
  2785.   D := Self.Date;
  2786.   if D <> NullDate then
  2787.     FDataLink.Field.AsDateTime := D + Frac(FDataLink.Field.AsDateTime)
  2788.   else FDataLink.Field.Clear;
  2789. end;
  2790. {$IFDEF WIN32}
  2791. procedure TDBDateEdit.CMGetDataLink(var Message: TMessage);
  2792. begin
  2793.   Message.Result := Integer(FDataLink);
  2794. end;
  2795. procedure TDBDateEdit.WMPaint(var Message: TWMPaint);
  2796. var
  2797.   S: string;
  2798. begin
  2799.   if (csPaintCopy in ControlState) and (FDataLink.Field <> nil) then begin
  2800.     if FDataLink.Field.IsNull then begin
  2801.       S := GetDateFormat;
  2802.       S := ReplaceStr(ReplaceStr(ReplaceStr(ReplaceStr(S, '/', DateSeparator),
  2803.         'Y', ' '), 'M', ' '), 'D', ' ');
  2804.     end
  2805.     else
  2806.       S := FormatDateTime(GetDateFormat, FDataLink.Field.AsDateTime);
  2807.   end else S := EditText;
  2808.   if not PaintComboEdit(Self, S, Alignment, True, FCanvas, Message) then
  2809.     inherited;
  2810. end;
  2811. procedure TDBDateEdit.AcceptValue(const Value: Variant);
  2812. begin
  2813.   if VarIsNull(Value) or VarIsEmpty(Value) then FDataLink.Field.Clear
  2814.   else FDataLink.Field.AsDateTime :=
  2815.     VarToDateTime(Value) + Frac(FDataLink.Field.AsDateTime);
  2816.   DoChange;
  2817. end;
  2818. {$ENDIF}
  2819. procedure TDBDateEdit.ApplyDate(Value: TDateTime);
  2820. begin
  2821.   FDataLink.Edit;
  2822.   inherited ApplyDate(Value);
  2823. end;
  2824. procedure TDBDateEdit.WMPaste(var Message: TMessage);
  2825. begin
  2826.   FDataLink.Edit;
  2827.   inherited;
  2828. end;
  2829. procedure TDBDateEdit.WMCut(var Message: TMessage);
  2830. begin
  2831.   FDataLink.Edit;
  2832.   inherited;
  2833. end;
  2834. procedure TDBDateEdit.CMEnter(var Message: TCMEnter);
  2835. begin
  2836.   inherited;
  2837. end;
  2838. procedure TDBDateEdit.CMExit(var Message: TCMExit);
  2839. begin
  2840.   try
  2841.     if not (csDesigning in ComponentState) and CheckOnExit then
  2842.       CheckValidDate;
  2843.     FDataLink.UpdateRecord;
  2844.   except
  2845.     SelectAll;
  2846.     if CanFocus then SetFocus;
  2847.     raise;
  2848.   end;
  2849.   CheckCursor;
  2850.   DoExit;
  2851. end;
  2852. {$IFDEF RX_D4}
  2853. function TDBDateEdit.UseRightToLeftAlignment: Boolean;
  2854. begin
  2855.   Result := DBUseRightToLeftAlignment(Self, Field);
  2856. end;
  2857. function TDBDateEdit.ExecuteAction(Action: TBasicAction): Boolean;
  2858. begin
  2859.   Result := inherited ExecuteAction(Action) or (FDataLink <> nil) and
  2860.     FDataLink.ExecuteAction(Action);
  2861. end;
  2862. function TDBDateEdit.UpdateAction(Action: TBasicAction): Boolean;
  2863. begin
  2864.   Result := inherited UpdateAction(Action) or (FDataLink <> nil) and
  2865.     FDataLink.UpdateAction(Action);
  2866. end;
  2867. {$ENDIF}
  2868. { TRxDBCalcEdit }
  2869. constructor TRxDBCalcEdit.Create(AOwner: TComponent);
  2870. begin
  2871.   inherited Create(AOwner);
  2872. {$IFDEF WIN32}
  2873.   ControlStyle := ControlStyle + [csReplicatable];
  2874. {$ENDIF}
  2875.   inherited ReadOnly := True;
  2876.   FDataLink := TFieldDataLink.Create;
  2877.   FDataLink.Control := Self;
  2878.   FDataLink.OnDataChange := DataChange;
  2879.   FDataLink.OnEditingChange := EditingChange;
  2880.   FDataLink.OnUpdateData := UpdateFieldData;
  2881.   AlwaysEnable := True;
  2882. end;
  2883. destructor TRxDBCalcEdit.Destroy;
  2884. begin
  2885.   FDataLink.Free;
  2886.   FDataLink := nil;
  2887.   inherited Destroy;
  2888. end;
  2889. procedure TRxDBCalcEdit.Notification(AComponent: TComponent;
  2890.   Operation: TOperation);
  2891. begin
  2892.   inherited Notification(AComponent, Operation);
  2893.   if (Operation = opRemove) and (FDataLink <> nil) and
  2894.     (AComponent = DataSource) then DataSource := nil;
  2895. end;
  2896. procedure TRxDBCalcEdit.KeyDown(var Key: Word; Shift: TShiftState);
  2897. begin
  2898.   inherited KeyDown(Key, Shift);
  2899.   if not ReadOnly and ((Key = VK_DELETE) or ((Key = VK_INSERT)
  2900.     and (ssShift in Shift))) then FDataLink.Edit;
  2901. end;
  2902. procedure TRxDBCalcEdit.KeyPress(var Key: Char);
  2903. begin
  2904.   inherited KeyPress(Key);
  2905.   case Key of
  2906.     ^H, ^V, ^X, #32..#255:
  2907.       if not PopupVisible then FDataLink.Edit;
  2908.     #27:
  2909.       begin
  2910.         FDataLink.Reset;
  2911.         SelectAll;
  2912.         Key := #0;
  2913.       end;
  2914.   end;
  2915. end;
  2916. function TRxDBCalcEdit.IsValidChar(Key: Char): Boolean;
  2917. begin
  2918.   Result := inherited IsValidChar(Key);
  2919.   if Result and (FDatalink.Field <> nil) then
  2920.     Result := FDatalink.Field.IsValidChar(Key);
  2921. end;
  2922. procedure TRxDBCalcEdit.UpdatePopup;
  2923. var
  2924.   Precision: Byte;
  2925. begin
  2926.   Precision := DefCalcPrecision;
  2927.   if (FDatalink <> nil) and (FDatalink.Field <> nil) and
  2928.     (FDatalink.Field is TFloatField) then
  2929.     Precision := TFloatField(FDatalink.Field).Precision;
  2930.   if FPopup <> nil then
  2931.     SetupPopupCalculator(FPopup, Precision, BeepOnError);
  2932. end;
  2933. function TRxDBCalcEdit.EditCanModify: Boolean;
  2934. begin
  2935.   Result := FDataLink.Edit;
  2936. end;
  2937. {$IFDEF WIN32}
  2938. function TRxDBCalcEdit.GetDisplayText: string;
  2939. var
  2940.   E: Extended;
  2941. begin
  2942.   if (csPaintCopy in ControlState) and (FDatalink.Field <> nil) then begin
  2943.     if FDataLink.Field.IsNull then E := 0.0
  2944.     else if FDataLink.Field.DataType in [ftSmallint, ftInteger, ftWord] then
  2945.       E := FDataLink.Field.AsInteger
  2946.     else if FDataLink.Field.DataType = ftBoolean then
  2947.       E := Ord(FDataLink.Field.AsBoolean)
  2948. {$IFDEF RX_D4}
  2949.     else if FDataLink.Field is TLargeintField then
  2950.       E := TLargeintField(FDataLink.Field).AsLargeInt
  2951. {$ENDIF}
  2952.     else E := FDataLink.Field.AsFloat;
  2953.     if FDataLink.Field.IsNull then Result := ''
  2954.     else Result := FormatDisplayText(E);
  2955.   end
  2956.   else begin
  2957.     if (FDataLink.Field = nil) then begin
  2958.       if (csDesigning in ComponentState) then Result := Format('(%s)', [Name])
  2959.       else Result := '';
  2960.     end
  2961.     else Result := inherited GetDisplayText;
  2962.   end;
  2963. end;
  2964. {$ENDIF}
  2965. procedure TRxDBCalcEdit.Reset;
  2966. begin
  2967.   FDataLink.Reset;
  2968.   inherited Reset;
  2969. end;
  2970. procedure TRxDBCalcEdit.Change;
  2971. begin
  2972.   if not Formatting then FDataLink.Modified;
  2973.   inherited Change;
  2974. end;
  2975. function TRxDBCalcEdit.GetDataSource: TDataSource;
  2976. begin
  2977.   Result := FDataLink.DataSource;
  2978. end;
  2979. procedure TRxDBCalcEdit.SetDataSource(Value: TDataSource);
  2980. begin
  2981.   if FDataLink.DataSource <> Value then begin
  2982. {$IFDEF RX_D4}
  2983.     if not (FDataLink.DataSourceFixed and (csLoading in ComponentState)) then
  2984. {$ENDIF}
  2985.       FDataLink.DataSource := Value;
  2986. {$IFDEF WIN32}
  2987.     if Value <> nil then Value.FreeNotification(Self);
  2988. {$ENDIF}
  2989.     UpdateFieldParams;
  2990.   end;
  2991. end;
  2992. function TRxDBCalcEdit.GetDataField: string;
  2993. begin
  2994.   Result := FDataLink.FieldName;
  2995. end;
  2996. procedure TRxDBCalcEdit.SetDataField(const Value: string);
  2997. begin
  2998.   if FDataLink.FieldName <> Value then begin
  2999.     FDataLink.FieldName := Value;
  3000.     UpdateFieldParams;
  3001.   end;
  3002. end;
  3003. procedure TRxDBCalcEdit.SetDefaultParams(Value: Boolean);
  3004. begin
  3005.   if DefaultParams <> Value then begin
  3006.     FDefaultParams := Value;
  3007.     if FDefaultParams then UpdateFieldParams;
  3008.   end;
  3009. end;
  3010. procedure TRxDBCalcEdit.UpdateFieldParams;
  3011. begin
  3012.   if FDatalink.Field <> nil then begin
  3013.     if FDatalink.Field is TNumericField then begin
  3014.       if TNumericField(FDatalink.Field).DisplayFormat <> '' then
  3015.         DisplayFormat := TNumericField(FDatalink.Field).DisplayFormat;
  3016.       Alignment := TNumericField(FDatalink.Field).Alignment;
  3017.     end;
  3018. {$IFDEF RX_D4}
  3019.     if FDatalink.Field is TLargeintField then begin
  3020.       MaxValue := TLargeintField(FDatalink.Field).MaxValue;
  3021.       MinValue := TLargeintField(FDatalink.Field).MinValue;
  3022.       DecimalPlaces := 0;
  3023.       if DisplayFormat = '' then DisplayFormat := ',#';
  3024.     end else
  3025. {$ENDIF}
  3026.     if FDatalink.Field is TIntegerField then begin
  3027.       MaxValue := TIntegerField(FDatalink.Field).MaxValue;
  3028.       MinValue := TIntegerField(FDatalink.Field).MinValue;
  3029.       DecimalPlaces := 0;
  3030.       if DisplayFormat = '' then DisplayFormat := ',#';
  3031.     end
  3032. {$IFDEF WIN32}
  3033.     else if FDatalink.Field is TBCDField then begin
  3034.       MaxValue := TBCDField(FDatalink.Field).MaxValue;
  3035.       MinValue := TBCDField(FDatalink.Field).MinValue;
  3036.     end
  3037. {$ENDIF}
  3038.     else if FDatalink.Field is TFloatField then begin
  3039.       MaxValue := TFloatField(FDatalink.Field).MaxValue;
  3040.       MinValue := TFloatField(FDatalink.Field).MinValue;
  3041.       DecimalPlaces := TFloatField(FDatalink.Field).Precision;
  3042.     end
  3043.     else if FDatalink.Field is TBooleanField then begin
  3044.       MinValue := 0;
  3045.       MaxValue := 1;
  3046.       DecimalPlaces := 0;
  3047.       if DisplayFormat = '' then DisplayFormat := ',#';
  3048.     end;
  3049.   end;
  3050.   UpdatePopup;
  3051. end;
  3052. function TRxDBCalcEdit.GetReadOnly: Boolean;
  3053. begin
  3054.   Result := FDataLink.ReadOnly;
  3055. end;
  3056. procedure TRxDBCalcEdit.SetReadOnly(Value: Boolean);
  3057. begin
  3058.   FDataLink.ReadOnly := Value;
  3059. end;
  3060. function TRxDBCalcEdit.GetField: TField;
  3061. begin
  3062.   Result := FDataLink.Field;
  3063. end;
  3064. procedure TRxDBCalcEdit.DataChange(Sender: TObject);
  3065. begin
  3066.   if FDefaultParams then UpdateFieldParams;
  3067.   if FDataLink.Field <> nil then begin
  3068.     if FDataLink.Field.IsNull then begin
  3069.       Self.Value := 0.0;
  3070.       EditText := '';
  3071.     end
  3072.     else if FDataLink.Field.DataType in [ftSmallint, ftInteger, ftWord] then
  3073.       Self.AsInteger := FDataLink.Field.AsInteger
  3074.     else if FDataLink.Field.DataType = ftBoolean then
  3075.       Self.AsInteger := Ord(FDataLink.Field.AsBoolean)
  3076. {$IFDEF RX_D4}
  3077.     else if FDataLink.Field is TLargeintField then
  3078.       Self.Value := TLargeintField(FDataLink.Field).AsLargeInt
  3079. {$ENDIF}
  3080.     else Self.Value := FDataLink.Field.AsFloat;
  3081.     DataChanged;
  3082.   end
  3083.   else begin
  3084.     if csDesigning in ComponentState then begin
  3085.       Self.Value := 0;
  3086.       EditText := Format('(%s)', [Name]);
  3087.     end
  3088.     else Self.Value := 0;
  3089.   end;
  3090. end;
  3091. procedure TRxDBCalcEdit.EditingChange(Sender: TObject);
  3092. begin
  3093.   inherited ReadOnly := not FDataLink.Editing;
  3094. end;
  3095. procedure TRxDBCalcEdit.UpdateFieldData(Sender: TObject);
  3096. begin
  3097.   inherited UpdateData;
  3098.   if (Value = 0) and ZeroEmpty then FDataLink.Field.Clear
  3099.   else if FDataLink.Field.DataType in [ftSmallint, ftInteger, ftWord] then
  3100.     FDataLink.Field.AsInteger := Self.AsInteger
  3101.   else if FDataLink.Field.DataType = ftBoolean then
  3102.     FDataLink.Field.AsBoolean := Boolean(Self.AsInteger)
  3103.   else FDataLink.Field.AsFloat := Self.Value;
  3104. end;
  3105. {$IFDEF WIN32}
  3106. procedure TRxDBCalcEdit.CMGetDataLink(var Message: TMessage);
  3107. begin
  3108.   Message.Result := Integer(FDataLink);
  3109. end;
  3110. procedure TRxDBCalcEdit.AcceptValue(const Value: Variant);
  3111. begin
  3112.   if VarIsNull(Value) or VarIsEmpty(Value) then FDataLink.Field.Clear
  3113.   else FDataLink.Field.Value := Value;
  3114.   DoChange;
  3115. end;
  3116. {$ENDIF}
  3117. procedure TRxDBCalcEdit.WMPaste(var Message: TMessage);
  3118. begin
  3119.   FDataLink.Edit;
  3120.   inherited;
  3121. end;
  3122. procedure TRxDBCalcEdit.WMCut(var Message: TMessage);
  3123. begin
  3124.   FDataLink.Edit;
  3125.   inherited;
  3126. end;
  3127. procedure TRxDBCalcEdit.CMEnter(var Message: TCMEnter);
  3128. begin
  3129.   inherited;
  3130. end;
  3131. procedure TRxDBCalcEdit.CMExit(var Message: TCMExit);
  3132. begin
  3133.   try
  3134.     CheckRange;
  3135.     FDataLink.UpdateRecord;
  3136.   except
  3137.     SelectAll;
  3138.     if CanFocus then SetFocus;
  3139.     raise;
  3140.   end;
  3141.   inherited;
  3142. end;
  3143. {$IFDEF RX_D4}
  3144. function TRxDBCalcEdit.UseRightToLeftAlignment: Boolean;
  3145. begin
  3146.   Result := DBUseRightToLeftAlignment(Self, Field);
  3147. end;
  3148. function TRxDBCalcEdit.ExecuteAction(Action: TBasicAction): Boolean;
  3149. begin
  3150.   Result := inherited ExecuteAction(Action) or (FDataLink <> nil) and
  3151.     FDataLink.ExecuteAction(Action);
  3152. end;
  3153. function TRxDBCalcEdit.UpdateAction(Action: TBasicAction): Boolean;
  3154. begin
  3155.   Result := inherited UpdateAction(Action) or (FDataLink <> nil) and
  3156.     FDataLink.UpdateAction(Action);
  3157. end;
  3158. {$ENDIF}
  3159. { TStatusDataLink }
  3160. type
  3161.   TStatusDataLink = class(TDataLink)
  3162.   private
  3163.     FLabel: TDBStatusLabel;
  3164.   protected
  3165.     procedure ActiveChanged; override;
  3166.     procedure EditingChanged; override;
  3167.     procedure DataSetChanged; override;
  3168.     procedure DataSetScrolled(Distance: Integer); override;
  3169.     procedure LayoutChanged; override;
  3170.   public
  3171.     constructor Create(ALabel: TDBStatusLabel);
  3172.     destructor Destroy; override;
  3173.   end;
  3174. constructor TStatusDataLink.Create(ALabel: TDBStatusLabel);
  3175. begin
  3176.   inherited Create;
  3177.   FLabel := ALabel;
  3178. end;
  3179. destructor TStatusDataLink.Destroy;
  3180. begin
  3181.   FLabel := nil;
  3182.   inherited Destroy;
  3183. end;
  3184. procedure TStatusDataLink.ActiveChanged;
  3185. begin
  3186.   DataSetChanged;
  3187. end;
  3188. procedure TStatusDataLink.DataSetScrolled(Distance: Integer);
  3189. begin
  3190.   if (FLabel <> nil) and (FLabel.Style = lsRecordNo) then
  3191.     FLabel.UpdateStatus;
  3192. end;
  3193. procedure TStatusDataLink.EditingChanged;
  3194. begin
  3195.   if (FLabel <> nil) and (FLabel.Style <> lsRecordSize) then
  3196.     FLabel.UpdateStatus;
  3197. end;
  3198. procedure TStatusDataLink.DataSetChanged;
  3199. begin
  3200.   if (FLabel <> nil) then FLabel.UpdateData;
  3201. end;
  3202. procedure TStatusDataLink.LayoutChanged;
  3203. begin
  3204.   if (FLabel <> nil) and (FLabel.Style <> lsRecordSize) then
  3205.     DataSetChanged; { ??? }
  3206. end;
  3207. { TDBStatusLabel }
  3208. const
  3209.   GlyphSpacing = 2;
  3210.   GlyphColumns = 7;
  3211. constructor TDBStatusLabel.Create(AOwner: TComponent);
  3212. begin
  3213.   inherited Create(AOwner);
  3214.   ShadowSize := 0;
  3215.   Layout := tlCenter;
  3216.   ControlStyle := ControlStyle - [csSetCaption {$IFDEF WIN32},
  3217.     csReplicatable {$ENDIF}];
  3218.   FRecordCount := -1;
  3219.   FRecordNo := -1;
  3220.   ShowAccelChar := False;
  3221.   FDataSetName := NullStr;
  3222.   FDataLink := TStatusDataLink.Create(Self);
  3223.   FStyle := lsState;
  3224.   GlyphAlign := glGlyphLeft;
  3225.   FEditColor := clRed;
  3226.   FCaptions := TStringList.Create;
  3227.   TStringList(FCaptions).OnChange := CaptionsChanged;
  3228.   FGlyph := TBitmap.Create;
  3229.   FGlyph.Handle := LoadBitmap(HInstance, 'DS_STATES');
  3230.   Caption := '';
  3231. end;
  3232. destructor TDBStatusLabel.Destroy;
  3233. begin
  3234.   FDataLink.Free;
  3235.   FDataLink := nil;
  3236.   DisposeStr(FDataSetName);
  3237.   TStringList(FCaptions).OnChange := nil;
  3238.   FCaptions.Free;
  3239.   FCaptions := nil;
  3240.   FCell.Free;
  3241.   FCell := nil;
  3242.   FGlyph.Free;
  3243.   FGlyph := nil;
  3244.   inherited Destroy;
  3245. end;
  3246. procedure TDBStatusLabel.Loaded;
  3247. begin
  3248.   inherited Loaded;
  3249.   UpdateData;
  3250. end;
  3251. function TDBStatusLabel.GetDefaultFontColor: TColor;
  3252. begin
  3253.   if (FStyle = lsState) and (FDatalink <> nil) and
  3254.     (GetDatasetState in [dsEdit, dsInsert]) then
  3255.     Result := FEditColor
  3256.   else Result := inherited GetDefaultFontColor;
  3257. end;
  3258. function TDBStatusLabel.GetLabelCaption: string;
  3259. begin
  3260.   if (csDesigning in ComponentState) and ((FStyle = lsState) or
  3261.     (FDatalink = nil) or not FDatalink.Active) then
  3262.     Result := Format('(%s)', [Name])
  3263.   else if ((FDatalink = nil) or (DataSource = nil)) then
  3264.     Result := ''
  3265.   else begin
  3266.     case FStyle of
  3267.       lsState:
  3268.         if FShowOptions in [doCaption, doBoth] then begin
  3269.           if DataSetName = '' then Result := GetCaption(DataSource.State)
  3270.           else Result := Format('%s: %s', [DataSetName, GetCaption(DataSource.State)]);
  3271.         end
  3272.         else { doGlyph } Result := '';
  3273.       lsRecordNo:
  3274.         if FDataLink.Active then begin
  3275.           if FRecordNo >= 0 then begin
  3276.             if FRecordCount >= 0 then
  3277.               Result := Format('%d:%d', [FRecordNo, FRecordCount])
  3278.             else Result := IntToStr(FRecordNo);
  3279.           end
  3280.           else begin
  3281.             if FRecordCount >= 0 then
  3282.               Result := Format('( %d )', [FRecordCount])
  3283.             else Result := '';
  3284.           end;
  3285.         end
  3286.         else Result := '';
  3287.       lsRecordSize:
  3288.         if FDatalink.Active then
  3289.           Result := IntToStr(FDatalink.DataSet.RecordSize)
  3290.         else Result := '';
  3291.     end;
  3292.   end;
  3293. end;
  3294. function TDBStatusLabel.GetDatasetState: TDataSetState;
  3295. begin
  3296.   if DataSource <> nil then
  3297.     Result := DataSource.State
  3298.   else Result := dsInactive;
  3299. end;
  3300. procedure TDBStatusLabel.SetName(const Value: TComponentName);
  3301. begin
  3302.   inherited SetName(Value);
  3303.   if (csDesigning in ComponentState) then Invalidate;
  3304. end;
  3305. procedure TDBStatusLabel.SetCaptions(Value: TStrings);
  3306. begin
  3307.   FCaptions.Assign(Value);
  3308. end;
  3309. function TDBStatusLabel.GetStatusKind(State: TDataSetState): TDBStatusKind;
  3310. begin
  3311. {$IFDEF WIN32}
  3312.   if not (State in [Low(TDBStatusKind)..High(TDBStatusKind)]) then begin
  3313.     case State of
  3314.       dsFilter: Result := dsSetKey;
  3315. {$IFDEF RX_D3}
  3316.       dsNewValue, dsOldValue, dsCurValue: Result := dsEdit;
  3317. {$ELSE}
  3318.       dsUpdateNew, dsUpdateOld: Result := dsEdit;
  3319. {$ENDIF}
  3320.       else Result := TDBStatusKind(State);
  3321.     end;
  3322.   end
  3323.   else
  3324. {$ENDIF WIN32}
  3325.     Result := TDBStatusKind(State);
  3326. end;
  3327. function TDBStatusLabel.GetCaption(State: TDataSetState): string;
  3328. const
  3329.   StrIds: array[TDBStatusKind] of Word = (SInactiveData, SBrowseData,
  3330.     SEditData, SInsertData, SSetKeyData, SCalcFieldsData);
  3331. var
  3332.   Kind: TDBStatusKind;
  3333. begin
  3334.   Kind := GetStatusKind(State);
  3335.   if (FCaptions <> nil) and (Ord(Kind) < FCaptions.Count) and
  3336.     (FCaptions[Ord(Kind)] <> '') then Result := FCaptions[Ord(Kind)]
  3337.   else Result := LoadStr(StrIds[Kind]);
  3338. end;
  3339. procedure TDBStatusLabel.Paint;
  3340. var
  3341.   GlyphOrigin: TPoint;
  3342. begin
  3343.   inherited Paint;
  3344.   if (FStyle = lsState) and (FShowOptions in [doGlyph, doBoth]) and
  3345.     (FCell <> nil) then
  3346.   begin
  3347.     if GlyphAlign = glGlyphLeft then
  3348.       GlyphOrigin.X := GlyphSpacing
  3349.     else {glGlyphRight}
  3350.       GlyphOrigin.X := Left + ClientWidth - RightMargin + GlyphSpacing;
  3351.     case Layout of
  3352.       tlTop: GlyphOrigin.Y := 0;
  3353.       tlCenter: GlyphOrigin.Y := (ClientHeight - FCell.Height) div 2;
  3354.       else { tlBottom } GlyphOrigin.Y := ClientHeight - FCell.Height;
  3355.     end;
  3356.     DrawBitmapTransparent(Canvas, GlyphOrigin.X, GlyphOrigin.Y,
  3357.       FCell, FGlyph.TransparentColor);
  3358.   end;
  3359. end;
  3360. procedure TDBStatusLabel.CaptionsChanged(Sender: TObject);
  3361. begin
  3362.   TStringList(FCaptions).OnChange := nil;
  3363.   try
  3364.     while (Pred(FCaptions.Count) > Ord(High(TDBStatusKind))) do
  3365.       FCaptions.Delete(FCaptions.Count - 1);
  3366.   finally
  3367.     TStringList(FCaptions).OnChange := CaptionsChanged;
  3368.   end;
  3369.   if not (csDesigning in ComponentState) then Invalidate;
  3370. end;
  3371. procedure TDBStatusLabel.UpdateData;
  3372.   function IsSequenced: Boolean;
  3373.   begin
  3374. {$IFDEF RX_D3}
  3375.     Result := FDatalink.DataSet.IsSequenced;
  3376. {$ELSE}
  3377.     Result := not ((FDatalink.DataSet is TDBDataSet) and
  3378.       TDBDataSet(FDatalink.DataSet).Database.IsSQLBased);
  3379. {$ENDIF}
  3380.   end;
  3381. begin
  3382.   FRecordCount := -1;
  3383.   if (FStyle = lsRecordNo) and FDataLink.Active and
  3384.     (DataSource.State in [dsBrowse, dsEdit]) then
  3385.   begin
  3386.     if Assigned(FOnGetRecordCount) then
  3387.       FOnGetRecordCount(Self, FDataLink.DataSet, FRecordCount)
  3388.     else if (FCalcCount or IsSequenced) then
  3389. {$IFDEF RX_D3}
  3390.       FRecordCount := FDataLink.DataSet.RecordCount;
  3391. {$ELSE}
  3392.       FRecordCount := DataSetRecordCount(FDataLink.DataSet)
  3393. {$ENDIF}
  3394.   end;
  3395.   UpdateStatus;
  3396. end;
  3397. procedure TDBStatusLabel.UpdateStatus;
  3398. begin
  3399.   if DataSource <> nil then begin
  3400.     case FStyle of
  3401.       lsState:
  3402.         if FShowOptions in [doGlyph, doBoth] then begin
  3403.           if GlyphAlign = glGlyphLeft then begin
  3404.             RightMargin := 0;
  3405.             LeftMargin := (FGlyph.Width div GlyphColumns) + GlyphSpacing * 2;
  3406.           end
  3407.           else {glGlyphRight} begin
  3408.             LeftMargin := 0;
  3409.             RightMargin := (FGlyph.Width div GlyphColumns) + GlyphSpacing * 2;
  3410.           end;
  3411.           if FCell = nil then FCell := TBitmap.Create;
  3412.           AssignBitmapCell(FGlyph, FCell, GlyphColumns, 1,
  3413.             Ord(GetStatusKind(DataSource.State)));
  3414.         end
  3415.         else { doCaption } begin
  3416.           FCell.Free;
  3417.           FCell := nil;
  3418.           LeftMargin := 0;
  3419.           RightMargin := 0;
  3420.         end;
  3421.       lsRecordNo:
  3422.         begin
  3423.           FCell.Free;
  3424.           FCell := nil;
  3425.           LeftMargin := 0;
  3426.           RightMargin := 0;
  3427.           FRecordNo := -1;
  3428.           if FDataLink.Active then begin
  3429.             if Assigned(FOnGetRecNo) then
  3430.               FOnGetRecNo(Self, FDataLink.DataSet, FRecordNo) else
  3431.             try
  3432. {$IFDEF RX_D3}
  3433.               with FDatalink.DataSet do
  3434.                 if not IsEmpty then FRecordNo := RecNo;
  3435. {$ELSE}
  3436.               FRecordNo := DataSetRecNo(FDatalink.DataSet);
  3437. {$ENDIF}
  3438.             except
  3439.             end;
  3440.           end;
  3441.         end;
  3442.       lsRecordSize:
  3443.         begin
  3444.           FCell.Free;
  3445.           FCell := nil;
  3446.           LeftMargin := 0;
  3447.           RightMargin := 0;
  3448.         end;
  3449.     end;
  3450.   end
  3451.   else begin
  3452.     FCell.Free;
  3453.     FCell := nil;
  3454.   end;
  3455.   AdjustBounds;
  3456.   Invalidate;
  3457. end;
  3458. procedure TDBStatusLabel.Notification(AComponent: TComponent;
  3459.   Operation: TOperation);
  3460. begin
  3461.   inherited Notification(AComponent, Operation);
  3462.   if (Operation = opRemove) and (FDataLink <> nil) and
  3463.     (AComponent = DataSource) then DataSource := nil;
  3464. end;
  3465. function TDBStatusLabel.GetDataSetName: string;
  3466. begin
  3467.   Result := FDataSetName^;
  3468.   if not (csDesigning in ComponentState) then begin
  3469.     if Assigned(FOnGetDataName) then Result := FOnGetDataName(Self)
  3470.     else if (Result = '') and (DataSource <> nil) and
  3471.       (DataSource.DataSet <> nil) then Result := DataSource.DataSet.Name;
  3472.   end;
  3473. end;
  3474. procedure TDBStatusLabel.SetDataSetName(Value: string);
  3475. begin
  3476.   AssignStr(FDataSetName, Value);
  3477.   Invalidate;
  3478. end;
  3479. function TDBStatusLabel.GetDataSource: TDataSource;
  3480. begin
  3481.   Result := FDataLink.DataSource;
  3482. end;
  3483. procedure TDBStatusLabel.SetDataSource(Value: TDataSource);
  3484. begin
  3485. {$IFDEF RX_D4}
  3486.   if not (FDataLink.DataSourceFixed and (csLoading in ComponentState)) then
  3487. {$ENDIF}
  3488.     FDataLink.DataSource := Value;
  3489. {$IFDEF WIN32}
  3490.   if Value <> nil then Value.FreeNotification(Self);
  3491. {$ENDIF}
  3492.   if not (csLoading in ComponentState) then UpdateData;
  3493. end;
  3494. procedure TDBStatusLabel.SetEditColor(Value: TColor);
  3495. begin
  3496.   if FEditColor <> Value then begin
  3497.     FEditColor := Value;
  3498.     if Style = lsState then Invalidate;
  3499.   end;
  3500. end;
  3501. procedure TDBStatusLabel.SetGlyphAlign(Value: TGlyphAlign);
  3502. begin
  3503.   if FGlyphAlign <> Value then begin
  3504.     FGlyphAlign := Value;
  3505.     UpdateStatus;
  3506.   end;
  3507. end;
  3508. procedure TDBStatusLabel.SetShowOptions(Value: TDBLabelOptions);
  3509. begin
  3510.   if FShowOptions <> Value then begin
  3511.     FShowOptions := Value;
  3512.     UpdateStatus;
  3513.   end;
  3514. end;
  3515. procedure TDBStatusLabel.SetCalcCount(Value: Boolean);
  3516. begin
  3517.   if FCalcCount <> Value then begin
  3518.     FCalcCount := Value;
  3519.     if not (csLoading in ComponentState) then UpdateData;
  3520.   end;
  3521. end;
  3522. procedure TDBStatusLabel.SetStyle(Value: TDBLabelStyle);
  3523. begin
  3524.   if FStyle <> Value then begin
  3525.     FStyle := Value;
  3526.     if not (csLoading in ComponentState) then UpdateData;
  3527.   end;
  3528. end;
  3529. {$IFDEF WIN32}
  3530. initialization
  3531. finalization
  3532.   DestroyLocals;
  3533. {$ELSE}
  3534. initialization
  3535.   AddExitProc(DestroyLocals);
  3536. {$ENDIF}
  3537. end.