ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/ibcontrols/IBDynamicGrid.pas
Revision: 41
Committed: Sat Jul 16 12:25:48 2016 UTC (7 years, 9 months ago) by tony
Content type: text/x-pascal
File size: 40078 byte(s)
Log Message:
Committing updates for Release R1-4-2

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 39 uses Math, IBQuery, LCLType, Variants;
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 35 and (Key in [VK_RETURN,VK_UP,VK_DOWN]) then Exit; {Ignore Return in a CustomMemo}
572    
573     if (AControl <> nil) and (AControl is TCustomGrid)
574     and (Key in [VK_RETURN,VK_UP,VK_DOWN,VK_TAB]) then Exit; {Ignore Return in a CustomMemo}
575    
576 tony 21 if assigned(FOnKeyDownHander) then
577     OnKeyDownHander(Sender,Key,Shift,Done);
578     if Done then Exit;
579    
580     {Allow Scrolling}
581     if Key in [VK_UP,VK_DOWN] then
582     KeyDown(Key,Shift)
583     else
584     {Cancel Editor}
585     if Key = VK_ESCAPE then
586     begin
587     if DataLink.DataSet.State in [dsInsert,dsEdit] then
588     DataLink.DataSet.Cancel;
589     KeyDown(Key,Shift);
590     end
591     {save}
592     else
593     if Key = VK_F2 then
594     HideEditorPanel;
595     end
596     end;
597    
598 tony 35 procedure TDBDynamicGrid.PerformEditorHide(Data: PtrInt);
599     var ExpandedRow: integer;
600     begin
601     if AppDestroying in Application.Flags then Exit;
602     ExpandedRow := integer(Data);
603     if (ExpandedRow >= 0) and (ExpandedRow < RowCount) then
604     RowHeights[ExpandedRow] := DefaultRowHeight;
605     if CanFocus then SetFocus;
606     DoOnResize;
607     ResetSizes;
608     DoOnChangeBounds;
609     if assigned(FOnEditorPanelHide) then
610     OnEditorPanelHide(self);
611     end;
612    
613 tony 21 procedure TDBDynamicGrid.SetEditorPanel(AValue: TWinControl);
614     begin
615     if FEditorPanel = AValue then Exit;
616     if FEditorPanel <> nil then
617     RemoveFreeNotification(FEditorPanel);
618     FEditorPanel := AValue;
619 tony 39 if FEditorPanel <> nil then
620     FreeNotification(FEditorPanel);
621 tony 21 end;
622    
623     procedure TDBDynamicGrid.ChangeBounds(ALeft, ATop, AWidth, AHeight: integer;
624     KeepBase: boolean);
625     begin
626     if assigned(FEditorPanel) and FEditorPanel.Visible then
627     Application.QueueAsyncCall(@DoShowEditorPanel,0); {Restore afterwards if necessary}
628     inherited ChangeBounds(ALeft, ATop, AWidth, AHeight, KeepBase);
629     end;
630    
631     procedure TDBDynamicGrid.DoEnter;
632     begin
633     inherited DoEnter;
634     FWeHaveFocus := true;
635     end;
636    
637     procedure TDBDynamicGrid.DoExit;
638     begin
639     FWeHaveFocus := false;
640     inherited DoExit;
641     end;
642    
643     procedure TDBDynamicGrid.Loaded;
644     begin
645     inherited Loaded;
646     if assigned(FEditorPanel) and not (csDesigning in ComponentState)then
647     FEditorPanel.Visible := false;
648 tony 35 if Visible then
649     DoGridResize
650 tony 21 end;
651    
652     procedure TDBDynamicGrid.DoOnResize;
653     begin
654     inherited DoOnResize;
655     DoGridResize
656     end;
657    
658     function TDBDynamicGrid.CreateColumns: TGridColumns;
659     begin
660     result := TDBGridColumns.Create(Self, TDBDynamicGridColumn);
661     end;
662    
663     procedure TDBDynamicGrid.HeaderSized(IsColumn: Boolean; Index: Integer);
664     begin
665     inherited HeaderSized(IsColumn, Index);
666     PositionTotals
667     end;
668    
669     procedure TDBDynamicGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
670     Y: Integer);
671     var Coord: TGridCoord;
672     begin
673 tony 35 FMouseDown := true;
674     try
675     inherited MouseDown(Button, Shift, X, Y);
676     finally
677     FMouseDown := false;
678     end;
679 tony 21
680     Coord := MouseCoord(X,Y);
681     if (Coord.X = 0) and (Coord.Y > 0) then
682     IndicatorClicked(Button,Shift);
683     end;
684    
685     procedure TDBDynamicGrid.Notification(AComponent: TComponent;
686     Operation: TOperation);
687 tony 39 var i: integer;
688 tony 21 begin
689     inherited Notification(AComponent, Operation);
690 tony 39 if (Operation = opRemove) and not (csDestroying in ComponentState) then
691     begin
692     if AComponent = FEditorPanel then
693     FEditorPanel := nil
694     else
695     if AComponent is TControl then
696     begin
697     for i := 0 to Columns.Count - 1 do
698     if TDBDynamicGridColumn(Columns[I]).ColumnTotalsControl = AComponent then
699     TDBDynamicGridColumn(Columns[I]).ColumnTotalsControl := nil;
700     end;
701     end
702 tony 21 end;
703    
704     procedure TDBDynamicGrid.TopLeftChanged;
705     begin
706     inherited TopLeftChanged;
707     UpdateEditorPanelBounds;
708     end;
709    
710     procedure TDBDynamicGrid.UpdateActive;
711     begin
712     inherited UpdateActive;
713    
714 tony 41 if not (csLoading in ComponentState) and assigned(DataLink)
715     and assigned(DataLink.DataSet) and DataLink.DataSet.Active then
716     DoGridResize;
717    
718 tony 21 if not (csLoading in ComponentState) and assigned(DataLink) and
719 tony 35 assigned(FEditorPanel) and not FEditorPanel.Visible and
720 tony 21 assigned(DataLink.DataSet) and (DataLink.DataSet.State = dsInsert) then
721     Application.QueueAsyncCall(@DoShowEditorPanel,0);
722     end;
723    
724     procedure TDBDynamicGrid.UpdateEditorPanelBounds;
725     var R: TRect;
726     Dummy: integer;
727     begin
728     if assigned(FEditorPanel) and FEditorPanel.Visible and
729     (FExpandedRow >= 0) and (FExpandedRow < RowCount) then
730     begin
731     // Upper and Lower bounds for this row
732     ColRowToOffSet(False, True, FExpandedRow, R.Top, R.Bottom);
733     //Left Bound for visible Columns
734     ColRowToOffSet(True,True,1,R.Left,Dummy);
735     //Right Bound for visible columns
736     ColRowToOffSet(True,True,ColCount - 1,Dummy,R.Right);
737     if ExpandEditorPanelBelowRow then
738     R.Top := R.Top + DefaultRowHeight;
739     FEditorPanel.BoundsRect := R;
740     end;
741     end;
742    
743     procedure TDBDynamicGrid.UpdateShowing;
744     begin
745     inherited UpdateShowing;
746     DoGridResize
747     end;
748    
749     procedure TDBDynamicGrid.HideEditorPanel;
750     begin
751     if Editor = FEditorPanel then
752 tony 35 EditorMode := false;
753 tony 21 end;
754    
755     procedure TDBDynamicGrid.ShowEditorPanel;
756 tony 41 var aEditor: TWinControl;
757 tony 21 begin
758 tony 27 if (csDesigning in ComponentState) or
759     (DataSource = nil) or (DataSource.DataSet = nil)
760     or ((DataSource.DataSet.RecordCount = 0) and (DataSource.DataSet.State <> dsInsert)) then
761     Exit;
762 tony 41 aEditor := FEditorPanel;
763     if assigned(FOnSelectPanelEditor) then
764     OnSelectPanelEditor(self,aEditor);
765     if FEditorPanel <> aEditor then
766     SetEditorPanel(aEditor);
767     Editor := aEditor;
768 tony 21 EditorMode := true;
769     end;
770    
771     constructor TDBDynamicGrid.Create(TheComponent: TComponent);
772     begin
773     inherited Create(TheComponent);
774     ScrollBars := ssAutoVertical;
775     if not (csDesigning in ComponentState) then
776     Application.AddOnKeyDownBeforeHandler(@KeyDownHandler,false);
777     end;
778    
779     destructor TDBDynamicGrid.Destroy;
780     begin
781     if not (csDesigning in ComponentState) then
782     Application.RemoveOnKeyDownBeforeHandler(@KeyDownHandler);
783     inherited Destroy;
784     end;
785    
786     procedure TDBDynamicGrid.ResizeColumns;
787     begin
788     DoGridResize;
789     end;
790    
791     { TDBDynamicGridColumn }
792    
793     procedure TDBDynamicGridColumn.SetWidth(AValue: integer);
794     begin
795     if Width = AValue then Exit;
796     inherited Width := AValue;
797     if not TDBDynamicGrid(Grid).FResizing then
798     FDesignWidth := Width
799     end;
800    
801     function TDBDynamicGridColumn.GetWidth: integer;
802     begin
803     Result := inherited Width
804     end;
805    
806 tony 39 type
807     THackedGrid = class(TIBDynamicGrid)
808     public
809     property FixedCols;
810     end;
811    
812 tony 21 { TDBLookupCellEditor }
813    
814 tony 39 function TDBLookupCellEditor.EditingKeyField: boolean;
815     begin
816     with TIBDynamicGridColumn(TDBGrid(FGrid).Columns[FCol - THackedGrid(FGrid).FixedCols]) do
817     Result := CompareText(FieldName, DBLookupProperties.DataFieldName) = 0;
818     end;
819    
820 tony 21 procedure TDBLookupCellEditor.WndProc(var TheMessage: TLMessage);
821     begin
822     if TheMessage.msg=LM_KILLFOCUS then begin
823     if HWND(TheMessage.WParam) = HWND(Handle) then begin
824     // lost the focus but it returns to ourselves
825     // eat the message.
826     TheMessage.Result := 0;
827     exit;
828     end;
829     end;
830     inherited WndProc(TheMessage);
831     end;
832    
833     procedure TDBLookupCellEditor.CloseUp;
834     begin
835     UpdateData(nil); {Force Record Update}
836     if FGrid<>nil then
837 tony 27 Begin
838 tony 39 if EditingKeyField then
839     begin
840     if not VarIsNull(KeyValue) then
841     (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, KeyValue)
842     end
843     else
844     (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, Trim(Text));
845 tony 27 (FGrid as TIBDynamicGrid).UpdateData;
846     end;
847 tony 21 inherited CloseUp;
848     end;
849    
850     procedure TDBLookupCellEditor.KeyDown(var Key: Word; Shift: TShiftState);
851     begin
852     if (Key = VK_TAB) and assigned(FGrid) then
853     TIBDynamicGrid(FGrid).KeyDown(Key,Shift)
854     else
855     inherited KeyDown(Key, Shift);
856     end;
857    
858 tony 27 procedure TDBLookupCellEditor.Loaded;
859     begin
860     inherited Loaded;
861     Text := '';
862     end;
863    
864 tony 21 procedure TDBLookupCellEditor.msg_GetValue(var Msg: TGridMessage);
865     begin
866     CheckAndInsert;
867     Msg.Col := FCol;
868     Msg.Row := FRow;
869 tony 39 if EditingKeyField then
870     begin
871     if not VarIsNull(KeyValue) then
872     Msg.Value:= KeyValue
873     else
874     Msg.Value:= ''
875     end
876     else
877     Msg.Value:= Trim(Text);
878 tony 21 end;
879    
880     procedure TDBLookupCellEditor.msg_SetGrid(var Msg: TGridMessage);
881     begin
882     FGrid:=Msg.Grid;
883     Msg.Options:=EO_AUTOSIZE or EO_SELECTALL or EO_HOOKKEYPRESS or EO_HOOKKEYUP;
884     end;
885    
886     procedure TDBLookupCellEditor.msg_SetValue(var Msg: TGridMessage);
887     begin
888     FGrid := Msg.Grid;
889     FCol := Msg.Col;
890     FRow := Msg.Row;
891     FEditText := Msg.Value;
892     TIBDynamicGrid(FGrid).SetupEditor(self,FCol);
893     end;
894    
895     procedure TDBLookupCellEditor.msg_SetPos(var Msg: TGridMessage);
896     begin
897     FCol := Msg.Col;
898     FRow := Msg.Row;
899     end;
900    
901     procedure TDBLookupCellEditor.msg_GetGrid(var Msg: TGridMessage);
902     begin
903     Msg.Grid := FGrid;
904     Msg.Options:= EO_IMPLEMENTED;
905     end;
906    
907     procedure TDBLookupCellEditor.EditingDone;
908     begin
909     inherited EditingDone;
910     if FGrid<>nil then
911     FGrid.EditingDone;
912     end;
913    
914     { TIBDynamicGridColumn }
915    
916     procedure TIBDynamicGridColumn.DoSetupEditor(Data: PtrInt);
917     var Editor: TDBlookupCellEditor;
918     begin
919     if AppDestroying in Application.Flags then Exit;
920    
921     Editor := TDBlookupCellEditor(Data);
922     Editor.DataSource := nil;
923     Editor.ListSource := nil; {Allows change without causing an error}
924     Editor.KeyValue := NULL;
925    
926     with DBLookupProperties do
927     begin
928     {Setup Properties}
929     Editor.AutoInsert := AutoInsert;
930     Editor.AutoComplete := AutoComplete;
931     Editor.AutoCompleteText := AutoCompleteText;
932     Editor.KeyPressInterval := KeyPressInterval;
933     Editor.Style := Style;
934     Editor.ItemHeight := ItemHeight;
935     Editor.ItemWidth := ItemWidth;
936     Editor.RelationName := RelationName;
937     Editor.OnAutoInsert := OnAutoInsert;
938     Editor.OnCanAutoInsert := OnCanAutoInsert;
939     Editor.OnDrawItem := OnDrawItem;
940 tony 31 Editor.OnCloseUp := OnCloseUp;
941 tony 21
942     {Setup Data Links}
943     if KeyField <> '' then
944     Editor.KeyField := KeyField
945     else
946     Editor.KeyField := ListField;
947     Editor.ListField := ListField;
948     Editor.DataField := DataFieldName;
949     end;
950     Application.QueueAsyncCall(@DoSetDataSources,PtrInt(Editor));
951     end;
952    
953     procedure TIBDynamicGridColumn.DoSetDataSources(Data: PtrInt);
954     var Editor: TDBlookupCellEditor;
955     begin
956     if AppDestroying in Application.Flags then Exit;
957    
958     Editor := TDBlookupCellEditor(Data);
959     with DBLookupProperties do
960     begin
961     Editor.ListSource := ListSource;
962     if DataFieldName <> '' then
963     Editor.DataSource := TDBGrid(Grid).DataSource;
964     end;
965 tony 39 if Editor.EditingKeyField then
966     begin
967     if not Field.IsNull then
968     Editor.KeyValue := Editor.FEditText
969     end
970     else
971     Editor.Text := Editor.FEditText;
972 tony 31 Editor.SelStart := Length(Editor.Text);
973 tony 21 end;
974    
975     procedure TIBDynamicGridColumn.SetInitialSortColumn(AValue: boolean);
976     begin
977     if FInitialSortColumn = AValue then Exit;
978     FInitialSortColumn := AValue;
979     (Grid as TIBDynamicGrid).UpdateSortColumn(self)
980     end;
981    
982     procedure TIBDynamicGridColumn.SetupEditor(Editor: TDBlookupCellEditor);
983     begin
984     Application.QueueAsyncCall(@DoSetupEditor,PtrInt(Editor));
985     end;
986    
987     constructor TIBDynamicGridColumn.Create(ACollection: TCollection);
988     begin
989     inherited Create(ACollection);
990     FDBLookupProperties := TDBLookupProperties.Create(self);
991     end;
992    
993     destructor TIBDynamicGridColumn.Destroy;
994     begin
995     if assigned(FDBLookupProperties) then FDBLookupProperties.Free;
996     inherited Destroy;
997     end;
998    
999    
1000     { TIBDynamicGrid }
1001    
1002     procedure TIBDynamicGrid.ColumnHeaderClick(Index: integer);
1003     begin
1004     FColHeaderClick := true;
1005     try
1006     if Index = FLastColIndex then
1007     FDescending := not FDescending;
1008    
1009     if assigned(FOnColumnHeaderClick) then
1010     OnColumnHeaderClick(self,Index);
1011    
1012     FLastColIndex := Index;
1013 tony 37 FFieldPosition := 0;
1014     if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active
1015     and (DataSource.DataSet is TIBParserDataSet) then
1016 tony 21 begin
1017 tony 37 if FLastColIndex < Columns.Count then
1018     {try and cache field position while dataset still open}
1019     FFieldPosition := TIBParserDataSet(DataSource.DataSet).Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1020 tony 21 DataSource.DataSet.Active := false;
1021     Application.QueueAsyncCall(@DoReopen,0)
1022     end;
1023     finally
1024     FColHeaderClick := false
1025     end;
1026     end;
1027    
1028     function TIBDynamicGrid.GetDataSource: TDataSource;
1029     begin
1030     if assigned(DataLink) then
1031     Result := inherited DataSource
1032     else
1033     Result := nil;
1034     end;
1035    
1036     function TIBDynamicGrid.GetEditorBorderStyle: TBorderStyle;
1037     begin
1038     if Editor = FDBLookupCellEditor then
1039     Result := FDBLookupCellEditor.BorderStyle
1040     else
1041     Result := inherited EditorBorderStyle
1042     end;
1043    
1044     procedure TIBDynamicGrid.SetDataSource(AValue: TDataSource);
1045     begin
1046     inherited DataSource := AValue;
1047 tony 27 IBControlLinkChanged;
1048 tony 21 end;
1049    
1050     procedure TIBDynamicGrid.SetEditorBorderStyle(AValue: TBorderStyle);
1051     begin
1052     inherited EditorBorderStyle := AValue;
1053     if FDBLookupCellEditor.BorderStyle <> AValue then
1054     begin
1055     FDBLookupCellEditor.BorderStyle := AValue;
1056     if (Editor = FDBLookupCellEditor) and EditorMode then
1057     EditorWidthChanged(Col,FDBLookupCellEditor.Width);
1058     end;
1059     end;
1060    
1061     procedure TIBDynamicGrid.ProcessColumns;
1062     var i: integer;
1063     begin
1064     for i := 0 to Columns.Count - 1 do
1065     begin
1066     if TIBDynamicGridColumn(columns[i]).InitialSortColumn then
1067 tony 37 begin
1068     FFieldPosition := 0;
1069 tony 21 FLastColIndex := i
1070 tony 37 end
1071 tony 21 end
1072     end;
1073    
1074     procedure TIBDynamicGrid.SetIndexFieldNames(AValue: string);
1075     var idx: integer;
1076     begin
1077     if FIndexFieldNames = AValue then Exit;
1078     FIndexFieldNames := AValue;
1079     idx := 1;
1080     FIndexFieldsList.Clear;
1081     while idx <= Length(AValue) do
1082     FIndexFieldsList.Add(ExtractFieldName(AValue,idx));
1083     end;
1084    
1085     procedure TIBDynamicGrid.UpdateSQL(Sender: TObject; Parser: TSelectSQLParser);
1086     var OrderBy: string;
1087     begin
1088 tony 27 if assigned(DataSource) and assigned(DataSource.DataSet)
1089 tony 21 and (DataSource.DataSet is TIBCustomDataSet) then
1090     begin
1091 tony 37 if (FFieldPosition = 0) and (FLastColIndex >= 0) and (FLastColIndex < Columns.Count) then
1092     {Not cached - let's hope we can find it before the dataset is opened.
1093     Won't work if dynamic columns}
1094     FFieldPosition := Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1095     if FFieldPosition > 0 then
1096 tony 35 begin
1097     if Descending then
1098 tony 37 Parser.OrderByClause := IntToStr(FFieldPosition) + ' desc'
1099 tony 35 else
1100 tony 37 Parser.OrderByClause := IntToStr(FFieldPosition) + ' asc';
1101 tony 35 end;
1102 tony 21
1103     if assigned(FOnUpdateSortOrder) then
1104     begin
1105     OrderBy := Parser.OrderByClause;
1106     OnUpdateSortOrder(self,FLastColIndex,OrderBy);
1107     Parser.OrderByClause := OrderBy
1108     end
1109     end;
1110     end;
1111    
1112     procedure TIBDynamicGrid.UpdateSortColumn(Sender: TObject);
1113     var i: integer;
1114     begin
1115     if Sender is TIBDynamicGridColumn then
1116     begin
1117     for i := 0 to Columns.Count -1 do
1118     if TObject(Columns[i]) <> Sender then
1119     TIBDynamicGridColumn(Columns[i]).InitialSortColumn := false
1120     end
1121    
1122     end;
1123    
1124 tony 27 procedure TIBDynamicGrid.RestorePosition;
1125 tony 21 begin
1126     if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active then
1127     begin
1128 tony 27 if assigned(FOnRestorePosition) then
1129     OnRestorePosition(self,@FBookmark);
1130 tony 21 if (Length(FBookmark) > 0) and
1131     DataSource.DataSet.Locate(FIndexFieldNames,FBookmark,[]) then Exit;
1132    
1133     if FDefaultPositionAtEnd then
1134     DataSource.DataSet.Last
1135     end;
1136     end;
1137    
1138 tony 27 procedure TIBDynamicGrid.SavePosition;
1139     var i: integer;
1140     F: TField;
1141     begin
1142     if FIndexFieldsList = nil then Exit;
1143    
1144     SetLength(FBookmark,FIndexFieldsList.Count);
1145     for i := 0 to FIndexFieldsList.Count - 1 do
1146     begin
1147     F := DataSource.DataSet.FindField(FIndexFieldsList[i]);
1148     if assigned(F) then
1149     FBookmark[i] := F.AsVariant;
1150     end;
1151     end;
1152    
1153 tony 21 procedure TIBDynamicGrid.DoReOpen(Data: PtrInt);
1154     begin
1155     DataSource.DataSet.Active := true;
1156     end;
1157    
1158 tony 27 procedure TIBDynamicGrid.IBControlLinkChanged;
1159     begin
1160     if (DataSource <> nil) and (DataSource.DataSet <> nil) and (DataSource.DataSet is TIBParserDataSet) then
1161     FIBControlLink.IBDataSet := TIBCustomDataSet(DataSource.DataSet)
1162     else
1163     FIBControlLink.IBDataSet := nil;
1164     end;
1165    
1166 tony 21 procedure TIBDynamicGrid.SetupEditor(aEditor: TDBLookupCellEditor; aCol: integer
1167     );
1168     var C: TIBDynamicGridColumn;
1169     begin
1170     C := ColumnFromGridColumn(aCol) as TIBDynamicGridColumn;
1171 tony 27 if (c <> nil) then
1172     C.SetupEditor(aEditor);
1173 tony 21 end;
1174    
1175     procedure TIBDynamicGrid.DoEditorHide;
1176     var i: integer;
1177     begin
1178     inherited DoEditorHide;
1179     if assigned(EditorPanel) then
1180     for i := 0 to EditorPanel.ControlCount -1 do
1181     if EditorPanel.Controls[i] is TIBLookupComboEditBox then
1182     EditorPanel.Controls[i].Perform(CM_VISIBLECHANGED, WParam(ord(false)), 0);
1183     end;
1184    
1185     procedure TIBDynamicGrid.Loaded;
1186     begin
1187     inherited Loaded;
1188 tony 29 IBControlLinkChanged;
1189 tony 21 ProcessColumns;
1190     end;
1191    
1192     function TIBDynamicGrid.CreateColumns: TGridColumns;
1193     begin
1194     result := TDBGridColumns.Create(Self, TIBDynamicGridColumn);
1195     end;
1196    
1197     procedure TIBDynamicGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
1198     Y: Integer);
1199     var Coord: TGridCoord;
1200     obe: boolean;
1201     function PtInRect(const Rect : TRect;const p : TPoint) : Boolean;
1202    
1203     begin
1204     PtInRect:=(p.y>=Rect.Top) and
1205     (p.y<Rect.Bottom) and
1206     (p.x>=Rect.Left) and
1207     (p.x<Rect.Right);
1208     end;
1209     begin
1210     if (Editor is TDBLookupCellEditor) and Editor.Visible
1211     and not PtInRect(Editor.BoundsRect,Point(X,Y)) then
1212     Editor.Perform(CM_EXIT,0,0); {Do insert new value if necessary}
1213     inherited MouseDown(Button, Shift, X, Y);
1214     obe := AllowOutboundEvents;
1215     AllowOutboundEvents := false;
1216     try
1217     Coord := MouseCoord(X,Y);
1218 tony 27 if AllowColumnSort and (Coord.X <> -1) and (FixedRows > 0) and
1219 tony 21 (Coord.Y = 0) and (MouseCoord(X+5,Y).X = Coord.X) {not on boundary}
1220     and (MouseCoord(X-5,Y).X = Coord.X) then
1221     ColumnHeaderClick(Coord.X-1);
1222     finally
1223     AllowOutboundEvents := obe
1224     end;
1225     end;
1226    
1227 tony 27 procedure TIBDynamicGrid.MoveSelection;
1228     begin
1229     inherited MoveSelection;
1230     SavePosition;
1231     end;
1232    
1233 tony 21 procedure TIBDynamicGrid.LinkActive(Value: Boolean);
1234     begin
1235 tony 27 IBControlLinkChanged;
1236 tony 21 inherited LinkActive(Value);
1237     if (FActive <> Value) and Value then
1238 tony 27 RestorePosition;
1239 tony 21 FActive := Value
1240     end;
1241    
1242     procedure TIBDynamicGrid.Notification(AComponent: TComponent;
1243     Operation: TOperation);
1244 tony 39 var i: integer;
1245 tony 21 begin
1246     inherited Notification(AComponent, Operation);
1247 tony 39 if (Operation = opRemove) then
1248     begin
1249     if (FIBControlLink <> nil) and (AComponent = DataSource) then
1250     FIBControlLink.IBDataSet := nil
1251     else
1252     if AComponent is TDataSource then
1253     begin
1254     for i := 0 to Columns.Count - 1 do
1255     if TIBDynamicGridColumn(Columns[I]).DBLookupProperties.ListSource = AComponent then
1256     TIBDynamicGridColumn(Columns[I]).DBLookupProperties.ListSource := nil;
1257     end
1258     end
1259 tony 21 end;
1260    
1261     procedure TIBDynamicGrid.UpdateActive;
1262     begin
1263     inherited UpdateActive;
1264 tony 27 if assigned(DataLink) and assigned(DataLink.DataSet) and
1265     DataLink.DataSet.Active and (DataLink.DataSet.State = dsInsert) then
1266     SavePosition;
1267 tony 21 end;
1268    
1269     constructor TIBDynamicGrid.Create(TheComponent: TComponent);
1270     begin
1271     inherited Create(TheComponent);
1272     FAllowColumnSort := true;
1273 tony 27 FIBControlLink := TIBGridControlLink.Create(self);
1274 tony 21 FIndexFieldsList := TStringList.Create;
1275     FIndexFieldsList.Delimiter := ';';
1276     FIndexFieldsList.StrictDelimiter := true;
1277     FDBLookupCellEditor := TDBLookupCellEditor.Create(nil);
1278     FDBLookupCellEditor.Name := 'DBLookupCellEditor';
1279     FDBLookupCellEditor.Visible := False;
1280     FDBLookupCellEditor.AutoSize := false;
1281     end;
1282    
1283     destructor TIBDynamicGrid.Destroy;
1284     begin
1285 tony 27 if assigned(FIBControlLink) then FIBControlLink.Free;
1286 tony 21 if assigned(FIndexFieldsList) then FIndexFieldsList.Free;
1287     if assigned(FDBLookupCellEditor) then FDBLookupCellEditor.Free;
1288     inherited Destroy;
1289     end;
1290    
1291     function TIBDynamicGrid.EditorByStyle(Style: TColumnButtonStyle): TWinControl;
1292     var C: TIBDynamicGridColumn;
1293     bs: TColumnButtonStyle;
1294     begin
1295     C := ColumnFromGridColumn(Col) as TIBDynamicGridColumn;
1296     if C <> nil then
1297     begin
1298     bs := C.ButtonStyle;
1299     if (bs in [cbsAuto,cbsPickList]) and assigned(C.DBLookupProperties.ListSource) then
1300     begin
1301     Result := FDBLookupCellEditor;
1302     Exit;
1303     end;
1304     end;
1305     Result := inherited EditorByStyle(Style);
1306     end;
1307    
1308     end.