ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/ibcontrols/IBDynamicGrid.pas
Revision: 45
Committed: Tue Dec 6 10:33:46 2016 UTC (7 years, 9 months ago) by tony
Content type: text/x-pascal
File size: 40319 byte(s)
Log Message:
Committing updates for Release R2-0-0

File Contents

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