ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/ibcontrols/IBDynamicGrid.pas
Revision: 49
Committed: Thu Feb 2 16:20:12 2017 UTC (7 years, 9 months ago) by tony
Content type: text/x-pascal
File size: 40417 byte(s)
Log Message:
Committing updates for Trunk

File Contents

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