ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/ibcontrols/IBDynamicGrid.pas
Revision: 80
Committed: Mon Jan 1 11:31:07 2018 UTC (6 years, 10 months ago) by tony
Content type: text/x-pascal
File size: 40493 byte(s)
Log Message:
Fixes merged into public release

File Contents

# User Rev Content
1 tony 21 (*
2     * IBX For Lazarus (Firebird Express)
3     *
4     * The contents of this file are subject to the Initial Developer's
5     * Public License Version 1.0 (the "License"); you may not use this
6     * file except in compliance with the License. You may obtain a copy
7     * of the License here:
8     *
9     * http://www.firebirdsql.org/index.php?op=doc&id=idpl
10     *
11     * Software distributed under the License is distributed on an "AS
12     * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
13     * implied. See the License for the specific language governing rights
14     * and limitations under the License.
15     *
16     * The Initial Developer of the Original Code is Tony Whyman.
17     *
18 tony 23 * The Original Code is (C) 2015 Tony Whyman, MWA Software
19 tony 21 * (http://www.mwasoftware.co.uk).
20     *
21     * All Rights Reserved.
22     *
23     * Contributor(s): ______________________________________.
24     *
25     *)
26 tony 35
27 tony 21 unit IBDynamicGrid;
28    
29     {$mode objfpc}{$H+}
30    
31     interface
32    
33     uses
34     Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, DBGrids, DB,
35 tony 27 IBSQLParser, Grids, IBLookupComboEditBox, LMessages, StdCtrls, ExtCtrls,
36     IBCustomDataSet;
37 tony 21
38     type
39     {
40     TIBDynamicGrid is a TDBGrid descendent that provides for:
41     - automatic resizing of selected columns to fill the available row length
42     - automatic positioning and sizing of a "totals" control, typically at the
43     column footer, on a per column basis.
44     - DataSet resorting on header row click, sorting the dataset by the selected column.
45     A second click on the same header cell reversed the sort order.
46     - Reselection of the same row following resorting.
47     - A new cell editor that provides the same functionality as TIBLookupComboEditBox.
48     Its properties are specified on a per column basis and allows for one or more
49     columns to have their values selected from a list provided by a dataset.
50     Autocomplete and autoinsert are also available. The existing picklist editor
51     is unaffected by the extension.
52     }
53    
54     TIBDynamicGrid = class;
55    
56     TOnColumnHeaderClick = procedure(Sender: TObject; var ColIndex: integer) of object;
57     TOnUpdateSortOrder = procedure (Sender: TObject; ColIndex: integer; var OrderBy: string) of Object;
58     TKeyDownHandler = procedure (Sender: TObject; var Key: Word; Shift: TShiftState; var Done: boolean) of object;
59    
60     { TDBDynamicGridColumn }
61    
62     TDBDynamicGridColumn = class(TColumn)
63     private
64     FAutoSizeColumn: boolean;
65     FColumnTotalsControl: TControl;
66     FDesignWidth: integer;
67     function GetWidth: integer;
68     procedure SetWidth(AValue: integer);
69     public
70     property DesignWidth: integer read FDesignWidth;
71     published
72     property ColumnTotalsControl: TControl read FColumnTotalsControl write FColumnTotalsControl;
73     property AutoSizeColumn: boolean read FAutoSizeColumn write FAutoSizeColumn;
74     property Width: integer read GetWidth write SetWidth;
75     end;
76    
77     TIBDynamicGridColumn = class;
78    
79     { TDBLookupProperties }
80    
81     TDBLookupProperties = class(TPersistent)
82     private
83     FAutoComplete: boolean;
84     FAutoCompleteText: TComboBoxAutoCompleteText;
85     FAutoInsert: boolean;
86     FDataFieldName: string;
87     FItemHeight: integer;
88     FItemWidth: integer;
89     FKeyField: string;
90     FKeyPressInterval: integer;
91     FListField: string;
92     FListSource: TDataSource;
93     FOnAutoInsert: TAutoInsert;
94     FOnCanAutoInsert: TCanAutoInsert;
95 tony 31 FOnCloseUp: TNotifyEvent;
96 tony 21 FOnDrawItem: TDrawItemEvent;
97     FOwner: TIBDynamicGridColumn;
98     FRelationName: string;
99     FStyle: TComboBoxStyle;
100     function GetAutoCompleteText: TComboBoxAutoCompleteText;
101     procedure SetAutoCompleteText(AValue: TComboBoxAutoCompleteText);
102     public
103     constructor Create(aOwner: TIBDynamicGridColumn);
104     property Owner: TIBDynamicGridColumn read FOwner;
105     published
106     property DataFieldName: string read FDataFieldName write FDataFieldName;
107     property KeyField: string read FKeyField write FKeyField;
108     property ItemHeight: integer read FItemHeight write FItemHeight;
109     property ItemWidth: integer read FItemWidth write FItemWidth;
110     property ListSource: TDataSource read FListSource write FListSource;
111     property ListField: string read FListField write FListField;
112     property AutoInsert: boolean read FAutoInsert write FAutoInsert default true;
113     property AutoComplete: boolean read FAutoComplete write FAutoComplete default true;
114     property AutoCompleteText: TComboBoxAutoCompleteText
115     read GetAutoCompleteText write SetAutoCompleteText
116     default DefaultComboBoxAutoCompleteText;
117     property KeyPressInterval: integer read FKeyPressInterval write FKeyPressInterval default 500;
118     property RelationName: string read FRelationName write FRelationName;
119     property Style: TComboBoxStyle read FStyle write FStyle default csDropDown;
120     property OnAutoInsert: TAutoInsert read FOnAutoInsert write FOnAutoInsert;
121     property OnCanAutoInsert: TCanAutoInsert read FOnCanAutoInsert write FOnCanAutoInsert;
122 tony 31 property OnCloseUp: TNotifyEvent read FOnCloseUp write FOnCloseUp;
123 tony 21 property OnDrawItem: TDrawItemEvent read FOnDrawItem write FOnDrawItem;
124     end;
125    
126     TDBLookupCellEditor = class;
127    
128     { TIBDynamicGridColumn }
129    
130     TIBDynamicGridColumn = class(TDBDynamicGridColumn)
131     private
132     FDBLookupProperties: TDBLookupProperties;
133     FInitialSortColumn: boolean;
134     procedure DoSetupEditor(Data: PtrInt);
135     procedure DoSetDataSources(Data: PtrInt);
136     procedure SetInitialSortColumn(AValue: boolean);
137     public
138     procedure SetupEditor(Editor: TDBlookupCellEditor);
139     constructor Create(ACollection: TCollection); override;
140     destructor Destroy; override;
141     published
142     property InitialSortColumn: boolean read FInitialSortColumn write SetInitialSortColumn;
143     property DBLookupProperties: TDBLookupProperties read FDBLookupProperties write FDBLookupProperties;
144     end;
145    
146     { TDBLookupCellEditor }
147    
148     TDBLookupCellEditor = class(TIBLookupComboEditBox)
149     private
150     FGrid: TCustomGrid;
151     FCol,FRow: Integer;
152     FEditText: string;
153 tony 39 function EditingKeyField: boolean;
154 tony 21 protected
155     procedure WndProc(var TheMessage : TLMessage); override;
156     procedure CloseUp; override;
157     procedure KeyDown(var Key : Word; Shift : TShiftState); override;
158 tony 27 procedure Loaded; override;
159 tony 21 procedure msg_GetValue(var Msg: TGridMessage); message GM_GETVALUE;
160     procedure msg_SetGrid(var Msg: TGridMessage); message GM_SETGRID;
161     procedure msg_SetValue(var Msg: TGridMessage); message GM_SETVALUE;
162     procedure msg_SetPos(var Msg: TGridMessage); message GM_SETPOS;
163     procedure msg_GetGrid(var Msg: TGridMessage); message GM_GETGRID;
164     public
165     procedure EditingDone; override;
166     property BorderStyle;
167     property OnEditingDone;
168     end;
169    
170 tony 41 TOnSelectPanelEditor = procedure(Sender: TObject; var aEditorPanel: TWinControl) of object;
171    
172 tony 21 TDBDynamicGrid = class(TDBGrid)
173     private
174     { Private declarations }
175     FExpandEditorPanelBelowRow: boolean;
176     FEditorPanel: TWinControl;
177     FExpandedRow: integer;
178     FOnBeforeEditorHide: TNotifyEvent;
179     FOnEditorPanelHide: TNotifyEvent;
180     FOnEditorPanelShow: TNotifyEvent;
181     FOnKeyDownHander: TKeyDownHandler;
182 tony 41 FOnSelectPanelEditor: TOnSelectPanelEditor;
183 tony 21 FResizing: boolean;
184     FWeHaveFocus: boolean;
185     FHidingEditorPanel: boolean;
186     FAllowHide: boolean;
187 tony 35 FMouseDown: boolean;
188 tony 31 function ActiveControl: TControl;
189 tony 21 procedure DoShowEditorPanel(Data: PtrInt);
190     procedure PositionTotals;
191     procedure KeyDownHandler(Sender: TObject; var Key: Word; Shift: TShiftState);
192 tony 35 procedure PerformEditorHide(Data: PtrInt);
193 tony 21 procedure SetEditorPanel(AValue: TWinControl);
194     protected
195     procedure ChangeBounds(ALeft, ATop, AWidth, AHeight: integer; KeepBase: boolean); override;
196     procedure DoEnter; override;
197     procedure DoExit; override;
198     procedure DoGridResize;
199     procedure DoEditorHide; override;
200     procedure DoEditorShow; override;
201     procedure DrawCellText(aCol,aRow: Integer; aRect: TRect; aState: TGridDrawState; aText: String); override;
202     Function EditingAllowed(ACol : Integer = -1) : Boolean; override;
203     procedure EditorHide; override;
204     procedure IndicatorClicked(Button: TMouseButton; Shift:TShiftState); virtual;
205     procedure KeyDown(var Key : Word; Shift : TShiftState); override;
206     procedure Loaded; override;
207     procedure DoOnResize; override;
208     function CreateColumns: TGridColumns; override;
209     procedure HeaderSized(IsColumn: Boolean; Index: Integer); override;
210     procedure MouseDown(Button: TMouseButton; Shift:TShiftState; X,Y:Integer); override;
211     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
212     procedure TopLeftChanged; override;
213     procedure UpdateActive; override;
214     procedure UpdateEditorPanelBounds;
215     procedure UpdateShowing; override;
216     public
217     procedure HideEditorPanel;
218     procedure ShowEditorPanel;
219     constructor Create(TheComponent: TComponent); override;
220     destructor Destroy ;override;
221     procedure ResizeColumns;
222 tony 27 property VisibleRowCount;
223 tony 21 published
224     property EditorPanel: TWinControl read FEditorPanel write SetEditorPanel;
225     property ExpandEditorPanelBelowRow: boolean read FExpandEditorPanelBelowRow write FExpandEditorPanelBelowRow;
226     property OnBeforeEditorHide: TNotifyEvent read FOnBeforeEditorHide write FOnBeforeEditorHide;
227     property OnEditorPanelShow: TNotifyEvent read FOnEditorPanelShow write FOnEditorPanelShow;
228     property OnEditorPanelHide: TNotifyEvent read FOnEditorPanelHide write FOnEditorPanelHide;
229     property OnKeyDownHander: TKeyDownHandler read FOnKeyDownHander write FOnKeyDownHander;
230 tony 41 property OnSelectPanelEditor: TOnSelectPanelEditor read FOnSelectPanelEditor
231     write FOnSelectPanelEditor;
232 tony 21 end;
233    
234 tony 27 {TIBGridControlLink}
235    
236     TIBGridControlLink = class(TIBControlLink)
237     private
238     FOwner: TIBDynamicGrid;
239     protected
240     procedure UpdateSQL(Sender: TObject); override;
241     public
242     constructor Create(AOwner: TIBDynamicGrid);
243     end;
244    
245     TLocationArray = array of variant;
246     PLocationArray = ^TLocationArray;
247     TOnRestorePosition = procedure(Sender: TObject; Location: PLocationArray) of object;
248    
249 tony 21 { TIBDynamicGrid }
250    
251     TIBDynamicGrid = class(TDBDynamicGrid)
252     private
253     { Private declarations }
254     FAllowColumnSort: boolean;
255 tony 27 FIBControlLink: TIBGridControlLink;
256 tony 21 FOnColumnHeaderClick: TOnColumnHeaderClick;
257 tony 27 FOnRestorePosition: TOnRestorePosition;
258 tony 21 FOnUpdateSortOrder: TOnUpdateSortOrder;
259     FDefaultPositionAtEnd: boolean;
260     FDescending: boolean;
261     FColHeaderClick: boolean;
262     FLastColIndex: integer;
263     FIndexFieldNames: string;
264     FIndexFieldsList: TStringList;
265 tony 27 FBookmark: TLocationArray;
266 tony 21 FDBLookupCellEditor: TDBLookupCellEditor;
267     FActive: boolean;
268 tony 37 FFieldPosition: integer;
269 tony 21 procedure ColumnHeaderClick(Index: integer);
270     function GetDataSource: TDataSource;
271     function GetEditorBorderStyle: TBorderStyle;
272 tony 27 procedure IBControlLinkChanged;
273 tony 21 procedure SetDataSource(AValue: TDataSource);
274     procedure SetEditorBorderStyle(AValue: TBorderStyle);
275     procedure ProcessColumns;
276     procedure SetIndexFieldNames(AValue: string);
277     procedure UpdateSQL(Sender: TObject; Parser: TSelectSQLParser);
278     procedure UpdateSortColumn(Sender: TObject);
279 tony 27 procedure RestorePosition;
280     procedure SavePosition;
281 tony 21 procedure DoReOpen(Data: PtrInt);
282     procedure SetupEditor(aEditor: TDBLookupCellEditor; aCol: integer);
283     protected
284     { Protected declarations }
285     procedure DoEditorHide; override;
286     procedure Loaded; override;
287     function CreateColumns: TGridColumns; override;
288     procedure MouseDown(Button: TMouseButton; Shift:TShiftState; X,Y:Integer); override;
289     procedure LinkActive(Value: Boolean); override;
290 tony 27 procedure MoveSelection; override;
291 tony 21 procedure Notification(AComponent: TComponent; Operation: TOperation); override;
292     procedure UpdateActive; override;
293     public
294     { Public declarations }
295     constructor Create(TheComponent: TComponent); override;
296     destructor Destroy; override;
297     function EditorByStyle(Style: TColumnButtonStyle): TWinControl; override;
298     property LastSortColumn: integer read FLastColIndex;
299     published
300     { Published declarations }
301     property AllowColumnSort: boolean read FAllowColumnSort write FAllowColumnSort default true;
302     property DataSource: TDataSource read GetDataSource write SetDataSource;
303     property Descending: boolean read FDescending write FDescending;
304     property EditorBorderStyle: TBorderStyle read GetEditorBorderStyle write SetEditorBorderStyle;
305     property DefaultPositionAtEnd: boolean read FDefaultPositionAtEnd write FDefaultPositionAtEnd;
306     property IndexFieldNames: string read FIndexFieldNames write SetIndexFieldNames;
307     property OnColumnHeaderClick: TOnColumnHeaderClick read FOnColumnHeaderClick write FOnColumnHeaderClick;
308 tony 27 property OnRestorePosition: TOnRestorePosition read FOnRestorePosition write FOnRestorePosition;
309 tony 21 property OnUpdateSortOrder: TOnUpdateSortOrder read FOnUpdateSortOrder write FOnUpdateSortOrder;
310     end;
311    
312     implementation
313    
314 tony 45 uses LCLType, Variants, EditBtn;
315 tony 21
316 tony 27 { TIBGridControlLink }
317    
318     constructor TIBGridControlLink.Create(AOwner: TIBDynamicGrid);
319     begin
320     inherited Create;
321     FOwner := AOwner;
322     end;
323    
324     procedure TIBGridControlLink.UpdateSQL(Sender: TObject);
325     begin
326     FOwner.UpdateSQL(self,TIBParserDataSet(Sender).Parser)
327     end;
328    
329 tony 21 { TDBLookupProperties }
330    
331     function TDBLookupProperties.GetAutoCompleteText: TComboBoxAutoCompleteText;
332     begin
333     Result := FAutoCompleteText;
334     if AutoComplete then
335     Result := Result + [cbactEnabled]
336     end;
337    
338     procedure TDBLookupProperties.SetAutoCompleteText(
339     AValue: TComboBoxAutoCompleteText);
340     begin
341     if AValue <> AutoCompleteText then
342     begin
343     FAutoComplete := cbactEnabled in AValue;
344     FAutoCompleteText := AValue - [cbactEnabled]
345     end;
346     end;
347    
348     constructor TDBLookupProperties.Create(aOwner: TIBDynamicGridColumn);
349     begin
350     inherited Create;
351     FOwner := aOwner;
352     FAutoInsert := true;
353     FAutoComplete := true;
354     FAutoCompleteText := DefaultComboBoxAutoCompleteText;
355     FKeyPressInterval := 500;
356     FListSource := nil;
357     FStyle := csDropDown;
358     end;
359    
360     { TDBDynamicGrid }
361    
362     procedure TDBDynamicGrid.DoGridResize;
363     var ColSum: integer;
364     ResizeColCount: integer;
365     I: integer;
366     adjustment: integer;
367     n: integer;
368     begin
369     if (csDesigning in ComponentState) or (Columns.Count = 0) then Exit;
370    
371     FResizing := true;
372     try
373     ColSum := 0;
374    
375 tony 35 if (ColCount = 1) and TDBDynamicGridColumn(Columns[0]).AutoSizeColumn then
376     Columns[0].Width := ClientWidth
377     else
378 tony 21 begin
379 tony 35 for I := 0 to ColCount - 1 do
380 tony 39 if (I < FixedCols) or Columns[I - FixedCols].Visible then
381 tony 35 ColSum := ColSum + ColWidths[I];
382 tony 21
383 tony 35 if Colsum <> ClientWidth then
384     begin
385     ResizeColCount := 0;
386     for I := 0 to Columns.Count -1 do
387 tony 39 if TDBDynamicGridColumn(Columns[I]).AutoSizeColumn and Columns[I].Visible then
388 tony 35 begin
389     Inc(ResizeColCount);
390     Colsum := Colsum + TDBDynamicGridColumn(Columns[I]).DesignWidth - Columns[I].Width;
391     Columns[I].Width := TDBDynamicGridColumn(Columns[I]).DesignWidth;
392     end;
393 tony 21
394 tony 35 if (Colsum < ClientWidth) and (ResizeColCount > 0) then
395     begin
396     adjustment := (ClientWidth - ColSum) div ResizeColCount;
397     n := (ClientWidth - ColSum) mod ResizeColCount;
398    
399     for I := 0 to Columns.Count -1 do
400 tony 39 if TDBDynamicGridColumn(Columns[I]).AutoSizeColumn and Columns[I].Visible then
401 tony 35 begin
402     if I = 0 then
403     Columns[I].Width := Columns[I].Width + adjustment + n
404     else
405     Columns[I].Width := Columns[I].Width + adjustment;
406     end;
407     end;
408     end;
409 tony 21 end;
410     PositionTotals;
411     UpdateEditorPanelBounds;
412     finally
413     FResizing := false
414     end;
415     end;
416    
417     procedure TDBDynamicGrid.DoEditorHide;
418     begin
419     inherited DoEditorHide;
420 tony 27 if Editor = FEditorPanel then
421     begin
422 tony 35 if FMouseDown then
423     Application.QueueAsyncCall(@PerformEditorHide,FExpandedRow)
424     else
425     PerformEditorHide(FExpandedRow);
426 tony 27 FExpandedRow := -1;
427     end;
428 tony 21 end;
429    
430     procedure TDBDynamicGrid.DoEditorShow;
431     begin
432 tony 35 if assigned(DataSource) and assigned(DataSource.DataSet) and
433     DataSource.DataSet.Active then
434     begin
435     if (DataSource.DataSet.RecordCount = 0) and (DataSource.DataSet.State <> dsInsert) then
436     DataSource.DataSet.Append
437     end;
438 tony 21 if Editor = FEditorPanel then
439     begin
440     if ExpandEditorPanelBelowRow then
441     RowHeights[Row] := FEditorPanel.Height + DefaultRowHeight
442     else
443     RowHeights[Row] := FEditorPanel.Height;
444     FExpandedRow := Row;
445     inherited DoEditorShow;
446     UpdateEditorPanelBounds; {Position Editor Panel over expanded Row}
447     FEditorPanel.PerformTab(true); {Select First Control}
448     if assigned(FOnEditorPanelShow) then
449     OnEditorPanelShow(self);
450 tony 35 if assigned(Editor) and Editor.Visible then
451     Editor.SetFocus;
452 tony 21 end
453     else
454     inherited DoEditorShow;
455     end;
456    
457     procedure TDBDynamicGrid.DrawCellText(aCol, aRow: Integer; aRect: TRect;
458     aState: TGridDrawState; aText: String);
459     var Style: TTextStyle;
460     OldStyle: TTextStyle;
461     begin
462     if ExpandEditorPanelBelowRow and assigned(FEditorPanel) and FEditorPanel.Visible and (aRow = FExpandedRow) then
463     begin
464     {Draw the text at the top of the cell}
465     Style := Canvas.TextStyle;
466     OldStyle := Style;
467     try
468     Style.Layout := tlTop;
469     Canvas.TextStyle := Style;
470     inherited DrawCellText(aCol, aRow, aRect, aState, aText);
471     finally
472     Canvas.TextStyle := OldStyle;
473     end;
474    
475     end
476     else
477     inherited DrawCellText(aCol, aRow, aRect, aState, aText);
478     end;
479    
480     function TDBDynamicGrid.EditingAllowed(ACol: Integer): Boolean;
481     begin
482     Result := ((FEditorPanel <> nil) and (FEditorPanel = Editor))
483     or inherited EditingAllowed(ACol);
484     end;
485    
486     procedure TDBDynamicGrid.EditorHide;
487     begin
488     if assigned(FOnBeforeEditorHide) then
489     OnBeforeEditorHide(self);
490     inherited EditorHide;
491     end;
492    
493     procedure TDBDynamicGrid.IndicatorClicked(Button: TMouseButton;
494     Shift: TShiftState);
495     begin
496     if assigned(FEditorPanel) then
497     begin
498     if FEditorPanel.Visible then
499     HideEditorPanel
500     else
501     ShowEditorPanel;
502     end;
503     end;
504    
505     procedure TDBDynamicGrid.KeyDown(var Key: Word; Shift: TShiftState);
506     begin
507     if (Key = VK_F2) and (Shift = []) and assigned(FEditorPanel) then
508     begin
509     if not FEditorPanel.Visible then
510     ShowEditorPanel
511     end
512     else
513     inherited KeyDown(Key, Shift);
514     end;
515    
516 tony 31 function TDBDynamicGrid.ActiveControl: TControl;
517     var AParent: TWinControl;
518     begin
519     Result := nil;
520     AParent := Parent;
521     while (AParent <> nil) and not (AParent is TCustomForm) do
522     AParent := AParent.Parent;
523     if (AParent <> nil) and (AParent is TCustomForm)then
524     Result := TCustomForm(AParent).ActiveControl;
525     end;
526    
527 tony 21 procedure TDBDynamicGrid.DoShowEditorPanel(Data: PtrInt);
528     begin
529     if AppDestroying in Application.Flags then Exit;
530     ShowEditorPanel;
531     end;
532    
533     procedure TDBDynamicGrid.PositionTotals;
534     var I: integer;
535     acol: TDBDynamicGridColumn;
536     LPos: integer;
537     begin
538     LPos := Left;
539     for I := 0 to FirstGridColumn - 1 do
540     LPos := LPos + ColWidths[I];
541    
542     for I := 0 to Columns.Count - 1 do
543     begin
544     acol := TDBDynamicGridColumn(Columns[I]);
545     if assigned(acol.FColumnTotalsControl) then
546     begin
547     acol.FColumnTotalsControl.AutoSize := false;
548     acol.FColumnTotalsControl.Left := LPos;
549     acol.FColumnTotalsControl.Width := acol.Width
550     end;
551     LPos := LPos + acol.Width;
552     end;
553     end;
554    
555     procedure TDBDynamicGrid.KeyDownHandler(Sender: TObject; var Key: Word;
556     Shift: TShiftState);
557     var Done: boolean;
558 tony 31 AControl: TControl;
559 tony 21 begin
560     if Visible and assigned(FEditorPanel) and FEditorPanel.Visible and FWeHaveFocus then
561     begin
562     Done := false;
563 tony 31 AControl := ActiveControl;
564     if (AControl <> nil) and (AControl is TCustomComboBox)
565     and ((Key in [VK_UP,VK_DOWN]) or
566     (TCustomComboBox(AControl).DroppedDown and (Key = VK_RETURN)) or
567     ((TCustomComboBox(AControl).Text <> '') and (Key = VK_ESCAPE))) then
568     Exit; {ignore these keys if we are in a combobox}
569    
570     if (AControl <> nil) and (AControl is TCustomMemo)
571 tony 49 and (Key in [VK_RETURN,VK_UP,VK_DOWN]) then Exit; {Ignore keys in a CustomMemo}
572 tony 35
573     if (AControl <> nil) and (AControl is TCustomGrid)
574 tony 49 and (Key in [VK_RETURN,VK_UP,VK_DOWN,VK_TAB]) then Exit; {Ignore keys in a Custom Grid}
575 tony 35
576 tony 49 if (AControl <> nil) and (AControl is TEBEdit) and (AControl.Owner is TDateEdit) then
577     begin
578     if (Key in [VK_LEFT,VK_RIGHT]) then Exit; {Ignore navigation keys}
579     if TDateEdit(AControl.Owner).DroppedDown and
580     (Key in [VK_RETURN,VK_UP,VK_DOWN,VK_ESCAPE]) then Exit; {Ignore TCalender navigation keys in a Data edit}
581     end;
582 tony 45
583 tony 21 if assigned(FOnKeyDownHander) then
584     OnKeyDownHander(Sender,Key,Shift,Done);
585     if Done then Exit;
586    
587     {Allow Scrolling}
588     if Key in [VK_UP,VK_DOWN] then
589     KeyDown(Key,Shift)
590     else
591     {Cancel Editor}
592     if Key = VK_ESCAPE then
593     begin
594     if DataLink.DataSet.State in [dsInsert,dsEdit] then
595     DataLink.DataSet.Cancel;
596     KeyDown(Key,Shift);
597     end
598     {save}
599     else
600     if Key = VK_F2 then
601     HideEditorPanel;
602     end
603     end;
604    
605 tony 35 procedure TDBDynamicGrid.PerformEditorHide(Data: PtrInt);
606     var ExpandedRow: integer;
607     begin
608     if AppDestroying in Application.Flags then Exit;
609     ExpandedRow := integer(Data);
610     if (ExpandedRow >= 0) and (ExpandedRow < RowCount) then
611     RowHeights[ExpandedRow] := DefaultRowHeight;
612     if CanFocus then SetFocus;
613     DoOnResize;
614     ResetSizes;
615     DoOnChangeBounds;
616     if assigned(FOnEditorPanelHide) then
617     OnEditorPanelHide(self);
618     end;
619    
620 tony 21 procedure TDBDynamicGrid.SetEditorPanel(AValue: TWinControl);
621     begin
622     if FEditorPanel = AValue then Exit;
623     if FEditorPanel <> nil then
624     RemoveFreeNotification(FEditorPanel);
625     FEditorPanel := AValue;
626 tony 39 if FEditorPanel <> nil then
627     FreeNotification(FEditorPanel);
628 tony 21 end;
629    
630     procedure TDBDynamicGrid.ChangeBounds(ALeft, ATop, AWidth, AHeight: integer;
631     KeepBase: boolean);
632     begin
633     if assigned(FEditorPanel) and FEditorPanel.Visible then
634     Application.QueueAsyncCall(@DoShowEditorPanel,0); {Restore afterwards if necessary}
635     inherited ChangeBounds(ALeft, ATop, AWidth, AHeight, KeepBase);
636     end;
637    
638     procedure TDBDynamicGrid.DoEnter;
639     begin
640     inherited DoEnter;
641     FWeHaveFocus := true;
642     end;
643    
644     procedure TDBDynamicGrid.DoExit;
645     begin
646     FWeHaveFocus := false;
647     inherited DoExit;
648     end;
649    
650     procedure TDBDynamicGrid.Loaded;
651     begin
652     inherited Loaded;
653     if assigned(FEditorPanel) and not (csDesigning in ComponentState)then
654     FEditorPanel.Visible := false;
655 tony 35 if Visible then
656     DoGridResize
657 tony 21 end;
658    
659     procedure TDBDynamicGrid.DoOnResize;
660     begin
661     inherited DoOnResize;
662     DoGridResize
663     end;
664    
665     function TDBDynamicGrid.CreateColumns: TGridColumns;
666     begin
667     result := TDBGridColumns.Create(Self, TDBDynamicGridColumn);
668     end;
669    
670     procedure TDBDynamicGrid.HeaderSized(IsColumn: Boolean; Index: Integer);
671     begin
672     inherited HeaderSized(IsColumn, Index);
673     PositionTotals
674     end;
675    
676     procedure TDBDynamicGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
677     Y: Integer);
678     var Coord: TGridCoord;
679     begin
680 tony 35 FMouseDown := true;
681     try
682     inherited MouseDown(Button, Shift, X, Y);
683     finally
684     FMouseDown := false;
685     end;
686 tony 21
687     Coord := MouseCoord(X,Y);
688     if (Coord.X = 0) and (Coord.Y > 0) then
689     IndicatorClicked(Button,Shift);
690     end;
691    
692     procedure TDBDynamicGrid.Notification(AComponent: TComponent;
693     Operation: TOperation);
694 tony 39 var i: integer;
695 tony 21 begin
696     inherited Notification(AComponent, Operation);
697 tony 39 if (Operation = opRemove) and not (csDestroying in ComponentState) then
698     begin
699     if AComponent = FEditorPanel then
700     FEditorPanel := nil
701     else
702     if AComponent is TControl then
703     begin
704     for i := 0 to Columns.Count - 1 do
705     if TDBDynamicGridColumn(Columns[I]).ColumnTotalsControl = AComponent then
706     TDBDynamicGridColumn(Columns[I]).ColumnTotalsControl := nil;
707     end;
708     end
709 tony 21 end;
710    
711     procedure TDBDynamicGrid.TopLeftChanged;
712     begin
713     inherited TopLeftChanged;
714     UpdateEditorPanelBounds;
715     end;
716    
717     procedure TDBDynamicGrid.UpdateActive;
718     begin
719     inherited UpdateActive;
720    
721 tony 41 if not (csLoading in ComponentState) and assigned(DataLink)
722     and assigned(DataLink.DataSet) and DataLink.DataSet.Active then
723     DoGridResize;
724    
725 tony 21 if not (csLoading in ComponentState) and assigned(DataLink) and
726 tony 35 assigned(FEditorPanel) and not FEditorPanel.Visible and
727 tony 21 assigned(DataLink.DataSet) and (DataLink.DataSet.State = dsInsert) then
728     Application.QueueAsyncCall(@DoShowEditorPanel,0);
729     end;
730    
731     procedure TDBDynamicGrid.UpdateEditorPanelBounds;
732     var R: TRect;
733     Dummy: integer;
734     begin
735     if assigned(FEditorPanel) and FEditorPanel.Visible and
736     (FExpandedRow >= 0) and (FExpandedRow < RowCount) then
737     begin
738     // Upper and Lower bounds for this row
739     ColRowToOffSet(False, True, FExpandedRow, R.Top, R.Bottom);
740     //Left Bound for visible Columns
741     ColRowToOffSet(True,True,1,R.Left,Dummy);
742     //Right Bound for visible columns
743     ColRowToOffSet(True,True,ColCount - 1,Dummy,R.Right);
744     if ExpandEditorPanelBelowRow then
745     R.Top := R.Top + DefaultRowHeight;
746     FEditorPanel.BoundsRect := R;
747     end;
748     end;
749    
750     procedure TDBDynamicGrid.UpdateShowing;
751     begin
752     inherited UpdateShowing;
753     DoGridResize
754     end;
755    
756     procedure TDBDynamicGrid.HideEditorPanel;
757     begin
758     if Editor = FEditorPanel then
759 tony 35 EditorMode := false;
760 tony 21 end;
761    
762     procedure TDBDynamicGrid.ShowEditorPanel;
763 tony 41 var aEditor: TWinControl;
764 tony 21 begin
765 tony 27 if (csDesigning in ComponentState) or
766     (DataSource = nil) or (DataSource.DataSet = nil)
767     or ((DataSource.DataSet.RecordCount = 0) and (DataSource.DataSet.State <> dsInsert)) then
768     Exit;
769 tony 41 aEditor := FEditorPanel;
770     if assigned(FOnSelectPanelEditor) then
771     OnSelectPanelEditor(self,aEditor);
772     if FEditorPanel <> aEditor then
773     SetEditorPanel(aEditor);
774     Editor := aEditor;
775 tony 21 EditorMode := true;
776     end;
777    
778     constructor TDBDynamicGrid.Create(TheComponent: TComponent);
779     begin
780     inherited Create(TheComponent);
781     ScrollBars := ssAutoVertical;
782     if not (csDesigning in ComponentState) then
783     Application.AddOnKeyDownBeforeHandler(@KeyDownHandler,false);
784     end;
785    
786     destructor TDBDynamicGrid.Destroy;
787     begin
788     if not (csDesigning in ComponentState) then
789     Application.RemoveOnKeyDownBeforeHandler(@KeyDownHandler);
790     inherited Destroy;
791     end;
792    
793     procedure TDBDynamicGrid.ResizeColumns;
794     begin
795     DoGridResize;
796     end;
797    
798     { TDBDynamicGridColumn }
799    
800     procedure TDBDynamicGridColumn.SetWidth(AValue: integer);
801     begin
802     if Width = AValue then Exit;
803     inherited Width := AValue;
804     if not TDBDynamicGrid(Grid).FResizing then
805     FDesignWidth := Width
806     end;
807    
808     function TDBDynamicGridColumn.GetWidth: integer;
809     begin
810     Result := inherited Width
811     end;
812    
813 tony 39 type
814     THackedGrid = class(TIBDynamicGrid)
815     public
816     property FixedCols;
817     end;
818    
819 tony 21 { TDBLookupCellEditor }
820    
821 tony 39 function TDBLookupCellEditor.EditingKeyField: boolean;
822     begin
823     with TIBDynamicGridColumn(TDBGrid(FGrid).Columns[FCol - THackedGrid(FGrid).FixedCols]) do
824     Result := CompareText(FieldName, DBLookupProperties.DataFieldName) = 0;
825     end;
826    
827 tony 21 procedure TDBLookupCellEditor.WndProc(var TheMessage: TLMessage);
828     begin
829     if TheMessage.msg=LM_KILLFOCUS then begin
830     if HWND(TheMessage.WParam) = HWND(Handle) then begin
831     // lost the focus but it returns to ourselves
832     // eat the message.
833     TheMessage.Result := 0;
834     exit;
835     end;
836     end;
837     inherited WndProc(TheMessage);
838     end;
839    
840     procedure TDBLookupCellEditor.CloseUp;
841     begin
842     UpdateData(nil); {Force Record Update}
843     if FGrid<>nil then
844 tony 27 Begin
845 tony 39 if EditingKeyField then
846     begin
847     if not VarIsNull(KeyValue) then
848     (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, KeyValue)
849     end
850     else
851     (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, Trim(Text));
852 tony 27 (FGrid as TIBDynamicGrid).UpdateData;
853     end;
854 tony 21 inherited CloseUp;
855     end;
856    
857     procedure TDBLookupCellEditor.KeyDown(var Key: Word; Shift: TShiftState);
858     begin
859     if (Key = VK_TAB) and assigned(FGrid) then
860     TIBDynamicGrid(FGrid).KeyDown(Key,Shift)
861     else
862     inherited KeyDown(Key, Shift);
863     end;
864    
865 tony 27 procedure TDBLookupCellEditor.Loaded;
866     begin
867     inherited Loaded;
868     Text := '';
869     end;
870    
871 tony 21 procedure TDBLookupCellEditor.msg_GetValue(var Msg: TGridMessage);
872     begin
873     CheckAndInsert;
874     Msg.Col := FCol;
875     Msg.Row := FRow;
876 tony 39 if EditingKeyField then
877     begin
878     if not VarIsNull(KeyValue) then
879     Msg.Value:= KeyValue
880     else
881     Msg.Value:= ''
882     end
883     else
884     Msg.Value:= Trim(Text);
885 tony 21 end;
886    
887     procedure TDBLookupCellEditor.msg_SetGrid(var Msg: TGridMessage);
888     begin
889     FGrid:=Msg.Grid;
890     Msg.Options:=EO_AUTOSIZE or EO_SELECTALL or EO_HOOKKEYPRESS or EO_HOOKKEYUP;
891     end;
892    
893     procedure TDBLookupCellEditor.msg_SetValue(var Msg: TGridMessage);
894     begin
895     FGrid := Msg.Grid;
896     FCol := Msg.Col;
897     FRow := Msg.Row;
898     FEditText := Msg.Value;
899     TIBDynamicGrid(FGrid).SetupEditor(self,FCol);
900     end;
901    
902     procedure TDBLookupCellEditor.msg_SetPos(var Msg: TGridMessage);
903     begin
904     FCol := Msg.Col;
905     FRow := Msg.Row;
906     end;
907    
908     procedure TDBLookupCellEditor.msg_GetGrid(var Msg: TGridMessage);
909     begin
910     Msg.Grid := FGrid;
911     Msg.Options:= EO_IMPLEMENTED;
912     end;
913    
914     procedure TDBLookupCellEditor.EditingDone;
915     begin
916     inherited EditingDone;
917     if FGrid<>nil then
918     FGrid.EditingDone;
919     end;
920    
921     { TIBDynamicGridColumn }
922    
923     procedure TIBDynamicGridColumn.DoSetupEditor(Data: PtrInt);
924     var Editor: TDBlookupCellEditor;
925     begin
926     if AppDestroying in Application.Flags then Exit;
927    
928     Editor := TDBlookupCellEditor(Data);
929     Editor.DataSource := nil;
930     Editor.ListSource := nil; {Allows change without causing an error}
931     Editor.KeyValue := NULL;
932    
933     with DBLookupProperties do
934     begin
935     {Setup Properties}
936     Editor.AutoInsert := AutoInsert;
937     Editor.AutoComplete := AutoComplete;
938     Editor.AutoCompleteText := AutoCompleteText;
939     Editor.KeyPressInterval := KeyPressInterval;
940     Editor.Style := Style;
941     Editor.ItemHeight := ItemHeight;
942     Editor.ItemWidth := ItemWidth;
943     Editor.RelationName := RelationName;
944     Editor.OnAutoInsert := OnAutoInsert;
945     Editor.OnCanAutoInsert := OnCanAutoInsert;
946     Editor.OnDrawItem := OnDrawItem;
947 tony 31 Editor.OnCloseUp := OnCloseUp;
948 tony 21
949     {Setup Data Links}
950     if KeyField <> '' then
951     Editor.KeyField := KeyField
952     else
953     Editor.KeyField := ListField;
954     Editor.ListField := ListField;
955     Editor.DataField := DataFieldName;
956     end;
957     Application.QueueAsyncCall(@DoSetDataSources,PtrInt(Editor));
958     end;
959    
960     procedure TIBDynamicGridColumn.DoSetDataSources(Data: PtrInt);
961     var Editor: TDBlookupCellEditor;
962     begin
963     if AppDestroying in Application.Flags then Exit;
964    
965     Editor := TDBlookupCellEditor(Data);
966     with DBLookupProperties do
967     begin
968     Editor.ListSource := ListSource;
969     if DataFieldName <> '' then
970     Editor.DataSource := TDBGrid(Grid).DataSource;
971     end;
972 tony 39 if Editor.EditingKeyField then
973     begin
974     if not Field.IsNull then
975     Editor.KeyValue := Editor.FEditText
976     end
977     else
978     Editor.Text := Editor.FEditText;
979 tony 31 Editor.SelStart := Length(Editor.Text);
980 tony 21 end;
981    
982     procedure TIBDynamicGridColumn.SetInitialSortColumn(AValue: boolean);
983     begin
984     if FInitialSortColumn = AValue then Exit;
985     FInitialSortColumn := AValue;
986     (Grid as TIBDynamicGrid).UpdateSortColumn(self)
987     end;
988    
989     procedure TIBDynamicGridColumn.SetupEditor(Editor: TDBlookupCellEditor);
990     begin
991     Application.QueueAsyncCall(@DoSetupEditor,PtrInt(Editor));
992     end;
993    
994     constructor TIBDynamicGridColumn.Create(ACollection: TCollection);
995     begin
996     inherited Create(ACollection);
997     FDBLookupProperties := TDBLookupProperties.Create(self);
998     end;
999    
1000     destructor TIBDynamicGridColumn.Destroy;
1001     begin
1002     if assigned(FDBLookupProperties) then FDBLookupProperties.Free;
1003 tony 80 Application.RemoveAsyncCalls(self);
1004 tony 21 inherited Destroy;
1005     end;
1006    
1007    
1008     { TIBDynamicGrid }
1009    
1010     procedure TIBDynamicGrid.ColumnHeaderClick(Index: integer);
1011     begin
1012     FColHeaderClick := true;
1013     try
1014     if Index = FLastColIndex then
1015     FDescending := not FDescending;
1016    
1017     if assigned(FOnColumnHeaderClick) then
1018     OnColumnHeaderClick(self,Index);
1019    
1020     FLastColIndex := Index;
1021 tony 37 FFieldPosition := 0;
1022     if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active
1023     and (DataSource.DataSet is TIBParserDataSet) then
1024 tony 21 begin
1025 tony 37 if FLastColIndex < Columns.Count then
1026     {try and cache field position while dataset still open}
1027     FFieldPosition := TIBParserDataSet(DataSource.DataSet).Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1028 tony 21 DataSource.DataSet.Active := false;
1029     Application.QueueAsyncCall(@DoReopen,0)
1030     end;
1031     finally
1032     FColHeaderClick := false
1033     end;
1034     end;
1035    
1036     function TIBDynamicGrid.GetDataSource: TDataSource;
1037     begin
1038     if assigned(DataLink) then
1039     Result := inherited DataSource
1040     else
1041     Result := nil;
1042     end;
1043    
1044     function TIBDynamicGrid.GetEditorBorderStyle: TBorderStyle;
1045     begin
1046     if Editor = FDBLookupCellEditor then
1047     Result := FDBLookupCellEditor.BorderStyle
1048     else
1049     Result := inherited EditorBorderStyle
1050     end;
1051    
1052     procedure TIBDynamicGrid.SetDataSource(AValue: TDataSource);
1053     begin
1054     inherited DataSource := AValue;
1055 tony 27 IBControlLinkChanged;
1056 tony 21 end;
1057    
1058     procedure TIBDynamicGrid.SetEditorBorderStyle(AValue: TBorderStyle);
1059     begin
1060     inherited EditorBorderStyle := AValue;
1061     if FDBLookupCellEditor.BorderStyle <> AValue then
1062     begin
1063     FDBLookupCellEditor.BorderStyle := AValue;
1064     if (Editor = FDBLookupCellEditor) and EditorMode then
1065     EditorWidthChanged(Col,FDBLookupCellEditor.Width);
1066     end;
1067     end;
1068    
1069     procedure TIBDynamicGrid.ProcessColumns;
1070     var i: integer;
1071     begin
1072     for i := 0 to Columns.Count - 1 do
1073     begin
1074     if TIBDynamicGridColumn(columns[i]).InitialSortColumn then
1075 tony 37 begin
1076     FFieldPosition := 0;
1077 tony 21 FLastColIndex := i
1078 tony 37 end
1079 tony 21 end
1080     end;
1081    
1082     procedure TIBDynamicGrid.SetIndexFieldNames(AValue: string);
1083     var idx: integer;
1084     begin
1085     if FIndexFieldNames = AValue then Exit;
1086     FIndexFieldNames := AValue;
1087     idx := 1;
1088     FIndexFieldsList.Clear;
1089     while idx <= Length(AValue) do
1090     FIndexFieldsList.Add(ExtractFieldName(AValue,idx));
1091     end;
1092    
1093     procedure TIBDynamicGrid.UpdateSQL(Sender: TObject; Parser: TSelectSQLParser);
1094     var OrderBy: string;
1095     begin
1096 tony 27 if assigned(DataSource) and assigned(DataSource.DataSet)
1097 tony 21 and (DataSource.DataSet is TIBCustomDataSet) then
1098     begin
1099 tony 37 if (FFieldPosition = 0) and (FLastColIndex >= 0) and (FLastColIndex < Columns.Count) then
1100     {Not cached - let's hope we can find it before the dataset is opened.
1101     Won't work if dynamic columns}
1102     FFieldPosition := Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1103     if FFieldPosition > 0 then
1104 tony 35 begin
1105     if Descending then
1106 tony 37 Parser.OrderByClause := IntToStr(FFieldPosition) + ' desc'
1107 tony 35 else
1108 tony 37 Parser.OrderByClause := IntToStr(FFieldPosition) + ' asc';
1109 tony 35 end;
1110 tony 21
1111     if assigned(FOnUpdateSortOrder) then
1112     begin
1113     OrderBy := Parser.OrderByClause;
1114     OnUpdateSortOrder(self,FLastColIndex,OrderBy);
1115     Parser.OrderByClause := OrderBy
1116     end
1117     end;
1118     end;
1119    
1120     procedure TIBDynamicGrid.UpdateSortColumn(Sender: TObject);
1121     var i: integer;
1122     begin
1123     if Sender is TIBDynamicGridColumn then
1124     begin
1125     for i := 0 to Columns.Count -1 do
1126     if TObject(Columns[i]) <> Sender then
1127     TIBDynamicGridColumn(Columns[i]).InitialSortColumn := false
1128     end
1129    
1130     end;
1131    
1132 tony 27 procedure TIBDynamicGrid.RestorePosition;
1133 tony 21 begin
1134     if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active then
1135     begin
1136 tony 27 if assigned(FOnRestorePosition) then
1137     OnRestorePosition(self,@FBookmark);
1138 tony 21 if (Length(FBookmark) > 0) and
1139     DataSource.DataSet.Locate(FIndexFieldNames,FBookmark,[]) then Exit;
1140    
1141     if FDefaultPositionAtEnd then
1142     DataSource.DataSet.Last
1143     end;
1144     end;
1145    
1146 tony 27 procedure TIBDynamicGrid.SavePosition;
1147     var i: integer;
1148     F: TField;
1149     begin
1150     if FIndexFieldsList = nil then Exit;
1151    
1152     SetLength(FBookmark,FIndexFieldsList.Count);
1153     for i := 0 to FIndexFieldsList.Count - 1 do
1154     begin
1155     F := DataSource.DataSet.FindField(FIndexFieldsList[i]);
1156     if assigned(F) then
1157     FBookmark[i] := F.AsVariant;
1158     end;
1159     end;
1160    
1161 tony 21 procedure TIBDynamicGrid.DoReOpen(Data: PtrInt);
1162     begin
1163     DataSource.DataSet.Active := true;
1164     end;
1165    
1166 tony 27 procedure TIBDynamicGrid.IBControlLinkChanged;
1167     begin
1168     if (DataSource <> nil) and (DataSource.DataSet <> nil) and (DataSource.DataSet is TIBParserDataSet) then
1169     FIBControlLink.IBDataSet := TIBCustomDataSet(DataSource.DataSet)
1170     else
1171     FIBControlLink.IBDataSet := nil;
1172     end;
1173    
1174 tony 21 procedure TIBDynamicGrid.SetupEditor(aEditor: TDBLookupCellEditor; aCol: integer
1175     );
1176     var C: TIBDynamicGridColumn;
1177     begin
1178     C := ColumnFromGridColumn(aCol) as TIBDynamicGridColumn;
1179 tony 27 if (c <> nil) then
1180     C.SetupEditor(aEditor);
1181 tony 21 end;
1182    
1183     procedure TIBDynamicGrid.DoEditorHide;
1184     var i: integer;
1185     begin
1186     inherited DoEditorHide;
1187     if assigned(EditorPanel) then
1188     for i := 0 to EditorPanel.ControlCount -1 do
1189     if EditorPanel.Controls[i] is TIBLookupComboEditBox then
1190     EditorPanel.Controls[i].Perform(CM_VISIBLECHANGED, WParam(ord(false)), 0);
1191     end;
1192    
1193     procedure TIBDynamicGrid.Loaded;
1194     begin
1195     inherited Loaded;
1196 tony 29 IBControlLinkChanged;
1197 tony 21 ProcessColumns;
1198     end;
1199    
1200     function TIBDynamicGrid.CreateColumns: TGridColumns;
1201     begin
1202     result := TDBGridColumns.Create(Self, TIBDynamicGridColumn);
1203     end;
1204    
1205     procedure TIBDynamicGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
1206     Y: Integer);
1207     var Coord: TGridCoord;
1208     obe: boolean;
1209     function PtInRect(const Rect : TRect;const p : TPoint) : Boolean;
1210    
1211     begin
1212     PtInRect:=(p.y>=Rect.Top) and
1213     (p.y<Rect.Bottom) and
1214     (p.x>=Rect.Left) and
1215     (p.x<Rect.Right);
1216     end;
1217     begin
1218     if (Editor is TDBLookupCellEditor) and Editor.Visible
1219     and not PtInRect(Editor.BoundsRect,Point(X,Y)) then
1220     Editor.Perform(CM_EXIT,0,0); {Do insert new value if necessary}
1221     inherited MouseDown(Button, Shift, X, Y);
1222     obe := AllowOutboundEvents;
1223     AllowOutboundEvents := false;
1224     try
1225     Coord := MouseCoord(X,Y);
1226 tony 27 if AllowColumnSort and (Coord.X <> -1) and (FixedRows > 0) and
1227 tony 21 (Coord.Y = 0) and (MouseCoord(X+5,Y).X = Coord.X) {not on boundary}
1228     and (MouseCoord(X-5,Y).X = Coord.X) then
1229     ColumnHeaderClick(Coord.X-1);
1230     finally
1231     AllowOutboundEvents := obe
1232     end;
1233     end;
1234    
1235 tony 27 procedure TIBDynamicGrid.MoveSelection;
1236     begin
1237     inherited MoveSelection;
1238     SavePosition;
1239     end;
1240    
1241 tony 21 procedure TIBDynamicGrid.LinkActive(Value: Boolean);
1242     begin
1243 tony 27 IBControlLinkChanged;
1244 tony 21 inherited LinkActive(Value);
1245     if (FActive <> Value) and Value then
1246 tony 27 RestorePosition;
1247 tony 21 FActive := Value
1248     end;
1249    
1250     procedure TIBDynamicGrid.Notification(AComponent: TComponent;
1251     Operation: TOperation);
1252 tony 39 var i: integer;
1253 tony 21 begin
1254     inherited Notification(AComponent, Operation);
1255 tony 39 if (Operation = opRemove) then
1256     begin
1257     if (FIBControlLink <> nil) and (AComponent = DataSource) then
1258     FIBControlLink.IBDataSet := nil
1259     else
1260     if AComponent is TDataSource then
1261     begin
1262     for i := 0 to Columns.Count - 1 do
1263     if TIBDynamicGridColumn(Columns[I]).DBLookupProperties.ListSource = AComponent then
1264     TIBDynamicGridColumn(Columns[I]).DBLookupProperties.ListSource := nil;
1265     end
1266     end
1267 tony 21 end;
1268    
1269     procedure TIBDynamicGrid.UpdateActive;
1270     begin
1271     inherited UpdateActive;
1272 tony 27 if assigned(DataLink) and assigned(DataLink.DataSet) and
1273     DataLink.DataSet.Active and (DataLink.DataSet.State = dsInsert) then
1274     SavePosition;
1275 tony 21 end;
1276    
1277     constructor TIBDynamicGrid.Create(TheComponent: TComponent);
1278     begin
1279     inherited Create(TheComponent);
1280     FAllowColumnSort := true;
1281 tony 27 FIBControlLink := TIBGridControlLink.Create(self);
1282 tony 21 FIndexFieldsList := TStringList.Create;
1283     FIndexFieldsList.Delimiter := ';';
1284     FIndexFieldsList.StrictDelimiter := true;
1285     FDBLookupCellEditor := TDBLookupCellEditor.Create(nil);
1286     FDBLookupCellEditor.Name := 'DBLookupCellEditor';
1287     FDBLookupCellEditor.Visible := False;
1288     FDBLookupCellEditor.AutoSize := false;
1289     end;
1290    
1291     destructor TIBDynamicGrid.Destroy;
1292     begin
1293 tony 27 if assigned(FIBControlLink) then FIBControlLink.Free;
1294 tony 21 if assigned(FIndexFieldsList) then FIndexFieldsList.Free;
1295     if assigned(FDBLookupCellEditor) then FDBLookupCellEditor.Free;
1296 tony 80 Application.RemoveAsyncCalls(self);
1297 tony 21 inherited Destroy;
1298     end;
1299    
1300     function TIBDynamicGrid.EditorByStyle(Style: TColumnButtonStyle): TWinControl;
1301     var C: TIBDynamicGridColumn;
1302     bs: TColumnButtonStyle;
1303     begin
1304     C := ColumnFromGridColumn(Col) as TIBDynamicGridColumn;
1305     if C <> nil then
1306     begin
1307     bs := C.ButtonStyle;
1308     if (bs in [cbsAuto,cbsPickList]) and assigned(C.DBLookupProperties.ListSource) then
1309     begin
1310     Result := FDBLookupCellEditor;
1311     Exit;
1312     end;
1313     end;
1314     Result := inherited EditorByStyle(Style);
1315     end;
1316    
1317     end.