home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 December / Chip_2001-12_cd1.bin / zkuste / delphi / kolekce / d456 / VOLGAPAK.ZIP / Source / VolDBGrid.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2001-09-20  |  156.9 KB  |  5,205 lines

  1. //---------------------------------------------------------------------------
  2. //  TvtiDBGrid - inherited from TCustomGrid
  3. //  Column Button Style may be cbsCombo,cbsLookup,cbsCalendar,cbsCheck,cbsEllipsis
  4. //  Combo dropdown list supports combo values
  5. //  Lookup dropdown list without adding calculated TField
  6. //  Dropdown list width may be greater then width of column
  7. //  Title columns as buttons, editable calculated fields
  8. //  Uses TvtiCalendar for dropdown calendar
  9. //---------------------------------------------------------------------------
  10. unit VolDBGrid;
  11.  
  12. interface
  13.  
  14. uses Windows, SysUtils, Messages, Classes, Controls, Forms, StdCtrls,
  15. {$IFDEF VER140} Variants, {$ENDIF}
  16.   Graphics, Grids, DBCtrls, Db, Menus, ImgList, VolCalend, VolDBConst;
  17.  
  18. type
  19.   TVolgaColumnValue = (cvColor, cvWidth, cvFont, cvAlignment, cvReadOnly, cvTitleColor,
  20.     cvTitleCaption, cvTitleAlignment, cvTitleFont, cvImeMode, cvImeName);
  21.   TVolgaColumnValues = set of TVolgaColumnValue;
  22.  
  23. const
  24.   ColumnTitleValues = [cvTitleColor..cvTitleFont];
  25.   cm_DeferLayout = WM_USER + 100;
  26.  
  27. type
  28.   TVolgaColumn = class;
  29.   TVolgaCustomDBGrid = class;
  30.  
  31.   TVolgaColumnTitle = class(TPersistent)
  32.   private
  33.     FColumn: TVolgaColumn;
  34.     FCaption: string;
  35.     FFont: TFont;
  36.     FColor: TColor;
  37.     FAlignment: TAlignment;
  38.     procedure FontChanged(Sender: TObject);
  39.     function GetAlignment: TAlignment;
  40.     function GetColor: TColor;
  41.     function GetCaption: string;
  42.     function GetFont: TFont;
  43.     function IsAlignmentStored: Boolean;
  44.     function IsColorStored: Boolean;
  45.     function IsFontStored: Boolean;
  46.     function IsCaptionStored: Boolean;
  47.     procedure SetAlignment(Value: TAlignment);
  48.     procedure SetColor(Value: TColor);
  49.     procedure SetFont(Value: TFont);
  50.     procedure SetCaption(const Value: string); virtual;
  51.   protected
  52.     procedure RefreshDefaultFont;
  53.   public
  54.     constructor Create(Column: TVolgaColumn);
  55.     destructor Destroy; override;
  56.     procedure Assign(Source: TPersistent); override;
  57.     function DefaultAlignment: TAlignment;
  58.     function DefaultColor: TColor;
  59.     function DefaultFont: TFont;
  60.     function DefaultCaption: string;
  61.     procedure RestoreDefaults; virtual;
  62.     property Column: TVolgaColumn read FColumn;
  63.   published
  64.     property Alignment: TAlignment read GetAlignment write SetAlignment
  65.       stored IsAlignmentStored;
  66.     property Caption: string read GetCaption write SetCaption stored IsCaptionStored;
  67.     property Color: TColor read GetColor write SetColor stored IsColorStored;
  68.     property Font: TFont read GetFont write SetFont stored IsFontStored;
  69.   end;
  70.  
  71.   TVolgaColumnButtonStyle = (cbsCombo, cbsLookup, cbsCalendar, cbsCheck, cbsEllipsis, cbsNone);  //Volga
  72.  
  73.   TVolgaColumn = class(TCollectionItem)
  74.   private
  75.     FField: TField;
  76.     FFieldName: string;
  77.     FColor: TColor;
  78.     FWidth: Integer;
  79.     FTitle: TVolgaColumnTitle;
  80.     FFont: TFont;
  81.     FImeMode: TImeMode;
  82.     FImeName: TImeName;
  83.     FPickList: TStrings;
  84.     FPickValues: TStrings;                //Volga
  85.     FPopupMenu: TPopupMenu;
  86.     FDropDownRows: Cardinal;
  87.     FDropDownWidth: Cardinal;             //Volga
  88.     FCanClick: Boolean;                   //Volga
  89.     FDown: Boolean;                       //Volga
  90.     FButtonStyle: TVolgaColumnButtonStyle;
  91.     FAlignment: TAlignment;
  92.     FReadonly: Boolean;
  93.     FAssignedValues: TVolgaColumnValues;
  94.     FVisible: Boolean;
  95.     FExpanded: Boolean;
  96.     FStored: Boolean;
  97.     FValueUnChecked: string;
  98.     FValueChecked: string;
  99.     FLookupDropDownFields: string;
  100.     FLookupKeyField: string;
  101.     FLookupLinkField: string;
  102.     FLookupDataSet: TDataSet;
  103.     FViewField:string;
  104.     FAutoDrop: Boolean;
  105.     FTextAsHint: Boolean;
  106.     procedure FontChanged(Sender: TObject);
  107.     function GetAlignment: TAlignment;
  108.     function GetColor: TColor;
  109.     function GetExpanded: Boolean;
  110.     function GetField: TField;
  111.     function GetFont: TFont;
  112.     function GetImeMode: TImeMode;
  113.     function GetImeName: TImeName;
  114.     function GetParentColumn: TVolgaColumn;
  115.     function GetPickList: TStrings;
  116.     function GetPickValues: TStrings;     //Volga
  117.     function GetReadOnly: Boolean;
  118.     function GetShowing: Boolean;
  119.     function GetWidth: Integer;
  120.     function GetVisible: Boolean;
  121.     function IsAlignmentStored: Boolean;
  122.     function IsColorStored: Boolean;
  123.     function IsFontStored: Boolean;
  124.     function IsImeModeStored: Boolean;
  125.     function IsImeNameStored: Boolean;
  126.     function IsReadOnlyStored: Boolean;
  127.     function IsWidthStored: Boolean;
  128.     procedure SetAlignment(Value: TAlignment); virtual;
  129.     procedure SetButtonStyle(Value: TVolgaColumnButtonStyle);
  130.     procedure SetColor(Value: TColor);
  131.     procedure SetExpanded(Value: Boolean);
  132.     procedure SetField(Value: TField); virtual;
  133.     procedure SetFieldName(const Value: string);
  134.     procedure SetFont(Value: TFont);
  135.     procedure SetImeMode(Value: TImeMode); virtual;
  136.     procedure SetImeName(Value: TImeName); virtual;
  137.     procedure SetPickList(Value: TStrings);
  138.     procedure SetPickValues(Value: TStrings); //Volga
  139.     procedure SetPopupMenu(Value: TPopupMenu);
  140.     procedure SetReadOnly(Value: Boolean); virtual;
  141.     procedure SetTitle(Value: TVolgaColumnTitle);
  142.     procedure SetWidth(Value: Integer); virtual;
  143.     procedure SetVisible(Value: Boolean);
  144.     function GetExpandable: Boolean;
  145.     procedure SetValueChecked(const Value: string);
  146.     procedure SetValueUnChecked(const Value: string);
  147.     procedure SetLookupDropDownFields(const Value: string);
  148.     procedure SetLookupKeyField(const Value: string);
  149.     procedure SetLookupLinkField(const Value: string);
  150.     procedure SetLookupDataSet(const Value: TDataSet);
  151.   protected
  152.     function CreateTitle: TVolgaColumnTitle; virtual;
  153.     function GetGrid: TVolgaCustomDBGrid;
  154.     function GetDisplayName: string; override;
  155.     procedure RefreshDefaultFont;
  156.     procedure SetIndex(Value: Integer); override;
  157.     property IsStored: Boolean read FStored write FStored default True;
  158.   public
  159.     constructor Create(Collection: TCollection); override;
  160.     destructor Destroy; override;
  161.     procedure Assign(Source: TPersistent); override;
  162.     function DefaultAlignment: TAlignment;
  163.     function DefaultColor: TColor;
  164.     function DefaultFont: TFont;
  165.     function DefaultImeMode: TImeMode;
  166.     function DefaultImeName: TImeName;
  167.     function DefaultReadOnly: Boolean;
  168.     function DefaultWidth: Integer;
  169.     function Depth: Integer;
  170.     function IsLinkActive:Boolean;
  171.     procedure RestoreDefaults; virtual;
  172.     procedure AssignList(const AList: TStrings);
  173.     property AssignedValues: TVolgaColumnValues read FAssignedValues;
  174.     property Down: Boolean read FDown write FDown;
  175.     property Expandable: Boolean read GetExpandable;
  176.     property Grid: TVolgaCustomDBGrid read GetGrid;
  177.     property Field: TField read GetField write SetField;
  178.     property ImeMode: TImeMode read GetImeMode write SetImeMode stored IsImeModeStored;
  179.     property ImeName: TImeName read GetImeName write SetImeName stored IsImeNameStored;
  180.     property ParentColumn: TVolgaColumn read GetParentColumn;
  181.     property Expanded: Boolean read GetExpanded write SetExpanded default False;
  182.     property Showing: Boolean read GetShowing;
  183.   published
  184.     property Alignment: TAlignment read GetAlignment write SetAlignment
  185.       stored IsAlignmentStored;
  186.     property AutoDropDown: Boolean read FAutoDrop write FAutoDrop default false;  //Volga
  187.     property ButtonStyle: TVolgaColumnButtonStyle read FButtonStyle write SetButtonStyle
  188.       default cbsNone;
  189.     property CanClick: Boolean read FCanClick write FCanClick default false; //Volga
  190.     property Color: TColor read GetColor write SetColor stored IsColorStored;
  191.     property DropDownRows: Cardinal read FDropDownRows write FDropDownRows default 10;
  192.     property DropDownWidth: Cardinal read FDropDownWidth write FDropDownWidth default 0;  //Volga
  193.     property FieldName: string read FFieldName write SetFieldName;
  194.     property Font: TFont read GetFont write SetFont stored IsFontStored;
  195.     property LongTextAsHint: Boolean read FTextAsHint write FTextAsHint default false;  //Volga
  196.     property LookupDropDownFields: string read FLookupDropDownFields write SetLookupDropDownFields;  //Volga
  197.     property LookupKeyField: string read FLookupKeyField write SetLookupKeyField;                    //Volga
  198.     property LookupLinkField: string read FLookupLinkField write SetLookupLinkField;                 //Volga
  199.     property LookupDataSet: TDataSet read FLookupDataSet write SetLookupDataSet;                       //Volga
  200.     property PickList: TStrings read GetPickList write SetPickList;
  201.     property PickValues: TStrings read GetPickValues write SetPickValues; //Volga
  202.     property PopupMenu: TPopupMenu read FPopupMenu write SetPopupMenu;
  203.     property ReadOnly: Boolean read GetReadOnly write SetReadOnly
  204.       stored IsReadOnlyStored;
  205.     property Title: TVolgaColumnTitle read FTitle write SetTitle;
  206.     property ValueChecked: string read FValueChecked write SetValueChecked;  //Volga
  207.     property ValueUnChecked: string read FValueUnChecked write SetValueUnChecked; //Volga
  208.     property Width: Integer read GetWidth write SetWidth stored IsWidthStored;
  209.     property Visible: Boolean read GetVisible write SetVisible;
  210.   end;
  211.  
  212.   TVolgaColumnClass = class of TVolgaColumn;
  213.  
  214.   TVolgaDBGridColumnsState = (csDefault, csCustomized);
  215.  
  216.   TVolgaDBGridColumns = class(TOwnedCollection)
  217.   private
  218.     FGrid: TVolgaCustomDBGrid;
  219.     function GetColumn(Index: Integer): TVolgaColumn;
  220.     function InternalAdd: TVolgaColumn;
  221.     procedure SetColumn(Index: Integer; Value: TVolgaColumn);
  222.     procedure SetState(NewState: TVolgaDBGridColumnsState);
  223.     function GetState: TVolgaDBGridColumnsState;
  224.   protected
  225.     function GetOwner: TPersistent; override;
  226.     procedure Update(Item: TCollectionItem); override;
  227.   public
  228.     constructor Create(Grid: TVolgaCustomDBGrid; ColumnClass: TVolgaColumnClass);
  229. //    function Add: TVolgaColumn;
  230.     procedure LoadFromFile(const Filename: string);
  231.     procedure LoadFromStream(S: TStream);
  232.     procedure RestoreDefaults;
  233.     procedure RebuildColumns;
  234.     procedure SaveToFile(const Filename: string);
  235.     procedure SaveToStream(S: TStream);
  236.     property State: TVolgaDBGridColumnsState read GetState write SetState;
  237.     property Grid: TVolgaCustomDBGrid read FGrid;
  238.     property Items[Index: Integer]: TVolgaColumn read GetColumn write SetColumn; default;
  239.   end;
  240.  
  241.   TGridDataLink = class(TDataLink)
  242.   private
  243.     FGrid: TVolgaCustomDBGrid;
  244.     FFieldCount: Integer;
  245.     FFieldMap: array of Integer;
  246.     FModified: Boolean;
  247.     FInUpdateData: Boolean;
  248.     FSparseMap: Boolean;
  249.     function GetDefaultFields: Boolean;
  250.     function GetFields(I: Integer): TField;
  251.   protected
  252.     procedure ActiveChanged; override;
  253.     procedure BuildAggMap;
  254.     procedure DataSetChanged; override;
  255.     procedure DataSetScrolled(Distance: Integer); override;
  256.     procedure FocusControl(Field: TFieldRef); override;
  257.     procedure EditingChanged; override;
  258.     function IsAggRow(Value: Integer): Boolean; virtual;
  259.     procedure LayoutChanged; override;
  260.     procedure RecordChanged(Field: TField); override;
  261.     procedure UpdateData; override;
  262.     function GetMappedIndex(ColIndex: Integer): Integer;
  263.   public
  264.     constructor Create(AGrid: TVolgaCustomDBGrid);
  265.     destructor Destroy; override;
  266.     function AddMapping(const FieldName: string): Boolean;
  267.     procedure ClearMapping;
  268.     procedure Modified;
  269.     procedure Reset;
  270.     property DefaultFields: Boolean read GetDefaultFields;
  271.     property FieldCount: Integer read FFieldCount;
  272.     property Fields[I: Integer]: TField read GetFields;
  273.     property SparseMap: Boolean read FSparseMap write FSparseMap;
  274.   end;
  275.  
  276.   TBookmarkList = class
  277.   private
  278.     FList: TStringList;
  279.     FGrid: TVolgaCustomDBGrid;
  280.     FCache: TBookmarkStr;
  281.     FCacheIndex: Integer;
  282.     FCacheFind: Boolean;
  283.     FLinkActive: Boolean;
  284.     function GetCount: Integer;
  285.     function GetCurrentRowSelected: Boolean;
  286.     function GetItem(Index: Integer): TBookmarkStr;
  287.     procedure SetCurrentRowSelected(Value: Boolean);
  288.     procedure StringsChanged(Sender: TObject);
  289.   protected
  290.     function CurrentRow: TBookmarkStr;
  291.     function Compare(const Item1, Item2: TBookmarkStr): Integer;
  292.     procedure LinkActive(Value: Boolean);
  293.   public
  294.     constructor Create(AGrid: TVolgaCustomDBGrid);
  295.     destructor Destroy; override;
  296.     procedure Clear;                      // free all bookmarks
  297.     procedure Delete;                     // delete all selected rows from dataset
  298.     function Find(const Item: TBookmarkStr; var Index: Integer): Boolean;
  299.     function IndexOf(const Item: TBookmarkStr): Integer;
  300.     function Refresh: Boolean;            // drop orphaned bookmarks; True = orphans found
  301.     property Count: Integer read GetCount;
  302.     property CurrentRowSelected: Boolean read GetCurrentRowSelected
  303.       write SetCurrentRowSelected;
  304.     property Items[Index: Integer]: TBookmarkStr read GetItem; default;
  305.   end;
  306.  
  307.   TVolgaDBGridOption = (dgEditing, dgAlwaysShowEditor, dgTitles, dgIndicator,
  308.     dgColumnResize, dgColLines, dgRowLines, dgTabs, dgRowSelect,
  309.     dgAlwaysShowSelection, dgConfirmDelete, dgCancelOnExit, dgMultiSelect, dgDragOutRows);
  310.   TVolgaDBGridOptions = set of TVolgaDBGridOption;
  311.  
  312.   TCalcFieldEditedEvent = procedure(Sender: TObject; Field: TField;  //Volga
  313.     Text: string) of object;                                         //Volga
  314.   TDrawDataCellEvent = procedure (Sender: TObject; const Rect: TRect; Field: TField;
  315.     State: TGridDrawState) of object;
  316.   TDrawTitleAttrEvent = procedure(Sender: TObject; Column: TVolgaColumn; AFont: TFont;
  317.     var AColor: TColor) of object;
  318.   TDrawCellAttrEvent = procedure(Sender: TObject; Column: TVolgaColumn; AFont: TFont;
  319.     var AColor: TColor; State: TGridDrawState) of object;
  320.   TDrawColumnCellEvent = procedure(Sender: TObject; const Rect: TRect;
  321.     DataCol: Integer; Column: TVolgaColumn; State: TGridDrawState) of object;
  322.   TVolgaDBGridClickEvent = procedure(Sender: TObject; Column: TVolgaColumn) of object; //Volga
  323.   TVolgaDBGridCloseUpEvent = procedure(Sender: TObject; Column: TVolgaColumn;
  324.     Selected: Boolean) of object; //Volga
  325.   TVolgaSpecialKeyDownEvent = procedure(Sender: TObject; Column: TVolgaColumn;
  326.     var Key: Word; AText: string) of object;  //Volga
  327.  
  328.   TVolgaCustomDBGrid = class(TCustomGrid)
  329.   private
  330.     FIndicators: TImageList;
  331.     FTitleFont: TFont;
  332.     FReadOnly: Boolean;
  333.     FOriginalImeName: TImeName;
  334.     FOriginalImeMode: TImeMode;
  335.     FUserChange: Boolean;
  336.     FIsESCKey: Boolean;
  337.     FLayoutFromDataset: Boolean;
  338.     FOptions: TVolgaDBGridOptions;
  339.     FTitleOffset, FIndicatorOffset: Byte;
  340.     FUpdateLock: Byte;
  341.     FLayoutLock: Byte;
  342.     FInColExit: Boolean;
  343.     FDefaultDrawing: Boolean;
  344.     FSelfChangingTitleFont: Boolean;
  345.     FSelecting: Boolean;
  346.     FSelRow: Integer;
  347.     FDataLink: TGridDataLink;
  348.     FOnColEnter: TNotifyEvent;
  349.     FOnColExit: TNotifyEvent;
  350.     FOnDrawDataCell: TDrawDataCellEvent;
  351.     FOnDrawColumnCell: TDrawColumnCellEvent;
  352.     FOnDrawTitleAttr: TDrawTitleAttrEvent;
  353.     FOnDrawCellAttr: TDrawCellAttrEvent;
  354.     FEditText: string;
  355.     FColumns: TVolgaDBGridColumns;
  356.     FVisibleColumns: TList;
  357.     FBookmarks: TBookmarkList;
  358.     FSelectionAnchor: TBookmarkStr;
  359.     FOnEditButtonClick: TVolgaDBGridClickEvent;
  360.     FOnColumnMoved: TMovedEvent;
  361.     FOnCalcFieldEdited: TCalcFieldEditedEvent;    //Volga
  362.     FOnCellClick: TVolgaDBGridClickEvent;
  363.     FOnTitleClick: TVolgaDBGridClickEvent;
  364.     FDragCol: TVolgaColumn;
  365.     FAllowInsert: Boolean;                  //Volga
  366.     FAllowDelete: Boolean;                  //Volga
  367.     FBeforeDropDown: TVolgaDBGridClickEvent;  //Volga
  368.     FAfterCloseUp: TVolgaDBGridCloseUpEvent;  //Volga
  369.     FSpecialKey: TVolgaSpecialKeyDownEvent;   //Volga
  370.     FSelectedFontColor: TColor;
  371.     FSelectedColor: TColor;   //Volga
  372.     function AcquireFocus: Boolean;
  373.     procedure DataChanged;
  374.     procedure EditingChanged;
  375.     function GetDataSource: TDataSource;
  376.     function GetFieldCount: Integer;
  377.     function GetFields(FieldIndex: Integer): TField;
  378.     function GetSelectedField: TField;
  379.     function GetSelectedIndex: Integer;
  380.     procedure InternalLayout;
  381.     procedure MoveCol(RawCol, Direction: Integer);
  382.     function PtInExpandButton(X, Y: Integer; var MasterCol: TVolgaColumn): Boolean;
  383.     procedure ReadColumns(Reader: TReader);
  384.     procedure RecordChanged(Field: TField);
  385.     procedure SetIme;
  386.     procedure SetColumns(Value: TVolgaDBGridColumns);
  387.     procedure SetDataSource(Value: TDataSource);
  388.     procedure SetOptions(Value: TVolgaDBGridOptions);
  389.     procedure SetSelectedField(Value: TField);
  390.     procedure SetSelectedIndex(Value: Integer);
  391.     procedure SetTitleFont(Value: TFont);
  392.     procedure TitleFontChanged(Sender: TObject);
  393.     procedure ToggleCheckBox(Column: TVolgaColumn; col, row:integer);
  394.     procedure UpdateData;
  395.     procedure UpdateActive;
  396.     procedure UpdateIme;
  397.     procedure UpdateScrollBar;
  398.     procedure UpdateRowCount;
  399.     procedure WriteColumns(Writer: TWriter);
  400.     procedure CMBiDiModeChanged(var Message: TMessage); message CM_BIDIMODECHANGED;
  401.     procedure CMExit(var Message: TMessage); message CM_EXIT;
  402.     procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  403.     procedure CMParentFontChanged(var Message: TMessage); message CM_PARENTFONTCHANGED;
  404.     procedure CMDeferLayout(var Message); message cm_DeferLayout;
  405.     procedure CMDesignHitTest(var Msg: TCMDesignHitTest); message CM_DESIGNHITTEST;
  406.     procedure WMSetCursor(var Msg: TWMSetCursor); message WM_SETCURSOR;
  407.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  408.     procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
  409.     procedure WMIMEStartComp(var Message: TMessage); message WM_IME_STARTCOMPOSITION;
  410.     procedure WMSetFocus(var Message: TWMSetFocus); message WM_SetFOCUS;
  411.     procedure WMKillFocus(var Message: TMessage); message WM_KillFocus;
  412.     procedure SetAllowDelete(const Value: Boolean);
  413.     procedure SetAllowInsert(const Value: Boolean);
  414.     procedure SetSelectedColor(const Value: TColor);
  415.     procedure SetSelectedFontColor(const Value: TColor);
  416.   protected
  417.     FUpdateFields: Boolean;
  418.     FAcquireFocus: Boolean;
  419.     function RawToDataColumn(ACol: Integer): Integer;
  420.     function DataToRawColumn(ACol: Integer): Integer;
  421.     function AcquireLayoutLock: Boolean;
  422.     procedure BeginLayout;
  423.     procedure BeginUpdate;
  424.     procedure CalcSizingState(X, Y: Integer; var State: TGridState;
  425.       var Index: Longint; var SizingPos, SizingOfs: Integer;
  426.       var FixedInfo: TGridDrawInfo); override;
  427.     procedure CancelLayout;
  428.     function CanEditAcceptKey(Key: Char): Boolean; override;
  429.     function CanEditModify: Boolean; override;
  430.     function CanEditShow: Boolean; override;
  431.     procedure CellClick(Column: TVolgaColumn); dynamic;
  432.     procedure ColumnMoved(FromIndex, ToIndex: Longint); override;
  433.     function CalcTitleRect(Col: TVolgaColumn; ARow: Integer;
  434.       var MasterCol: TVolgaColumn): TRect;
  435.     function ColumnAtDepth(Col: TVolgaColumn; ADepth: Integer): TVolgaColumn;
  436.     procedure ColEnter; dynamic;
  437.     procedure ColExit; dynamic;
  438.     procedure ColWidthsChanged; override;
  439.     function CreateColumns: TVolgaDBGridColumns; dynamic;
  440.     function CreateEditor: TInplaceEdit; override;
  441.     procedure CreateWnd; override;
  442.     procedure DeferLayout;
  443.     procedure DefineFieldMap; virtual;
  444.     procedure DefineProperties(Filer: TFiler); override;
  445.     procedure DefaultDrawDataCell(const Rect: TRect; Field: TField;
  446.       State: TGridDrawState);
  447.     procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
  448.       override;
  449.     procedure DrawDataCell(const Rect: TRect; Field: TField;
  450.       State: TGridDrawState);
  451.     procedure DrawColumnCell(const Rect: TRect; DataCol: Integer;
  452.       Column: TVolgaColumn; State: TGridDrawState); dynamic;
  453.     procedure EditButtonClick; dynamic;
  454.     procedure EndLayout;
  455.     procedure EndUpdate;
  456.     function GetColField(DataCol: Integer): TField;
  457.     function GetEditLimit: Integer; override;
  458.     function GetEditMask(ACol, ARow: Longint): string; override;
  459.     function GetEditText(ACol, ARow: Longint): string; override;
  460.     function GetFieldValue(ACol: Integer): string;
  461.     function HighlightCell(DataCol, DataRow: Integer; const Value: string;
  462.       AState: TGridDrawState): Boolean; virtual;
  463.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  464.     procedure KeyPress(var Key: Char); override;
  465.     procedure InvalidateTitles;
  466.     procedure LayoutChanged; virtual;
  467.     procedure LinkActive(Value: Boolean); virtual;
  468.     procedure Loaded; override;
  469.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  470.       X, Y: Integer); override;
  471.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
  472.       X, Y: Integer); override;
  473.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  474.     procedure Scroll(Distance: Integer); virtual;
  475.     procedure SetColumnAttributes; virtual;
  476.     procedure SetEditText(ACol, ARow: Longint; const Value: string); override;
  477.     function StoreColumns: Boolean;
  478.     procedure TimedScroll(Direction: TGridScrollDirection); override;
  479.     procedure TitleClick(Column: TVolgaColumn); dynamic;
  480.     procedure TopLeftChanged; override;
  481.     function UseRightToLeftAlignmentForField(const AField: TField;
  482.       Alignment: TAlignment): Boolean;
  483.     function BeginColumnDrag(var Origin, Destination: Integer;
  484.       const MousePt: TPoint): Boolean; override;
  485.     function CheckColumnDrag(var Origin, Destination: Integer;
  486.       const MousePt: TPoint): Boolean; override;
  487.     function EndColumnDrag(var Origin, Destination: Integer;
  488.       const MousePt: TPoint): Boolean; override;
  489.     property AllowDelete: Boolean read FAllowDelete write SetAllowDelete default True;
  490.     property AllowInsert: Boolean read FAllowInsert write SetAllowInsert default True;
  491.     property Columns: TVolgaDBGridColumns read FColumns write SetColumns;
  492.     property DefaultDrawing: Boolean read FDefaultDrawing write FDefaultDrawing default
  493.       True;
  494.     property DataLink: TGridDataLink read FDataLink;
  495.     property IndicatorOffset: Byte read FIndicatorOffset;
  496.     property LayoutLock: Byte read FLayoutLock;
  497.     property Options: TVolgaDBGridOptions read FOptions write SetOptions
  498.       default [dgEditing, dgTitles, dgIndicator, dgColumnResize, dgColLines,
  499.       dgRowLines, dgTabs, dgConfirmDelete, dgCancelOnExit];
  500.     property ParentColor default False;
  501.     property ReadOnly: Boolean read FReadOnly write FReadOnly default False;
  502.     property SelectedRows: TBookmarkList read FBookmarks;
  503.     property SelectedColor: TColor read FSelectedColor write SetSelectedColor default clHighlight;  //volga
  504.     property SelectedFontColor: TColor read FSelectedFontColor write SetSelectedFontColor
  505.       default clHighlightText; //volga
  506.     property TitleFont: TFont read FTitleFont write SetTitleFont;
  507.     property UpdateLock: Byte read FUpdateLock;
  508.     property OnColEnter: TNotifyEvent read FOnColEnter write FOnColEnter;
  509.     property OnColExit: TNotifyEvent read FOnColExit write FOnColExit;
  510.     property OnDrawDataCell: TDrawDataCellEvent read FOnDrawDataCell
  511.       write FOnDrawDataCell; { obsolete }
  512.     property OnDrawColumnCell: TDrawColumnCellEvent read FOnDrawColumnCell
  513.       write FOnDrawColumnCell;
  514.     property OnDrawTitleAttr: TDrawTitleAttrEvent read FOnDrawTitleAttr
  515.       write FOnDrawTitleAttr;
  516.     property OnDrawCellAttr: TDrawCellAttrEvent read FOnDrawCellAttr
  517.       write FOnDrawCellAttr;
  518.     property OnEditButtonClick: TVolgaDBGridClickEvent read FOnEditButtonClick
  519.       write FOnEditButtonClick;
  520.     property OnCalcFieldEdited: TCalcFieldEditedEvent read FOnCalcFieldEdited  //Volga
  521.       write FOnCalcFieldEdited;                                                //Volga
  522.     property OnColumnMoved: TMovedEvent read FOnColumnMoved write FOnColumnMoved;
  523.     property OnCellClick: TVolgaDBGridClickEvent read FOnCellClick write FOnCellClick;
  524.     property OnTitleClick: TVolgaDBGridClickEvent read FOnTitleClick write FOnTitleClick;
  525.     property BeforeDropDown: TVolgaDBGridClickEvent read FBeforeDropDown write FBeforeDropDown; //Volga
  526.     property AfterCloseUp: TVolgaDBGridCloseUpEvent read FAfterCloseUp write FAfterCloseUp;     //Volga
  527.     property OnSpecialKeyDown: TVolgaSpecialKeyDownEvent read FSpecialKey write FSpecialKey;    //Volga
  528.   public
  529.     constructor Create(AOwner: TComponent); override;
  530.     destructor Destroy; override;
  531.     function ColumnByName(const AName: string): TVolgaColumn;
  532.     property DataSource: TDataSource read GetDataSource write SetDataSource;
  533.     procedure DefaultDrawColumnCell(const Rect: TRect; DataCol: Integer;
  534.       Column: TVolgaColumn; State: TGridDrawState);
  535.     procedure DefaultHandler(var Msg); override;
  536.     function ExecuteAction(Action: TBasicAction): Boolean; override;
  537.     procedure ShowPopupEditor(Column: TVolgaColumn; X: Integer = Low(Integer);
  538.       Y: Integer = Low(Integer)); dynamic;
  539.     procedure InvalidateCurrentRow;
  540.     function UpdateAction(Action: TBasicAction): Boolean; override;
  541.     function ValidFieldIndex(FieldIndex: Integer): Boolean;
  542.     property EditorMode;
  543.     property FieldCount: Integer read GetFieldCount;
  544.     property Fields[FieldIndex: Integer]: TField read GetFields;
  545.     property SelectedField: TField read GetSelectedField write SetSelectedField;
  546.     property SelectedIndex: Integer read GetSelectedIndex write SetSelectedIndex;
  547.   end;
  548.  
  549.   TVolgaDBGrid = class(TVolgaCustomDBGrid)
  550.   public
  551.     property Canvas;
  552.     property SelectedRows;
  553.   published
  554.     property Align;
  555.     property AllowDelete;
  556.     property AllowInsert;
  557.     property Anchors;
  558.     property BiDiMode;
  559.     property BorderStyle;
  560.     property Color;
  561.     property Columns stored False;        //StoreColumns;
  562.     property Constraints;
  563.     property Ctl3D;
  564.     property DataSource;
  565.     property DefaultDrawing;
  566.     property DragCursor;
  567.     property DragKind;
  568.     property DragMode;
  569.     property Enabled;
  570.     property FixedColor;
  571.     property Font;
  572.     property ImeMode;
  573.     property ImeName;
  574.     property Options;
  575.     property ParentBiDiMode;
  576.     property ParentColor;
  577.     property ParentCtl3D;
  578.     property ParentFont;
  579.     property ParentShowHint;
  580.     property PopupMenu;
  581.     property ReadOnly;
  582.     property SelectedColor;    //volga
  583.     property SelectedFontColor; //volga
  584.     property ShowHint;
  585.     property TabOrder;
  586.     property TabStop;
  587.     property TitleFont;
  588.     property Visible;
  589.     property BeforeDropDown; //Volga
  590.     property AfterCloseUp; //Volga
  591.     property OnCalcFieldEdited;     //Volga
  592.     property OnCellClick;
  593.     property OnColEnter;
  594.     property OnColExit;
  595.     property OnColumnMoved;
  596.     property OnDrawColumnCell;
  597.     property OnDrawCellAttr;     //Volga
  598.     property OnDrawTitleAttr;    //Volga
  599.     property OnDblClick;
  600.     property OnDragDrop;
  601.     property OnDragOver;
  602.     property OnEditButtonClick;
  603.     property OnEndDock;
  604.     property OnEndDrag;
  605.     property OnEnter;
  606.     property OnExit;
  607.     property OnKeyDown;
  608.     property OnKeyPress;
  609.     property OnKeyUp;
  610.     property OnMouseDown;
  611.     property OnMouseMove;
  612.     property OnMouseUp;
  613.     property OnSpecialKeyDown; //Volga
  614.     property OnStartDock;
  615.     property OnStartDrag;
  616.     property OnTitleClick;
  617.   end;
  618.  
  619. const
  620.   IndicatorWidth = 11;
  621.  
  622. implementation
  623.  
  624. uses Math, DBConsts, Dialogs;
  625.  
  626. {$R VolDBGRID.RES}
  627.  
  628. const
  629.   bmArrow = 'VDBGARROW';
  630.   bmEdit = 'VDBEDIT';
  631.   bmInsert = 'VDBINSERT';
  632.   bmMultiDot = 'VDBMULTIDOT';
  633.   bmMultiArrow = 'VDBMULTIARROW';
  634.   MaxMapSize = (MaxInt div 2) div SizeOf(Integer); { 250 million }
  635.  
  636. { Error reporting }
  637.  
  638. procedure RaiseGridError(const S: string);
  639. begin
  640.   raise EInvalidGridOperation.Create(S);
  641. end;
  642.  
  643. procedure KillMessage(Wnd: HWnd; Msg: Integer);
  644. // Delete the requested message from the queue, but throw back
  645. // any WM_QUIT msgs that PeekMessage may also return
  646. var
  647.   M: TMsg;
  648. begin
  649.   M.Message := 0;
  650.   if PeekMessage(M, Wnd, Msg, Msg, pm_Remove) and (M.Message = WM_QUIT) then
  651.     PostQuitMessage(M.wparam);
  652. end;
  653.  
  654. { TVolgaDBGridInplaceEdit }
  655.  
  656. type
  657.   TVolgaEditStyle = (esSimple, esEllipsis, esPickList, esDataList, esCalendar); //Volga
  658.   TPopupListbox = class;
  659.   TVolgaPopupCalendar = class;                   //Volga
  660.  
  661.   TVolgaDBGridInplaceEdit = class(TInplaceEdit)
  662.   private
  663.     FButtonWidth: Integer;
  664.     FDataList: TDBLookupListBox;
  665.     FPickList: TPopupListbox;
  666.     FCalendar: TVolgaPopupCalendar;         //Volga
  667.     FActiveList: TWinControl;
  668.     FEditStyle: TVolgaEditStyle;
  669.     FListVisible: Boolean;
  670.     FLookupSource: TDatasource;
  671.     FTracking: Boolean;
  672.     FPressed: Boolean;
  673.     procedure ListMouseUp(Sender: TObject; Button: TMouseButton;
  674.       Shift: TShiftState; X, Y: Integer);
  675.     procedure SetEditStyle(Value: TVolgaEditStyle);
  676.     procedure StopTracking;
  677.     procedure TrackButton(X, Y: Integer);
  678.     procedure CMCancelMode(var Message: TCMCancelMode); message CM_CancelMode;
  679.     procedure WMCancelMode(var Message: TMessage); message WM_CancelMode;
  680.     procedure WMKillFocus(var Message: TMessage); message WM_KillFocus;
  681.     procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message wm_LButtonDblClk;
  682.     procedure WMPaint(var Message: TWMPaint); message wm_Paint;
  683.     procedure WMSetCursor(var Message: TWMSetCursor); message WM_SetCursor;
  684.     function OverButton(const P: TPoint): Boolean;
  685.     function ButtonRect: TRect;
  686.     procedure CalSelectDate(Sender:TObject);
  687.   protected
  688.     procedure BoundsChanged; override;
  689.     procedure CloseUp(Accept: Boolean);
  690.     procedure DoDropDownKeys(var Key: Word; Shift: TShiftState);
  691.     procedure DropDown;
  692.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  693.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  694.       X, Y: Integer); override;
  695.     procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  696.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
  697.       X, Y: Integer); override;
  698.     procedure PaintWindow(DC: HDC); override;
  699.     procedure UpdateContents; override;
  700.     procedure WndProc(var Message: TMessage); override;
  701.     property EditStyle: TVolgaEditStyle read FEditStyle write SetEditStyle;
  702.     property ActiveList: TWinControl read FActiveList write FActiveList;
  703.     property DataList: TDBLookupListBox read FDataList;
  704.     property PickList: TPopupListbox read FPickList;
  705.   public
  706.     constructor Create(Owner: TComponent); override;
  707.   end;
  708.  
  709. { TPopupListbox }
  710.  
  711.   TPopupListbox = class(TCustomListbox)
  712.   private
  713.     FSearchText: string;
  714.     FSearchTickCount: Longint;
  715.   protected
  716.     procedure CreateParams(var Params: TCreateParams); override;
  717.     procedure CreateWnd; override;
  718.     procedure KeyPress(var Key: Char); override;
  719.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  720.   end;
  721.  
  722.  { TVolgaPopupCalendar }//Volga
  723.  
  724.   TVolgaPopupCalendar = class(TVolgaCalendar)
  725.   protected
  726.     procedure CreateParams(var Params: TCreateParams); override;
  727.     procedure CreateWnd; override;
  728.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  729.   end;                                    //Volga
  730.  
  731. procedure TPopupListBox.CreateParams(var Params: TCreateParams);
  732. begin
  733.   inherited CreateParams(Params);
  734.   with Params do
  735.   begin
  736.     Style := Style or WS_BORDER;
  737.     ExStyle := WS_EX_TOOLWINDOW or WS_EX_TOPMOST;
  738.     AddBiDiModeExStyle(ExStyle);
  739.     WindowClass.Style := CS_SAVEBITS;
  740.   end;
  741. end;
  742.  
  743. procedure TPopupListbox.CreateWnd;
  744. begin
  745.   inherited CreateWnd;
  746.   Windows.SetParent(Handle, 0);
  747.   CallWindowProc(DefWndProc, Handle, wm_SetFocus, 0, 0);
  748. end;
  749.  
  750. procedure TPopupListbox.Keypress(var Key: Char);
  751. var
  752.   TickCount: Integer;
  753. begin
  754.   case Key of
  755.     #8, #27: FSearchText := '';
  756.     #32..#255:
  757.       begin
  758.         TickCount := GetTickCount;
  759.         if TickCount - FSearchTickCount > 5000 then FSearchText := '';
  760.         FSearchTickCount := TickCount;
  761.         if Length(FSearchText) < 32 then FSearchText := FSearchText + Key;
  762.         SendMessage(Handle, LB_SelectString, WORD(-1), Longint(PChar(FSearchText)));
  763.         Key := #0;
  764.       end;
  765.   end;
  766.   inherited Keypress(Key);
  767. end;
  768.  
  769. procedure TPopupListbox.MouseUp(Button: TMouseButton; Shift: TShiftState;
  770.   X, Y: Integer);
  771. begin
  772.   inherited MouseUp(Button, Shift, X, Y);
  773.   TVolgaDBGridInPlaceEdit(Owner).CloseUp((X >= 0) and (Y >= 0) and
  774.     (X < Width) and (Y < Height));
  775. end;
  776.  
  777. //Volga
  778. procedure TVolgaPopupCalendar.CreateParams(var Params: TCreateParams);
  779. begin
  780.   inherited CreateParams(Params);
  781.   with Params do
  782.   begin
  783.     Style := Style or WS_BORDER;
  784.     ExStyle := WS_EX_TOOLWINDOW or WS_EX_TOPMOST;
  785. //  AddBiDiModeExStyle(ExStyle);
  786.     WindowClass.Style := CS_SAVEBITS;
  787.   end;
  788. end;
  789.  
  790. procedure TVolgaPopupCalendar.CreateWnd;
  791. begin
  792.   inherited CreateWnd;
  793.   Windows.SetParent(Handle, 0);
  794.   CallWindowProc(DefWndProc, Handle, wm_SetFocus, 0, 0);
  795. end;
  796.  
  797. procedure TVolgaPopupCalendar.MouseUp(Button: TMouseButton; Shift: TShiftState;
  798.   X, Y: Integer);
  799. begin
  800.   inherited MouseUp(Button, Shift, X, Y);
  801.   if ((X >= 2) and (Y >= 41) and (X < Width-2) and (Y < Height-20)) then
  802.     TVolgaDBGridInPlaceEdit(Owner).CloseUp(true)
  803.   else if (X<0) or (Y<0) or (X>Width) or (Y>Height) then
  804.     TVolgaDBGridInPlaceEdit(Owner).CloseUp(false)
  805. end;
  806. //Volga
  807.  
  808. { TVolgaDBGridInplaceEdit }
  809.  
  810. constructor TVolgaDBGridInplaceEdit.Create(Owner: TComponent);
  811. begin
  812.   inherited Create(Owner);
  813.   FLookupSource := TDataSource.Create(Self);
  814.   FButtonWidth := GetSystemMetrics(SM_CXVSCROLL) - 4; //Volga
  815.   FEditStyle := esSimple;
  816. end;
  817.  
  818. procedure TVolgaDBGridInplaceEdit.BoundsChanged;
  819. var
  820.   R: TRect;
  821. begin
  822.   SetRect(R, 2, 2, Width - 2, Height);
  823.   if (FEditStyle <> esSimple) then
  824.     if not TVolgaCustomDBGrid(Owner).UseRightToLeftAlignment then
  825.       Dec(R.Right, FButtonWidth)
  826.     else
  827.       Inc(R.Left, FButtonWidth - 2);
  828.   SendMessage(Handle, EM_SETRECTNP, 0, LongInt(@R));
  829.   SendMessage(Handle, EM_SCROLLCARET, 0, 0);
  830.   if SysLocale.FarEast then
  831.     SetImeCompositionWindow(Font, R.Left, R.Top);
  832. end;
  833.  
  834. procedure TVolgaDBGridInplaceEdit.CloseUp(Accept: Boolean);
  835. var
  836.   MasterField: TField;
  837.   ListValue: Variant;
  838.   ind: integer;                           //Volga
  839. begin
  840.   if FListVisible then
  841.   begin
  842.     if GetCapture <> 0 then SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
  843.     if FActiveList = FDataList then
  844.       ListValue := FDataList.KeyValue
  845.     else
  846.       if FActiveList = FPickList then begin //Volga
  847.       ind := FPickList.ItemIndex;         //Volga
  848.       if ind <> -1 then
  849.         with TVolgaCustomDBGrid(Grid), Columns[SelectedIndex] do
  850.           if (PickValues <> nil) and (PickValues.Count = PickList.Count) then //Volga
  851.             ListValue := PickValues[ind]  //Volga
  852.           else
  853.             ListValue := PickList[ind];
  854.     end else                              //Volga
  855.       if FActiveList = FCalendar then begin //Volga
  856.         ListValue := DateToStr(FCalendar.Date); //Volga
  857.       end;                                  //Volga
  858.     SetWindowPos(FActiveList.Handle, 0, 0, 0, 0, 0, SWP_NOZORDER or
  859.       SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_HIDEWINDOW);
  860.     FListVisible := False;
  861.     if Assigned(FDataList) then   //ε≥÷σ∩ΦδΦ lookup-Σα≥α±σ≥
  862.       FDataList.ListSource := nil;
  863.     FLookupSource.Dataset := nil;
  864.     Invalidate;
  865.     if Accept then begin
  866.       if FActiveList = FDataList then                               //Volga
  867.         with TVolgaCustomDBGrid(Grid),Columns[SelectedIndex] do
  868.         begin
  869.           MasterField := Field.DataSet.FieldByName(LookupKeyField);  //Volga
  870.           if MasterField.CanModify then
  871.           begin
  872.             Field.DataSet.Edit;
  873.             MasterField.Value := ListValue;
  874.           end;
  875.         end
  876.       else
  877.         if (not VarIsNull(ListValue)) and EditCanModify then
  878.         with TVolgaCustomDBGrid(Grid) do
  879.           Columns[SelectedIndex].Field.Text := ListValue;
  880.     end;
  881.     with TVolgaCustomDBGrid(Grid) do
  882.       if Assigned(AfterCloseUp) then
  883.         AfterCloseUp(TVolgaCustomDBGrid(Grid), Columns[SelectedIndex], Accept);
  884.   end;
  885. end;
  886.  
  887. procedure TVolgaDBGridInplaceEdit.DoDropDownKeys(var Key: Word; Shift: TShiftState);
  888. begin
  889.   case Key of
  890.     VK_UP, VK_DOWN:
  891.       if ssAlt in Shift then
  892.       begin
  893.         if EditStyle in [esPickList, esDataList, esCalendar] then //Volga
  894.           if FListVisible then CloseUp(True) else DropDown;
  895.         Key := 0;
  896.       end;
  897.     VK_RETURN, VK_ESCAPE:
  898.       begin
  899.         if FListVisible and not (ssAlt in Shift) then
  900.         begin
  901.           CloseUp(Key = VK_RETURN);
  902.           Key := 0;
  903.         end;
  904. //        if Key=VK_RETURN then  //Volga
  905. //          with TVolgaCustomDBGrid(Grid) do SelectedIndex := SelectedIndex+1;
  906.       end;
  907.     VK_SPACE, $30..$5A, VK_NUMPAD0..VK_NUMPAD9: ;    //ß≤ΩΓσφφε-÷Φ⌠≡εΓ√σ ΩδαΓΦ°Φ - φΦ≈σπε φσ Σσδασ∞
  908.     else //⌠≤φΩ÷Φεφαδⁿφ√σ ΩδαΓΦ°Φ, end,home,insert,delete Φ ≥.∩.
  909.       with TVolgaCustomDBGrid(Grid) do         //Volga
  910.       if Assigned(OnSpecialKeyDown) then
  911.         OnSpecialKeyDown(TVolgaCustomDBGrid(Grid), Columns[SelectedIndex], Key, EditText);
  912.   end;
  913. end;
  914.  
  915. procedure TVolgaDBGridInplaceEdit.DropDown;
  916. var
  917.   P: TPoint;
  918.   I, J, X, Y: Integer;
  919.   Column: TVolgaColumn;
  920.   FValue: Variant;
  921. begin
  922.   if not FListVisible and Assigned(FActiveList) then
  923.   begin
  924.     with TVolgaCustomDBGrid(Grid) do begin
  925.       Column := Columns[SelectedIndex];
  926.       if Assigned(BeforeDropDown) then
  927.         BeforeDropDown(TVolgaCustomDBGrid(Grid), Column);
  928.       if Column.DropDownWidth > 0 then    //Volga
  929.         FActiveList.Width := Column.DropDownWidth //Volga
  930.       else FActiveList.Width := Column.Width;
  931.     end;
  932.     if FActiveList = FDataList then
  933.       with Column do
  934.       begin
  935.         FDataList.Color := Color;
  936.         FDataList.Font := Font;
  937.         FDataList.RowCount := DropDownRows;
  938.         FLookupSource.DataSet := LookupDataSet;
  939.         FDataList.ListField := LookupDropDownFields;  //Volga
  940.         FDataList.KeyField := LookupLinkField;        //Volga
  941.         FDataList.ListFieldIndex := 0;                //Γ ±δ≤≈ασ φσ±ΩεδⁿΩΦ⌡ ∩εδσΘ!!!
  942.         FDataList.ListSource := FLookupSource;
  943.         //∩√≥ασ∞±  Φ±Ωα≥ⁿ Γ ±∩Φ±Ωσ φ≤µφεσ τφα≈σφΦσ
  944.         if IsLinkActive then begin
  945.           FValue := Field.DataSet.FieldByName(LookupKeyField).Value;
  946.           FDataList.KeyValue := FValue; //Volga
  947.           LookupDataSet.Locate(LookupLinkField,FValue,[]);
  948.         end;
  949.       end
  950.     else if FActiveList = FPickList then  //Volga
  951.     begin
  952.       FPickList.Color := Color;
  953.       FPickList.Font := Font;
  954.       FPickList.Items := Column.Picklist;
  955.       if FPickList.Items.Count >= Integer(Column.DropDownRows) then
  956.         FPickList.Height := Integer(Column.DropDownRows) * FPickList.ItemHeight + 4
  957.       else
  958.         FPickList.Height := FPickList.Items.Count * FPickList.ItemHeight + 4;
  959.       if Column.Field.IsNull then
  960.         FPickList.ItemIndex := -1
  961.       else
  962.         if (Column.PickValues <> nil) and (Column.PickValues.Count = //Volga
  963.         Column.PickList.Count) then       //Volga
  964.         FPickList.ItemIndex := Column.PickValues.IndexOf(Column.Field.Text) //Volga
  965.       else
  966.         FPickList.ItemIndex := Column.PickList.IndexOf(Column.Field.Text);
  967.       J := FPickList.ClientWidth;
  968.       for I := 0 to FPickList.Items.Count - 1 do
  969.       begin
  970.         Y := FPickList.Canvas.TextWidth(FPickList.Items[I]);
  971.         if Y > J then J := Y;
  972.       end;
  973.       FPickList.ClientWidth := J;
  974.     end
  975.     else                                  //Volga
  976.     begin                                 //ΩαδσφΣα≡ⁿ
  977.       if Column.Field.IsNull then         //Volga
  978.         FCalendar.Date := Date            //Volga
  979.       else FCalendar.Date := Column.Field.AsDateTime; //Volga
  980.     end;                                  //Volga
  981.     P := Parent.ClientToScreen(Point(Left, Top));
  982.     X := P.X;
  983.     Y := P.Y + Height;
  984.     if X + FActiveList.Width > Screen.Width then X := Screen.Width - FActiveList.Width;
  985.     if Y + FActiveList.Height > Screen.Height then Y := P.Y - FActiveList.Height;
  986.     SetWindowPos(FActiveList.Handle, HWND_TOP, X, Y, 0, 0,
  987.       SWP_NOSIZE or SWP_NOACTIVATE or SWP_SHOWWINDOW);
  988.     FListVisible := True;
  989.     Invalidate;
  990.     Windows.SetFocus(Handle);
  991.   end;
  992. end;
  993.  
  994. type
  995.   TWinControlCracker = class(TWinControl) end;
  996.  
  997. procedure TVolgaDBGridInplaceEdit.KeyDown(var Key: Word; Shift: TShiftState);
  998. begin
  999.   if (EditStyle = esEllipsis) and (Key = VK_RETURN) and (Shift = [ssCtrl]) then
  1000.   begin
  1001.     TVolgaCustomDBGrid(Grid).EditButtonClick;
  1002.     KillMessage(Handle, WM_CHAR);
  1003.   end
  1004.   else
  1005.     inherited KeyDown(Key, Shift);
  1006. end;
  1007.  
  1008. procedure TVolgaDBGridInplaceEdit.ListMouseUp(Sender: TObject; Button: TMouseButton;
  1009.   Shift: TShiftState; X, Y: Integer);
  1010. begin
  1011.   if Button = mbLeft then
  1012.     CloseUp(PtInRect(FActiveList.ClientRect, Point(X, Y)));
  1013. end;
  1014.  
  1015. procedure TVolgaDBGridInplaceEdit.MouseDown(Button: TMouseButton; Shift: TShiftState;
  1016.   X, Y: Integer);
  1017. begin
  1018.   if (Button = mbLeft) and (FEditStyle <> esSimple) and
  1019.     OverButton(Point(X, Y)) then
  1020.   begin
  1021.     if FListVisible then
  1022.       CloseUp(False)
  1023.     else
  1024.     begin
  1025.       MouseCapture := True;
  1026.       FTracking := True;
  1027.       TrackButton(X, Y);
  1028.       if Assigned(FActiveList) then
  1029.         DropDown;
  1030.     end;
  1031.   end;
  1032.   inherited MouseDown(Button, Shift, X, Y);
  1033. end;
  1034.  
  1035. procedure TVolgaDBGridInplaceEdit.MouseMove(Shift: TShiftState; X, Y: Integer);
  1036. var
  1037.   ListPos: TPoint;
  1038.   MousePos: TSmallPoint;
  1039. begin
  1040.   if FTracking then
  1041.   begin
  1042.     TrackButton(X, Y);
  1043.     if FListVisible then
  1044.     begin
  1045.       ListPos := FActiveList.ScreenToClient(ClientToScreen(Point(X, Y)));
  1046.       if PtInRect(FActiveList.ClientRect, ListPos) then
  1047.       begin
  1048.         StopTracking;
  1049.         MousePos := PointToSmallPoint(ListPos);
  1050.         SendMessage(FActiveList.Handle, WM_LBUTTONDOWN, 0, Integer(MousePos));
  1051.         Exit;
  1052.       end;
  1053.     end;
  1054.   end;
  1055.   inherited MouseMove(Shift, X, Y);
  1056. end;
  1057.  
  1058. procedure TVolgaDBGridInplaceEdit.MouseUp(Button: TMouseButton; Shift: TShiftState;
  1059.   X, Y: Integer);
  1060. var
  1061.   WasPressed: Boolean;
  1062. begin
  1063.   WasPressed := FPressed;
  1064.   StopTracking;
  1065.   if (Button = mbLeft) and (FEditStyle = esEllipsis) and WasPressed then
  1066.     TVolgaCustomDBGrid(Grid).EditButtonClick;
  1067.   inherited MouseUp(Button, Shift, X, Y);
  1068. end;
  1069.  
  1070. procedure TVolgaDBGridInplaceEdit.StopTracking;
  1071. begin
  1072.   if FTracking then
  1073.   begin
  1074.     TrackButton(-1, -1);
  1075.     FTracking := False;
  1076.     MouseCapture := False;
  1077.   end;
  1078. end;
  1079.  
  1080. procedure TVolgaDBGridInplaceEdit.TrackButton(X, Y: Integer);
  1081. var
  1082.   NewState: Boolean;
  1083.   R: TRect;
  1084. begin
  1085.   R := ButtonRect;
  1086.   NewState := PtInRect(R, Point(X, Y));
  1087.   if FPressed <> NewState then
  1088.   begin
  1089.     FPressed := NewState;
  1090.     InvalidateRect(Handle, @R, False);
  1091.   end;
  1092. end;
  1093.  
  1094. procedure TVolgaDBGridInplaceEdit.PaintWindow(DC: HDC);
  1095. var
  1096.   R: TRect;
  1097.   Flags: Integer;
  1098.   W, X, Y: Integer;
  1099. begin
  1100.   if (FEditStyle <> esSimple) then
  1101.   begin
  1102.     R := ButtonRect;
  1103.     Flags := 0;
  1104.     if FEditStyle in [esDataList, esPickList, esCalendar] then //Volga
  1105.     begin
  1106.       if FActiveList = nil then
  1107.         Flags := DFCS_INACTIVE
  1108.       else if FPressed then
  1109.         Flags := DFCS_FLAT or DFCS_PUSHED;
  1110.       DrawFrameControl(DC, R, DFC_SCROLL, Flags or DFCS_SCROLLCOMBOBOX);
  1111.     end
  1112.     else                                  { esEllipsis }
  1113.     begin
  1114.       if FPressed then Flags := BF_FLAT;
  1115.       DrawEdge(DC, R, EDGE_RAISED, BF_RECT or BF_MIDDLE or Flags);
  1116.       X := R.Left + ((R.Right - R.Left) shr 1) - 1 + Ord(FPressed);
  1117.       Y := R.Top + ((R.Bottom - R.Top) shr 1) - 1 + Ord(FPressed);
  1118.       W := FButtonWidth shr 3;
  1119.       if W = 0 then W := 1;
  1120.       PatBlt(DC, X, Y, W, W, BLACKNESS);
  1121.       PatBlt(DC, X - (W * 2), Y, W, W, BLACKNESS);
  1122.       PatBlt(DC, X + (W * 2), Y, W, W, BLACKNESS);
  1123.     end;
  1124.     ExcludeClipRect(DC, R.Left, R.Top, R.Right, R.Bottom);
  1125.   end;
  1126.   inherited PaintWindow(DC);
  1127. end;
  1128.  
  1129. procedure TVolgaDBGridInplaceEdit.SetEditStyle(Value: TVolgaEditStyle);
  1130. begin
  1131.   if Value = FEditStyle then Exit;
  1132.   FEditStyle := Value;
  1133.   case Value of
  1134.     esPickList:
  1135.       begin
  1136.         if FPickList = nil then
  1137.         begin
  1138.           FPickList := TPopupListbox.Create(Self);
  1139.           FPickList.Visible := False;
  1140.           FPickList.Parent := Self;
  1141.           FPickList.OnMouseUp := ListMouseUp;
  1142.           FPickList.IntegralHeight := True;
  1143.           FPickList.ItemHeight := 11;
  1144.         end;
  1145.         FActiveList := FPickList;
  1146.       end;
  1147.     esDataList:
  1148.       begin
  1149.         if FDataList = nil then
  1150.         begin
  1151.           FDataList := TPopupDataList.Create(Self);
  1152.           FDataList.Visible := False;
  1153.           FDataList.Parent := Self;
  1154.           FDataList.OnMouseUp := ListMouseUp;
  1155.         end;
  1156.         FActiveList := FDataList;
  1157.       end;
  1158.     esCalendar:                           //Volga
  1159.       begin
  1160.         if FCalendar = nil then
  1161.         begin
  1162.           FCalendar := TVolgaPopupCalendar.Create(Self);
  1163.           FCalendar.Visible := False;
  1164.           FCalendar.Parent := Self;
  1165.           FCalendar.OnMouseUp := ListMouseUp;
  1166.           FCalendar.OnSelectDate := CalSelectDate;
  1167.         end;
  1168.         FActiveList := FCalendar;
  1169.       end;                                //Volga
  1170.   else                                    { cbsNone, cbsEllipsis, or read only field }
  1171.     FActiveList := nil;
  1172.   end;
  1173.   with TVolgaCustomDBGrid(Grid) do
  1174.     Self.ReadOnly := Columns[SelectedIndex].ReadOnly;
  1175.   Repaint;
  1176. end;
  1177.  
  1178. procedure TVolgaDBGridInplaceEdit.UpdateContents;
  1179. var
  1180.   Column: TVolgaColumn;
  1181.   NewStyle: TVolgaEditStyle;
  1182.   MasterField: TField;
  1183. begin
  1184.   with TVolgaCustomDBGrid(Grid) do
  1185.     Column := Columns[SelectedIndex];
  1186.   NewStyle := esSimple;
  1187.   case Column.ButtonStyle of
  1188.     cbsEllipsis: NewStyle := esEllipsis;
  1189.     cbsCombo:
  1190.       if Assigned(Column.Picklist) and (Column.PickList.Count > 0) and
  1191.       not Column.Readonly then
  1192.         NewStyle := esPickList;
  1193.     cbsLookup:
  1194.       if Assigned(Column.Field) and Column.IsLinkActive then
  1195.         with Column do
  1196.         begin
  1197.           {Show the dropdown button only if the field is editable }
  1198.           MasterField := Field.Dataset.FieldByName(LookupKeyField);
  1199.           {Column.DefaultReadonly will always be True for a lookup field.
  1200.           Test if Column.ReadOnly has been assigned a value of True }
  1201.           if Assigned(MasterField) and MasterField.CanModify and not Column.ReadOnly then
  1202.             with TVolgaCustomDBGrid(Grid) do
  1203.               if not ReadOnly and DataLink.Active and not Datalink.ReadOnly then
  1204.                 NewStyle := esDataList
  1205.         end;
  1206.     cbsCalendar:
  1207.       if not Column.Readonly then //Volga
  1208.         NewStyle := esCalendar;        //Volga
  1209.   end;
  1210.   EditStyle := NewStyle;
  1211.   inherited UpdateContents;  //ßσ≡σ≥±  ≥σΩ±≥ Φτ  ≈σΘΩΦ π≡ΦΣα
  1212.   Font.Assign(Column.Font);
  1213. end;
  1214.  
  1215. procedure TVolgaDBGridInplaceEdit.CMCancelMode(var Message: TCMCancelMode);
  1216. begin
  1217.   if (Message.Sender <> nil) and (Message.Sender <> Self) and
  1218.   (Message.Sender <> FActiveList) and (Message.Sender.Parent <> FActiveList) then
  1219.     CloseUp(False);
  1220. end;
  1221.  
  1222. procedure TVolgaDBGridInplaceEdit.WMCancelMode(var Message: TMessage);
  1223. begin
  1224.   StopTracking;
  1225.   inherited;
  1226. end;
  1227.  
  1228. procedure TVolgaDBGridInplaceEdit.WMKillFocus(var Message: TMessage);
  1229. begin
  1230.   if not SysLocale.FarEast then inherited
  1231.   else
  1232.   begin
  1233.     ImeName := Screen.DefaultIme;
  1234.     ImeMode := imDontCare;
  1235.     inherited;
  1236.     if HWND(Message.WParam) <> TVolgaCustomDBGrid(Grid).Handle then
  1237.       ActivateKeyboardLayout(Screen.DefaultKbLayout, KLF_ACTIVATE);
  1238.   end;
  1239.   CloseUp(False);
  1240. end;
  1241.  
  1242. function TVolgaDBGridInplaceEdit.ButtonRect: TRect;
  1243. begin
  1244.   if not TVolgaCustomDBGrid(Owner).UseRightToLeftAlignment then
  1245.     Result := Rect(Width - FButtonWidth, 0 {1}, Width {- 1}, Height {- 1}) //Volga
  1246.   else
  1247.     Result := Rect(0, 0, FButtonWidth, Height);
  1248. end;
  1249.  
  1250. function TVolgaDBGridInplaceEdit.OverButton(const P: TPoint): Boolean;
  1251. begin
  1252.   Result := PtInRect(ButtonRect, P);
  1253. end;
  1254.  
  1255. procedure TVolgaDBGridInplaceEdit.WMLButtonDblClk(var Message: TWMLButtonDblClk);
  1256. begin
  1257.   with Message do
  1258.     if (FEditStyle <> esSimple) and OverButton(Point(XPos, YPos)) then
  1259.       Exit;
  1260.   inherited;
  1261. end;
  1262.  
  1263. procedure TVolgaDBGridInplaceEdit.WMPaint(var Message: TWMPaint);
  1264. begin
  1265. //  ControlState := ControlState + [csCustomPaint];
  1266.   PaintHandler(Message);
  1267. //  ControlState := ControlState - [csCustomPaint];
  1268. end;
  1269.  
  1270. procedure TVolgaDBGridInplaceEdit.WMSetCursor(var Message: TWMSetCursor);
  1271. var
  1272.   P: TPoint;
  1273. begin
  1274.   GetCursorPos(P);
  1275.   P := ScreenToClient(P);
  1276.   if (FEditStyle <> esSimple) and OverButton(P) then
  1277.     Windows.SetCursor(Screen.Cursors[crHandPoint]) //Volga
  1278.   else
  1279.     inherited;
  1280. end;
  1281.  
  1282. procedure TVolgaDBGridInplaceEdit.WndProc(var Message: TMessage);
  1283. var
  1284.   Column: TVolgaColumn;
  1285. begin
  1286.   case Message.Msg of
  1287.     wm_KeyDown, wm_SysKeyDown, wm_Char:
  1288. //    if EditStyle in [esPickList, esDataList, esCalendar] then //Volga
  1289.         with TWMKey(Message) do
  1290.         begin
  1291.           DoDropDownKeys(CharCode, KeyDataToShiftState(KeyData));
  1292.           if (Message.Msg = wm_Char) and (CharCode >= 32) and not
  1293.           FListVisible and (EditStyle in [esPickList, esDataList]) then begin
  1294.             with TVolgaCustomDBGrid(Grid) do
  1295.               Column := Columns[SelectedIndex];
  1296.             if Column.AutoDropDown then
  1297.               DropDown; //Γ√∩αΣασ∞, σ±δΦ ≤±≥αφεΓδσφε AutoDropDown Φ φαµα≥α ß≤ΩΓα
  1298.           end;
  1299.           if (CharCode <> 0) and FListVisible then
  1300.           begin   //∩σ≡σφα∩≡αΓδ σ∞ ±εεß∙σφΦσ Γ√∩αΓ°σ∞≤ Ωεφ≥≡εδ■
  1301.             with TMessage(Message) do
  1302.               SendMessage(FActiveList.Handle, Msg, WParam, LParam);
  1303.             Exit;
  1304.           end;
  1305.         end;
  1306.   end;
  1307.   inherited;
  1308. end;
  1309.  
  1310. procedure TVolgaDBGridInplaceEdit.CalSelectDate(Sender: TObject);
  1311. begin  //Γ ΩαδσφΣα≡σ Γ√ß≡αφα Σα≥α
  1312.   CloseUp(true);
  1313. end;
  1314.  
  1315. { TGridDataLink }
  1316.  
  1317. type
  1318.   TIntArray = array[0..MaxMapSize] of Integer;
  1319.   PIntArray = ^TIntArray;
  1320.  
  1321. constructor TGridDataLink.Create(AGrid: TVolgaCustomDBGrid);
  1322. begin
  1323.   inherited Create;
  1324.   FGrid := AGrid;
  1325.   VisualControl := True;
  1326. end;
  1327.  
  1328. destructor TGridDataLink.Destroy;
  1329. begin
  1330.   ClearMapping;
  1331.   inherited Destroy;
  1332. end;
  1333.  
  1334. function TGridDataLink.GetDefaultFields: Boolean;
  1335. var
  1336.   I: Integer;
  1337. begin
  1338.   Result := True;
  1339.   if DataSet <> nil then Result := DataSet.DefaultFields;
  1340.   if Result and SparseMap then
  1341.     for I := 0 to FFieldCount - 1 do
  1342.       if FFieldMap[I] < 0 then
  1343.       begin
  1344.         Result := False;
  1345.         Exit;
  1346.       end;
  1347. end;
  1348.  
  1349. function TGridDataLink.GetFields(I: Integer): TField;
  1350. begin
  1351.   if (0 <= I) and (I < FFieldCount) and (FFieldMap[I] >= 0) then
  1352.     Result := DataSet.FieldList[FFieldMap[I]]
  1353.   else
  1354.     Result := nil;
  1355. end;
  1356.  
  1357. function TGridDataLink.AddMapping(const FieldName: string): Boolean;
  1358. var
  1359.   Field: TField;
  1360.   NewSize: Integer;
  1361. begin
  1362.   Result := True;
  1363.   if FFieldCount >= MaxMapSize then RaiseGridError(STooManyColumns);
  1364.   if SparseMap then
  1365.     Field := DataSet.FindField(FieldName)
  1366.   else
  1367.     Field := DataSet.FieldByName(FieldName);
  1368.  
  1369.   if FFieldCount = Length(FFieldMap) then
  1370.   begin
  1371.     NewSize := Length(FFieldMap);
  1372.     if NewSize = 0 then
  1373.       NewSize := 8
  1374.     else
  1375.       Inc(NewSize, NewSize);
  1376.     if (NewSize < FFieldCount) then
  1377.       NewSize := FFieldCount + 1;
  1378.     if (NewSize > MaxMapSize) then
  1379.       NewSize := MaxMapSize;
  1380.     SetLength(FFieldMap, NewSize);
  1381.   end;
  1382.   if Assigned(Field) then
  1383.   begin
  1384.     FFieldMap[FFieldCount] := Dataset.FieldList.IndexOfObject(Field);
  1385.     Field.FreeNotification(FGrid);
  1386.   end
  1387.   else
  1388.     FFieldMap[FFieldCount] := -1;
  1389.   Inc(FFieldCount);
  1390. end;
  1391.  
  1392. procedure TGridDataLink.ActiveChanged;
  1393. begin
  1394.   FGrid.LinkActive(Active);
  1395.   FModified := False;
  1396. end;
  1397.  
  1398. procedure TGridDataLink.ClearMapping;
  1399. begin
  1400.   FFieldMap := nil;
  1401.   FFieldCount := 0;
  1402. end;
  1403.  
  1404. procedure TGridDataLink.Modified;
  1405. begin
  1406.   FModified := True;
  1407. end;
  1408.  
  1409. procedure TGridDataLink.DataSetChanged;
  1410. begin
  1411.   FGrid.DataChanged;
  1412.   FModified := False;
  1413. end;
  1414.  
  1415. procedure TGridDataLink.DataSetScrolled(Distance: Integer);
  1416. begin
  1417.   FGrid.Scroll(Distance);
  1418. end;
  1419.  
  1420. procedure TGridDataLink.LayoutChanged;
  1421. var
  1422.   SaveState: Boolean;
  1423. begin
  1424.   { FLayoutFromDataset determines whether default column width is forced to
  1425.     be at least wide enough for the column title.  }
  1426.   SaveState := FGrid.FLayoutFromDataset;
  1427.   FGrid.FLayoutFromDataset := True;
  1428.   try
  1429.     FGrid.LayoutChanged;
  1430.   finally
  1431.     FGrid.FLayoutFromDataset := SaveState;
  1432.   end;
  1433.   inherited LayoutChanged;
  1434. end;
  1435.  
  1436. procedure TGridDataLink.FocusControl(Field: TFieldRef);
  1437. begin
  1438.   if Assigned(Field) and Assigned(Field^) then
  1439.   begin
  1440.     FGrid.SelectedField := Field^;
  1441.     if (FGrid.SelectedField = Field^) and FGrid.AcquireFocus then
  1442.     begin
  1443.       Field^ := nil;
  1444.       FGrid.ShowEditor;
  1445.     end;
  1446.   end;
  1447. end;
  1448.  
  1449. procedure TGridDataLink.EditingChanged;
  1450. begin
  1451.   FGrid.EditingChanged;
  1452. end;
  1453.  
  1454. procedure TGridDataLink.RecordChanged(Field: TField);
  1455. begin
  1456.   FGrid.RecordChanged(Field);
  1457.   FModified := False;
  1458. end;
  1459.  
  1460. procedure TGridDataLink.UpdateData;
  1461. begin
  1462.   FInUpdateData := True;
  1463.   try
  1464.     if FModified then FGrid.UpdateData;
  1465.     FModified := False;
  1466.   finally
  1467.     FInUpdateData := False;
  1468.   end;
  1469. end;
  1470.  
  1471. function TGridDataLink.GetMappedIndex(ColIndex: Integer): Integer;
  1472. begin
  1473.   if (0 <= ColIndex) and (ColIndex < FFieldCount) then
  1474.     Result := FFieldMap[ColIndex]
  1475.   else
  1476.     Result := -1;
  1477. end;
  1478.  
  1479. procedure TGridDataLink.Reset;
  1480. begin
  1481.   if FModified then RecordChanged(nil) else Dataset.Cancel;
  1482. end;
  1483.  
  1484. function TGridDataLink.IsAggRow(Value: Integer): Boolean;
  1485. begin
  1486.   Result := False;
  1487. end;
  1488.  
  1489. procedure TGridDataLink.BuildAggMap;
  1490. begin
  1491. end;
  1492.  
  1493. { TVolgaColumnTitle }
  1494. constructor TVolgaColumnTitle.Create(Column: TVolgaColumn);
  1495. begin
  1496.   inherited Create;
  1497.   FColumn := Column;
  1498.   FFont := TFont.Create;
  1499.   FFont.Assign(DefaultFont);
  1500.   FFont.OnChange := FontChanged;
  1501. end;
  1502.  
  1503. destructor TVolgaColumnTitle.Destroy;
  1504. begin
  1505.   FFont.Free;
  1506.   inherited Destroy;
  1507. end;
  1508.  
  1509. procedure TVolgaColumnTitle.Assign(Source: TPersistent);
  1510. begin
  1511.   if Source is TVolgaColumnTitle then
  1512.   begin
  1513.     if cvTitleAlignment in TVolgaColumnTitle(Source).FColumn.FAssignedValues then
  1514.       Alignment := TVolgaColumnTitle(Source).Alignment;
  1515.     if cvTitleColor in TVolgaColumnTitle(Source).FColumn.FAssignedValues then
  1516.       Color := TVolgaColumnTitle(Source).Color;
  1517.     if cvTitleCaption in TVolgaColumnTitle(Source).FColumn.FAssignedValues then
  1518.       Caption := TVolgaColumnTitle(Source).Caption;
  1519.     if cvTitleFont in TVolgaColumnTitle(Source).FColumn.FAssignedValues then
  1520.       Font := TVolgaColumnTitle(Source).Font;
  1521.   end
  1522.   else
  1523.     inherited Assign(Source);
  1524. end;
  1525.  
  1526. function TVolgaColumnTitle.DefaultAlignment: TAlignment;
  1527. begin
  1528.   Result := taCenter;
  1529. end;
  1530.  
  1531. function TVolgaColumnTitle.DefaultColor: TColor;
  1532. var
  1533.   Grid: TVolgaCustomDBGrid;
  1534. begin
  1535.   Grid := FColumn.GetGrid;
  1536.   if Assigned(Grid) then
  1537.     Result := Grid.FixedColor
  1538.   else
  1539.     Result := clBtnFace;
  1540. end;
  1541.  
  1542. function TVolgaColumnTitle.DefaultFont: TFont;
  1543. var
  1544.   Grid: TVolgaCustomDBGrid;
  1545. begin
  1546.   Grid := FColumn.GetGrid;
  1547.   if Assigned(Grid) then
  1548.     Result := Grid.TitleFont
  1549.   else
  1550.     Result := FColumn.Font;
  1551. end;
  1552.  
  1553. function TVolgaColumnTitle.DefaultCaption: string;
  1554. var
  1555.   Field: TField;
  1556. begin
  1557.   Field := FColumn.Field;
  1558.   if Assigned(Field) then
  1559.     Result := Field.DisplayName
  1560.   else
  1561.     Result := FColumn.FieldName;
  1562. end;
  1563.  
  1564. procedure TVolgaColumnTitle.FontChanged(Sender: TObject);
  1565. begin
  1566.   Include(FColumn.FAssignedValues, cvTitleFont);
  1567.   FColumn.Changed(True);
  1568. end;
  1569.  
  1570. function TVolgaColumnTitle.GetAlignment: TAlignment;
  1571. begin
  1572.   if cvTitleAlignment in FColumn.FAssignedValues then
  1573.     Result := FAlignment
  1574.   else
  1575.     Result := DefaultAlignment;
  1576. end;
  1577.  
  1578. function TVolgaColumnTitle.GetColor: TColor;
  1579. begin
  1580.   if cvTitleColor in FColumn.FAssignedValues then
  1581.     Result := FColor
  1582.   else
  1583.     Result := DefaultColor;
  1584. end;
  1585.  
  1586. function TVolgaColumnTitle.GetCaption: string;
  1587. begin
  1588.   if cvTitleCaption in FColumn.FAssignedValues then
  1589.     Result := FCaption
  1590.   else
  1591.     Result := DefaultCaption;
  1592. end;
  1593.  
  1594. function TVolgaColumnTitle.GetFont: TFont;
  1595. var
  1596.   Save: TNotifyEvent;
  1597.   Def: TFont;
  1598. begin
  1599.   if not (cvTitleFont in FColumn.FAssignedValues) then
  1600.   begin
  1601.     Def := DefaultFont;
  1602.     if (FFont.Handle <> Def.Handle) or (FFont.Color <> Def.Color) then
  1603.     begin
  1604.       Save := FFont.OnChange;
  1605.       FFont.OnChange := nil;
  1606.       FFont.Assign(DefaultFont);
  1607.       FFont.OnChange := Save;
  1608.     end;
  1609.   end;
  1610.   Result := FFont;
  1611. end;
  1612.  
  1613. function TVolgaColumnTitle.IsAlignmentStored: Boolean;
  1614. begin
  1615.   Result := (cvTitleAlignment in FColumn.FAssignedValues) and
  1616.     (FAlignment <> DefaultAlignment);
  1617. end;
  1618.  
  1619. function TVolgaColumnTitle.IsColorStored: Boolean;
  1620. begin
  1621.   Result := (cvTitleColor in FColumn.FAssignedValues) and
  1622.     (FColor <> DefaultColor);
  1623. end;
  1624.  
  1625. function TVolgaColumnTitle.IsFontStored: Boolean;
  1626. begin
  1627.   Result := (cvTitleFont in FColumn.FAssignedValues);
  1628. end;
  1629.  
  1630. function TVolgaColumnTitle.IsCaptionStored: Boolean;
  1631. begin
  1632.   Result := (cvTitleCaption in FColumn.FAssignedValues) and
  1633.     (FCaption <> DefaultCaption);
  1634. end;
  1635.  
  1636. procedure TVolgaColumnTitle.RefreshDefaultFont;
  1637. var
  1638.   Save: TNotifyEvent;
  1639. begin
  1640.   if (cvTitleFont in FColumn.FAssignedValues) then Exit;
  1641.   Save := FFont.OnChange;
  1642.   FFont.OnChange := nil;
  1643.   try
  1644.     FFont.Assign(DefaultFont);
  1645.   finally
  1646.     FFont.OnChange := Save;
  1647.   end;
  1648. end;
  1649.  
  1650. procedure TVolgaColumnTitle.RestoreDefaults;
  1651. var
  1652.   FontAssigned: Boolean;
  1653. begin
  1654.   FontAssigned := cvTitleFont in FColumn.FAssignedValues;
  1655.   FColumn.FAssignedValues := FColumn.FAssignedValues - ColumnTitleValues;
  1656.   FCaption := '';
  1657.   RefreshDefaultFont;
  1658.   { If font was assigned, changing it back to default may affect grid title
  1659.     height, and title height changes require layout and redraw of the grid. }
  1660.   FColumn.Changed(FontAssigned);
  1661. end;
  1662.  
  1663. procedure TVolgaColumnTitle.SetAlignment(Value: TAlignment);
  1664. begin
  1665.   if (cvTitleAlignment in FColumn.FAssignedValues) and (Value = FAlignment) then Exit;
  1666.   FAlignment := Value;
  1667.   Include(FColumn.FAssignedValues, cvTitleAlignment);
  1668.   FColumn.Changed(False);
  1669. end;
  1670.  
  1671. procedure TVolgaColumnTitle.SetColor(Value: TColor);
  1672. begin
  1673.   if (cvTitleColor in FColumn.FAssignedValues) and (Value = FColor) then Exit;
  1674.   FColor := Value;
  1675.   Include(FColumn.FAssignedValues, cvTitleColor);
  1676.   FColumn.Changed(False);
  1677. end;
  1678.  
  1679. procedure TVolgaColumnTitle.SetFont(Value: TFont);
  1680. begin
  1681.   FFont.Assign(Value);
  1682. end;
  1683.  
  1684. procedure TVolgaColumnTitle.SetCaption(const Value: string);
  1685. var
  1686.   Grid: TVolgaCustomDBGrid;
  1687. begin
  1688.   if Column.IsStored then
  1689.   begin
  1690.     if (cvTitleCaption in FColumn.FAssignedValues) and (Value = FCaption) then Exit;
  1691.     FCaption := Value;
  1692.     Include(Column.FAssignedValues, cvTitleCaption);
  1693.     Column.Changed(False);
  1694.   end
  1695.   else
  1696.   begin
  1697.     Grid := Column.GetGrid;
  1698.     if Assigned(Grid) and (Grid.Datalink.Active) and Assigned(Column.Field) then
  1699.       Column.Field.DisplayLabel := Value;
  1700.   end;
  1701. end;
  1702.  
  1703. { TVolgaColumn }
  1704.  
  1705. constructor TVolgaColumn.Create(Collection: TCollection);
  1706. var
  1707.   Grid: TVolgaCustomDBGrid;
  1708. begin
  1709.   Grid := nil;
  1710.   if Assigned(Collection) and (Collection is TVolgaDBGridColumns) then
  1711.     Grid := TVolgaDBGridColumns(Collection).Grid;
  1712.   if Assigned(Grid) then Grid.BeginLayout;
  1713.   try
  1714.     inherited Create(Collection);
  1715.     FDropDownRows := 10;                  //Volga
  1716.     FDropDownWidth := 0;                  //Volga
  1717.     FButtonStyle := cbsNone;
  1718.     FFont := TFont.Create;
  1719.     FFont.Assign(DefaultFont);
  1720.     FFont.OnChange := FontChanged;
  1721.     FImeMode := imDontCare;
  1722.     FImeName := Screen.DefaultIme;
  1723.     FTitle := CreateTitle;
  1724.     FVisible := True;
  1725.     FExpanded := False;
  1726.     FCanClick := False;     //Volga
  1727.     FAutoDrop := False;     //Volga
  1728.     FStored := True;
  1729.     FDown := False;         //Volga
  1730.     FTextAsHint := False;   //Volga
  1731. //    FPickList := nil;
  1732. //    FPickValues := nil;     //Volga
  1733.   finally
  1734.     if Assigned(Grid) then Grid.EndLayout;
  1735.   end;
  1736. end;
  1737.  
  1738. destructor TVolgaColumn.Destroy;
  1739. begin
  1740.   FTitle.Free;
  1741.   FFont.Free;
  1742.   FPickList.Free;
  1743.   FPickValues.Free;                       //Volga
  1744.   inherited Destroy;
  1745. end;
  1746.  
  1747. procedure TVolgaColumn.Assign(Source: TPersistent);
  1748. begin
  1749.   if Source is TVolgaColumn then
  1750.   begin
  1751.     if Assigned(Collection) then Collection.BeginUpdate;
  1752.     try
  1753.       RestoreDefaults;
  1754.       FieldName := TVolgaColumn(Source).FieldName;
  1755.       if cvColor in TVolgaColumn(Source).AssignedValues then
  1756.         Color := TVolgaColumn(Source).Color;
  1757.       if cvWidth in TVolgaColumn(Source).AssignedValues then
  1758.         Width := TVolgaColumn(Source).Width;
  1759.       if cvFont in TVolgaColumn(Source).AssignedValues then
  1760.         Font := TVolgaColumn(Source).Font;
  1761.       if cvImeMode in TVolgaColumn(Source).AssignedValues then
  1762.         ImeMode := TVolgaColumn(Source).ImeMode;
  1763.       if cvImeName in TVolgaColumn(Source).AssignedValues then
  1764.         ImeName := TVolgaColumn(Source).ImeName;
  1765.       if cvAlignment in TVolgaColumn(Source).AssignedValues then
  1766.         Alignment := TVolgaColumn(Source).Alignment;
  1767.       if cvReadOnly in TVolgaColumn(Source).AssignedValues then
  1768.         ReadOnly := TVolgaColumn(Source).ReadOnly;
  1769.       Title := TVolgaColumn(Source).Title;
  1770.       DropDownRows := TVolgaColumn(Source).DropDownRows;
  1771.       DropDownWidth := TVolgaColumn(Source).DropDownWidth; //Volga
  1772.       CanClick := TVolgaColumn(Source).CanClick; //Volga
  1773.       LongTextAsHint := TVolgaColumn(Source).LongTextAsHint; //Volga
  1774.       ButtonStyle := TVolgaColumn(Source).ButtonStyle;
  1775.       PickList := TVolgaColumn(Source).PickList;
  1776.       PickValues := TVolgaColumn(Source).PickValues; //Volga
  1777.       LookupDropDownFields := TVolgaColumn(Source).LookupDropDownFields; //Volga
  1778.       LookupKeyField := TVolgaColumn(Source).LookupKeyField; //Volga
  1779.       LookupLinkField := TVolgaColumn(Source).LookupLinkField; //Volga
  1780.       LookupDataSet := TVolgaColumn(Source).LookupDataSet; //Volga
  1781.       PopupMenu := TVolgaColumn(Source).PopupMenu;
  1782.       FVisible := TVolgaColumn(Source).FVisible;
  1783.       FExpanded := TVolgaColumn(Source).FExpanded;
  1784.     finally
  1785.       if Assigned(Collection) then Collection.EndUpdate;
  1786.     end;
  1787.   end
  1788.   else
  1789.     inherited Assign(Source);
  1790. end;
  1791.  
  1792. function TVolgaColumn.CreateTitle: TVolgaColumnTitle;
  1793. begin
  1794.   Result := TVolgaColumnTitle.Create(Self);
  1795. end;
  1796.  
  1797. function TVolgaColumn.DefaultAlignment: TAlignment;
  1798. begin
  1799.   if Assigned(Field) then
  1800.     if (ButtonStyle = cbsCombo) or (ButtonStyle = cbsLookup) then
  1801.       Result := taLeftJustify
  1802.     else Result := FField.Alignment
  1803.   else
  1804.     Result := taLeftJustify;
  1805. end;
  1806.  
  1807. function TVolgaColumn.DefaultColor: TColor;
  1808. var
  1809.   Grid: TVolgaCustomDBGrid;
  1810. begin
  1811.   Grid := GetGrid;
  1812.   if Assigned(Grid) then
  1813.     Result := Grid.Color
  1814.   else
  1815.     Result := clWindow;
  1816. end;
  1817.  
  1818. function TVolgaColumn.DefaultFont: TFont;
  1819. var
  1820.   Grid: TVolgaCustomDBGrid;
  1821. begin
  1822.   Grid := GetGrid;
  1823.   if Assigned(Grid) then
  1824.     Result := Grid.Font
  1825.   else
  1826.     Result := FFont;
  1827. end;
  1828.  
  1829. function TVolgaColumn.DefaultImeMode: TImeMode;
  1830. var
  1831.   Grid: TVolgaCustomDBGrid;
  1832. begin
  1833.   Grid := GetGrid;
  1834.   if Assigned(Grid) then
  1835.     Result := Grid.ImeMode
  1836.   else
  1837.     Result := FImeMode;
  1838. end;
  1839.  
  1840. function TVolgaColumn.DefaultImeName: TImeName;
  1841. var
  1842.   Grid: TVolgaCustomDBGrid;
  1843. begin
  1844.   Grid := GetGrid;
  1845.   if Assigned(Grid) then
  1846.     Result := Grid.ImeName
  1847.   else
  1848.     Result := FImeName;
  1849. end;
  1850.  
  1851. function TVolgaColumn.DefaultReadOnly: Boolean;
  1852. var
  1853.   Grid: TVolgaCustomDBGrid;
  1854. begin
  1855.   Grid := GetGrid;
  1856.   Result := (Assigned(Grid) and Grid.ReadOnly) or
  1857.     (Assigned(Field) and FField.ReadOnly);
  1858. end;
  1859.  
  1860. function TVolgaColumn.DefaultWidth: Integer;
  1861. var
  1862.   W: Integer;
  1863.   RestoreCanvas: Boolean;
  1864.   TM: TTextMetric;
  1865. begin
  1866.   if GetGrid = nil then
  1867.   begin
  1868.     Result := 64;
  1869.     Exit;
  1870.   end;
  1871.   with GetGrid do
  1872.   begin
  1873.     if Assigned(Field) then
  1874.     begin
  1875.       RestoreCanvas := not HandleAllocated;
  1876.       if RestoreCanvas then
  1877.         Canvas.Handle := GetDC(0);
  1878.       try
  1879.         Canvas.Font := Self.Font;
  1880.         GetTextMetrics(Canvas.Handle, TM);
  1881.         Result := Field.DisplayWidth * (Canvas.TextWidth('0') - TM.tmOverhang)
  1882.           + TM.tmOverhang + 4;
  1883.         if dgTitles in Options then
  1884.         begin
  1885.           Canvas.Font := Title.Font;
  1886.           W := Canvas.TextWidth(Title.Caption) + 4;
  1887.           if Result < W then
  1888.             Result := W;
  1889.         end;
  1890.       finally
  1891.         if RestoreCanvas then
  1892.         begin
  1893.           ReleaseDC(0, Canvas.Handle);
  1894.           Canvas.Handle := 0;
  1895.         end;
  1896.       end;
  1897.     end
  1898.     else
  1899.       Result := DefaultColWidth;
  1900.   end;
  1901. end;
  1902.  
  1903. procedure TVolgaColumn.FontChanged;
  1904. begin
  1905.   Include(FAssignedValues, cvFont);
  1906.   Title.RefreshDefaultFont;
  1907.   Changed(False);
  1908. end;
  1909.  
  1910. function TVolgaColumn.GetAlignment: TAlignment;
  1911. begin
  1912.   if cvAlignment in FAssignedValues then
  1913.     Result := FAlignment
  1914.   else
  1915.     Result := DefaultAlignment;
  1916. end;
  1917.  
  1918. function TVolgaColumn.GetColor: TColor;
  1919. begin
  1920.   if cvColor in FAssignedValues then
  1921.     Result := FColor
  1922.   else
  1923.     Result := DefaultColor;
  1924. end;
  1925.  
  1926. function TVolgaColumn.GetExpanded: Boolean;
  1927. begin
  1928.   Result := FExpanded and Expandable;
  1929. end;
  1930.  
  1931. function TVolgaColumn.GetField: TField;
  1932. var
  1933.   Grid: TVolgaCustomDBGrid;
  1934. begin { Returns Nil if FieldName can't be found in dataset }
  1935.   Grid := GetGrid;
  1936.   if (FField = nil) and (Length(FFieldName) > 0) and Assigned(Grid) and
  1937.     Assigned(Grid.DataLink.DataSet) then
  1938.     with Grid.Datalink.Dataset do
  1939.       if Active or (not DefaultFields) then
  1940.         SetField(FindField(FieldName));
  1941.   Result := FField;
  1942. end;
  1943.  
  1944. function TVolgaColumn.GetFont: TFont;
  1945. var
  1946.   Save: TNotifyEvent;
  1947. begin
  1948.   if not (cvFont in FAssignedValues) and (FFont.Handle <> DefaultFont.Handle) then
  1949.   begin
  1950.     Save := FFont.OnChange;
  1951.     FFont.OnChange := nil;
  1952.     FFont.Assign(DefaultFont);
  1953.     FFont.OnChange := Save;
  1954.   end;
  1955.   Result := FFont;
  1956. end;
  1957.  
  1958. function TVolgaColumn.GetGrid: TVolgaCustomDBGrid;
  1959. begin
  1960.   if Assigned(Collection) and (Collection is TVolgaDBGridColumns) then
  1961.     Result := TVolgaDBGridColumns(Collection).Grid
  1962.   else
  1963.     Result := nil;
  1964. end;
  1965.  
  1966. function TVolgaColumn.GetDisplayName: string;
  1967. begin
  1968.   Result := FFieldName;
  1969.   if Result = '' then Result := inherited GetDisplayName;
  1970. end;
  1971.  
  1972. function TVolgaColumn.GetImeMode: TImeMode;
  1973. begin
  1974.   if cvImeMode in FAssignedValues then
  1975.     Result := FImeMode
  1976.   else
  1977.     Result := DefaultImeMode;
  1978. end;
  1979.  
  1980. function TVolgaColumn.GetImeName: TImeName;
  1981. begin
  1982.   if cvImeName in FAssignedValues then
  1983.     Result := FImeName
  1984.   else
  1985.     Result := DefaultImeName;
  1986. end;
  1987.  
  1988. function TVolgaColumn.GetParentColumn: TVolgaColumn;
  1989. var
  1990.   Col: TVolgaColumn;
  1991.   Fld: TField;
  1992.   I: Integer;
  1993. begin
  1994.   Result := nil;
  1995.   Fld := Field;
  1996.   if (Fld <> nil) and (Fld.ParentField <> nil) and (Collection <> nil) then
  1997.     for I := Index - 1 downto 0 do
  1998.     begin
  1999.       Col := TVolgaColumn(Collection.Items[I]);
  2000.       if Fld.ParentField = Col.Field then
  2001.       begin
  2002.         Result := Col;
  2003.         Exit;
  2004.       end;
  2005.     end;
  2006. end;
  2007.  
  2008. function TVolgaColumn.GetPickList: TStrings;
  2009. begin
  2010.   if FPickList = nil then
  2011.     FPickList := TStringList.Create;
  2012.   Result := FPickList;
  2013. end;
  2014.  
  2015. function TVolgaColumn.GetPickValues: TStrings; //Volga
  2016. begin
  2017.   if FPickValues = nil then
  2018.     FPickValues := TStringList.Create;
  2019.   Result := FPickValues;
  2020. end;                                      //Volga
  2021.  
  2022. function TVolgaColumn.GetReadOnly: Boolean;
  2023. begin
  2024.   if cvReadOnly in FAssignedValues then
  2025.     Result := FReadOnly
  2026.   else
  2027.     Result := DefaultReadOnly;
  2028. end;
  2029.  
  2030. function TVolgaColumn.GetShowing: Boolean;
  2031. var
  2032.   Col: TVolgaColumn;
  2033. begin
  2034.   Result := not Expanded and Visible;
  2035.   if Result then
  2036.   begin
  2037.     Col := Self;
  2038.     repeat
  2039.       Col := Col.ParentColumn;
  2040.     until (Col = nil) or not Col.Expanded;
  2041.     Result := Col = nil;
  2042.   end;
  2043. end;
  2044.  
  2045. function TVolgaColumn.GetVisible: Boolean;
  2046. var
  2047.   Col: TVolgaColumn;
  2048. begin
  2049.   Result := FVisible;
  2050.   if Result then
  2051.   begin
  2052.     Col := ParentColumn;
  2053.     Result := Result and ((Col = nil) or Col.Visible);
  2054.   end;
  2055. end;
  2056.  
  2057. function TVolgaColumn.GetWidth: Integer;
  2058. begin
  2059.   if not Showing then
  2060.     Result := -1
  2061.   else if cvWidth in FAssignedValues then
  2062.     Result := FWidth
  2063.   else
  2064.     Result := DefaultWidth;
  2065. end;
  2066.  
  2067. function TVolgaColumn.IsAlignmentStored: Boolean;
  2068. begin
  2069.   Result := (cvAlignment in FAssignedValues) and (FAlignment <> DefaultAlignment);
  2070. end;
  2071.  
  2072. function TVolgaColumn.IsColorStored: Boolean;
  2073. begin
  2074.   Result := (cvColor in FAssignedValues) and (FColor <> DefaultColor);
  2075. end;
  2076.  
  2077. function TVolgaColumn.IsFontStored: Boolean;
  2078. begin
  2079.   Result := (cvFont in FAssignedValues);
  2080. end;
  2081.  
  2082. function TVolgaColumn.IsImeModeStored: Boolean;
  2083. begin
  2084.   Result := (cvImeMode in FAssignedValues) and (FImeMode <> DefaultImeMode);
  2085. end;
  2086.  
  2087. function TVolgaColumn.IsImeNameStored: Boolean;
  2088. begin
  2089.   Result := (cvImeName in FAssignedValues) and (FImeName <> DefaultImeName);
  2090. end;
  2091.  
  2092. function TVolgaColumn.IsReadOnlyStored: Boolean;
  2093. begin
  2094.   Result := (cvReadOnly in FAssignedValues) and (FReadOnly <> DefaultReadOnly);
  2095. end;
  2096.  
  2097. function TVolgaColumn.IsWidthStored: Boolean;
  2098. begin
  2099.   Result := (cvWidth in FAssignedValues) and (FWidth <> DefaultWidth);
  2100. end;
  2101.  
  2102. procedure TVolgaColumn.RefreshDefaultFont;
  2103. var
  2104.   Save: TNotifyEvent;
  2105. begin
  2106.   if cvFont in FAssignedValues then Exit;
  2107.   Save := FFont.OnChange;
  2108.   FFont.OnChange := nil;
  2109.   try
  2110.     FFont.Assign(DefaultFont);
  2111.   finally
  2112.     FFont.OnChange := Save;
  2113.   end;
  2114. end;
  2115.  
  2116. procedure TVolgaColumn.RestoreDefaults;
  2117. var
  2118.   FontAssigned: Boolean;
  2119. begin
  2120.   FontAssigned := cvFont in FAssignedValues;
  2121.   FTitle.RestoreDefaults;
  2122.   FAssignedValues := [];
  2123.   RefreshDefaultFont;
  2124.   FPickList.Free;
  2125.   FPickList := nil;
  2126.   FPickValues.Free;                       //Volga
  2127.   FPickValues := nil;                     //Volga
  2128.   ButtonStyle := cbsNone;                 //Volga
  2129.   CanClick := false;                      //Volga
  2130.   LongTextAsHint := false;                //Volga
  2131.   Changed(FontAssigned);
  2132. end;
  2133.  
  2134. procedure TVolgaColumn.SetAlignment(Value: TAlignment);
  2135. var
  2136.   Grid: TVolgaCustomDBGrid;
  2137. begin
  2138.   if IsStored then
  2139.   begin
  2140.     if (cvAlignment in FAssignedValues) and (Value = FAlignment) then Exit;
  2141.     FAlignment := Value;
  2142.     Include(FAssignedValues, cvAlignment);
  2143.     Changed(False);
  2144.   end
  2145.   else
  2146.   begin
  2147.     Grid := GetGrid;
  2148.     if Assigned(Grid) and (Grid.Datalink.Active) and Assigned(Field)
  2149.     and (ButtonStyle <> cbsCombo) and (ButtonStyle <> cbsLookup) then  //Volga
  2150.       Field.Alignment := Value;
  2151.   end;
  2152. end;
  2153.  
  2154. procedure TVolgaColumn.SetButtonStyle(Value: TVolgaColumnButtonStyle);
  2155. begin
  2156.   if Value = FButtonStyle then Exit;
  2157.   FButtonStyle := Value;
  2158.   Changed(False);
  2159. end;
  2160.  
  2161. procedure TVolgaColumn.SetColor(Value: TColor);
  2162. begin
  2163.   if (cvColor in FAssignedValues) and (Value = FColor) then Exit;
  2164.   FColor := Value;
  2165.   Include(FAssignedValues, cvColor);
  2166.   Changed(False);
  2167. end;
  2168.  
  2169. procedure TVolgaColumn.SetField(Value: TField);
  2170. begin
  2171.   if FField = Value then Exit;
  2172.   FField := Value;
  2173.   if Assigned(Value) then
  2174.     FFieldName := Value.FullName;
  2175.   if not IsStored then
  2176.   begin
  2177.     if Value = nil then
  2178.       FFieldName := '';
  2179.     RestoreDefaults;
  2180.   end;
  2181.   Changed(False);
  2182. end;
  2183.  
  2184. procedure TVolgaColumn.SetFieldName(const Value: string);
  2185. var
  2186.   AField: TField;
  2187.   Grid: TVolgaCustomDBGrid;
  2188. begin
  2189.   AField := nil;
  2190.   Grid := GetGrid;
  2191.   if Assigned(Grid) and Assigned(Grid.DataLink.DataSet) and
  2192.     not (csLoading in Grid.ComponentState) and (Length(Value) > 0) then
  2193.     AField := Grid.DataLink.DataSet.FindField(Value); { no exceptions }
  2194.   FFieldName := Value;
  2195.   SetField(AField);
  2196.   Changed(False);
  2197. end;
  2198.  
  2199. procedure TVolgaColumn.SetFont(Value: TFont);
  2200. begin
  2201.   FFont.Assign(Value);
  2202.   Include(FAssignedValues, cvFont);
  2203.   Changed(False);
  2204. end;
  2205.  
  2206. procedure TVolgaColumn.SetImeMode(Value: TImeMode);
  2207. begin
  2208.   if (cvImeMode in FAssignedValues) or (Value <> DefaultImeMode) then
  2209.   begin
  2210.     FImeMode := Value;
  2211.     Include(FAssignedValues, cvImeMode);
  2212.   end;
  2213.   Changed(False);
  2214. end;
  2215.  
  2216. procedure TVolgaColumn.SetImeName(Value: TImeName);
  2217. begin
  2218.   if (cvImeName in FAssignedValues) or (Value <> DefaultImeName) then
  2219.   begin
  2220.     FImeName := Value;
  2221.     Include(FAssignedValues, cvImeName);
  2222.   end;
  2223.   Changed(False);
  2224. end;
  2225.  
  2226. procedure TVolgaColumn.SetIndex(Value: Integer);
  2227. var
  2228.   Grid: TVolgaCustomDBGrid;
  2229.   Fld: TField;
  2230.   I, OldIndex: Integer;
  2231.   Col: TVolgaColumn;
  2232. begin
  2233.   OldIndex := Index;
  2234.   Grid := GetGrid;
  2235.  
  2236.   if IsStored then
  2237.   begin
  2238.     Grid.BeginLayout;
  2239.     try
  2240.       I := OldIndex + 1;                  // move child columns along with parent
  2241.       while (I < Collection.Count) and (TVolgaColumn(Collection.Items[I]).ParentColumn =
  2242.         Self) do
  2243.         Inc(I);
  2244.       Dec(I);
  2245.       if OldIndex > Value then            // column moving left
  2246.       begin
  2247.         while I > OldIndex do
  2248.         begin
  2249.           Collection.Items[I].Index := Value;
  2250.           Inc(OldIndex);
  2251.         end;
  2252.         inherited SetIndex(Value);
  2253.       end
  2254.       else
  2255.       begin
  2256.         inherited SetIndex(Value);
  2257.         while I > OldIndex do
  2258.         begin
  2259.           Collection.Items[OldIndex].Index := Value;
  2260.           Dec(I);
  2261.         end;
  2262.       end;
  2263.     finally
  2264.       Grid.EndLayout;
  2265.     end;
  2266.   end
  2267.   else
  2268.   begin
  2269.     if (Grid <> nil) and Grid.Datalink.Active then
  2270.     begin
  2271.       if Grid.AcquireLayoutLock then
  2272.       try
  2273.         Col := Grid.ColumnAtDepth(Grid.Columns[Value], Depth);
  2274.         if (Col <> nil) then
  2275.         begin
  2276.           Fld := Col.Field;
  2277.           if Assigned(Fld) then
  2278.             Field.Index := Fld.Index;
  2279.         end;
  2280.       finally
  2281.         Grid.EndLayout;
  2282.       end;
  2283.     end;
  2284.     inherited SetIndex(Value);
  2285.   end;
  2286. end;
  2287.  
  2288. procedure TVolgaColumn.SetPickList(Value: TStrings);
  2289. begin
  2290.   if Value = nil then
  2291.   begin
  2292.     FPickList.Free;
  2293.     FPickList := nil;
  2294.     Exit;
  2295.   end;
  2296.   PickList.Assign(Value);
  2297. end;
  2298.  
  2299. procedure TVolgaColumn.SetPickValues(Value: TStrings); //Volga
  2300. begin
  2301.   if Value = nil then
  2302.   begin
  2303.     FPickValues.Free;
  2304.     FPickValues := nil;
  2305.     Exit;
  2306.   end;
  2307.   PickValues.Assign(Value);
  2308. end;                                      //Volga
  2309.  
  2310. procedure TVolgaColumn.SetPopupMenu(Value: TPopupMenu);
  2311. begin
  2312.   FPopupMenu := Value;
  2313.   if Value <> nil then Value.FreeNotification(GetGrid);
  2314. end;
  2315.  
  2316. procedure TVolgaColumn.SetReadOnly(Value: Boolean);
  2317. var
  2318.   Grid: TVolgaCustomDBGrid;
  2319. begin
  2320.   Grid := GetGrid;
  2321.   if not IsStored and Assigned(Grid) and Grid.Datalink.Active and Assigned(Field) then
  2322.     Field.ReadOnly := Value
  2323.   else
  2324.   begin
  2325.     if (cvReadOnly in FAssignedValues) and (Value = FReadOnly) then Exit;
  2326.     FReadOnly := Value;
  2327.     Include(FAssignedValues, cvReadOnly);
  2328.     Changed(False);
  2329.   end;
  2330. end;
  2331.  
  2332. procedure TVolgaColumn.SetTitle(Value: TVolgaColumnTitle);
  2333. begin
  2334.   FTitle.Assign(Value);
  2335. end;
  2336.  
  2337. procedure TVolgaColumn.SetWidth(Value: Integer);
  2338. var
  2339.   Grid: TVolgaCustomDBGrid;
  2340.   TM: TTextMetric;
  2341.   DoSetWidth: Boolean;
  2342. begin
  2343.   DoSetWidth := IsStored;
  2344.   if not DoSetWidth then
  2345.   begin
  2346.     Grid := GetGrid;
  2347.     if Assigned(Grid) then
  2348.     begin
  2349.       if Grid.HandleAllocated and Assigned(Field) and Grid.FUpdateFields then
  2350.         with Grid do
  2351.         begin
  2352.           Canvas.Font := Self.Font;
  2353.           GetTextMetrics(Canvas.Handle, TM);
  2354.           Field.DisplayWidth := (Value + (TM.tmAveCharWidth div 2) - TM.tmOverhang - 3)
  2355.             div TM.tmAveCharWidth;
  2356.         end;
  2357.       if (not Grid.FLayoutFromDataset) or (cvWidth in FAssignedValues) then
  2358.         DoSetWidth := True;
  2359.     end
  2360.     else
  2361.       DoSetWidth := True;
  2362.   end;
  2363.   if DoSetWidth then
  2364.   begin
  2365.     if ((cvWidth in FAssignedValues) or (Value <> DefaultWidth))
  2366.       and (Value <> -1) then
  2367.     begin
  2368.       FWidth := Value;
  2369.       Include(FAssignedValues, cvWidth);
  2370.     end;
  2371.     Changed(False);
  2372.   end;
  2373. end;
  2374.  
  2375. procedure TVolgaColumn.SetVisible(Value: Boolean);
  2376. begin
  2377.   if Value <> FVisible then
  2378.   begin
  2379.     FVisible := Value;
  2380.     Changed(True);
  2381.   end;
  2382. end;
  2383.  
  2384. procedure TVolgaColumn.SetExpanded(Value: Boolean);
  2385. const
  2386.   Direction: array[Boolean] of ShortInt = (-1, 1);
  2387. var
  2388.   Grid: TVolgaCustomDBGrid;
  2389.   WasShowing: Boolean;
  2390. begin
  2391.   if Value <> FExpanded then
  2392.   begin
  2393.     Grid := GetGrid;
  2394.     WasShowing := (Grid <> nil) and Grid.Columns[Grid.SelectedIndex].Showing;
  2395.     FExpanded := Value;
  2396.     Changed(True);
  2397.     if (Grid <> nil) and WasShowing then
  2398.     begin
  2399.       if not Grid.Columns[Grid.SelectedIndex].Showing then
  2400.         // The selected cell was hidden by this expand operation
  2401.         // Select 1st child (next col = 1) when parent is expanded
  2402.         // Select child's parent (prev col = -1) when parent is collapsed
  2403.         Grid.MoveCol(Grid.Col, Direction[FExpanded]);
  2404.     end;
  2405.   end;
  2406. end;
  2407.  
  2408. function TVolgaColumn.Depth: Integer;
  2409. var
  2410.   Col: TVolgaColumn;
  2411. begin
  2412.   Result := 0;
  2413.   Col := ParentColumn;
  2414.   if Col <> nil then Result := Col.Depth + 1;
  2415. end;
  2416.  
  2417. function TVolgaColumn.GetExpandable: Boolean;
  2418. var
  2419.   Fld: TField;
  2420. begin
  2421.   Fld := Field;
  2422.   Result := (Fld <> nil) and (Fld.DataType in [ftADT, ftArray]);
  2423. end;
  2424.  
  2425. procedure TVolgaColumn.SetValueChecked(const Value: string); //Volga
  2426. begin
  2427.   if Value <> FValueChecked then
  2428.   begin
  2429.     FValueChecked := Value;
  2430.     if ButtonStyle = cbsCheck then Changed(False);
  2431.   end;
  2432. end;  //Volga
  2433.  
  2434. procedure TVolgaColumn.SetValueUnChecked(const Value: string); //Volga
  2435. begin
  2436.   if Value <> FValueUnChecked then
  2437.   begin
  2438.     FValueUnChecked := Value;
  2439.     if ButtonStyle = cbsCheck then Changed(False);
  2440.   end;
  2441. end; //Volga
  2442.  
  2443. function TVolgaColumn.IsLinkActive: Boolean;
  2444. begin
  2445.   try
  2446.     Result := (LookupDataSet <> nil)
  2447.     and LookupDataSet.Active and (LookupLinkField > '') and
  2448.     (LookupDropDownFields > '') and (LookupKeyField > '');
  2449.   except Result := false; end;
  2450. end;
  2451.  
  2452. procedure TVolgaColumn.SetLookupDropDownFields(const Value: string);
  2453. begin
  2454.   if Value <> FLookupDropDownFields then
  2455.   begin
  2456.     FLookupDropDownFields := Value;
  2457.     if Pos(';',FLookupDropDownFields) > 0 then  //ΓΦΣΦ∞εσ ∩εδσ Γ±σπΣα ∩σ≡Γεσ Φτ ±∩Φ±Ωα!
  2458.       FViewField := Copy(FLookupDropDownFields,1,Pos(';',FLookupDropDownFields)-1)
  2459.     else
  2460.       FViewField := FLookupDropDownFields;
  2461.     if ButtonStyle = cbsLookup then Changed(False);
  2462.   end;
  2463. end;
  2464.  
  2465. procedure TVolgaColumn.SetLookupKeyField(const Value: string);
  2466. begin
  2467.   if Value <> FLookupKeyField then
  2468.   begin
  2469.     FLookupKeyField := Value;
  2470.     if ButtonStyle = cbsLookup then Changed(False);
  2471.   end;
  2472. end;
  2473.  
  2474. procedure TVolgaColumn.SetLookupLinkField(const Value: string);
  2475. begin
  2476.   if Value <> FLookupLinkField then
  2477.   begin
  2478.     FLookupLinkField := Value;
  2479.     if ButtonStyle = cbsLookup then Changed(False);
  2480.   end;
  2481. end;
  2482.  
  2483. procedure TVolgaColumn.SetLookupDataSet(const Value: TDataSet);
  2484. begin
  2485. //  CheckInactive;
  2486.   if (Value <> nil) and (Field <> nil) and (Value = Field.DataSet) then
  2487.     DatabaseError(V_LOOKUPSOURCEERROR, GetGrid);
  2488.   FLookupDataSet := Value;
  2489. end;
  2490.  
  2491. procedure TVolgaColumn.AssignList(const AList: TStrings);  //Volga
  2492. var i:integer;
  2493. begin //∩≡Φ±ΓεΦ≥ⁿ ±≡ατ≤ Items Φ Values Φτ ±∩Φ±Ωα ≥Φ∩α Name=Value
  2494.   if FPickList = nil then
  2495.     FPickList := TStringList.Create
  2496.   else FPickList.Clear;
  2497.   if FPickValues = nil then
  2498.     FPickValues := TStringList.Create
  2499.   else FPickValues.Clear;
  2500.   for i := 0 to AList.Count-1 do begin
  2501.     FPickList.Add(AList.Names[i]);
  2502.     FPickValues.Add(AList.Values[AList.Names[i]]);
  2503.   end;
  2504. end;
  2505.  
  2506. { TVolgaDBGridColumns }
  2507.  
  2508. constructor TVolgaDBGridColumns.Create(Grid: TVolgaCustomDBGrid; ColumnClass:
  2509.   TVolgaColumnClass);
  2510. begin
  2511.   inherited Create(Grid, ColumnClass);
  2512.   FGrid := Grid;
  2513. end;
  2514.  
  2515. //function TVolgaDBGridColumns.Add: TVolgaColumn;
  2516. //begin
  2517. //  Result := TVolgaColumn(inherited Add);
  2518. //end;
  2519.  
  2520. function TVolgaDBGridColumns.GetColumn(Index: Integer): TVolgaColumn;
  2521. begin
  2522.   Result := TVolgaColumn(inherited Items[Index]);
  2523. end;
  2524.  
  2525. function TVolgaDBGridColumns.GetOwner: TPersistent;
  2526. begin
  2527.   Result := FGrid;
  2528. end;
  2529.  
  2530. procedure TVolgaDBGridColumns.LoadFromFile(const Filename: string);
  2531. var
  2532.   S: TFileStream;
  2533. begin
  2534.   S := TFileStream.Create(Filename, fmOpenRead);
  2535.   try
  2536.     LoadFromStream(S);
  2537.   finally
  2538.     S.Free;
  2539.   end;
  2540. end;
  2541.  
  2542. type
  2543.   TVolgaColumnsWrapper = class(TComponent)
  2544.   private
  2545.     FColumns: TVolgaDBGridColumns;
  2546.   published
  2547.     property Columns: TVolgaDBGridColumns read FColumns write FColumns;
  2548.   end;
  2549.  
  2550. procedure TVolgaDBGridColumns.LoadFromStream(S: TStream);
  2551. var
  2552.   Wrapper: TVolgaColumnsWrapper;
  2553. begin
  2554.   Wrapper := TVolgaColumnsWrapper.Create(nil);
  2555.   try
  2556.     Wrapper.Columns := FGrid.CreateColumns;
  2557.     S.ReadComponent(Wrapper);
  2558.     Assign(Wrapper.Columns);
  2559.   finally
  2560.     Wrapper.Columns.Free;
  2561.     Wrapper.Free;
  2562.   end;
  2563. end;
  2564.  
  2565. procedure TVolgaDBGridColumns.RestoreDefaults;
  2566. var
  2567.   I: Integer;
  2568. begin
  2569.   BeginUpdate;
  2570.   try
  2571.     for I := 0 to Count - 1 do
  2572.       Items[I].RestoreDefaults;
  2573.   finally
  2574.     EndUpdate;
  2575.   end;
  2576. end;
  2577.  
  2578. procedure TVolgaDBGridColumns.RebuildColumns;
  2579.  
  2580.   procedure AddFields(Fields: TFields; Depth: Integer);
  2581.   var
  2582.     I: Integer;
  2583.   begin
  2584.     Inc(Depth);
  2585.     for I := 0 to Fields.Count - 1 do
  2586.     begin
  2587.       TVolgaColumn(Add).FieldName := Fields[I].FullName;
  2588.       if Fields[I].DataType in [ftADT, ftArray] then
  2589.         AddFields((Fields[I] as TObjectField).Fields, Depth);
  2590.     end;
  2591.   end;
  2592.  
  2593. begin
  2594.   if Assigned(FGrid) and Assigned(FGrid.DataSource) and
  2595.     Assigned(FGrid.Datasource.Dataset) then
  2596.   begin
  2597.     FGrid.BeginLayout;
  2598.     try
  2599.       Clear;
  2600.       AddFields(FGrid.Datasource.Dataset.Fields, 0);
  2601.     finally
  2602.       FGrid.EndLayout;
  2603.     end
  2604.   end
  2605.   else
  2606.     Clear;
  2607. end;
  2608.  
  2609. procedure TVolgaDBGridColumns.SaveToFile(const Filename: string);
  2610. var
  2611.   S: TStream;
  2612. begin
  2613.   S := TFileStream.Create(Filename, fmCreate);
  2614.   try
  2615.     SaveToStream(S);
  2616.   finally
  2617.     S.Free;
  2618.   end;
  2619. end;
  2620.  
  2621. procedure TVolgaDBGridColumns.SaveToStream(S: TStream);
  2622. var
  2623.   Wrapper: TVolgaColumnsWrapper;
  2624. begin
  2625.   Wrapper := TVolgaColumnsWrapper.Create(nil);
  2626.   try
  2627.     Wrapper.Columns := Self;
  2628.     S.WriteComponent(Wrapper);
  2629.   finally
  2630.     Wrapper.Free;
  2631.   end;
  2632. end;
  2633.  
  2634. procedure TVolgaDBGridColumns.SetColumn(Index: Integer; Value: TVolgaColumn);
  2635. begin
  2636.   Items[Index].Assign(Value);
  2637. end;
  2638.  
  2639. procedure TVolgaDBGridColumns.SetState(NewState: TVolgaDBGridColumnsState);
  2640. begin
  2641.   if NewState = State then Exit;
  2642.   if NewState = csDefault then
  2643.     Clear
  2644.   else
  2645.     RebuildColumns;
  2646. end;
  2647.  
  2648. procedure TVolgaDBGridColumns.Update(Item: TCollectionItem);
  2649. var
  2650.   Raw: Integer;
  2651. begin
  2652.   if (FGrid = nil) or (csLoading in FGrid.ComponentState) then Exit;
  2653.   if Item = nil then
  2654.   begin
  2655.     FGrid.LayoutChanged;
  2656.   end
  2657.   else
  2658.   begin
  2659.     Raw := FGrid.DataToRawColumn(Item.Index);
  2660.     FGrid.InvalidateCol(Raw);
  2661.     FGrid.ColWidths[Raw] := TVolgaColumn(Item).Width;
  2662.   end;
  2663. end;
  2664.  
  2665. function TVolgaDBGridColumns.InternalAdd: TVolgaColumn;
  2666. begin
  2667.   Result := TVolgaColumn(Add);
  2668.   Result.IsStored := False;
  2669. end;
  2670.  
  2671. function TVolgaDBGridColumns.GetState: TVolgaDBGridColumnsState;
  2672. begin
  2673.   Result := TVolgaDBGridColumnsState((Count > 0) and Items[0].IsStored);
  2674. end;
  2675.  
  2676. { TBookmarkList }
  2677.  
  2678. constructor TBookmarkList.Create(AGrid: TVolgaCustomDBGrid);
  2679. begin
  2680.   inherited Create;
  2681.   FList := TStringList.Create;
  2682.   FList.OnChange := StringsChanged;
  2683.   FGrid := AGrid;
  2684. end;
  2685.  
  2686. destructor TBookmarkList.Destroy;
  2687. begin
  2688.   Clear;
  2689.   FList.Free;
  2690.   inherited Destroy;
  2691. end;
  2692.  
  2693. procedure TBookmarkList.Clear;
  2694. begin
  2695.   if FList.Count = 0 then Exit;
  2696.   FList.Clear;
  2697.   FGrid.Invalidate;
  2698. end;
  2699.  
  2700. function TBookmarkList.Compare(const Item1, Item2: TBookmarkStr): Integer;
  2701. begin
  2702.   with FGrid.Datalink.Datasource.Dataset do
  2703.     Result := CompareBookmarks(TBookmark(Item1), TBookmark(Item2));
  2704. end;
  2705.  
  2706. function TBookmarkList.CurrentRow: TBookmarkStr;
  2707. begin
  2708.   if not FLinkActive then RaiseGridError(sDataSetClosed);
  2709.   Result := FGrid.Datalink.Datasource.Dataset.Bookmark;
  2710. end;
  2711.  
  2712. function TBookmarkList.GetCurrentRowSelected: Boolean;
  2713. var
  2714.   Index: Integer;
  2715. begin
  2716.   Result := Find(CurrentRow, Index);
  2717. end;
  2718.  
  2719. function TBookmarkList.Find(const Item: TBookmarkStr; var Index: Integer): Boolean;
  2720. var
  2721.   L, H, I, C: Integer;
  2722. begin
  2723.   if (Item = FCache) and (FCacheIndex >= 0) then
  2724.   begin
  2725.     Index := FCacheIndex;
  2726.     Result := FCacheFind;
  2727.     Exit;
  2728.   end;
  2729.   Result := False;
  2730.   L := 0;
  2731.   H := FList.Count - 1;
  2732.   while L <= H do
  2733.   begin
  2734.     I := (L + H) shr 1;
  2735.     C := Compare(FList[I], Item);
  2736.     if C < 0 then L := I + 1 else
  2737.     begin
  2738.       H := I - 1;
  2739.       if C = 0 then
  2740.       begin
  2741.         Result := True;
  2742.         L := I;
  2743.       end;
  2744.     end;
  2745.   end;
  2746.   Index := L;
  2747.   FCache := Item;
  2748.   FCacheIndex := Index;
  2749.   FCacheFind := Result;
  2750. end;
  2751.  
  2752. function TBookmarkList.GetCount: Integer;
  2753. begin
  2754.   Result := FList.Count;
  2755. end;
  2756.  
  2757. function TBookmarkList.GetItem(Index: Integer): TBookmarkStr;
  2758. begin
  2759.   Result := FList[Index];
  2760. end;
  2761.  
  2762. function TBookmarkList.IndexOf(const Item: TBookmarkStr): Integer;
  2763. begin
  2764.   if not Find(Item, Result) then
  2765.     Result := -1;
  2766. end;
  2767.  
  2768. procedure TBookmarkList.LinkActive(Value: Boolean);
  2769. begin
  2770.   Clear;
  2771.   FLinkActive := Value;
  2772. end;
  2773.  
  2774. procedure TBookmarkList.Delete;
  2775. var
  2776.   I: Integer;
  2777. begin
  2778.   with FGrid.Datalink.Datasource.Dataset do
  2779.   begin
  2780.     DisableControls;
  2781.     try
  2782.       for I := FList.Count - 1 downto 0 do
  2783.       begin
  2784.         Bookmark := FList[I];
  2785.         Delete;
  2786.         FList.Delete(I);
  2787.       end;
  2788.     finally
  2789.       EnableControls;
  2790.     end;
  2791.   end;
  2792. end;
  2793.  
  2794. function TBookmarkList.Refresh: Boolean;
  2795. var
  2796.   I: Integer;
  2797. begin
  2798.   Result := False;
  2799.   with FGrid.DataLink.Datasource.Dataset do
  2800.   try
  2801.     CheckBrowseMode;
  2802.     for I := FList.Count - 1 downto 0 do
  2803.       if not BookmarkValid(TBookmark(FList[I])) then
  2804.       begin
  2805.         Result := True;
  2806.         FList.Delete(I);
  2807.       end;
  2808.   finally
  2809.     UpdateCursorPos;
  2810.     if Result then FGrid.Invalidate;
  2811.   end;
  2812. end;
  2813.  
  2814. procedure TBookmarkList.SetCurrentRowSelected(Value: Boolean);
  2815. var
  2816.   Index: Integer;
  2817.   Current: TBookmarkStr;
  2818. begin
  2819.   Current := CurrentRow;
  2820.   if (Length(Current) = 0) or (Find(Current, Index) = Value) then Exit;
  2821.   if Value then
  2822.     FList.Insert(Index, Current)
  2823.   else
  2824.     FList.Delete(Index);
  2825.   FGrid.InvalidateRow(FGrid.Row);
  2826. end;
  2827.  
  2828. procedure TBookmarkList.StringsChanged(Sender: TObject);
  2829. begin
  2830.   FCache := '';
  2831.   FCacheIndex := -1;
  2832. end;
  2833.  
  2834. { TVolgaCustomDBGrid }
  2835.  
  2836. var
  2837.   DrawBitmap: TBitmap;
  2838.   UserCount: Integer;
  2839.  
  2840. procedure UsesBitmap;
  2841. begin
  2842.   if UserCount = 0 then
  2843.     DrawBitmap := TBitmap.Create;
  2844.   Inc(UserCount);
  2845. end;
  2846.  
  2847. procedure ReleaseBitmap;
  2848. begin
  2849.   Dec(UserCount);
  2850.   if UserCount = 0 then DrawBitmap.Free;
  2851. end;
  2852.  
  2853. procedure WriteText(ACanvas: TCanvas; ARect: TRect; DX, DY: Integer;
  2854.   const Text: string; Alignment: TAlignment; ARightToLeft: Boolean);
  2855. const
  2856.   AlignFlags: array[TAlignment] of Integer =
  2857.     (DT_LEFT or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX,
  2858.     DT_RIGHT or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX,
  2859.     DT_CENTER or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX);
  2860.   RTL: array[Boolean] of Integer = (0, DT_RTLREADING);
  2861. var
  2862.   B, R: TRect;
  2863.   Hold, Left: Integer;
  2864.   I: TColorRef;
  2865. begin
  2866.   I := ColorToRGB(ACanvas.Brush.Color);
  2867.   if GetNearestColor(ACanvas.Handle, I) = I then
  2868.   begin                                   { Use ExtTextOut for solid colors }
  2869.     { In BiDi, because we changed the window origin, the text that does not
  2870.       change alignment, actually gets its alignment changed. }
  2871.     if (ACanvas.CanvasOrientation = coRightToLeft) and (not ARightToLeft) then
  2872.       ChangeBiDiModeAlignment(Alignment);
  2873.     case Alignment of
  2874.       taLeftJustify:
  2875.         Left := ARect.Left + DX;
  2876.       taRightJustify:
  2877.         Left := ARect.Right - ACanvas.TextWidth(Text) - 3;
  2878.     else                                  { taCenter }
  2879.       Left := ARect.Left + (ARect.Right - ARect.Left) shr 1
  2880.         - (ACanvas.TextWidth(Text) shr 1);
  2881.     end;
  2882.     ACanvas.TextRect(ARect, Left, ARect.Top + DY, Text);
  2883.   end
  2884.   else begin { Use FillRect and Drawtext for dithered colors }
  2885.     DrawBitmap.Canvas.Lock;
  2886.     try
  2887.       with DrawBitmap, ARect do { Use offscreen bitmap to eliminate flicker and }
  2888.       begin { brush origin tics in painting / scrolling.    }
  2889.         Width := Max(Width, Right - Left);
  2890.         Height := Max(Height, Bottom - Top);
  2891.         R := Rect(DX, DY, Right - Left - 1, Bottom - Top - 1);
  2892.         B := Rect(0, 0, Right - Left, Bottom - Top);
  2893.       end;
  2894.       with DrawBitmap.Canvas do
  2895.       begin
  2896.         Font := ACanvas.Font;
  2897.         Font.Color := ACanvas.Font.Color;
  2898.         Brush := ACanvas.Brush;
  2899.         Brush.Style := bsSolid;
  2900.         FillRect(B);
  2901.         SetBkMode(Handle, TRANSPARENT);
  2902.         if (ACanvas.CanvasOrientation = coRightToLeft) then
  2903.           ChangeBiDiModeAlignment(Alignment);
  2904.         DrawText(Handle, PChar(Text), Length(Text), R,
  2905.           AlignFlags[Alignment] or RTL[ARightToLeft]);
  2906.       end;
  2907.       if (ACanvas.CanvasOrientation = coRightToLeft) then
  2908.       begin
  2909.         Hold := ARect.Left;
  2910.         ARect.Left := ARect.Right;
  2911.         ARect.Right := Hold;
  2912.       end;
  2913.       ACanvas.CopyRect(ARect, DrawBitmap.Canvas, B);
  2914.     finally
  2915.       DrawBitmap.Canvas.Unlock;
  2916.     end;
  2917.   end;
  2918. end;
  2919.  
  2920. constructor TVolgaCustomDBGrid.Create(AOwner: TComponent);
  2921. var
  2922.   Bmp: TBitmap;
  2923. begin
  2924.   inherited Create(AOwner);
  2925.   inherited DefaultDrawing := False;
  2926.   FAcquireFocus := True;
  2927.   Bmp := TBitmap.Create;
  2928.   try
  2929.     Bmp.LoadFromResourceName(HInstance, bmArrow);
  2930.     FIndicators := TImageList.CreateSize(Bmp.Width, Bmp.Height);
  2931.     FIndicators.AddMasked(Bmp, clWhite);
  2932.     Bmp.LoadFromResourceName(HInstance, bmEdit);
  2933.     FIndicators.AddMasked(Bmp, clWhite);
  2934.     Bmp.LoadFromResourceName(HInstance, bmInsert);
  2935.     FIndicators.AddMasked(Bmp, clWhite);
  2936.     Bmp.LoadFromResourceName(HInstance, bmMultiDot);
  2937.     FIndicators.AddMasked(Bmp, clWhite);
  2938.     Bmp.LoadFromResourceName(HInstance, bmMultiArrow);
  2939.     FIndicators.AddMasked(Bmp, clWhite);
  2940.   finally
  2941.     Bmp.Free;
  2942.   end;
  2943.   FTitleOffset := 1;
  2944.   FIndicatorOffset := 1;
  2945.   FUpdateFields := True;
  2946.   FAllowDelete := True;   //Volga
  2947.   FAllowInsert := True;   //Volga
  2948.   FOptions := [dgEditing, dgTitles, dgIndicator, dgColumnResize,
  2949.     dgColLines, dgRowLines, dgTabs, dgConfirmDelete, dgCancelOnExit];
  2950.   if SysLocale.PriLangID = LANG_KOREAN then
  2951.     Include(FOptions, dgAlwaysShowEditor);
  2952.   DesignOptionsBoost := [goColSizing];
  2953.   VirtualView := True;
  2954.   UsesBitmap;
  2955.   ScrollBars := ssHorizontal;
  2956.   inherited Options := [goFixedHorzLine, goFixedVertLine, goHorzLine,
  2957.     goVertLine, goColSizing, goColMoving, goTabs, goEditing];
  2958.   FColumns := CreateColumns;
  2959.   FVisibleColumns := TList.Create;
  2960.   inherited RowCount := 2;
  2961.   inherited ColCount := 2;
  2962.   FDataLink := TGridDataLink.Create(Self);
  2963.   Color := clWindow;
  2964.   FSelectedColor := clHighlight;         //volga
  2965.   FSelectedFontColor := clHighlightText; //volga
  2966.   ParentColor := False;
  2967.   FTitleFont := TFont.Create;
  2968.   FTitleFont.OnChange := TitleFontChanged;
  2969.   FSaveCellExtents := False;
  2970.   FUserChange := True;
  2971.   FDefaultDrawing := True;
  2972.   FBookmarks := TBookmarkList.Create(Self);
  2973.   HideEditor;
  2974. end;
  2975.  
  2976. destructor TVolgaCustomDBGrid.Destroy;
  2977. begin
  2978.   FColumns.Free;
  2979.   FColumns := nil;
  2980.   FVisibleColumns.Free;
  2981.   FVisibleColumns := nil;
  2982.   FDataLink.Free;
  2983.   FDataLink := nil;
  2984.   FIndicators.Free;
  2985.   FTitleFont.Free;
  2986.   FTitleFont := nil;
  2987.   FBookmarks.Free;
  2988.   FBookmarks := nil;
  2989.   inherited Destroy;
  2990.   ReleaseBitmap;
  2991. end;
  2992.  
  2993. function TVolgaCustomDBGrid.AcquireFocus: Boolean;
  2994. begin
  2995.   Result := True;
  2996.   if FAcquireFocus and CanFocus and not (csDesigning in ComponentState) then
  2997.   begin
  2998.     SetFocus;
  2999.     Result := Focused or (InplaceEditor <> nil) and InplaceEditor.Focused;
  3000.   end;
  3001. end;
  3002.  
  3003. function TVolgaCustomDBGrid.RawToDataColumn(ACol: Integer): Integer;
  3004. begin
  3005.   Result := ACol - FIndicatorOffset;
  3006. end;
  3007.  
  3008. function TVolgaCustomDBGrid.DataToRawColumn(ACol: Integer): Integer;
  3009. begin
  3010.   Result := ACol + FIndicatorOffset;
  3011. end;
  3012.  
  3013. function TVolgaCustomDBGrid.AcquireLayoutLock: Boolean;
  3014. begin
  3015.   Result := (FUpdateLock = 0) and (FLayoutLock = 0);
  3016.   if Result then BeginLayout;
  3017. end;
  3018.  
  3019. procedure TVolgaCustomDBGrid.BeginLayout;
  3020. begin
  3021.   BeginUpdate;
  3022.   if FLayoutLock = 0 then Columns.BeginUpdate;
  3023.   Inc(FLayoutLock);
  3024. end;
  3025.  
  3026. procedure TVolgaCustomDBGrid.BeginUpdate;
  3027. begin
  3028.   Inc(FUpdateLock);
  3029. end;
  3030.  
  3031. procedure TVolgaCustomDBGrid.CancelLayout;
  3032. begin
  3033.   if FLayoutLock > 0 then
  3034.   begin
  3035.     if FLayoutLock = 1 then
  3036.       Columns.EndUpdate;
  3037.     Dec(FLayoutLock);
  3038.     EndUpdate;
  3039.   end;
  3040. end;
  3041.  
  3042. function TVolgaCustomDBGrid.CanEditAcceptKey(Key: Char): Boolean;
  3043. begin
  3044.   with Columns[SelectedIndex] do
  3045.     Result := FDatalink.Active and Assigned(Field) and Field.IsValidChar(Key);
  3046. end;
  3047.  
  3048. function TVolgaCustomDBGrid.CanEditModify: Boolean;
  3049. begin
  3050.   Result := False;
  3051.   if not ReadOnly and FDatalink.Active and not FDatalink.Readonly then
  3052.     with Columns[SelectedIndex] do
  3053.       if (not ReadOnly) and Assigned(Field) and
  3054.         //Volga - Σασ∞ ≡σΣαΩ≥Φ≡εΓα≥ⁿ Γ√≈Φ±δ σ∞√σ ∩εδ 
  3055.         (Field.CanModify or (FDatalink.DataSet.CanModify and (Field.FieldKind = fkCalculated)))
  3056.         and (not (Field.DataType in ftNonTextTypes) or Assigned(Field.OnSetText)) then
  3057.       begin
  3058.         FDatalink.Edit;
  3059.         Result := FDatalink.Editing;
  3060.         if Result then FDatalink.Modified;
  3061.       end;
  3062. end;
  3063.  
  3064. function TVolgaCustomDBGrid.CanEditShow: Boolean;
  3065. begin
  3066.   Result := (LayoutLock = 0) and inherited CanEditShow;
  3067. end;
  3068.  
  3069. procedure TVolgaCustomDBGrid.CellClick(Column: TVolgaColumn);
  3070. begin
  3071.   if not (csDesigning in ComponentState) and Column.LongTextAsHint //Volga
  3072.   and Assigned(Column.Field) then begin                            //Volga
  3073.     //ΩεδεφΩα Σεδµφα ∩εΩατ√Γα≥ⁿ ⌡Φφ≥?                              //Volga
  3074.     Application.CancelHint;                                        //Volga
  3075.     Hint := Column.Field.Text;                                     //Volga
  3076.   end;                                                             //Volga
  3077.   if Assigned(FOnCellClick) then FOnCellClick(Self, Column);
  3078. end;
  3079.  
  3080. procedure TVolgaCustomDBGrid.ColEnter;
  3081. begin
  3082.   UpdateIme;
  3083.   if Assigned(FOnColEnter) then FOnColEnter(Self);
  3084. end;
  3085.  
  3086. procedure TVolgaCustomDBGrid.ColExit;
  3087. begin
  3088.   if Assigned(FOnColExit) then FOnColExit(Self);
  3089. end;
  3090.  
  3091. procedure TVolgaCustomDBGrid.ColumnMoved(FromIndex, ToIndex: Longint);
  3092. begin
  3093.   FromIndex := RawToDataColumn(FromIndex);
  3094.   ToIndex := RawToDataColumn(ToIndex);
  3095.   Columns[FromIndex].Index := ToIndex;
  3096.   if Assigned(FOnColumnMoved) then FOnColumnMoved(Self, FromIndex, ToIndex);
  3097. end;
  3098.  
  3099. procedure TVolgaCustomDBGrid.ColWidthsChanged;
  3100. var
  3101.   I: Integer;
  3102. begin
  3103.   inherited ColWidthsChanged;
  3104.   if (FDatalink.Active or (FColumns.State = csCustomized)) and
  3105.     AcquireLayoutLock then
  3106.   try
  3107.     for I := FIndicatorOffset to ColCount - 1 do
  3108.       FColumns[I - FIndicatorOffset].Width := ColWidths[I];
  3109.   finally
  3110.     EndLayout;
  3111.   end;
  3112. end;
  3113.  
  3114. function TVolgaCustomDBGrid.CreateColumns: TVolgaDBGridColumns;
  3115. begin
  3116.   Result := TVolgaDBGridColumns.Create(Self, TVolgaColumn);
  3117. end;
  3118.  
  3119. function TVolgaCustomDBGrid.CreateEditor: TInplaceEdit;
  3120. begin
  3121.   Result := TVolgaDBGridInplaceEdit.Create(Self);
  3122. end;
  3123.  
  3124. procedure TVolgaCustomDBGrid.CreateWnd;
  3125. begin
  3126.   BeginUpdate; { prevent updates in WMSize message that follows WMCreate }
  3127.   try
  3128.     inherited CreateWnd;
  3129.   finally
  3130.     EndUpdate;
  3131.   end;
  3132.   UpdateRowCount;
  3133.   UpdateActive;
  3134.   UpdateScrollBar;
  3135.   FOriginalImeName := ImeName;
  3136.   FOriginalImeMode := ImeMode;
  3137. end;
  3138.  
  3139. procedure TVolgaCustomDBGrid.DataChanged;
  3140. begin
  3141.   if not HandleAllocated then Exit;
  3142.   UpdateRowCount;
  3143.   UpdateScrollBar;
  3144.   UpdateActive;
  3145.   InvalidateEditor;
  3146.   ValidateRect(Handle, nil);
  3147.   Invalidate;
  3148. end;
  3149.  
  3150. procedure TVolgaCustomDBGrid.DefaultHandler(var Msg);
  3151. var
  3152.   P: TPopupMenu;
  3153.   Cell: TGridCoord;
  3154. begin
  3155.   inherited DefaultHandler(Msg);
  3156.   if TMessage(Msg).Msg = wm_RButtonUp then
  3157.     with TWMRButtonUp(Msg) do
  3158.     begin
  3159.       Cell := MouseCoord(XPos, YPos);
  3160.       if (Cell.X < FIndicatorOffset) or (Cell.Y < 0) then Exit;
  3161.       P := Columns[RawToDataColumn(Cell.X)].PopupMenu;
  3162.       if (P <> nil) and P.AutoPopup then
  3163.       begin
  3164.         SendCancelMode(nil);
  3165.         P.PopupComponent := Self;
  3166.         with ClientToScreen(SmallPointToPoint(Pos)) do
  3167.           P.Popup(X, Y);
  3168.         Result := 1;
  3169.       end;
  3170.     end;
  3171. end;
  3172.  
  3173. procedure TVolgaCustomDBGrid.DeferLayout;
  3174. var
  3175.   M: TMsg;
  3176. begin
  3177.   if HandleAllocated and
  3178.     not PeekMessage(M, Handle, cm_DeferLayout, cm_DeferLayout, pm_NoRemove) then
  3179.     PostMessage(Handle, cm_DeferLayout, 0, 0);
  3180.   CancelLayout;
  3181. end;
  3182.  
  3183. procedure TVolgaCustomDBGrid.DefineFieldMap;
  3184. var
  3185.   I: Integer;
  3186. begin
  3187.   if FColumns.State = csCustomized then
  3188.   begin { Build the column/field map from the column attributes }
  3189.     DataLink.SparseMap := True;
  3190.     for I := 0 to FColumns.Count - 1 do
  3191.       FDataLink.AddMapping(FColumns[I].FieldName);
  3192.   end
  3193.   else { Build the column/field map from the field list order }
  3194.   begin
  3195.     FDataLink.SparseMap := False;
  3196.     with Datalink.Dataset do
  3197.       for I := 0 to FieldList.Count - 1 do
  3198.         with FieldList[I] do if Visible then Datalink.AddMapping(FullName);
  3199.   end;
  3200. end;
  3201.  
  3202. function TVolgaCustomDBGrid.UseRightToLeftAlignmentForField(const AField: TField;
  3203.   Alignment: TAlignment): Boolean;
  3204. begin
  3205.   Result := False;
  3206.   if IsRightToLeft then
  3207.     Result := OkToChangeFieldAlignment(AField, Alignment);
  3208. end;
  3209.  
  3210. procedure TVolgaCustomDBGrid.DefaultDrawDataCell(const Rect: TRect; Field: TField;
  3211.   State: TGridDrawState);
  3212. var
  3213.   Alignment: TAlignment;
  3214.   Value: string;
  3215. begin
  3216.   Alignment := taLeftJustify;
  3217.   Value := '';
  3218.   if Assigned(Field) then
  3219.   begin
  3220.     Alignment := Field.Alignment;
  3221.     Value := Field.DisplayText;
  3222.   end;
  3223.   WriteText(Canvas, Rect, 2, 2, Value, Alignment,
  3224.     UseRightToLeftAlignmentForField(Field, Alignment));
  3225. end;
  3226.  
  3227. procedure TVolgaCustomDBGrid.DefaultDrawColumnCell(const Rect: TRect;
  3228.   DataCol: Integer; Column: TVolgaColumn; State: TGridDrawState);
  3229. var
  3230.   Value: string;
  3231. begin
  3232.   Value := '';
  3233.   if Assigned(Column.Field) then
  3234.     Value := Column.Field.DisplayText;
  3235.   WriteText(Canvas, Rect, 2, 2, Value, Column.Alignment,
  3236.     UseRightToLeftAlignmentForField(Column.Field, Column.Alignment));
  3237. end;
  3238.  
  3239. procedure TVolgaCustomDBGrid.ReadColumns(Reader: TReader);
  3240. begin
  3241.   Columns.Clear;
  3242.   Reader.ReadValue;
  3243.   Reader.ReadCollection(Columns);
  3244. end;
  3245.  
  3246. procedure TVolgaCustomDBGrid.WriteColumns(Writer: TWriter);
  3247. begin
  3248.   Writer.WriteCollection(Columns);
  3249. end;
  3250.  
  3251. procedure TVolgaCustomDBGrid.DefineProperties(Filer: TFiler);
  3252. begin
  3253.   Filer.DefineProperty('Columns', ReadColumns, WriteColumns,
  3254.     ((Columns.State = csCustomized) and (Filer.Ancestor = nil)) or
  3255.     ((Filer.Ancestor <> nil) and
  3256.     ((Columns.State <> TVolgaCustomDBGrid(Filer.Ancestor).Columns.State) or
  3257. {$IFDEF VER140}
  3258.     (not CollectionsEqual(Columns, TVolgaCustomDBGrid(Filer.Ancestor).Columns,
  3259.      Self.Owner, TVolgaCustomDBGrid(Filer.Ancestor).Columns.FGrid.Owner)))));
  3260. {$ELSE}
  3261.     (not CollectionsEqual(Columns, TVolgaCustomDBGrid(Filer.Ancestor).Columns)))));
  3262. {$ENDIF}
  3263. end;
  3264.  
  3265. function TVolgaCustomDBGrid.ColumnAtDepth(Col: TVolgaColumn; ADepth: Integer): TVolgaColumn;
  3266. begin
  3267.   Result := Col;
  3268.   while (Result <> nil) and (Result.Depth > ADepth) do
  3269.     Result := Result.ParentColumn;
  3270. end;
  3271.  
  3272. function TVolgaCustomDBGrid.CalcTitleRect(Col: TVolgaColumn; ARow: Integer;
  3273.   var MasterCol: TVolgaColumn): TRect;
  3274. var
  3275.   I, J: Integer;
  3276.   InBiDiMode: Boolean;
  3277.   DrawInfo: TGridDrawInfo;
  3278. begin
  3279.   MasterCol := ColumnAtDepth(Col, ARow);
  3280.   if MasterCol = nil then Exit;
  3281.  
  3282.   I := DataToRawColumn(MasterCol.Index);
  3283.   if I >= LeftCol then
  3284.     J := MasterCol.Depth
  3285.   else
  3286.   begin
  3287.     I := LeftCol;
  3288.     if Col.Depth > ARow then
  3289.       J := ARow
  3290.     else
  3291.       J := Col.Depth;
  3292.   end;
  3293.  
  3294.   Result := CellRect(I, J);
  3295.  
  3296.   InBiDiMode := UseRightToLeftAlignment and
  3297.     (Canvas.CanvasOrientation = coLeftToRight);
  3298.  
  3299.   for I := Col.Index to Columns.Count - 1 do
  3300.   begin
  3301.     if ColumnAtDepth(Columns[I], ARow) <> MasterCol then Break;
  3302.     if not InBiDiMode then
  3303.     begin
  3304.       J := CellRect(DataToRawColumn(I), ARow).Right;
  3305.       if J = 0 then Break;
  3306.       Result.Right := Max(Result.Right, J);
  3307.     end
  3308.     else
  3309.     begin
  3310.       J := CellRect(DataToRawColumn(I), ARow).Left;
  3311.       if J >= ClientWidth then Break;
  3312.       Result.Left := J;
  3313.     end;
  3314.   end;
  3315.   J := Col.Depth;
  3316.   if (J <= ARow) and (J < FixedRows - 1) then
  3317.   begin
  3318.     CalcFixedInfo(DrawInfo);
  3319.     Result.Bottom := DrawInfo.Vert.FixedBoundary - DrawInfo.Vert.EffectiveLineWidth;
  3320.   end;
  3321. end;
  3322.  
  3323. procedure TVolgaCustomDBGrid.DrawCell(ACol, ARow: Longint; ARect: TRect; AState:
  3324.   TGridDrawState);
  3325. var
  3326.   FrameOffs: Byte;
  3327.  
  3328.   function RowIsMultiSelected: Boolean;
  3329.   var
  3330.     Index: Integer;
  3331.   begin
  3332.     Result := (dgMultiSelect in Options) and Datalink.Active and
  3333.       FBookmarks.Find(Datalink.Datasource.Dataset.Bookmark, Index);
  3334.   end;
  3335.  
  3336.   procedure DrawTitleCell(ACol, ARow: Integer; Column: TVolgaColumn; var AState:
  3337.     TGridDrawState);
  3338.   const
  3339.     ScrollArrows: array[Boolean, Boolean] of Integer =
  3340.       ((DFCS_SCROLLRIGHT, DFCS_SCROLLLEFT), (DFCS_SCROLLLEFT, DFCS_SCROLLRIGHT));
  3341.   var
  3342.     MasterCol: TVolgaColumn;
  3343.     TitleRect, TextRect, ButtonRect: TRect;
  3344.     I: Integer;
  3345.     InBiDiMode: Boolean;
  3346.     AFont: TFont;    //Volga
  3347.     AColor: TColor;  //Volga
  3348.   begin
  3349.     TitleRect := CalcTitleRect(Column, ARow, MasterCol);
  3350.  
  3351.     if MasterCol = nil then
  3352.     begin
  3353.       Canvas.FillRect(ARect);
  3354.       Exit;
  3355.     end;
  3356.  
  3357.     AFont := MasterCol.Title.Font;   //Volga
  3358.     AColor := MasterCol.Title.Color; //Volga
  3359.     if Assigned(FOnDrawTitleAttr) then FOnDrawTitleAttr(Self, MasterCol, AFont, AColor); //Volga
  3360.     Canvas.Font := AFont;            //Volga
  3361.     Canvas.Brush.Color := AColor;    //Volga
  3362.     if [dgRowLines, dgColLines] * Options = [dgRowLines, dgColLines] then
  3363.       InflateRect(TitleRect, -1, -1);
  3364.     TextRect := TitleRect;
  3365.     I := GetSystemMetrics(SM_CXHSCROLL);
  3366.     if ((TextRect.Right - TextRect.Left) > I) and MasterCol.Expandable then
  3367.     begin
  3368.       Dec(TextRect.Right, I);
  3369.       ButtonRect := TitleRect;
  3370.       ButtonRect.Left := TextRect.Right;
  3371.       I := SaveDC(Canvas.Handle);
  3372.       try
  3373.         Canvas.FillRect(ButtonRect);
  3374.         InflateRect(ButtonRect, -1, -1);
  3375.         IntersectClipRect(Canvas.Handle, ButtonRect.Left,
  3376.           ButtonRect.Top, ButtonRect.Right, ButtonRect.Bottom);
  3377.         InflateRect(ButtonRect, 1, 1);
  3378.         { DrawFrameControl doesn't draw properly when orienatation has changed.
  3379.           It draws as ExtTextOut does. }
  3380.         InBiDiMode := Canvas.CanvasOrientation = coRightToLeft;
  3381.         if InBiDiMode then                { stretch the arrows box }
  3382.           Inc(ButtonRect.Right, GetSystemMetrics(SM_CXHSCROLL) + 4);
  3383.         DrawFrameControl(Canvas.Handle, ButtonRect, DFC_SCROLL,
  3384.           ScrollArrows[InBiDiMode, MasterCol.Expanded] or DFCS_FLAT);
  3385.       finally
  3386.         RestoreDC(Canvas.Handle, I);
  3387.       end;
  3388.     end;
  3389.     with MasterCol.Title do
  3390.       if MasterCol.Down then              //Volga
  3391.         WriteText(Canvas, TextRect, FrameOffs + 1, FrameOffs + 1, Caption, Alignment,  //Volga
  3392.           IsRightToLeft)                  //Volga
  3393.       else
  3394.         WriteText(Canvas, TextRect, FrameOffs, FrameOffs, Caption, Alignment,
  3395.           IsRightToLeft);
  3396.     if [dgRowLines, dgColLines] * Options = [dgRowLines, dgColLines] then
  3397.     begin
  3398.       InflateRect(TitleRect, 1, 1);
  3399.       if MasterCol.Down then begin        //Volga ταπεδεΓεΩ φαµα≥!!
  3400.         DrawEdge(Canvas.Handle, TitleRect, BDR_SUNKENINNER, BF_BOTTOMRIGHT);
  3401.         DrawEdge(Canvas.Handle, TitleRect, BDR_SUNKENINNER, BF_TOPLEFT);
  3402.       end else begin
  3403.         DrawEdge(Canvas.Handle, TitleRect, BDR_RAISEDINNER, BF_BOTTOMRIGHT);
  3404.         DrawEdge(Canvas.Handle, TitleRect, BDR_RAISEDINNER, BF_TOPLEFT);
  3405.       end;
  3406.     end;
  3407.     AState := AState - [gdFixed];         // prevent box drawing later
  3408.   end;
  3409.  
  3410.   procedure DrawCheckBoxColumn(ARect:TRect; Column: TVolgaColumn;
  3411.     AState: TGridDrawState; Value: string);  //Volga
  3412.   var CRect: TRect; h,l,t:integer;
  3413.   begin
  3414.     Canvas.FillRect(ARect);  //τα∩εδφ σ∞ ⌠εφ, σ±δΦ Ωδσ≥Ωα Γ√Σσδσφα, ≥ε Γ√Σσδσφφ√∞ ÷Γσ≥ε∞
  3415.     h := ARect.Bottom - ARect.Top - 4;  //Γ√±ε≥α ≈σΩßεΩ±α
  3416.     if h > (ARect.Right - ARect.Left - 2) then h := ARect.Right - ARect.Left - 4;
  3417.     l := (ARect.Right - ARect.Left - h) div 2;  //ε≥±≥≤∩ ε≥ δσΓεπε Ω≡α 
  3418.     t := (ARect.Bottom - ARect.Top - h) div 2;  //ε≥±≥≤∩ ε≥ Γσ≡⌡φσπε Ω≡α 
  3419.     CRect := Rect(ARect.Left+l, ARect.Top+t, ARect.Right-l, ARect.Bottom-t);
  3420.     if Value = Column.ValueChecked then //≡Φ±≤σ∞ Ω≡σ±≥ΦΩ
  3421.       DrawFrameControl(Canvas.Handle, CRect, DFC_BUTTON, DFCS_BUTTONCHECK or DFCS_CHECKED)
  3422.     else
  3423.       DrawFrameControl(Canvas.Handle, CRect, DFC_BUTTON, DFCS_BUTTONCHECK);
  3424.   end;                                      //Volga
  3425.  
  3426. var
  3427.   OldActive: Integer;
  3428.   Indicator: Integer;
  3429.   Highlight: Boolean;
  3430.   Value: string;
  3431.   VarValue: Variant;
  3432.   DrawColumn: TVolgaColumn;
  3433.   MultiSelected: Boolean;
  3434.   ALeft: Integer;
  3435.   ind: integer;    //Volga
  3436.   AFont: TFont;    //Volga
  3437.   AColor: TColor;  //Volga
  3438. begin
  3439.   if csLoading in ComponentState then
  3440.   begin
  3441.     Canvas.Brush.Color := Color;
  3442.     Canvas.FillRect(ARect);
  3443.     Exit;
  3444.   end;
  3445.  
  3446.   Dec(ARow, FTitleOffset);
  3447.   Dec(ACol, FIndicatorOffset);
  3448.  
  3449.   if (gdFixed in AState) and ([dgRowLines, dgColLines] * Options =
  3450.     [dgRowLines, dgColLines]) then
  3451.   begin
  3452.     InflateRect(ARect, -1, -1);
  3453.     FrameOffs := 1;
  3454.   end
  3455.   else
  3456.     FrameOffs := 2;
  3457.  
  3458.   if (gdFixed in AState) and (ACol < 0) then
  3459.   begin
  3460.     Canvas.Brush.Color := FixedColor;
  3461.     Canvas.FillRect(ARect);
  3462.     if Assigned(DataLink) and DataLink.Active then
  3463.     begin
  3464.       MultiSelected := False;
  3465.       if ARow >= 0 then
  3466.       begin
  3467.         OldActive := FDataLink.ActiveRecord;
  3468.         try
  3469.           FDatalink.ActiveRecord := ARow;
  3470.           MultiSelected := RowIsMultiselected;
  3471.         finally
  3472.           FDatalink.ActiveRecord := OldActive;
  3473.         end;
  3474.       end;
  3475.       if (ARow = FDataLink.ActiveRecord) or MultiSelected then
  3476.       begin
  3477.         Indicator := 0;
  3478.         if FDataLink.DataSet <> nil then
  3479.           case FDataLink.DataSet.State of
  3480.             dsEdit: Indicator := 1;
  3481.             dsInsert: Indicator := 2;
  3482.             dsBrowse:
  3483.               if MultiSelected then
  3484.                 if (ARow <> FDatalink.ActiveRecord) then
  3485.                   Indicator := 3
  3486.                 else
  3487.                   Indicator := 4;         // multiselected and current row
  3488.           end;
  3489.         FIndicators.BkColor := FixedColor;
  3490.         ALeft := ARect.Right - FIndicators.Width - FrameOffs;
  3491.         if Canvas.CanvasOrientation = coRightToLeft then Inc(ALeft);
  3492.         FIndicators.Draw(Canvas, ALeft,
  3493.           (ARect.Top + ARect.Bottom - FIndicators.Height) shr 1, Indicator, True);
  3494.         if ARow = FDatalink.ActiveRecord then
  3495.           FSelRow := ARow + FTitleOffset;
  3496.       end;
  3497.     end;
  3498.   end
  3499.   else with Canvas do
  3500.     begin
  3501.       DrawColumn := Columns[ACol];
  3502.       if not DrawColumn.Showing then Exit;
  3503.       if not (gdFixed in AState) then
  3504.       begin
  3505.         Font := DrawColumn.Font;
  3506.         Brush.Color := DrawColumn.Color;
  3507.       end;
  3508.       if ARow < 0 then
  3509.         DrawTitleCell(ACol, ARow + FTitleOffset, DrawColumn, AState)
  3510.       else if (FDataLink = nil) or not FDataLink.Active then
  3511.         FillRect(ARect)
  3512.       else
  3513.       begin
  3514.         Value := '';
  3515.         OldActive := FDataLink.ActiveRecord;
  3516.         try
  3517.           FDataLink.ActiveRecord := ARow;
  3518.           if (FDataLink.Dataset.RecordCount > 0) or (FDataLink.Dataset.State = dsInsert) then begin
  3519.             if Assigned(DrawColumn.Field) then begin
  3520.               if DrawColumn.Field is TMemoField then  //Volga
  3521.                 Value := DrawColumn.Field.AsString    //Volga
  3522.               else Value := DrawColumn.Field.DisplayText;
  3523.               case DrawColumn.ButtonStyle of
  3524.                 cbsCombo:
  3525.                   if (DrawColumn.PickValues <> nil) and (DrawColumn.PickList.Count > 0) and  //Volga
  3526.                     (DrawColumn.PickValues.Count = DrawColumn.PickList.Count) then begin //Volga
  3527.                     ind := DrawColumn.PickValues.IndexOf(DrawColumn.Field.Text); //Volga
  3528.                     if ind >= 0 then            //Volga
  3529.                       Value := DrawColumn.PickList[ind] //Volga
  3530.                     else Value := '';           //Volga
  3531.                   end;
  3532.                 cbsLookup:
  3533.                   with DrawColumn do
  3534.                     if IsLinkActive then begin  //φα∩≡ ∞≤■ Φ∙σ∞ Γ Lookup-≥αßδΦ÷σ!!!!!!!
  3535.                       if LookupLinkField = FViewField then
  3536.                         //Σδ  ßαδ.±≈σ≥εΓ φα∩≡Φ∞σ≡ (Φφα≈σ ß≤ΩΓα ─ φσ ∩εΩατ√Γασ≥± )
  3537.                         VarValue := FDataLink.Dataset.FieldValues[FieldName]
  3538.                       else
  3539.                         VarValue := LookupDataSet.Lookup(LookupLinkField,
  3540.                         FDataLink.Dataset.FieldValues[LookupKeyField], FViewField);
  3541.                       if not VarIsNull(VarValue) then Value := VarValue
  3542.                       else Value := '';
  3543.                     end;
  3544.               end;
  3545.             end;
  3546.           end;
  3547.           Highlight := HighlightCell(ACol, ARow, Value, AState);
  3548.           if Highlight then
  3549.           begin
  3550.             Brush.Color := SelectedColor;        //clHighlight   //volga
  3551.             Font.Color := SelectedFontColor;     //clHighlightText;   //volga
  3552.           end;
  3553.           if not Enabled then
  3554.             Font.Color := clGrayText;
  3555.           AColor := Brush.Color;  //Volga
  3556.           AFont := Font;          //Volga
  3557.           if Assigned(FOnDrawCellAttr) then  //Volga
  3558.             FOnDrawCellAttr(Self, DrawColumn, AFont, AColor, AState);
  3559.           Brush.Color := AColor;  //Volga
  3560.           Font := AFont;          //Volga
  3561.           if FDefaultDrawing then
  3562.             if DrawColumn.ButtonStyle <> cbsCheck then
  3563.               WriteText(Canvas, ARect, 2, 2, Value, DrawColumn.Alignment,
  3564.               UseRightToLeftAlignmentForField(DrawColumn.Field, DrawColumn.Alignment))
  3565.             else
  3566.               DrawCheckBoxColumn(ARect, DrawColumn, AState, Value);  //Volga
  3567.           if Columns.State = csDefault then
  3568.             DrawDataCell(ARect, DrawColumn.Field, AState);
  3569.           DrawColumnCell(ARect, ACol, DrawColumn, AState);  //Γ√τεΓ ■τσ≡±Ωεπε ≡Φ±εΓαφΦ ,σ±δΦ φατφα≈σφε
  3570.         finally
  3571.           FDataLink.ActiveRecord := OldActive;
  3572.         end;
  3573.         if FDefaultDrawing and (gdSelected in AState)
  3574.           and ((dgAlwaysShowSelection in Options) or Focused)
  3575.           and not (csDesigning in ComponentState)
  3576.           and not (dgRowSelect in Options) and (UpdateLock = 0)
  3577.           and (ValidParentForm(Self).ActiveControl = Self) then
  3578.           //τΣσ±ⁿ ∞εµφε φα≡Φ±εΓα≥ⁿ Ωφε∩Ω≤, σ±δΦ εφα φ≤µφα
  3579.           Windows.DrawFocusRect(Handle, ARect);
  3580.       end;
  3581.     end;
  3582.   if (gdFixed in AState) and ([dgRowLines, dgColLines] * Options =
  3583.     [dgRowLines, dgColLines]) then
  3584.   begin
  3585.     InflateRect(ARect, 1, 1);
  3586.     DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_BOTTOMRIGHT);
  3587.     DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_TOPLEFT);
  3588.   end;
  3589. end;
  3590.  
  3591. procedure TVolgaCustomDBGrid.DrawDataCell(const Rect: TRect; Field: TField;
  3592.   State: TGridDrawState);
  3593. begin
  3594.   if Assigned(FOnDrawDataCell) then FOnDrawDataCell(Self, Rect, Field, State);
  3595. end;
  3596.  
  3597. procedure TVolgaCustomDBGrid.DrawColumnCell(const Rect: TRect; DataCol: Integer;
  3598.   Column: TVolgaColumn; State: TGridDrawState);
  3599. begin
  3600.   if Assigned(OnDrawColumnCell) then
  3601.     OnDrawColumnCell(Self, Rect, DataCol, Column, State);
  3602. end;
  3603.  
  3604. procedure TVolgaCustomDBGrid.EditButtonClick;
  3605. begin
  3606.   if Assigned(FOnEditButtonClick) then
  3607.     FOnEditButtonClick(Self, Columns[SelectedIndex])
  3608.   else
  3609.     ShowPopupEditor(Columns[SelectedIndex]);
  3610. end;
  3611.  
  3612. procedure TVolgaCustomDBGrid.EditingChanged;
  3613. begin
  3614.   if dgIndicator in Options then InvalidateCell(0, FSelRow);
  3615. end;
  3616.  
  3617. procedure TVolgaCustomDBGrid.EndLayout;
  3618. begin
  3619.   if FLayoutLock > 0 then
  3620.   begin
  3621.     try
  3622.       try
  3623.         if FLayoutLock = 1 then
  3624.           InternalLayout;
  3625.       finally
  3626.         if FLayoutLock = 1 then
  3627.           FColumns.EndUpdate;
  3628.       end;
  3629.     finally
  3630.       Dec(FLayoutLock);
  3631.       EndUpdate;
  3632.     end;
  3633.   end;
  3634. end;
  3635.  
  3636. procedure TVolgaCustomDBGrid.EndUpdate;
  3637. begin
  3638.   if FUpdateLock > 0 then
  3639.     Dec(FUpdateLock);
  3640. end;
  3641.  
  3642. function TVolgaCustomDBGrid.GetColField(DataCol: Integer): TField;
  3643. begin
  3644.   Result := nil;
  3645.   if (DataCol >= 0) and FDatalink.Active and (DataCol < Columns.Count) then
  3646.     Result := Columns[DataCol].Field;
  3647. end;
  3648.  
  3649. function TVolgaCustomDBGrid.GetDataSource: TDataSource;
  3650. begin
  3651.   Result := FDataLink.DataSource;
  3652. end;
  3653.  
  3654. function TVolgaCustomDBGrid.GetEditLimit: Integer;
  3655. begin
  3656.   Result := 0;
  3657.   if Assigned(SelectedField) and (SelectedField.DataType = ftString) then
  3658.     Result := SelectedField.Size;
  3659. end;
  3660.  
  3661. function TVolgaCustomDBGrid.GetEditMask(ACol, ARow: Longint): string;
  3662. begin
  3663.   Result := '';
  3664.   if FDatalink.Active then
  3665.     with Columns[RawToDataColumn(ACol)] do
  3666.       if Assigned(Field) then
  3667.         Result := Field.EditMask;
  3668. end;
  3669.  
  3670. function TVolgaCustomDBGrid.GetEditText(ACol, ARow: Longint): string;
  3671. var ind: integer;                         //Volga
  3672.   VarValue: Variant;
  3673. begin
  3674.   Result := '';
  3675.   if FDatalink.Active then
  3676.     with Columns[RawToDataColumn(ACol)] do
  3677.       if Assigned(Field) then begin
  3678.         Result := Field.Text;          //Volga  Γ±σπΣα Φτ ∩εδ  ┴─!!!
  3679.         case ButtonStyle of
  3680.           cbsCombo:
  3681.             if (PickValues <> nil) and (PickList.Count > 0) and
  3682.               (PickValues.Count = PickList.Count) then begin //Volga
  3683.                 ind := PickValues.IndexOf(Field.Text); //Volga
  3684.                 if ind >= 0 then                //Volga
  3685.                   Result := PickList[ind]       //Volga
  3686.                 else Result := '';              //Volga
  3687.             end;
  3688.           cbsLookup:
  3689.             if IsLinkActive then begin  //φα∩≡ ∞≤■ Φ∙σ∞ Γ Lookup-≥αßδΦ÷σ!!!!!!!
  3690.               if LookupLinkField = FViewField then
  3691.                 //Σδ  ßαδ.±≈σ≥εΓ φα∩≡Φ∞σ≡ (Φφα≈σ ß≤ΩΓα ─ φσ ∩εΩατ√Γασ≥± )
  3692.                 VarValue := FDataLink.Dataset.FieldValues[FieldName]
  3693.               else
  3694.                 VarValue := LookupDataSet.Lookup(LookupLinkField,
  3695.                 FDataLink.Dataset.FieldValues[LookupKeyField], FViewField);
  3696.               if not VarIsNull(VarValue) then Result := VarValue
  3697.               else Result := '';
  3698.             end;
  3699.         end;
  3700.       end;
  3701.   FEditText := Result;
  3702. end;
  3703.  
  3704. function TVolgaCustomDBGrid.GetFieldCount: Integer;
  3705. begin
  3706.   Result := FDatalink.FieldCount;
  3707. end;
  3708.  
  3709. function TVolgaCustomDBGrid.GetFields(FieldIndex: Integer): TField;
  3710. begin
  3711.   Result := FDatalink.Fields[FieldIndex];
  3712. end;
  3713.  
  3714. function TVolgaCustomDBGrid.GetFieldValue(ACol: Integer): string;
  3715. var
  3716.   Field: TField;
  3717. begin
  3718.   Result := '';
  3719.   Field := GetColField(ACol);
  3720.   if Field <> nil then Result := Field.DisplayText;
  3721. end;
  3722.  
  3723. function TVolgaCustomDBGrid.GetSelectedField: TField;
  3724. var
  3725.   Index: Integer;
  3726. begin
  3727.   Index := SelectedIndex;
  3728.   if Index <> -1 then
  3729.     Result := Columns[Index].Field
  3730.   else
  3731.     Result := nil;
  3732. end;
  3733.  
  3734. function TVolgaCustomDBGrid.GetSelectedIndex: Integer;
  3735. begin
  3736.   Result := RawToDataColumn(Col);
  3737. end;
  3738.  
  3739. function TVolgaCustomDBGrid.HighlightCell(DataCol, DataRow: Integer;
  3740.   const Value: string; AState: TGridDrawState): Boolean;
  3741. var
  3742.   Index: Integer;
  3743. begin
  3744.   Result := False;
  3745.   if (dgMultiSelect in Options) and Datalink.Active then
  3746.     Result := FBookmarks.Find(Datalink.Datasource.Dataset.Bookmark, Index);
  3747.   if not Result then
  3748.     Result := (gdSelected in AState)
  3749.       and ((dgAlwaysShowSelection in Options) or Focused)
  3750.         { updatelock eliminates flicker when tabbing between rows }
  3751.     and ((UpdateLock = 0) or (dgRowSelect in Options));
  3752. end;
  3753.  
  3754. procedure TVolgaCustomDBGrid.KeyDown(var Key: Word; Shift: TShiftState);
  3755. var
  3756.   KeyDownEvent: TKeyEvent;
  3757.  
  3758.   procedure ClearSelection;
  3759.   begin
  3760.     if (dgMultiSelect in Options) then
  3761.     begin
  3762.       FBookmarks.Clear;
  3763.       FSelecting := False;
  3764.     end;
  3765.   end;
  3766.  
  3767.   procedure DoSelection(Select: Boolean; Direction: Integer);
  3768.   var
  3769.     AddAfter: Boolean;
  3770.   begin
  3771.     AddAfter := False;
  3772.     BeginUpdate;
  3773.     try
  3774.       if (dgMultiSelect in Options) and FDatalink.Active then
  3775.         if Select and (ssShift in Shift) then
  3776.         begin
  3777.           if not FSelecting then
  3778.           begin
  3779.             FSelectionAnchor := FBookmarks.CurrentRow;
  3780.             FBookmarks.CurrentRowSelected := True;
  3781.             FSelecting := True;
  3782.             AddAfter := True;
  3783.           end
  3784.           else
  3785.             with FBookmarks do
  3786.             begin
  3787.               AddAfter := Compare(CurrentRow, FSelectionAnchor) <> -Direction;
  3788.               if not AddAfter then
  3789.                 CurrentRowSelected := False;
  3790.             end
  3791.         end
  3792.         else
  3793.           ClearSelection;
  3794.       FDatalink.MoveBy(Direction);
  3795.       if AddAfter then FBookmarks.CurrentRowSelected := True;
  3796.     finally
  3797.       EndUpdate;
  3798.     end;
  3799.   end;
  3800.  
  3801.   procedure NextRow(Select: Boolean);
  3802.   begin
  3803.     with FDatalink.Dataset do
  3804.     begin
  3805.       if (State = dsInsert) and not Modified and not FDatalink.FModified then
  3806.         if FDataLink.EOF then Exit else Cancel
  3807.       else
  3808.         DoSelection(Select, 1);
  3809.       if FDataLink.EOF and CanModify and (not ReadOnly) and (dgEditing in Options)
  3810.       and AllowInsert then  //Volga
  3811.         Append;
  3812.     end;
  3813.   end;
  3814.  
  3815.   procedure PriorRow(Select: Boolean);
  3816.   begin
  3817.     with FDatalink.Dataset do
  3818.       if (State = dsInsert) and not Modified and FDataLink.EOF and
  3819.         not FDatalink.FModified then
  3820.         Cancel
  3821.       else
  3822.         DoSelection(Select, -1);
  3823.   end;
  3824.  
  3825.   procedure Tab(GoForward: Boolean);
  3826.   var
  3827.     ACol, Original: Integer;
  3828.   begin
  3829.     ACol := Col;
  3830.     Original := ACol;
  3831.     BeginUpdate; { Prevent highlight flicker on tab to next/prior row }
  3832.     try
  3833.       while True do
  3834.       begin
  3835.         if GoForward then
  3836.           Inc(ACol) else
  3837.           Dec(ACol);
  3838.         if ACol >= ColCount then
  3839.         begin
  3840.           NextRow(False);
  3841.           ACol := FIndicatorOffset;
  3842.         end
  3843.         else if ACol < FIndicatorOffset then
  3844.         begin
  3845.           PriorRow(False);
  3846.           ACol := ColCount - FIndicatorOffset;
  3847.         end;
  3848.         if ACol = Original then Exit;
  3849.         if TabStops[ACol] then
  3850.         begin
  3851.           MoveCol(ACol, 0);
  3852.           Exit;
  3853.         end;
  3854.       end;
  3855.     finally
  3856.       EndUpdate;
  3857.     end;
  3858.   end;
  3859.  
  3860.   function DeletePrompt: Boolean;
  3861.   var
  3862.     Msg: string;
  3863.   begin
  3864.     if (FBookmarks.Count > 1) then
  3865.       Msg := V_DELETEROWS    //Volga
  3866.     else
  3867.       Msg := V_DELETEONEROW;             //Volga
  3868.     Result := AllowDelete and (not (dgConfirmDelete in Options) or  //Volga
  3869.       (MessageDlg(Msg, mtConfirmation, mbOKCancel, 0) <> idCancel));
  3870.   end;
  3871.  
  3872. const
  3873.   RowMovementKeys = [VK_UP, VK_PRIOR, VK_DOWN, VK_NEXT, VK_HOME, VK_END];
  3874.  
  3875. begin
  3876.   KeyDownEvent := OnKeyDown;
  3877.   if Assigned(KeyDownEvent) then KeyDownEvent(Self, Key, Shift);
  3878.   if not FDatalink.Active or not CanGridAcceptKey(Key, Shift) then Exit;
  3879.   if UseRightToLeftAlignment then
  3880.     if Key = VK_LEFT then
  3881.       Key := VK_RIGHT
  3882.     else if Key = VK_RIGHT then
  3883.       Key := VK_LEFT;
  3884.   with FDatalink.DataSet do
  3885.     if ssCtrl in Shift then
  3886.     begin
  3887.       if (Key in RowMovementKeys) then ClearSelection;
  3888.       case Key of
  3889.         VK_UP, VK_PRIOR: FDataLink.MoveBy(-FDatalink.ActiveRecord);
  3890.         VK_DOWN, VK_NEXT: FDataLink.MoveBy(FDatalink.BufferCount - FDatalink.ActiveRecord - 1);
  3891.         VK_LEFT: MoveCol(FIndicatorOffset, 1);
  3892.         VK_RIGHT: MoveCol(ColCount - 1, -1);
  3893.         VK_HOME: First;
  3894.         VK_END: Last;
  3895.         VK_DELETE:
  3896.           if (not ReadOnly) and not IsEmpty
  3897.             and CanModify and DeletePrompt then
  3898.             if FBookmarks.Count > 0 then
  3899.               FBookmarks.Delete
  3900.             else
  3901.               Delete;
  3902.       end
  3903.     end
  3904.     else
  3905.       case Key of
  3906.         VK_UP: PriorRow(True);
  3907.         VK_DOWN: NextRow(True);
  3908.         VK_LEFT:
  3909.           if dgRowSelect in Options then
  3910.             PriorRow(False) else
  3911.             MoveCol(Col - 1, -1);
  3912.         VK_RIGHT:
  3913.           if dgRowSelect in Options then
  3914.             NextRow(False) else
  3915.             MoveCol(Col + 1, 1);
  3916.         VK_HOME:
  3917.           if (ColCount = FIndicatorOffset + 1)
  3918.             or (dgRowSelect in Options) then
  3919.           begin
  3920.             ClearSelection;
  3921.             First;
  3922.           end
  3923.           else
  3924.             MoveCol(FIndicatorOffset, 1);
  3925.         VK_END:
  3926.           if (ColCount = FIndicatorOffset + 1)
  3927.             or (dgRowSelect in Options) then
  3928.           begin
  3929.             ClearSelection;
  3930.             Last;
  3931.           end
  3932.           else
  3933.             MoveCol(ColCount - 1, -1);
  3934.         VK_NEXT:
  3935.           begin
  3936.             ClearSelection;
  3937.             FDataLink.MoveBy(VisibleRowCount);
  3938.           end;
  3939.         VK_PRIOR:
  3940.           begin
  3941.             ClearSelection;
  3942.             FDataLink.MoveBy(-VisibleRowCount);
  3943.           end;
  3944.         VK_INSERT:
  3945.           if CanModify and (not ReadOnly) and (dgEditing in Options)
  3946.           and AllowInsert then  //Volga
  3947.           begin
  3948.             ClearSelection;
  3949.             Insert;
  3950.           end;
  3951.         VK_TAB,VK_RETURN: if not (ssAlt in Shift) then Tab(not (ssShift in Shift));  //Volga
  3952.         VK_ESCAPE:
  3953.           begin
  3954.             if SysLocale.PriLangID = LANG_KOREAN then
  3955.               FIsESCKey := True;
  3956.             FDatalink.Reset;
  3957.             ClearSelection;
  3958.             if not (dgAlwaysShowEditor in Options) then HideEditor;
  3959.           end;
  3960.         VK_F2: EditorMode := True;
  3961.       end;
  3962. end;
  3963.  
  3964. procedure TVolgaCustomDBGrid.KeyPress(var Key: Char);
  3965. begin
  3966.   FIsESCKey := False;
  3967.   if not (dgAlwaysShowEditor in Options) and (Key = #13) then
  3968.     FDatalink.UpdateData;
  3969.   inherited KeyPress(Key);
  3970. end;
  3971.  
  3972. { InternalLayout is called with layout locks and column locks in effect }
  3973. procedure TVolgaCustomDBGrid.InternalLayout;
  3974.  
  3975.   function FieldIsMapped(F: TField): Boolean;
  3976.   var
  3977.     X: Integer;
  3978.   begin
  3979.     Result := False;
  3980.     if F = nil then Exit;
  3981.     for X := 0 to FDatalink.FieldCount - 1 do
  3982.       if FDatalink.Fields[X] = F then
  3983.       begin
  3984.         Result := True;
  3985.         Exit;
  3986.       end;
  3987.   end;
  3988.  
  3989.   procedure CheckForPassthroughs;         // check for Columns.State flip-flop
  3990.   var
  3991.     SeenPassthrough: Boolean;
  3992.     I, J: Integer;
  3993.     Column: TVolgaColumn;
  3994.   begin
  3995.     SeenPassthrough := False;
  3996.     for I := 0 to FColumns.Count - 1 do
  3997.       if not FColumns[I].IsStored then
  3998.         SeenPassthrough := True
  3999.       else if SeenPassthrough then
  4000.       begin // we have both persistent and non-persistent columns.  Kill the latter
  4001.         for J := FColumns.Count - 1 downto 0 do
  4002.         begin
  4003.           Column := FColumns[J];
  4004.           if not Column.IsStored then
  4005.             Column.Free;
  4006.         end;
  4007.         Exit;
  4008.       end;
  4009.   end;
  4010.  
  4011.   procedure ReSetColumnFieldBindings;
  4012.   var
  4013.     I, J, K: Integer;
  4014.     Fld: TField;
  4015.     Column: TVolgaColumn;
  4016.   begin
  4017.     if FColumns.State = csDefault then
  4018.     begin
  4019.        { Destroy columns whose fields have been destroyed or are no longer
  4020.          in field map }
  4021.       if (not FDataLink.Active) and (FDatalink.DefaultFields) then
  4022.         FColumns.Clear
  4023.       else
  4024.         for J := FColumns.Count - 1 downto 0 do
  4025.           with FColumns[J] do
  4026.             if not Assigned(Field)
  4027.               or not FieldIsMapped(Field) then Free;
  4028.       I := FDataLink.FieldCount;
  4029.       if (I = 0) and (FColumns.Count = 0) then Inc(I);
  4030.       for J := 0 to I - 1 do
  4031.       begin
  4032.         Fld := FDatalink.Fields[J];
  4033.         if Assigned(Fld) then
  4034.         begin
  4035.           K := J;
  4036.            { Pointer compare is valid here because the grid sets matching
  4037.              column.field properties to nil in response to field object
  4038.              free notifications.  Closing a dataset that has only default
  4039.              field objects will destroy all the fields and set associated
  4040.              column.field props to nil. }
  4041.           while (K < FColumns.Count) and (FColumns[K].Field <> Fld) do
  4042.             Inc(K);
  4043.           if K < FColumns.Count then
  4044.             Column := FColumns[K]
  4045.           else
  4046.           begin
  4047.             Column := FColumns.InternalAdd;
  4048.             Column.Field := Fld;
  4049.           end;
  4050.         end
  4051.         else
  4052.           Column := FColumns.InternalAdd;
  4053.         Column.Index := J;
  4054.       end;
  4055.     end
  4056.     else
  4057.     begin
  4058.       { Force columns to reaquire fields (in case dataset has changed) }
  4059.       for I := 0 to FColumns.Count - 1 do
  4060.         FColumns[I].Field := nil;
  4061.     end;
  4062.   end;
  4063.  
  4064.   procedure MeasureTitleHeights;
  4065.   var
  4066.     I, J, K, D, B: Integer;
  4067.     RestoreCanvas: Boolean;
  4068.     Heights: array of Integer;
  4069.   begin
  4070.     RestoreCanvas := not HandleAllocated;
  4071.     if RestoreCanvas then
  4072.       Canvas.Handle := GetDC(0);
  4073.     try
  4074.       Canvas.Font := Font;
  4075.       K := Canvas.TextHeight('Wg') + 3;
  4076.       if dgRowLines in Options then
  4077.         Inc(K, GridLineWidth);
  4078.       DefaultRowHeight := K;
  4079.       B := GetSystemMetrics(SM_CYHSCROLL);
  4080.       if dgTitles in Options then
  4081.       begin
  4082.         SetLength(Heights, FTitleOffset + 1);
  4083.         for I := 0 to FColumns.Count - 1 do
  4084.         begin
  4085.           Canvas.Font := FColumns[I].Title.Font;
  4086.           D := FColumns[I].Depth;
  4087.           if D <= High(Heights) then
  4088.           begin
  4089.             J := Canvas.TextHeight('Wg') + 4;
  4090.             if FColumns[I].Expandable and (B > J) then
  4091.               J := B;
  4092.             Heights[D] := Max(J, Heights[D]);
  4093.           end;
  4094.         end;
  4095.         if Heights[0] = 0 then
  4096.         begin
  4097.           Canvas.Font := FTitleFont;
  4098.           Heights[0] := Canvas.TextHeight('Wg') + 4;
  4099.         end;
  4100.         for I := 0 to High(Heights) - 1 do
  4101.           RowHeights[I] := Heights[I];
  4102.       end;
  4103.     finally
  4104.       if RestoreCanvas then
  4105.       begin
  4106.         ReleaseDC(0, Canvas.Handle);
  4107.         Canvas.Handle := 0;
  4108.       end;
  4109.     end;
  4110.   end;
  4111.  
  4112. var
  4113.   I, J: Integer;
  4114. begin
  4115.   if (csLoading in ComponentState) then Exit;
  4116.  
  4117.   if HandleAllocated then KillMessage(Handle, cm_DeferLayout);
  4118.  
  4119.   CheckForPassthroughs;
  4120.   FIndicatorOffset := 0;
  4121.   if dgIndicator in Options then
  4122.     Inc(FIndicatorOffset);
  4123.   FDatalink.ClearMapping;
  4124.   if FDatalink.Active then DefineFieldMap;
  4125.   DoubleBuffered := (FDatalink.Dataset <> nil) and FDatalink.Dataset.ObjectView;
  4126.   ReSetColumnFieldBindings;
  4127.   FVisibleColumns.Clear;
  4128.   for I := 0 to FColumns.Count - 1 do
  4129.     if FColumns[I].Showing then FVisibleColumns.Add(FColumns[I]);
  4130.   ColCount := FColumns.Count + FIndicatorOffset;
  4131.   inherited FixedCols := FIndicatorOffset;
  4132.   FTitleOffset := 0;
  4133.   if dgTitles in Options then
  4134.   begin
  4135.     FTitleOffset := 1;
  4136.     if (FDatalink <> nil) and (FDatalink.Dataset <> nil)
  4137.       and FDatalink.Dataset.ObjectView then
  4138.     begin
  4139.       for I := 0 to FColumns.Count - 1 do
  4140.       begin
  4141.         if FColumns[I].Showing then
  4142.         begin
  4143.           J := FColumns[I].Depth;
  4144.           if J >= FTitleOffset then FTitleOffset := J + 1;
  4145.         end;
  4146.       end;
  4147.     end;
  4148.   end;
  4149.   UpdateRowCount;
  4150.   MeasureTitleHeights;
  4151.   SetColumnAttributes;
  4152.   UpdateActive;
  4153.   Invalidate;
  4154. end;
  4155.  
  4156. procedure TVolgaCustomDBGrid.LayoutChanged;
  4157. begin
  4158.   if AcquireLayoutLock then
  4159.     EndLayout;
  4160. end;
  4161.  
  4162. procedure TVolgaCustomDBGrid.LinkActive(Value: Boolean);
  4163. var
  4164.   Comp: TComponent;
  4165.   I: Integer;
  4166. begin
  4167.   if not Value then HideEditor;
  4168.   FBookmarks.LinkActive(Value);
  4169.   try
  4170.     LayoutChanged;
  4171.   finally
  4172.     for I := ComponentCount - 1 downto 0 do
  4173.     begin
  4174.       Comp := Components[I];              // Free all the popped-up subgrids
  4175.       if (Comp is TVolgaCustomDBGrid)
  4176.         and (TVolgaCustomDBGrid(Comp).DragKind = dkDock) then
  4177.         Comp.Free;
  4178.     end;
  4179.     UpdateScrollBar;
  4180.     if Value and (dgAlwaysShowEditor in Options) then ShowEditor;
  4181.   end;
  4182. end;
  4183.  
  4184. procedure TVolgaCustomDBGrid.Loaded;
  4185. begin
  4186.   inherited Loaded;
  4187.   if FColumns.Count > 0 then
  4188.     ColCount := FColumns.Count;
  4189.   LayoutChanged;
  4190. end;
  4191.  
  4192. function TVolgaCustomDBGrid.PtInExpandButton(X, Y: Integer; var MasterCol: TVolgaColumn): Boolean;
  4193. var
  4194.   Cell: TGridCoord;
  4195.   R: TRect;
  4196. begin
  4197.   MasterCol := nil;
  4198.   Result := False;
  4199.   Cell := MouseCoord(X, Y);
  4200.   if (Cell.Y < FTitleOffset) and FDatalink.Active
  4201.     and (Cell.X >= FIndicatorOffset)
  4202.     and (RawToDataColumn(Cell.X) < Columns.Count) then
  4203.   begin
  4204.     R := CalcTitleRect(Columns[RawToDataColumn(Cell.X)], Cell.Y, MasterCol);
  4205.     if not UseRightToLeftAlignment then
  4206.       R.Left := R.Right - GetSystemMetrics(SM_CXHSCROLL)
  4207.     else
  4208.       R.Right := R.Left + GetSystemMetrics(SM_CXHSCROLL);
  4209.     Result := MasterCol.Expandable and PtInRect(R, Point(X, Y));
  4210.   end;
  4211. end;
  4212.  
  4213. procedure TVolgaCustomDBGrid.MouseDown(Button: TMouseButton; Shift: TShiftState;
  4214.   X, Y: Integer);
  4215. var
  4216.   Cell: TGridCoord;
  4217.   OldCol, OldRow: Integer;
  4218.   MasterCol: TVolgaColumn;
  4219. begin
  4220.   if not AcquireFocus then Exit;
  4221.   if (ssDouble in Shift) and (Button = mbLeft) then
  4222.   begin
  4223.     DblClick;
  4224.     Exit;
  4225.   end;
  4226.  
  4227.   if Sizing(X, Y) then
  4228.   begin
  4229.     FDatalink.UpdateData;
  4230.     inherited MouseDown(Button, Shift, X, Y);
  4231.     Exit;
  4232.   end;
  4233.  
  4234.   Cell := MouseCoord(X, Y);
  4235.   if (Cell.X < 0) and (Cell.Y < 0) then
  4236.   begin
  4237.     inherited MouseDown(Button, Shift, X, Y);
  4238.     Exit;
  4239.   end;
  4240.  
  4241.   if (DragKind = dkDock) and (Cell.X < FIndicatorOffset) and
  4242.     (Cell.Y < FTitleOffset) and (not (csDesigning in ComponentState)) then
  4243.   begin
  4244.     BeginDrag(false);
  4245.     Exit;
  4246.   end;
  4247.  
  4248.   if PtInExpandButton(X, Y, MasterCol) then
  4249.   begin
  4250.     MasterCol.Expanded := not MasterCol.Expanded;
  4251.     ReleaseCapture;
  4252.     UpdateDesigner;
  4253.     Exit;
  4254.   end;
  4255.  
  4256.   if ((csDesigning in ComponentState) {or (dgColumnResize in Options)}) and //Volga
  4257.     (Cell.Y < FTitleOffset) then
  4258.   begin
  4259.     FDataLink.UpdateData;
  4260.     inherited MouseDown(Button, Shift, X, Y);
  4261.     Exit;
  4262.   end;
  4263.  
  4264.   //Volga ∩ε∩αδΦ φα ταπεδεΓε≈φ≤■  ≈σΘΩ≤ Γε Γ≡σ∞  Γ√∩εδφσφΦ 
  4265.   if ((Cell.Y < FTitleOffset) and (Cell.X >= FIndicatorOffset)) then
  4266.   begin
  4267.     FDataLink.UpdateData;
  4268.     MasterCol := Columns[RawToDataColumn(Cell.X)];
  4269.     if (MasterCol <> nil) and MasterCol.CanClick then
  4270.     begin
  4271.       MasterCol.Down := True;
  4272.       InvalidateCell(Cell.X, Cell.Y);     //∩σ≡σ≡Φ±εΓ√Γασ∞  ≈σΘΩ≤ φαµα≥εΘ
  4273.     end
  4274.     else
  4275.       inherited MouseDown(Button, Shift, X, Y);
  4276.     Exit;
  4277.   end;                                    //Volga
  4278.  
  4279.   if FDatalink.Active then
  4280.     with Cell do
  4281.     begin
  4282.       BeginUpdate; { eliminates highlight flicker when selection moves }
  4283.       try
  4284.         FDatalink.UpdateData;             // validate before moving
  4285.         HideEditor;
  4286.         OldCol := Col;
  4287.         OldRow := Row;
  4288.         if (Y >= FTitleOffset) and (Y - Row <> 0) then
  4289.           FDatalink.MoveBy(Y - Row);
  4290.         if X >= FIndicatorOffset then
  4291.           MoveCol(X, 0);
  4292.         if (dgMultiSelect in Options) and FDatalink.Active then
  4293.           with FBookmarks do
  4294.           begin
  4295.             FSelecting := False;
  4296.             if ssCtrl in Shift then
  4297.               CurrentRowSelected := not CurrentRowSelected
  4298.             else
  4299.             begin
  4300.               Clear;
  4301.               CurrentRowSelected := True;
  4302.             end;
  4303.           end;
  4304.         if (Button = mbLeft) and (X >= FIndicatorOffset) then begin
  4305.           MasterCol := Columns[RawToDataColumn(X)]; //± ΩαΩεΘ ΩεδεφΩεΘ ≡αßε≥ασ∞? Volga
  4306.           if MasterCol.ButtonStyle = cbsCheck then begin //∩σ≡σΩδ■≈Φ≥ⁿ ≈σΩßεΩ±
  4307.             ToggleCheckBox(MasterCol, X, Y); //Volga
  4308.             ReleaseCapture;                  //Volga
  4309.           end else if (((X = OldCol) and (Y = OldRow)) or (dgAlwaysShowEditor in Options)) then
  4310.             ShowEditor                      { put grid in edit mode }
  4311.           else
  4312.             InvalidateEditor;               { draw editor, if needed }
  4313.         end;
  4314.       finally
  4315.         EndUpdate;
  4316.       end;
  4317.       if (DragKind = dkDrag) and (dgDragOutRows in Options) then
  4318.         //φα≈Φφασ∞ ε∩σ≡α÷Φ■ drag
  4319.         BeginDrag(false, 5);
  4320.     end;
  4321. end;
  4322.  
  4323. procedure TVolgaCustomDBGrid.ToggleCheckBox(Column: TVolgaColumn; col, row:integer);
  4324. var value: string;          //Volga
  4325.     tempField: TField;
  4326. begin
  4327.   tempField:=Column.Field;
  4328.   if not Assigned(tempField) then exit;
  4329.   if Column.ReadOnly or not (dgEditing in Options) then exit;
  4330.   if (not DataSource.AutoEdit) and
  4331.     (not (DataSource.state in [dsEdit, dsInsert])) then exit;
  4332.   DataLink.Edit;
  4333.   value:=Column.Field.Text;
  4334.   if value=Column.ValueChecked then Column.Field.Text:=Column.ValueUnChecked
  4335.   else Column.Field.Text:=Column.ValueChecked;
  4336.   DrawCell(col, row, CellRect(col, row), [gdSelected]);
  4337. end;  //Volga
  4338.  
  4339. procedure TVolgaCustomDBGrid.MouseUp(Button: TMouseButton; Shift: TShiftState;
  4340.   X, Y: Integer);
  4341. var
  4342.   Cell: TGridCoord;
  4343.   SaveState: TGridState;
  4344.   i, isel, idown: integer;                        //Volga
  4345. begin
  4346.   SaveState := FGridState;
  4347.   inherited MouseUp(Button, Shift, X, Y);
  4348.   if (SaveState = gsRowSizing) or (SaveState = gsColSizing) or
  4349.     ((InplaceEditor <> nil) and (InplaceEditor.Visible) and
  4350.     (PtInRect(InplaceEditor.BoundsRect, Point(X, Y)))) then Exit;
  4351.   Cell := MouseCoord(X, Y);
  4352.   isel := RawToDataColumn(Cell.X);    //Volga
  4353.   //∩σ≡σßΦ≡ασ∞ Γ±σ ΩεδεφΩΦ Φ ε≥µΦ∞ασ∞ Φ⌡ Γ±σ
  4354.   idown := -1;
  4355.   for i := 0 to Columns.Count - 1 do      //Volga
  4356.     if Columns[i].Down then begin         //Volga
  4357.       Columns[i].Down := False;           //Volga
  4358.       idown := i;
  4359.       Break;                              //Volga
  4360.     end;                                  //Volga
  4361.   if (Button = mbLeft) and (Cell.X >= FIndicatorOffset) and (Cell.Y >= 0) then
  4362.     if Cell.Y < FTitleOffset then
  4363.       if (Columns[isel].CanClick and (idown = isel)) then  //Volga
  4364.         TitleClick(Columns[isel])     //Volga ε≥µα≥α Φ∞σφφε ≥α ΩεδεφΩα, Ωε≥.ß√δα ≡αφσσ φαµα≥α
  4365.       else
  4366.     else CellClick(Columns[isel]);       //Volga
  4367.   if idown >= 0 then
  4368.     InvalidateCell(DataToRawColumn(idown), 0); //Volga ∩σ≡σ≡Φ±εΓα≥ⁿ ΩεδεφΩ≤ ε≥µα≥εΘ
  4369. end;
  4370.  
  4371. procedure TVolgaCustomDBGrid.MoveCol(RawCol, Direction: Integer);
  4372. var
  4373.   OldCol: Integer;
  4374. begin
  4375.   FDatalink.UpdateData;
  4376.   if RawCol >= ColCount then
  4377.     RawCol := ColCount - 1;
  4378.   if RawCol < FIndicatorOffset then RawCol := FIndicatorOffset;
  4379.   if Direction <> 0 then
  4380.   begin
  4381.     while (RawCol < ColCount) and (RawCol >= FIndicatorOffset) and
  4382.       (ColWidths[RawCol] <= 0) do
  4383.       Inc(RawCol, Direction);
  4384.     if (RawCol >= ColCount) or (RawCol < FIndicatorOffset) then Exit;
  4385.   end;
  4386.   OldCol := Col;
  4387.   if RawCol <> OldCol then
  4388.   begin
  4389.     if not FInColExit then
  4390.     begin
  4391.       FInColExit := True;
  4392.       try
  4393.         ColExit;
  4394.       finally
  4395.         FInColExit := False;
  4396.       end;
  4397.       if Col <> OldCol then Exit;
  4398.     end;
  4399.     if not (dgAlwaysShowEditor in Options) then HideEditor;
  4400.     Col := RawCol;
  4401.     ColEnter;
  4402.   end;
  4403. end;
  4404.  
  4405. procedure TVolgaCustomDBGrid.Notification(AComponent: TComponent;
  4406.   Operation: TOperation);
  4407. var
  4408.   I: Integer;
  4409.   NeedLayout: Boolean;
  4410. begin
  4411.   inherited Notification(AComponent, Operation);
  4412.   if (Operation = opRemove) then
  4413.   begin
  4414.     if (AComponent is TPopupMenu) then
  4415.     begin
  4416.       for I := 0 to Columns.Count - 1 do
  4417.         if Columns[I].PopupMenu = AComponent then
  4418.           Columns[I].PopupMenu := nil;
  4419.     end
  4420.     else if (AComponent is TDataSet) then
  4421.       begin
  4422.         NeedLayout := False;
  4423.         BeginLayout;
  4424.         try
  4425.           for I := 0 to Columns.Count - 1 do
  4426.             with Columns[I] do
  4427.               if LookupDataSet = AComponent then
  4428.               begin
  4429.                 LookupDataSet := nil;
  4430.                 NeedLayout := True;
  4431.               end;
  4432.         finally
  4433.           if NeedLayout and Assigned(FDatalink.Dataset)
  4434.             and not FDatalink.Dataset.ControlsDisabled then
  4435.             EndLayout
  4436.           else
  4437.             DeferLayout;
  4438.         end;
  4439.       end
  4440.     else if (FDataLink <> nil) then
  4441.       if (AComponent = DataSource) then
  4442.         DataSource := nil
  4443.       else if (AComponent is TField) then
  4444.       begin
  4445.         NeedLayout := False;
  4446.         BeginLayout;
  4447.         try
  4448.           for I := 0 to Columns.Count - 1 do
  4449.             with Columns[I] do
  4450.               if Field = AComponent then
  4451.               begin
  4452.                 Field := nil;
  4453.                 NeedLayout := True;
  4454.               end;
  4455.         finally
  4456.           if NeedLayout and Assigned(FDatalink.Dataset)
  4457.             and not FDatalink.Dataset.ControlsDisabled then
  4458.             EndLayout
  4459.           else
  4460.             DeferLayout;
  4461.         end;
  4462.       end;
  4463.   end;
  4464. end;
  4465.  
  4466. procedure TVolgaCustomDBGrid.RecordChanged(Field: TField);
  4467. var
  4468.   I: Integer;
  4469.   CField: TField;
  4470. begin
  4471.   if not HandleAllocated then Exit;
  4472.   if Field = nil then
  4473.     Invalidate
  4474.   else
  4475.   begin
  4476.     for I := 0 to Columns.Count - 1 do
  4477.       if Columns[I].Field = Field then
  4478.         InvalidateCol(DataToRawColumn(I));
  4479.   end;
  4480.   CField := SelectedField;
  4481.   if ((Field = nil) or (CField = Field)) and
  4482.     (Assigned(CField) and (CField.Text <> FEditText) and
  4483.     ((SysLocale.PriLangID <> LANG_KOREAN) or FIsESCKey)) then
  4484.   begin
  4485.     InvalidateEditor;
  4486.     if InplaceEditor <> nil then InplaceEditor.Deselect;
  4487.   end;
  4488. end;
  4489.  
  4490. procedure TVolgaCustomDBGrid.Scroll(Distance: Integer);
  4491. var
  4492.   OldRect, NewRect: TRect;
  4493.   RowHeight: Integer;
  4494. begin
  4495.   if not HandleAllocated then Exit;
  4496.   OldRect := BoxRect(0, Row, ColCount - 1, Row);
  4497.   if (FDataLink.ActiveRecord >= RowCount - FTitleOffset) then UpdateRowCount;
  4498.   UpdateScrollBar;
  4499.   UpdateActive;
  4500.   NewRect := BoxRect(0, Row, ColCount - 1, Row);
  4501.   ValidateRect(Handle, @OldRect);
  4502.   InvalidateRect(Handle, @OldRect, False);
  4503.   InvalidateRect(Handle, @NewRect, False);
  4504.   if Distance <> 0 then
  4505.   begin
  4506.     HideEditor;
  4507.     try
  4508.       if Abs(Distance) > VisibleRowCount then
  4509.       begin
  4510.         Invalidate;
  4511.         Exit;
  4512.       end
  4513.       else
  4514.       begin
  4515.         RowHeight := DefaultRowHeight;
  4516.         if dgRowLines in Options then Inc(RowHeight, GridLineWidth);
  4517.         if dgIndicator in Options then
  4518.         begin
  4519.           OldRect := BoxRect(0, FSelRow, ColCount - 1, FSelRow);
  4520.           InvalidateRect(Handle, @OldRect, False);
  4521.         end;
  4522.         NewRect := BoxRect(0, FTitleOffset, ColCount - 1, 1000);
  4523.         ScrollWindowEx(Handle, 0, -RowHeight * Distance, @NewRect, @NewRect,
  4524.           0, nil, SW_Invalidate);
  4525.         if dgIndicator in Options then
  4526.         begin
  4527.           NewRect := BoxRect(0, Row, ColCount - 1, Row);
  4528.           InvalidateRect(Handle, @NewRect, False);
  4529.         end;
  4530.       end;
  4531.     finally
  4532.       if dgAlwaysShowEditor in Options then ShowEditor;
  4533.     end;
  4534.   end;
  4535.   if UpdateLock = 0 then Update;
  4536. end;
  4537.  
  4538. procedure TVolgaCustomDBGrid.SetColumns(Value: TVolgaDBGridColumns);
  4539. begin
  4540.   Columns.Assign(Value);
  4541. end;
  4542.  
  4543. function ReadOnlyField(Field: TField): Boolean;
  4544. var
  4545.   MasterField: TField;
  4546. begin
  4547.   Result := Field.ReadOnly;
  4548.   if not Result and (Field.FieldKind = fkLookup) then
  4549.   begin
  4550.     Result := True;
  4551.     if Field.DataSet = nil then Exit;
  4552.     MasterField := Field.Dataset.FindField(Field.KeyFields);
  4553.     if MasterField = nil then Exit;
  4554.     Result := MasterField.ReadOnly;
  4555.   end;
  4556. end;
  4557.  
  4558. procedure TVolgaCustomDBGrid.SetColumnAttributes;
  4559. var
  4560.   I: Integer;
  4561. begin
  4562.   for I := 0 to FColumns.Count - 1 do
  4563.     with FColumns[I] do
  4564.     begin  //Σασ∞ ≡σΣαΩ≥Φ≡εΓα≥ⁿ Calculated-∩εδ !!!!!!!!
  4565.       TabStops[I + FIndicatorOffset] := Showing and not ReadOnly and DataLink.Active and
  4566.         Assigned(Field) and {not (Field.FieldKind = fkCalculated) and } not    //Volga
  4567.           ReadOnlyField(Field);
  4568.       ColWidths[I + FIndicatorOffset] := Width;
  4569.     end;
  4570.   if (dgIndicator in Options) then
  4571.     ColWidths[0] := IndicatorWidth;
  4572. end;
  4573.  
  4574. procedure TVolgaCustomDBGrid.SetDataSource(Value: TDataSource);
  4575. begin
  4576.   if Value = FDatalink.Datasource then Exit;
  4577.   FBookmarks.Clear;
  4578.   FDataLink.DataSource := Value;
  4579.   if Value <> nil then Value.FreeNotification(Self);
  4580.   LinkActive(FDataLink.Active);
  4581. end;
  4582.  
  4583. procedure TVolgaCustomDBGrid.SetEditText(ACol, ARow: Longint; const Value: string);
  4584. var Column: TVolgaColumn;                   //Volga
  4585.   ind: integer;                           //Volga
  4586. begin
  4587.   Column := Columns[RawToDataColumn(ACol)]; //Volga
  4588.   if (Column.PickList.Count > 0) and (Column.PickValues <> nil) //Volga
  4589.   and (Column.PickList.Count = Column.PickValues.Count) then begin //Volga
  4590.     ind := Column.PickList.IndexOf(Value); //Volga
  4591.     if ind >= 0 then                      //Volga
  4592.       FEditText := Column.PickValues[ind] //Volga
  4593.     else                                  //Volga
  4594.       FEditText := '';                    //φσ φα°δΦ ≥αΩεσ τφα≈σφΦσ!!
  4595.   end else
  4596.     FEditText := Value;                     //??????????
  4597. end;
  4598.  
  4599. procedure TVolgaCustomDBGrid.SetOptions(Value: TVolgaDBGridOptions);
  4600. const
  4601.   LayoutOptions = [dgEditing, dgAlwaysShowEditor, dgTitles, dgIndicator,
  4602.     dgColLines, dgRowLines, dgRowSelect, dgAlwaysShowSelection];
  4603. var
  4604.   NewGridOptions: TGridOptions;
  4605.   ChangedOptions: TVolgaDBGridOptions;
  4606. begin
  4607.   if FOptions <> Value then
  4608.   begin
  4609.     NewGridOptions := [];
  4610.     if dgColLines in Value then
  4611.       NewGridOptions := NewGridOptions + [goFixedVertLine, goVertLine];
  4612.     if dgRowLines in Value then
  4613.       NewGridOptions := NewGridOptions + [goFixedHorzLine, goHorzLine];
  4614.     if dgColumnResize in Value then
  4615.       NewGridOptions := NewGridOptions + [goColSizing, goColMoving];
  4616.     if dgTabs in Value then Include(NewGridOptions, goTabs);
  4617.     if dgDragOutRows in Value then Include(Value, dgRowSelect);
  4618.     if dgRowSelect in Value then
  4619.     begin
  4620.       Include(NewGridOptions, goRowSelect);
  4621.       Exclude(Value, dgAlwaysShowEditor);
  4622.       Exclude(Value, dgEditing);
  4623.     end;
  4624.     if dgEditing in Value then Include(NewGridOptions, goEditing);
  4625.     if dgAlwaysShowEditor in Value then Include(NewGridOptions, goAlwaysShowEditor);
  4626.     inherited Options := NewGridOptions;
  4627.     if dgMultiSelect in (FOptions - Value) then FBookmarks.Clear;
  4628.     ChangedOptions := (FOptions + Value) - (FOptions * Value);
  4629.     FOptions := Value;
  4630.     FAllowInsert := FAllowInsert and (dgEditing in FOptions); //Volga
  4631.     FAllowDelete := FAllowDelete and (dgEditing in FOptions); //Volga
  4632.     if ChangedOptions * LayoutOptions <> [] then LayoutChanged;
  4633.   end;
  4634. end;
  4635.  
  4636. procedure TVolgaCustomDBGrid.SetSelectedField(Value: TField);
  4637. var
  4638.   I: Integer;
  4639. begin
  4640.   if Value = nil then Exit;
  4641.   for I := 0 to Columns.Count - 1 do
  4642.     if Columns[I].Field = Value then
  4643.       MoveCol(DataToRawColumn(I), 0);
  4644. end;
  4645.  
  4646. procedure TVolgaCustomDBGrid.SetSelectedIndex(Value: Integer);
  4647. begin
  4648.   MoveCol(DataToRawColumn(Value), 0);
  4649. end;
  4650.  
  4651. procedure TVolgaCustomDBGrid.SetTitleFont(Value: TFont);
  4652. begin
  4653.   FTitleFont.Assign(Value);
  4654.   if dgTitles in Options then LayoutChanged;
  4655. end;
  4656.  
  4657. function TVolgaCustomDBGrid.StoreColumns: Boolean;
  4658. begin
  4659.   Result := Columns.State = csCustomized;
  4660. end;
  4661.  
  4662. procedure TVolgaCustomDBGrid.TimedScroll(Direction: TGridScrollDirection);
  4663. begin
  4664.   if FDatalink.Active then
  4665.   begin
  4666.     with FDatalink do
  4667.     begin
  4668.       if sdUp in Direction then
  4669.       begin
  4670.         FDataLink.MoveBy(-ActiveRecord - 1);
  4671.         Exclude(Direction, sdUp);
  4672.       end;
  4673.       if sdDown in Direction then
  4674.       begin
  4675.         FDataLink.MoveBy(RecordCount - ActiveRecord);
  4676.         Exclude(Direction, sdDown);
  4677.       end;
  4678.     end;
  4679.     if Direction <> [] then inherited TimedScroll(Direction);
  4680.   end;
  4681. end;
  4682.  
  4683. procedure TVolgaCustomDBGrid.TitleClick(Column: TVolgaColumn);
  4684. begin
  4685.   if Assigned(FOnTitleClick) then FOnTitleClick(Self, Column);
  4686. end;
  4687.  
  4688. procedure TVolgaCustomDBGrid.TitleFontChanged(Sender: TObject);
  4689. begin
  4690.   if (not FSelfChangingTitleFont) and not (csLoading in ComponentState) then
  4691.     ParentFont := False;
  4692.   if dgTitles in Options then LayoutChanged;
  4693. end;
  4694.  
  4695. procedure TVolgaCustomDBGrid.UpdateActive;
  4696. var
  4697.   NewRow: Integer;
  4698.   Field: TField;
  4699. begin
  4700.   if FDatalink.Active and HandleAllocated and not (csLoading in ComponentState) then
  4701.   begin
  4702.     NewRow := FDatalink.ActiveRecord + FTitleOffset;
  4703.     if Row <> NewRow then
  4704.     begin
  4705.       if not (dgAlwaysShowEditor in Options) then HideEditor;
  4706.       MoveColRow(Col, NewRow, False, False);
  4707.       InvalidateEditor;
  4708.     end;
  4709.     Field := SelectedField;
  4710.     if Assigned(Field) and (Field.Text <> FEditText) then
  4711.       InvalidateEditor;
  4712.   end;
  4713. end;
  4714.  
  4715. procedure TVolgaCustomDBGrid.UpdateData;
  4716. var
  4717.   Field: TField;
  4718. begin
  4719.   Field := SelectedField;
  4720.   if Assigned(Field) then
  4721.     if (Field.FieldKind <> fkCalculated) then     //Volga
  4722.       Field.Text := FEditText
  4723.     else //∩ε±δσ ≡σΣαΩ≥Φ≡εΓαφΦ  Calc-∩εδσΘ        //Volga
  4724.       if Assigned(FOnCalcFieldEdited) then        //Volga
  4725.         FOnCalcFieldEdited(Self,Field,FEditText); //Volga
  4726. end;
  4727.  
  4728. procedure TVolgaCustomDBGrid.UpdateRowCount;
  4729. var
  4730.   OldRowCount: Integer;
  4731. begin
  4732.   OldRowCount := RowCount;
  4733.   if RowCount <= FTitleOffset then RowCount := FTitleOffset + 1;
  4734.   FixedRows := FTitleOffset;
  4735.   with FDataLink do
  4736.     if not Active or (RecordCount = 0) or not HandleAllocated then
  4737.       RowCount := 1 + FTitleOffset
  4738.     else
  4739.     begin
  4740.       RowCount := 1000;
  4741.       FDataLink.BufferCount := VisibleRowCount;
  4742.       RowCount := RecordCount + FTitleOffset;
  4743.       if dgRowSelect in Options then TopRow := FixedRows;
  4744.       UpdateActive;
  4745.     end;
  4746.   if OldRowCount <> RowCount then Invalidate;
  4747. end;
  4748.  
  4749. procedure TVolgaCustomDBGrid.UpdateScrollBar;
  4750. var
  4751.   SIOld, SINew: TScrollInfo;
  4752. begin
  4753.   if FDatalink.Active and HandleAllocated then
  4754.     with FDatalink.DataSet do
  4755.     begin
  4756.       SIOld.cbSize := sizeof(SIOld);
  4757.       SIOld.fMask := SIF_ALL;
  4758.       GetScrollInfo(Self.Handle, SB_VERT, SIOld);
  4759.       SINew := SIOld;
  4760.       if IsSequenced then
  4761.       begin
  4762.         SINew.nMin := 1;
  4763.         SINew.nPage := Self.VisibleRowCount;
  4764.         SINew.nMax := Integer(DWORD(RecordCount) + SINew.nPage - 1);
  4765.         if State in [dsInactive, dsBrowse, dsEdit] then
  4766.           SINew.nPos := RecNo;            // else keep old pos
  4767.       end
  4768.       else
  4769.       begin
  4770.         SINew.nMin := 0;
  4771.         SINew.nPage := 0;
  4772.         SINew.nMax := 4;
  4773.         if FDataLink.BOF then SINew.nPos := 0
  4774.         else if FDataLink.EOF then SINew.nPos := 4
  4775.         else SINew.nPos := 2;
  4776.       end;
  4777.       if (SINew.nMin <> SIOld.nMin) or (SINew.nMax <> SIOld.nMax) or
  4778.         (SINew.nPage <> SIOld.nPage) or (SINew.nPos <> SIOld.nPos) then
  4779.         SetScrollInfo(Self.Handle, SB_VERT, SINew, True);
  4780.     end;
  4781. end;
  4782.  
  4783. function TVolgaCustomDBGrid.ValidFieldIndex(FieldIndex: Integer): Boolean;
  4784. begin
  4785.   Result := DataLink.GetMappedIndex(FieldIndex) >= 0;
  4786. end;
  4787.  
  4788. procedure TVolgaCustomDBGrid.CMParentFontChanged(var Message: TMessage);
  4789. begin
  4790.   inherited;
  4791.   if ParentFont then
  4792.   begin
  4793.     FSelfChangingTitleFont := True;
  4794.     try
  4795.       TitleFont := Font;
  4796.     finally
  4797.       FSelfChangingTitleFont := False;
  4798.     end;
  4799.     LayoutChanged;
  4800.   end;
  4801. end;
  4802.  
  4803. procedure TVolgaCustomDBGrid.CMBiDiModeChanged(var Message: TMessage);
  4804. var
  4805.   Loop: Integer;
  4806. begin
  4807.   inherited;
  4808.   for Loop := 0 to ComponentCount - 1 do
  4809.     if Components[Loop] is TVolgaCustomDBGrid then
  4810.       with Components[Loop] as TVolgaCustomDBGrid do
  4811.         { Changing the window, echos down to the subgrid }
  4812.         if Parent <> nil then
  4813.           Parent.BiDiMode := Self.BiDiMode;
  4814. end;
  4815.  
  4816. procedure TVolgaCustomDBGrid.CMExit(var Message: TMessage);
  4817. begin
  4818.   try
  4819.     if FDatalink.Active then
  4820.       with FDatalink.Dataset do
  4821.         if (dgEditing in Options) and (dgCancelOnExit in Options) and
  4822.         (State = dsInsert) and not Modified and not FDatalink.FModified then
  4823.           Cancel
  4824.         else
  4825.           FDataLink.UpdateData;
  4826.   except
  4827.     SetFocus;
  4828.     raise;
  4829.   end;
  4830.   inherited;
  4831. end;
  4832.  
  4833. procedure TVolgaCustomDBGrid.CMFontChanged(var Message: TMessage);
  4834. var
  4835.   I: Integer;
  4836. begin
  4837.   inherited;
  4838.   BeginLayout;
  4839.   try
  4840.     for I := 0 to Columns.Count - 1 do
  4841.       Columns[I].RefreshDefaultFont;
  4842.   finally
  4843.     EndLayout;
  4844.   end;
  4845. end;
  4846.  
  4847. procedure TVolgaCustomDBGrid.CMDeferLayout(var Message);
  4848. begin
  4849.   if AcquireLayoutLock then
  4850.     EndLayout
  4851.   else
  4852.     DeferLayout;
  4853. end;
  4854.  
  4855. procedure TVolgaCustomDBGrid.CMDesignHitTest(var Msg: TCMDesignHitTest);
  4856. var
  4857.   MasterCol: TVolgaColumn;
  4858. begin
  4859.   inherited;
  4860.   if (Msg.Result = 1) and ((FDataLink = nil) or
  4861.     ((Columns.State = csDefault) and
  4862.     (FDataLink.DefaultFields or (not FDataLink.Active)))) then
  4863.     Msg.Result := 0
  4864.   else if (Msg.Result = 0) and (FDataLink <> nil) and (FDataLink.Active)
  4865.     and (Columns.State = csCustomized)
  4866.     and PtInExpandButton(Msg.XPos, Msg.YPos, MasterCol) then
  4867.     Msg.Result := 1;
  4868. end;
  4869.  
  4870. procedure TVolgaCustomDBGrid.WMSetCursor(var Msg: TWMSetCursor);
  4871. begin
  4872.   if (csDesigning in ComponentState) and
  4873.     ((FDataLink = nil) or
  4874.     ((Columns.State = csDefault) and
  4875.     (FDataLink.DefaultFields or not FDataLink.Active))) then
  4876.     Windows.SetCursor(LoadCursor(0, IDC_ARROW))
  4877.   else inherited;
  4878. end;
  4879.  
  4880. procedure TVolgaCustomDBGrid.WMSize(var Message: TWMSize);
  4881. begin
  4882.   inherited;
  4883.   if UpdateLock = 0 then UpdateRowCount;
  4884.   InvalidateTitles;
  4885. end;
  4886.  
  4887. procedure TVolgaCustomDBGrid.WMVScroll(var Message: TWMVScroll);
  4888. var
  4889.   SI: TScrollInfo;
  4890. begin
  4891.   if not AcquireFocus then Exit;
  4892.   if FDatalink.Active then
  4893.     with Message, FDataLink.DataSet do
  4894.       case ScrollCode of
  4895.         SB_LINEUP: FDataLink.MoveBy(-FDatalink.ActiveRecord - 1);
  4896.         SB_LINEDOWN: FDataLink.MoveBy(FDatalink.RecordCount - FDatalink.ActiveRecord);
  4897.         SB_PAGEUP: FDataLink.MoveBy(-VisibleRowCount);
  4898.         SB_PAGEDOWN: FDataLink.MoveBy(VisibleRowCount);
  4899.         SB_THUMBPOSITION:
  4900.           begin
  4901.             if IsSequenced then
  4902.             begin
  4903.               SI.cbSize := sizeof(SI);
  4904.               SI.fMask := SIF_ALL;
  4905.               GetScrollInfo(Self.Handle, SB_VERT, SI);
  4906.               if SI.nTrackPos <= 1 then First
  4907.               else if SI.nTrackPos >= RecordCount then Last
  4908.               else RecNo := SI.nTrackPos;
  4909.             end
  4910.             else
  4911.               case Pos of
  4912.                 0: First;
  4913.                 1: FDataLink.MoveBy(-VisibleRowCount);
  4914.                 2: Exit;
  4915.                 3: FDataLink.MoveBy(VisibleRowCount);
  4916.                 4: Last;
  4917.               end;
  4918.           end;
  4919.         SB_BOTTOM: Last;
  4920.         SB_TOP: First;
  4921.       end;
  4922. end;
  4923.  
  4924. procedure TVolgaCustomDBGrid.SetIme;
  4925. var
  4926.   Column: TVolgaColumn;
  4927. begin
  4928.   if not SysLocale.FarEast then Exit;
  4929.   if Columns.Count = 0 then Exit;
  4930.  
  4931.   ImeName := FOriginalImeName;
  4932.   ImeMode := FOriginalImeMode;
  4933.   Column := Columns[SelectedIndex];
  4934.   if Column.IsImeNameStored then ImeName := Column.ImeName;
  4935.   if Column.IsImeModeStored then ImeMode := Column.ImeMode;
  4936.  
  4937.   if InplaceEditor <> nil then
  4938.   begin
  4939.     TVolgaDBGridInplaceEdit(Self).ImeName := ImeName;
  4940.     TVolgaDBGridInplaceEdit(Self).ImeMode := ImeMode;
  4941.   end;
  4942. end;
  4943.  
  4944. procedure TVolgaCustomDBGrid.UpdateIme;
  4945. begin
  4946.   if not SysLocale.FarEast then Exit;
  4947.   SetIme;
  4948.   SetImeName(ImeName);
  4949.   SetImeMode(Handle, ImeMode);
  4950. end;
  4951.  
  4952. procedure TVolgaCustomDBGrid.WMIMEStartComp(var Message: TMessage);
  4953. begin
  4954.   inherited;
  4955.   ShowEditor;
  4956. end;
  4957.  
  4958. procedure TVolgaCustomDBGrid.WMSetFocus(var Message: TWMSetFocus);
  4959. begin
  4960.   if not ((InplaceEditor <> nil) and
  4961.     (Message.FocusedWnd = InplaceEditor.Handle)) then SetIme;
  4962.   inherited;
  4963. end;
  4964.  
  4965. procedure TVolgaCustomDBGrid.WMKillFocus(var Message: TMessage);
  4966. begin
  4967.   if not SysLocale.FarEast then inherited
  4968.   else
  4969.   begin
  4970.     ImeName := Screen.DefaultIme;
  4971.     ImeMode := imDontCare;
  4972.     inherited;
  4973.     if not ((InplaceEditor <> nil) and
  4974.       (HWND(Message.WParam) = InplaceEditor.Handle)) then
  4975.       ActivateKeyboardLayout(Screen.DefaultKbLayout, KLF_ACTIVATE);
  4976.   end;
  4977. end;
  4978.  
  4979. { Defer action processing to datalink }
  4980.  
  4981. function TVolgaCustomDBGrid.ExecuteAction(Action: TBasicAction): Boolean;
  4982. begin
  4983.   Result := (DataLink <> nil) and DataLink.ExecuteAction(Action);
  4984. end;
  4985.  
  4986. function TVolgaCustomDBGrid.UpdateAction(Action: TBasicAction): Boolean;
  4987. begin
  4988.   Result := (DataLink <> nil) and DataLink.UpdateAction(Action);
  4989. end;
  4990.  
  4991. procedure TVolgaCustomDBGrid.ShowPopupEditor(Column: TVolgaColumn; X, Y: Integer);
  4992. var
  4993.   SubGrid: TVolgaCustomDBGrid;
  4994.   DS: TDataSource;
  4995.   I: Integer;
  4996.   FloatRect: TRect;
  4997.   Cmp: TControl;
  4998. begin
  4999.   if not ((Column.Field <> nil) and (Column.Field is TDataSetField)) then Exit;
  5000.  
  5001.   // find existing popup for this column field, if any, and show it
  5002.   for I := 0 to ComponentCount - 1 do
  5003.     if Components[I] is TVolgaCustomDBGrid then
  5004.     begin
  5005.       SubGrid := TVolgaCustomDBGrid(Components[I]);
  5006.       if (SubGrid.DataSource <> nil) and
  5007.         (SubGrid.DataSource.DataSet = (Column.Field as TDatasetField).NestedDataset) then
  5008.       begin
  5009.         SubGrid.Parent.Show;
  5010.         SubGrid.SetFocus;
  5011.         Exit;
  5012.       end;
  5013.     end;
  5014.  
  5015.   // create another instance of this kind of grid
  5016.   SubGrid := TVolgaCustomDBGrid(TComponentClass(Self.ClassType).Create(Self));
  5017.   try
  5018.     DS := TDataSource.Create(SubGrid);    // incestuous, but easy cleanup
  5019.     DS.Dataset := (Column.Field as TDatasetField).NestedDataset;
  5020.     SubGrid.DataSource := DS;
  5021.     SubGrid.Columns.State := Columns.State;
  5022.     SubGrid.Columns[0].Expanded := True;
  5023.     SubGrid.Visible := False;
  5024.     SubGrid.FloatingDockSiteClass := TCustomDockForm;
  5025.     FloatRect.TopLeft := ClientToScreen(CellRect(Col, Row).BottomRight);
  5026.     if X > Low(Integer) then FloatRect.Left := X;
  5027.     if Y > Low(Integer) then FloatRect.Top := Y;
  5028.     FloatRect.Right := FloatRect.Left + Width;
  5029.     FloatRect.Bottom := FloatRect.Top + Height;
  5030.     SubGrid.ManualFloat(FloatRect);
  5031. //    SubGrid.ManualDock(nil,nil,alClient);
  5032.     SubGrid.Parent.BiDiMode := Self.BiDiMode; { This carries the BiDi setting }
  5033.     I := SubGrid.CellRect(SubGrid.ColCount - 1, 0).Right;
  5034.     if (I > 0) and (I < Screen.Width div 2) then
  5035.       SubGrid.Parent.ClientWidth := I
  5036.     else
  5037.       SubGrid.Parent.Width := Screen.Width div 4;
  5038.     SubGrid.Parent.Height := Screen.Height div 4;
  5039.     SubGrid.Align := alClient;
  5040.     SubGrid.DragKind := dkDock;
  5041.     SubGrid.Color := Color;
  5042.     SubGrid.Ctl3D := Ctl3D;
  5043.     SubGrid.Cursor := Cursor;
  5044.     SubGrid.Enabled := Enabled;
  5045.     SubGrid.FixedColor := FixedColor;
  5046.     SubGrid.Font := Font;
  5047.     SubGrid.HelpContext := HelpContext;
  5048.     SubGrid.IMEMode := IMEMode;
  5049.     SubGrid.IMEName := IMEName;
  5050.     SubGrid.Options := Options;
  5051.     Cmp := Self;
  5052.     while (Cmp <> nil) and (TVolgaCustomDBGrid(Cmp).PopupMenu = nil) do
  5053.       Cmp := Cmp.Parent;
  5054.     if Cmp <> nil then
  5055.       SubGrid.PopupMenu := TVolgaCustomDBGrid(Cmp).PopupMenu;
  5056.     SubGrid.TitleFont := TitleFont;
  5057.     SubGrid.Visible := True;
  5058.     SubGrid.Parent.Show;
  5059.   except
  5060.     SubGrid.Free;
  5061.     raise;
  5062.   end;
  5063. end;
  5064.  
  5065. procedure TVolgaCustomDBGrid.CalcSizingState(X, Y: Integer;
  5066.   var State: TGridState; var Index, SizingPos, SizingOfs: Integer;
  5067.   var FixedInfo: TGridDrawInfo);
  5068. var
  5069.   R: TGridCoord;
  5070. begin
  5071.   inherited CalcSizingState(X, Y, State, Index, SizingPos, SizingOfs, FixedInfo);
  5072.   if (State = gsColSizing) and (FDataLink <> nil)
  5073.     and (FDatalink.Dataset <> nil) and FDataLink.Dataset.ObjectView then
  5074.   begin
  5075.     R := MouseCoord(X, Y);
  5076.     R.X := RawToDataColumn(R.X);
  5077.     if (R.X >= 0) and (R.X < Columns.Count) and (Columns[R.X].Depth > R.Y) then
  5078.       State := gsNormal;
  5079.   end;
  5080. end;
  5081.  
  5082. function TVolgaCustomDBGrid.CheckColumnDrag(var Origin, Destination: Integer;
  5083.   const MousePt: TPoint): Boolean;
  5084. var
  5085.   I, ARow: Integer;
  5086.   DestCol: TVolgaColumn;
  5087. begin
  5088.   Result := inherited CheckColumnDrag(Origin, Destination, MousePt);
  5089.   if Result and (FDatalink.Dataset <> nil) and FDatalink.Dataset.ObjectView then
  5090.   begin
  5091.     assert(FDragCol <> nil);
  5092.     ARow := FDragCol.Depth;
  5093.     if Destination <> Origin then
  5094.     begin
  5095.       DestCol := ColumnAtDepth(Columns[RawToDataColumn(Destination)], ARow);
  5096.       if DestCol.ParentColumn <> FDragCol.ParentColumn then
  5097.         if Destination < Origin then
  5098.           DestCol := Columns[FDragCol.ParentColumn.Index + 1]
  5099.         else
  5100.         begin
  5101.           I := DestCol.Index;
  5102.           while DestCol.ParentColumn <> FDragCol.ParentColumn do
  5103.           begin
  5104.             Dec(I);
  5105.             DestCol := Columns[I];
  5106.           end;
  5107.         end;
  5108.       if (DestCol.Index > FDragCol.Index) then
  5109.       begin
  5110.         I := DestCol.Index + 1;
  5111.         while (I < Columns.Count) and (ColumnAtDepth(Columns[I], ARow) = DestCol) do
  5112.           Inc(I);
  5113.         DestCol := Columns[I - 1];
  5114.       end;
  5115.       Destination := DataToRawColumn(DestCol.Index);
  5116.     end;
  5117.   end;
  5118. end;
  5119.  
  5120. function TVolgaCustomDBGrid.BeginColumnDrag(var Origin, Destination: Integer;
  5121.   const MousePt: TPoint): Boolean;
  5122. var
  5123.   I, ARow: Integer;
  5124. begin
  5125.   Result := inherited BeginColumnDrag(Origin, Destination, MousePt);
  5126.   if Result and (FDatalink.Dataset <> nil) and FDatalink.Dataset.ObjectView then
  5127.   begin
  5128.     ARow := MouseCoord(MousePt.X, MousePt.Y).Y;
  5129.     FDragCol := ColumnAtDepth(Columns[RawToDataColumn(Origin)], ARow);
  5130.     if FDragCol = nil then Exit;
  5131.     I := DataToRawColumn(FDragCol.Index);
  5132.     if Origin <> I then Origin := I;
  5133.     Destination := Origin;
  5134.   end;
  5135. end;
  5136.  
  5137. function TVolgaCustomDBGrid.EndColumnDrag(var Origin, Destination: Integer;
  5138.   const MousePt: TPoint): Boolean;
  5139. begin
  5140.   Result := inherited EndColumnDrag(Origin, Destination, MousePt);
  5141.   FDragCol := nil;
  5142. end;
  5143.  
  5144. procedure TVolgaCustomDBGrid.InvalidateTitles;
  5145. var
  5146.   R: TRect;
  5147.   DrawInfo: TGridDrawInfo;
  5148. begin
  5149.   if HandleAllocated and (dgTitles in Options) and (FDatalink <> nil) and
  5150.     (FDatalink.Dataset <> nil) then
  5151.   begin
  5152.     CalcFixedInfo(DrawInfo);
  5153.     R := Rect(0, 0, Width, DrawInfo.Vert.FixedBoundary);
  5154.     InvalidateRect(Handle, @R, False);
  5155.   end;
  5156. end;
  5157.  
  5158. procedure TVolgaCustomDBGrid.TopLeftChanged;
  5159. begin
  5160.   InvalidateTitles;
  5161.   inherited TopLeftChanged;
  5162. end;
  5163.  
  5164. procedure TVolgaCustomDBGrid.InvalidateCurrentRow; //Volga
  5165. var i:integer;
  5166. begin
  5167.   for i:= 0 to colCount-1 do InvalidateCell(i, row);
  5168. end;
  5169.  
  5170. procedure TVolgaCustomDBGrid.SetAllowDelete(const Value: Boolean);
  5171. begin                                           //Volga
  5172.   FAllowDelete := Value and (dgEditing in Options);
  5173. end;
  5174.  
  5175. procedure TVolgaCustomDBGrid.SetAllowInsert(const Value: Boolean);
  5176. begin                                          //Volga
  5177.   FAllowInsert := Value and (dgEditing in Options);
  5178. end;
  5179.  
  5180. function TVolgaCustomDBGrid.ColumnByName(const AName: string): TVolgaColumn;
  5181. var i: integer;
  5182. begin
  5183.   Result := nil;
  5184.   for i := 0 to Columns.Count-1 do
  5185.     if AnsiCompareText(Columns[i].FieldName, AName) = 0 then begin
  5186.       Result := Columns[i];
  5187.       Exit;
  5188.     end;
  5189. end;
  5190.  
  5191. procedure TVolgaCustomDBGrid.SetSelectedColor(const Value: TColor);
  5192. begin  //volga
  5193.   FSelectedColor := Value;
  5194.   Invalidate;
  5195. end;
  5196.  
  5197. procedure TVolgaCustomDBGrid.SetSelectedFontColor(const Value: TColor);
  5198. begin  //volga
  5199.   FSelectedFontColor := Value;
  5200.   Invalidate;
  5201. end;
  5202.  
  5203. end.
  5204.  
  5205.