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