ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/journaling/ibcontrols/IBDynamicGrid.pas
(Generate patch)

Comparing ibx/trunk/ibcontrols/IBDynamicGrid.pas (file contents):
Revision 23 by tony, Fri Mar 13 10:26:52 2015 UTC vs.
Revision 315 by tony, Thu Feb 25 11:56:36 2021 UTC

# Line 23 | Line 23
23   *  Contributor(s): ______________________________________.
24   *
25   *)
26 +
27   unit IBDynamicGrid;
28  
29   {$mode objfpc}{$H+}
# Line 31 | Line 32 | interface
32  
33   uses
34    Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, DBGrids, DB,
35 <  IBSqlParser, Grids, IBLookupComboEditBox, LMessages, StdCtrls, ExtCtrls;
35 >  IBSQLParser, Grids, IBLookupComboEditBox, LMessages, StdCtrls, ExtCtrls,
36 >  IBCustomDataSet;
37  
38   type
39    {
# Line 39 | Line 41 | type
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.
44 >   - DataSet re-sorting 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.
# Line 55 | Line 57 | type
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  
58  { TDynamicGridDataLink }
59
60  TDynamicGridDataLink = class(TDataLink)
61  private
62    FOwner: TIBDynamicGrid;
63  protected
64    procedure DataEvent(Event: TDataEvent; Info: Ptrint); override;
65    procedure DataSetScrolled(Distance: Integer); override;
66  public
67    constructor Create(AOwner: TIBDynamicGrid);
68  end;
69
60    { TDBDynamicGridColumn }
61  
62    TDBDynamicGridColumn = class(TColumn)
# Line 102 | Line 92 | type
92      FListSource: TDataSource;
93      FOnAutoInsert: TAutoInsert;
94      FOnCanAutoInsert: TCanAutoInsert;
95 +    FOnCloseUp: TNotifyEvent;
96      FOnDrawItem: TDrawItemEvent;
97      FOwner: TIBDynamicGridColumn;
98      FRelationName: string;
# Line 128 | Line 119 | type
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 +    property OnCloseUp: TNotifyEvent read FOnCloseUp write FOnCloseUp;
123      property OnDrawItem: TDrawItemEvent read FOnDrawItem write FOnDrawItem;
124   end;
125  
# Line 158 | Line 150 | end;
150      FGrid: TCustomGrid;
151      FCol,FRow: Integer;
152      FEditText: string;
153 +    function EditingKeyField: boolean;
154    protected
155      procedure WndProc(var TheMessage : TLMessage); override;
156      procedure CloseUp; override;
157      procedure KeyDown(var Key : Word; Shift : TShiftState); override;
158 +    procedure Loaded; override;
159      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;
# Line 173 | Line 167 | end;
167      property OnEditingDone;
168    end;
169  
170 +  TOnSelectPanelEditor = procedure(Sender: TObject; var aEditorPanel: TWinControl) of object;
171 +
172    TDBDynamicGrid = class(TDBGrid)
173    private
174      { Private declarations }
# Line 183 | Line 179 | end;
179      FOnEditorPanelHide: TNotifyEvent;
180      FOnEditorPanelShow: TNotifyEvent;
181      FOnKeyDownHander: TKeyDownHandler;
182 +    FOnSelectPanelEditor: TOnSelectPanelEditor;
183      FResizing: boolean;
184      FWeHaveFocus: boolean;
185 <    FHidingEditorPanel: boolean;
186 <    FAllowHide: boolean;
185 >    FMouseDown: boolean;
186 >    function ActiveControl: TControl;
187      procedure DoShowEditorPanel(Data: PtrInt);
188      procedure PositionTotals;
189      procedure KeyDownHandler(Sender: TObject; var Key: Word; Shift: TShiftState);
190 +    procedure PerformEditorHide(Data: PtrInt);
191      procedure SetEditorPanel(AValue: TWinControl);
192    protected
193      procedure ChangeBounds(ALeft, ATop, AWidth, AHeight: integer; KeepBase: boolean); override;
# Line 219 | Line 217 | end;
217      constructor Create(TheComponent: TComponent); override;
218      destructor Destroy ;override;
219      procedure ResizeColumns;
220 +    property VisibleRowCount;
221    published
222      property EditorPanel: TWinControl read FEditorPanel write SetEditorPanel;
223      property ExpandEditorPanelBelowRow: boolean read FExpandEditorPanelBelowRow write FExpandEditorPanelBelowRow;
# Line 226 | Line 225 | end;
225      property OnEditorPanelShow: TNotifyEvent read FOnEditorPanelShow write FOnEditorPanelShow;
226      property OnEditorPanelHide: TNotifyEvent read FOnEditorPanelHide write FOnEditorPanelHide;
227      property OnKeyDownHander: TKeyDownHandler read FOnKeyDownHander write FOnKeyDownHander;
228 +    property OnSelectPanelEditor: TOnSelectPanelEditor read FOnSelectPanelEditor
229 +                                                       write FOnSelectPanelEditor;
230   end;
231  
232 +  {TIBGridControlLink}
233 +
234 +  TIBGridControlLink = class(TIBControlLink)
235 +  private
236 +    FOwner: TIBDynamicGrid;
237 +  protected
238 +    procedure UpdateSQL(Sender: TObject); override;
239 +  public
240 +    constructor Create(AOwner: TIBDynamicGrid);
241 +  end;
242 +
243 +  TLocationArray = array of variant;
244 +  PLocationArray = ^TLocationArray;
245 +  TOnRestorePosition = procedure(Sender: TObject; Location: PLocationArray) of object;
246 +
247    { TIBDynamicGrid }
248  
249    TIBDynamicGrid = class(TDBDynamicGrid)
250    private
251      { Private declarations }
252      FAllowColumnSort: boolean;
253 <    FDataLink: TDynamicGridDataLink;
253 >    FIBControlLink: TIBGridControlLink;
254      FOnColumnHeaderClick: TOnColumnHeaderClick;
255 +    FOnRestorePosition: TOnRestorePosition;
256      FOnUpdateSortOrder: TOnUpdateSortOrder;
257      FDefaultPositionAtEnd: boolean;
258      FDescending: boolean;
# Line 243 | Line 260 | end;
260      FLastColIndex: integer;
261      FIndexFieldNames: string;
262      FIndexFieldsList: TStringList;
263 <    FBookmark: array of variant;
263 >    FBookmark: TLocationArray;
264      FDBLookupCellEditor: TDBLookupCellEditor;
265      FActive: boolean;
266 +    FFieldPosition: integer;
267      procedure ColumnHeaderClick(Index: integer);
268      function GetDataSource: TDataSource;
269      function GetEditorBorderStyle: TBorderStyle;
270 +    procedure IBControlLinkChanged;
271      procedure SetDataSource(AValue: TDataSource);
272      procedure SetEditorBorderStyle(AValue: TBorderStyle);
273      procedure ProcessColumns;
274      procedure SetIndexFieldNames(AValue: string);
275      procedure UpdateSQL(Sender: TObject; Parser: TSelectSQLParser);
276      procedure UpdateSortColumn(Sender: TObject);
277 <    procedure DataSetScrolled(Sender: TObject);
278 <    procedure RestorePosition(Data: PtrInt);
277 >    procedure RestorePosition;
278 >    procedure SavePosition;
279      procedure DoReOpen(Data: PtrInt);
280      procedure SetupEditor(aEditor: TDBLookupCellEditor; aCol: integer);
281    protected
# Line 266 | Line 285 | end;
285      function  CreateColumns: TGridColumns; override;
286      procedure MouseDown(Button: TMouseButton; Shift:TShiftState; X,Y:Integer); override;
287      procedure LinkActive(Value: Boolean); override;
288 +    procedure MoveSelection; override;
289      procedure Notification(AComponent: TComponent; Operation: TOperation); override;
290      procedure UpdateActive; override;
291    public
# Line 283 | Line 303 | end;
303      property DefaultPositionAtEnd: boolean read  FDefaultPositionAtEnd write FDefaultPositionAtEnd;
304      property IndexFieldNames: string read FIndexFieldNames write SetIndexFieldNames;
305      property OnColumnHeaderClick: TOnColumnHeaderClick read FOnColumnHeaderClick write FOnColumnHeaderClick;
306 +    property OnRestorePosition: TOnRestorePosition read FOnRestorePosition write FOnRestorePosition;
307      property OnUpdateSortOrder: TOnUpdateSortOrder read FOnUpdateSortOrder write FOnUpdateSortOrder;
308   end;
309  
310   implementation
311  
312 < uses Math, IBQuery, IBCustomDataSet, LCLType;
312 > uses LCLType, Variants, EditBtn;
313 >
314 > { TIBGridControlLink }
315 >
316 > constructor TIBGridControlLink.Create(AOwner: TIBDynamicGrid);
317 > begin
318 >  inherited Create;
319 >  FOwner := AOwner;
320 > end;
321 >
322 > procedure TIBGridControlLink.UpdateSQL(Sender: TObject);
323 > begin
324 >  FOwner.UpdateSQL(self,TIBParserDataSet(Sender).Parser)
325 > end;
326  
327   { TDBLookupProperties }
328  
# Line 335 | Line 369 | begin
369    FResizing := true;
370    try
371      ColSum := 0;
338    for I := 0 to  ColCount - 1 do
339       ColSum := ColSum + ColWidths[I];
372  
373 <    if Colsum <> ClientWidth then
373 >    if (ColCount = 1) and TDBDynamicGridColumn(Columns[0]).AutoSizeColumn then
374 >      Columns[0].Width := ClientWidth
375 >    else
376      begin
377 <      ResizeColCount := 0;
378 <      for I := 0 to Columns.Count -1 do
379 <        if TDBDynamicGridColumn(Columns[I]).AutoSizeColumn then
380 <        begin
381 <          Inc(ResizeColCount);
382 <          Colsum := Colsum + TDBDynamicGridColumn(Columns[I]).DesignWidth - Columns[I].Width;
383 <          Columns[I].Width := TDBDynamicGridColumn(Columns[I]).DesignWidth;
384 <        end;
385 <
386 <        if (Colsum < ClientWidth) and (ResizeColCount > 0) then
387 <        begin
388 <          adjustment := (ClientWidth - ColSum) div ResizeColCount;
389 <          n := (ClientWidth - ColSum) mod ResizeColCount;
390 <
391 <          for I := 0 to Columns.Count -1 do
392 <            if TDBDynamicGridColumn(Columns[I]).AutoSizeColumn then
393 <            begin
394 <              if I = 0 then
395 <                Columns[I].Width := Columns[I].Width + adjustment + n
396 <              else
397 <                Columns[I].Width := Columns[I].Width + adjustment;
398 <            end;
399 <        end;
377 >      for I := 0 to  ColCount - 1 do
378 >        if (I < FixedCols) or Columns[I - FixedCols].Visible then
379 >         ColSum := ColSum + ColWidths[I];
380 >
381 >      if Colsum <> ClientWidth then
382 >      begin
383 >        ResizeColCount := 0;
384 >        for I := 0 to Columns.Count -1 do
385 >          if TDBDynamicGridColumn(Columns[I]).AutoSizeColumn and Columns[I].Visible then
386 >          begin
387 >            Inc(ResizeColCount);
388 >            Colsum := Colsum + TDBDynamicGridColumn(Columns[I]).DesignWidth - Columns[I].Width;
389 >            Columns[I].Width := TDBDynamicGridColumn(Columns[I]).DesignWidth;
390 >          end;
391 >
392 >          if (Colsum < ClientWidth) and (ResizeColCount > 0) then
393 >          begin
394 >            adjustment := (ClientWidth - ColSum) div ResizeColCount;
395 >            n := (ClientWidth - ColSum) mod ResizeColCount;
396 >
397 >            for I := 0 to Columns.Count -1 do
398 >              if TDBDynamicGridColumn(Columns[I]).AutoSizeColumn and Columns[I].Visible then
399 >              begin
400 >                if I = 0 then
401 >                  Columns[I].Width := Columns[I].Width + adjustment + n
402 >                else
403 >                  Columns[I].Width := Columns[I].Width + adjustment;
404 >              end;
405 >          end;
406 >      end;
407      end;
408      PositionTotals;
409      UpdateEditorPanelBounds;
# Line 374 | Line 415 | end;
415   procedure TDBDynamicGrid.DoEditorHide;
416   begin
417    inherited DoEditorHide;
418 <  if (FExpandedRow >= 0) and (FExpandedRow < RowCount) then
419 <    RowHeights[FExpandedRow] := DefaultRowHeight;
420 <  FExpandedRow := -1;
421 <  if CanFocus then SetFocus;
422 <  if assigned(FOnEditorPanelHide) then
423 <     OnEditorPanelHide(self);
424 <  DoOnResize;
418 >  if Editor = FEditorPanel then
419 >  begin
420 >    if FMouseDown then
421 >      Application.QueueAsyncCall(@PerformEditorHide,FExpandedRow)
422 >    else
423 >      PerformEditorHide(FExpandedRow);
424 >    FExpandedRow := -1;
425 >  end;
426   end;
427  
428   procedure TDBDynamicGrid.DoEditorShow;
429   begin
430 +  if assigned(DataSource) and assigned(DataSource.DataSet) and
431 +             DataSource.DataSet.Active then
432 +  begin
433 +    if (DataSource.DataSet.RecordCount = 0) and (DataSource.DataSet.State <> dsInsert) then
434 +      DataSource.DataSet.Append
435 +  end;
436    if Editor = FEditorPanel then
437    begin
438      if ExpandEditorPanelBelowRow then
# Line 397 | Line 445 | begin
445      FEditorPanel.PerformTab(true);  {Select First Control}
446      if assigned(FOnEditorPanelShow) then
447         OnEditorPanelShow(self);
448 +    if assigned(Editor) and Editor.Visible then
449 +      Editor.SetFocus;
450    end
451    else
452      inherited DoEditorShow;
# Line 461 | Line 511 | begin
511      inherited KeyDown(Key, Shift);
512   end;
513  
514 + function TDBDynamicGrid.ActiveControl: TControl;
515 + var AParent: TWinControl;
516 + begin
517 +  Result := nil;
518 +  AParent := Parent;
519 +  while (AParent <> nil) and  not (AParent is TCustomForm) do
520 +    AParent := AParent.Parent;
521 +  if (AParent <> nil) and (AParent is TCustomForm)then
522 +      Result := TCustomForm(AParent).ActiveControl;
523 + end;
524 +
525   procedure TDBDynamicGrid.DoShowEditorPanel(Data: PtrInt);
526   begin
527    if AppDestroying in Application.Flags then Exit;
# Line 492 | Line 553 | end;
553   procedure TDBDynamicGrid.KeyDownHandler(Sender: TObject; var Key: Word;
554    Shift: TShiftState);
555   var Done: boolean;
556 +    AControl: TControl;
557   begin
558    if Visible and assigned(FEditorPanel) and FEditorPanel.Visible and FWeHaveFocus then
559    begin
560      Done := false;
561 +    AControl := ActiveControl;
562 +    if (AControl <> nil) and (AControl is TCustomComboBox)
563 +                         and ((Key in [VK_UP,VK_DOWN]) or
564 +                         (TCustomComboBox(AControl).DroppedDown and (Key = VK_RETURN)) or
565 +                         ((TCustomComboBox(AControl).Text <> '') and (Key =  VK_ESCAPE))) then
566 +      Exit; {ignore these keys if we are in a  combobox}
567 +
568 +    if (AControl <> nil) and (AControl is TCustomMemo)
569 +                         and (Key in [VK_RETURN,VK_UP,VK_DOWN]) then Exit; {Ignore keys in a CustomMemo}
570 +
571 +    if (AControl <> nil) and (AControl is TCustomGrid)
572 +                         and (Key in [VK_RETURN,VK_UP,VK_DOWN,VK_TAB]) then Exit; {Ignore keys in a Custom Grid}
573 +
574 +    if (AControl <> nil) and (AControl is TEBEdit) and (AControl.Owner is TDateEdit) then
575 +    begin
576 +      if (Key in [VK_LEFT,VK_RIGHT]) then Exit; {Ignore navigation keys}
577 +      if TDateEdit(AControl.Owner).DroppedDown and
578 +        (Key in [VK_RETURN,VK_UP,VK_DOWN,VK_ESCAPE]) then Exit; {Ignore TCalender navigation keys in a Data edit}
579 +    end;
580 +
581      if assigned(FOnKeyDownHander) then
582        OnKeyDownHander(Sender,Key,Shift,Done);
583      if Done then Exit;
# Line 518 | Line 600 | begin
600    end
601   end;
602  
603 + procedure TDBDynamicGrid.PerformEditorHide(Data: PtrInt);
604 + var ExpandedRow: integer;
605 + begin
606 +  if AppDestroying in Application.Flags then Exit;
607 +  ExpandedRow := integer(Data);
608 +  if (ExpandedRow >= 0) and (ExpandedRow < RowCount) then
609 +    RowHeights[ExpandedRow] := DefaultRowHeight;
610 +  if CanFocus then SetFocus;
611 +  DoOnResize;
612 +  ResetSizes;
613 +  DoOnChangeBounds;
614 +  if assigned(FOnEditorPanelHide) then
615 +     OnEditorPanelHide(self);
616 + end;
617 +
618   procedure TDBDynamicGrid.SetEditorPanel(AValue: TWinControl);
619   begin
620    if FEditorPanel = AValue then Exit;
621    if FEditorPanel <> nil then
622       RemoveFreeNotification(FEditorPanel);
623    FEditorPanel := AValue;
624 <  FreeNotification(FEditorPanel);
624 >  if FEditorPanel <> nil then
625 >     FreeNotification(FEditorPanel);
626   end;
627  
628   procedure TDBDynamicGrid.ChangeBounds(ALeft, ATop, AWidth, AHeight: integer;
# Line 552 | Line 650 | begin
650    inherited Loaded;
651    if assigned(FEditorPanel) and not (csDesigning in ComponentState)then
652      FEditorPanel.Visible := false;
653 <  DoGridResize
653 >  if Visible then
654 >    DoGridResize
655   end;
656  
657   procedure TDBDynamicGrid.DoOnResize;
# Line 576 | Line 675 | procedure TDBDynamicGrid.MouseDown(Butto
675    Y: Integer);
676   var Coord: TGridCoord;
677   begin
678 <  inherited MouseDown(Button, Shift, X, Y);
678 >  FMouseDown := true;
679 >  try
680 >    inherited MouseDown(Button, Shift, X, Y);
681 >  finally
682 >    FMouseDown := false;
683 >  end;
684  
685    Coord := MouseCoord(X,Y);
686    if (Coord.X = 0) and (Coord.Y > 0) then
# Line 585 | Line 689 | end;
689  
690   procedure TDBDynamicGrid.Notification(AComponent: TComponent;
691    Operation: TOperation);
692 + var i: integer;
693   begin
694    inherited Notification(AComponent, Operation);
695 <  if (Operation = opRemove) and
696 <     (AComponent = FEditorPanel) then FEditorPanel := nil;
695 >  if (Operation = opRemove) and not (csDestroying in ComponentState) then
696 >  begin
697 >    if AComponent = FEditorPanel then
698 >      FEditorPanel := nil
699 >    else
700 >    if AComponent is TControl then
701 >    begin
702 >      for i := 0 to Columns.Count - 1 do
703 >        if TDBDynamicGridColumn(Columns[I]).ColumnTotalsControl = AComponent then
704 >          TDBDynamicGridColumn(Columns[I]).ColumnTotalsControl := nil;
705 >    end;
706 >  end
707   end;
708  
709   procedure TDBDynamicGrid.TopLeftChanged;
# Line 601 | Line 716 | procedure TDBDynamicGrid.UpdateActive;
716   begin
717    inherited UpdateActive;
718  
719 +  if not (csLoading in ComponentState) and assigned(DataLink)
720 +                       and assigned(DataLink.DataSet) and DataLink.DataSet.Active then
721 +    DoGridResize;
722 +
723    if not (csLoading in ComponentState) and assigned(DataLink) and
724 +     assigned(FEditorPanel) and not FEditorPanel.Visible and
725       assigned(DataLink.DataSet) and (DataLink.DataSet.State = dsInsert) then
726       Application.QueueAsyncCall(@DoShowEditorPanel,0);
727   end;
# Line 634 | Line 754 | end;
754   procedure TDBDynamicGrid.HideEditorPanel;
755   begin
756    if Editor = FEditorPanel then
757 <    EditorMode := false;
757 >      EditorMode := false;
758   end;
759  
760   procedure TDBDynamicGrid.ShowEditorPanel;
761 + var aEditor: TWinControl;
762   begin
763 <  if csDesigning in ComponentState then Exit;
764 <  Editor := FEditorPanel;
763 >  if (csDesigning in ComponentState) or
764 >   (DataSource = nil) or (DataSource.DataSet = nil)
765 >     or ((DataSource.DataSet.RecordCount = 0) and (DataSource.DataSet.State <> dsInsert)) then
766 >     Exit;
767 >  aEditor := FEditorPanel;
768 >  if assigned(FOnSelectPanelEditor) then
769 >    OnSelectPanelEditor(self,aEditor);
770 >  if FEditorPanel <> aEditor then
771 >    SetEditorPanel(aEditor);
772 >  Editor := aEditor;
773    EditorMode := true;
774   end;
775  
# Line 679 | Line 808 | begin
808    Result := inherited Width
809   end;
810  
811 + type
812 +  THackedGrid = class(TIBDynamicGrid)
813 +  public
814 +    property FixedCols;
815 +  end;
816 +
817   { TDBLookupCellEditor }
818  
819 + function TDBLookupCellEditor.EditingKeyField: boolean;
820 + begin
821 +  with TIBDynamicGridColumn(TDBGrid(FGrid).Columns[FCol - THackedGrid(FGrid).FixedCols]) do
822 +    Result := CompareText(FieldName, DBLookupProperties.DataFieldName) = 0;
823 + end;
824 +
825   procedure TDBLookupCellEditor.WndProc(var TheMessage: TLMessage);
826   begin
827    if TheMessage.msg=LM_KILLFOCUS then begin
# Line 698 | Line 839 | procedure TDBLookupCellEditor.CloseUp;
839   begin
840    UpdateData(nil); {Force Record Update}
841    if FGrid<>nil then
842 <    (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, Text);
842 >  Begin
843 >    if EditingKeyField then
844 >    begin
845 >      if not VarIsNull(KeyValue) then
846 >       (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, KeyValue)
847 >    end
848 >    else
849 >      (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, Trim(Text));
850 >    (FGrid as TIBDynamicGrid).UpdateData;
851 >  end;
852    inherited CloseUp;
853   end;
854  
# Line 710 | Line 860 | begin
860      inherited KeyDown(Key, Shift);
861   end;
862  
863 + procedure TDBLookupCellEditor.Loaded;
864 + begin
865 +  inherited Loaded;
866 +  Text := '';
867 + end;
868 +
869   procedure TDBLookupCellEditor.msg_GetValue(var Msg: TGridMessage);
870   begin
871    CheckAndInsert;
872    Msg.Col := FCol;
873    Msg.Row := FRow;
874 <  Msg.Value:= Trim(Text);
874 >  if EditingKeyField then
875 >  begin
876 >    if not VarIsNull(KeyValue) then
877 >      Msg.Value:= KeyValue
878 >    else
879 >      Msg.Value:= ''
880 >  end
881 >  else
882 >    Msg.Value:= Trim(Text);
883   end;
884  
885   procedure TDBLookupCellEditor.msg_SetGrid(var Msg: TGridMessage);
# Line 730 | Line 894 | begin
894    FCol := Msg.Col;
895    FRow := Msg.Row;
896    FEditText := Msg.Value;
733  SelStart := Length(Text);
897    TIBDynamicGrid(FGrid).SetupEditor(self,FCol);
898   end;
899  
# Line 779 | Line 942 | begin
942      Editor.OnAutoInsert := OnAutoInsert;
943      Editor.OnCanAutoInsert := OnCanAutoInsert;
944      Editor.OnDrawItem := OnDrawItem;
945 +    Editor.OnCloseUp := OnCloseUp;
946  
947      {Setup Data Links}
948      if KeyField <> '' then
# Line 803 | Line 967 | begin
967      if DataFieldName <> '' then
968          Editor.DataSource := TDBGrid(Grid).DataSource;
969    end;
970 <  Editor.Text := Editor.FEditText;
970 >  if Editor.EditingKeyField then
971 >  begin
972 >    if not Field.IsNull then
973 >      Editor.KeyValue := Editor.FEditText
974 >  end
975 >  else
976 >    Editor.Text := Editor.FEditText;
977 >  Editor.SelStart := Length(Editor.Text);
978   end;
979  
980   procedure TIBDynamicGridColumn.SetInitialSortColumn(AValue: boolean);
# Line 827 | Line 998 | end;
998   destructor TIBDynamicGridColumn.Destroy;
999   begin
1000    if assigned(FDBLookupProperties) then FDBLookupProperties.Free;
1001 +  Application.RemoveAsyncCalls(self);
1002    inherited Destroy;
1003   end;
1004  
833 { TDynamicGridDataLink }
834
835 procedure TDynamicGridDataLink.DataEvent(Event: TDataEvent; Info: Ptrint);
836 begin
837  if (Event = deCheckBrowseMode) and (Info = 1) and not DataSet.Active then
838  begin
839    if (DataSet is TIBDataSet) then
840      FOwner.UpdateSQL(self,TIBDataSet(DataSet).Parser)
841    else
842    if (DataSet is TIBQuery) then
843      FOwner.UpdateSQL(self,TIBQuery(DataSet).Parser)
844  end
845  else
846  inherited DataEvent(Event, Info);
847 end;
848
849 procedure TDynamicGridDataLink.DataSetScrolled(Distance: Integer);
850 begin
851  inherited DataSetScrolled(Distance);
852  FOwner.DataSetScrolled(self)
853 end;
854
855 constructor TDynamicGridDataLink.Create(AOwner: TIBDynamicGrid);
856 begin
857  inherited Create;
858  FOwner := AOwner
859 end;
860
1005  
1006   { TIBDynamicGrid }
1007  
# Line 872 | Line 1016 | begin
1016        OnColumnHeaderClick(self,Index);
1017  
1018      FLastColIndex := Index;
1019 <    if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active then
1019 >    FFieldPosition := 0;
1020 >    if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active
1021 >       and (DataSource.DataSet is TIBParserDataSet) then
1022      begin
1023 +      if FLastColIndex < Columns.Count then
1024 +      {try and cache field position while dataset still open}
1025 +        FFieldPosition := TIBParserDataSet(DataSource.DataSet).Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1026        DataSource.DataSet.Active := false;
1027        Application.QueueAsyncCall(@DoReopen,0)
1028      end;
# Line 901 | Line 1050 | end;
1050   procedure TIBDynamicGrid.SetDataSource(AValue: TDataSource);
1051   begin
1052    inherited DataSource := AValue;
1053 <  FDataLink.DataSource := AValue;
1053 >  IBControlLinkChanged;
1054   end;
1055  
1056   procedure TIBDynamicGrid.SetEditorBorderStyle(AValue: TBorderStyle);
# Line 921 | Line 1070 | begin
1070    for i := 0 to Columns.Count - 1 do
1071    begin
1072      if TIBDynamicGridColumn(columns[i]).InitialSortColumn then
1073 +    begin
1074 +      FFieldPosition := 0;
1075        FLastColIndex := i
1076 +    end
1077    end
1078   end;
1079  
# Line 938 | Line 1090 | end;
1090  
1091   procedure TIBDynamicGrid.UpdateSQL(Sender: TObject; Parser: TSelectSQLParser);
1092   var OrderBy: string;
941    FieldPosition: integer;
1093   begin
1094 <    if (Sender = TObject(FDataLink)) and assigned(DataSource) and assigned(DataSource.DataSet)
1094 >    if assigned(DataSource) and assigned(DataSource.DataSet)
1095        and (DataSource.DataSet is TIBCustomDataSet) then
1096      begin
1097 <      FieldPosition := Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1098 <      if FieldPosition = 0 then Exit;
1099 <
1100 <      if Descending then
1101 <        Parser.OrderByClause := IntToStr(FieldPosition) + ' desc'
1102 <      else
1103 <        Parser.OrderByClause := IntToStr(FieldPosition) + ' asc';
1097 >      if (FFieldPosition = 0) and (FLastColIndex >= 0) and (FLastColIndex < Columns.Count) then
1098 >        {Not cached - let's hope we can find it before the dataset is opened.
1099 >         Won't work if dynamic columns}
1100 >        FFieldPosition := Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1101 >      if FFieldPosition > 0 then
1102 >      begin
1103 >        if Descending then
1104 >          Parser.OrderByClause := IntToStr(FFieldPosition) + ' desc'
1105 >        else
1106 >          Parser.OrderByClause := IntToStr(FFieldPosition) + ' asc';
1107 >      end;
1108  
1109        if assigned(FOnUpdateSortOrder) then
1110        begin
# Line 972 | Line 1127 | begin
1127  
1128   end;
1129  
1130 < procedure TIBDynamicGrid.DataSetScrolled(Sender: TObject);
976 < var i: integer;
977 <    F: TField;
978 < begin
979 <    SetLength(FBookmark,FIndexFieldsList.Count);
980 <    for i := 0 to FIndexFieldsList.Count - 1 do
981 <    begin
982 <      F := DataSource.DataSet.FindField(FIndexFieldsList[i]);
983 <      if assigned(F) then
984 <         FBookmark[i] := F.AsVariant;
985 <    end;
986 < end;
987 <
988 < procedure TIBDynamicGrid.RestorePosition(Data: PtrInt);
1130 > procedure TIBDynamicGrid.RestorePosition;
1131   begin
990  if AppDestroying in Application.Flags then Exit;
991
1132    if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active then
1133    begin
1134 +    if assigned(FOnRestorePosition) then
1135 +      OnRestorePosition(self,@FBookmark);
1136      if (Length(FBookmark) > 0) and
1137        DataSource.DataSet.Locate(FIndexFieldNames,FBookmark,[]) then Exit;
1138  
# Line 999 | Line 1141 | begin
1141    end;
1142   end;
1143  
1144 + procedure TIBDynamicGrid.SavePosition;
1145 + var i: integer;
1146 +    F: TField;
1147 + begin
1148 +  if FIndexFieldsList = nil then Exit;
1149 +
1150 +  SetLength(FBookmark,FIndexFieldsList.Count);
1151 +  for i := 0 to FIndexFieldsList.Count - 1 do
1152 +  begin
1153 +    F := DataSource.DataSet.FindField(FIndexFieldsList[i]);
1154 +    if assigned(F) then
1155 +       FBookmark[i] := F.AsVariant;
1156 +  end;
1157 + end;
1158 +
1159   procedure TIBDynamicGrid.DoReOpen(Data: PtrInt);
1160   begin
1161    DataSource.DataSet.Active := true;
1162   end;
1163  
1164 + procedure TIBDynamicGrid.IBControlLinkChanged;
1165 + begin
1166 +  if (DataSource <> nil) and (DataSource.DataSet <> nil) and (DataSource.DataSet is TIBParserDataSet) then
1167 +    FIBControlLink.IBDataSet := TIBCustomDataSet(DataSource.DataSet)
1168 +  else
1169 +    FIBControlLink.IBDataSet := nil;
1170 + end;
1171 +
1172   procedure TIBDynamicGrid.SetupEditor(aEditor: TDBLookupCellEditor; aCol: integer
1173    );
1174   var C: TIBDynamicGridColumn;
1175   begin
1176    C := ColumnFromGridColumn(aCol) as TIBDynamicGridColumn;
1177 <  C.SetupEditor(aEditor);
1177 >  if (c <> nil) then
1178 >    C.SetupEditor(aEditor);
1179   end;
1180  
1181   procedure TIBDynamicGrid.DoEditorHide;
# Line 1025 | Line 1191 | end;
1191   procedure TIBDynamicGrid.Loaded;
1192   begin
1193    inherited Loaded;
1194 +  IBControlLinkChanged;
1195    ProcessColumns;
1196   end;
1197  
# Line 1054 | Line 1221 | begin
1221    AllowOutboundEvents := false;
1222    try
1223      Coord := MouseCoord(X,Y);
1224 <  if AllowColumnSort and  (Coord.X <> -1) and
1224 >  if AllowColumnSort and  (Coord.X <> -1) and (FixedRows > 0) and
1225     (Coord.Y = 0) and (MouseCoord(X+5,Y).X = Coord.X) {not on boundary}
1226                     and (MouseCoord(X-5,Y).X = Coord.X) then
1227      ColumnHeaderClick(Coord.X-1);
# Line 1063 | Line 1230 | begin
1230    end;
1231   end;
1232  
1233 + procedure TIBDynamicGrid.MoveSelection;
1234 + begin
1235 +  inherited MoveSelection;
1236 +  SavePosition;
1237 + end;
1238 +
1239   procedure TIBDynamicGrid.LinkActive(Value: Boolean);
1240   begin
1241 +  IBControlLinkChanged;
1242    inherited LinkActive(Value);
1243    if (FActive <> Value) and Value then
1244 <    Application.QueueAsyncCall(@RestorePosition,0);
1244 >    RestorePosition;
1245    FActive := Value
1246   end;
1247  
1248   procedure TIBDynamicGrid.Notification(AComponent: TComponent;
1249    Operation: TOperation);
1250 + var i: integer;
1251   begin
1252    inherited Notification(AComponent, Operation);
1253 <  if (Operation = opRemove) and
1254 <     (FDataLink <> nil) and (AComponent = DataSource) then DataSource := nil;
1253 >  if (Operation = opRemove) then
1254 >  begin
1255 >    if (FIBControlLink <> nil) and (AComponent = DataSource) then
1256 >      FIBControlLink.IBDataSet := nil
1257 >    else
1258 >    if AComponent is TDataSource then
1259 >    begin
1260 >      for i := 0 to Columns.Count - 1 do
1261 >        if TIBDynamicGridColumn(Columns[I]).DBLookupProperties.ListSource = AComponent then
1262 >          TIBDynamicGridColumn(Columns[I]).DBLookupProperties.ListSource := nil;
1263 >    end
1264 >  end
1265   end;
1266  
1267   procedure TIBDynamicGrid.UpdateActive;
1268   begin
1269    inherited UpdateActive;
1270 <  if assigned(FDataLink) and assigned(FDataLink.DataSet) and
1271 <     FDataLink.DataSet.Active and (FDataLink.DataSet.State = dsInsert) then
1272 <    DataSetScrolled(nil);
1270 >  if assigned(DataLink) and assigned(DataLink.DataSet) and
1271 >     DataLink.DataSet.Active and (DataLink.DataSet.State = dsInsert) then
1272 >   SavePosition;
1273   end;
1274  
1275   constructor TIBDynamicGrid.Create(TheComponent: TComponent);
1276   begin
1277    inherited Create(TheComponent);
1278    FAllowColumnSort := true;
1279 <  FDataLink := TDynamicGridDataLink.Create(self);
1279 >  FIBControlLink := TIBGridControlLink.Create(self);
1280    FIndexFieldsList := TStringList.Create;
1281    FIndexFieldsList.Delimiter := ';';
1282    FIndexFieldsList.StrictDelimiter := true;
# Line 1103 | Line 1288 | end;
1288  
1289   destructor TIBDynamicGrid.Destroy;
1290   begin
1291 <  if assigned(FDataLink) then FDataLink.Free;
1291 >  if assigned(FIBControlLink) then FIBControlLink.Free;
1292    if assigned(FIndexFieldsList) then FIndexFieldsList.Free;
1293    if assigned(FDBLookupCellEditor) then FDBLookupCellEditor.Free;
1294 +  Application.RemoveAsyncCalls(self);
1295    inherited Destroy;
1296   end;
1297  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines