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

Comparing ibx/trunk/ibcontrols/IBDynamicGrid.pas (file contents):
Revision 21 by tony, Thu Feb 26 10:33:34 2015 UTC vs.
Revision 80 by tony, Mon Jan 1 11:31:07 2018 UTC

# Line 15 | Line 15
15   *
16   *  The Initial Developer of the Original Code is Tony Whyman.
17   *
18 < *  The Original Code is (C) 2011 Tony Whyman, MWA Software
18 > *  The Original Code is (C) 2015 Tony Whyman, MWA Software
19   *  (http://www.mwasoftware.co.uk).
20   *
21   *  All Rights Reserved.
# 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 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;
187 +    FMouseDown: boolean;
188 +    function ActiveControl: TControl;
189      procedure DoShowEditorPanel(Data: PtrInt);
190      procedure PositionTotals;
191      procedure KeyDownHandler(Sender: TObject; var Key: Word; Shift: TShiftState);
192 +    procedure PerformEditorHide(Data: PtrInt);
193      procedure SetEditorPanel(AValue: TWinControl);
194    protected
195      procedure ChangeBounds(ALeft, ATop, AWidth, AHeight: integer; KeepBase: boolean); override;
# Line 219 | Line 219 | end;
219      constructor Create(TheComponent: TComponent); override;
220      destructor Destroy ;override;
221      procedure ResizeColumns;
222 +    property VisibleRowCount;
223    published
224      property EditorPanel: TWinControl read FEditorPanel write SetEditorPanel;
225      property ExpandEditorPanelBelowRow: boolean read FExpandEditorPanelBelowRow write FExpandEditorPanelBelowRow;
# Line 226 | Line 227 | end;
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 +    property OnSelectPanelEditor: TOnSelectPanelEditor read FOnSelectPanelEditor
231 +                                                       write FOnSelectPanelEditor;
232   end;
233  
234 +  {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    { TIBDynamicGrid }
250  
251    TIBDynamicGrid = class(TDBDynamicGrid)
252    private
253      { Private declarations }
254      FAllowColumnSort: boolean;
255 <    FDataLink: TDynamicGridDataLink;
255 >    FIBControlLink: TIBGridControlLink;
256      FOnColumnHeaderClick: TOnColumnHeaderClick;
257 +    FOnRestorePosition: TOnRestorePosition;
258      FOnUpdateSortOrder: TOnUpdateSortOrder;
259      FDefaultPositionAtEnd: boolean;
260      FDescending: boolean;
# Line 243 | Line 262 | end;
262      FLastColIndex: integer;
263      FIndexFieldNames: string;
264      FIndexFieldsList: TStringList;
265 <    FBookmark: array of variant;
265 >    FBookmark: TLocationArray;
266      FDBLookupCellEditor: TDBLookupCellEditor;
267      FActive: boolean;
268 +    FFieldPosition: integer;
269      procedure ColumnHeaderClick(Index: integer);
270      function GetDataSource: TDataSource;
271      function GetEditorBorderStyle: TBorderStyle;
272 +    procedure IBControlLinkChanged;
273      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 <    procedure DataSetScrolled(Sender: TObject);
280 <    procedure RestorePosition(Data: PtrInt);
279 >    procedure RestorePosition;
280 >    procedure SavePosition;
281      procedure DoReOpen(Data: PtrInt);
282      procedure SetupEditor(aEditor: TDBLookupCellEditor; aCol: integer);
283    protected
# Line 266 | Line 287 | end;
287      function  CreateColumns: TGridColumns; override;
288      procedure MouseDown(Button: TMouseButton; Shift:TShiftState; X,Y:Integer); override;
289      procedure LinkActive(Value: Boolean); override;
290 +    procedure MoveSelection; override;
291      procedure Notification(AComponent: TComponent; Operation: TOperation); override;
292      procedure UpdateActive; override;
293    public
# Line 283 | Line 305 | end;
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 +    property OnRestorePosition: TOnRestorePosition read FOnRestorePosition write FOnRestorePosition;
309      property OnUpdateSortOrder: TOnUpdateSortOrder read FOnUpdateSortOrder write FOnUpdateSortOrder;
310   end;
311  
312   implementation
313  
314 < uses Math, IBQuery, IBCustomDataSet, LCLType;
314 > uses LCLType, Variants, EditBtn;
315 >
316 > { 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   { TDBLookupProperties }
330  
# Line 335 | Line 371 | begin
371    FResizing := true;
372    try
373      ColSum := 0;
338    for I := 0 to  ColCount - 1 do
339       ColSum := ColSum + ColWidths[I];
374  
375 <    if Colsum <> ClientWidth then
375 >    if (ColCount = 1) and TDBDynamicGridColumn(Columns[0]).AutoSizeColumn then
376 >      Columns[0].Width := ClientWidth
377 >    else
378      begin
379 <      ResizeColCount := 0;
380 <      for I := 0 to Columns.Count -1 do
381 <        if TDBDynamicGridColumn(Columns[I]).AutoSizeColumn then
382 <        begin
383 <          Inc(ResizeColCount);
384 <          Colsum := Colsum + TDBDynamicGridColumn(Columns[I]).DesignWidth - Columns[I].Width;
385 <          Columns[I].Width := TDBDynamicGridColumn(Columns[I]).DesignWidth;
386 <        end;
387 <
388 <        if (Colsum < ClientWidth) and (ResizeColCount > 0) then
389 <        begin
390 <          adjustment := (ClientWidth - ColSum) div ResizeColCount;
391 <          n := (ClientWidth - ColSum) mod ResizeColCount;
392 <
393 <          for I := 0 to Columns.Count -1 do
394 <            if TDBDynamicGridColumn(Columns[I]).AutoSizeColumn then
395 <            begin
396 <              if I = 0 then
397 <                Columns[I].Width := Columns[I].Width + adjustment + n
398 <              else
399 <                Columns[I].Width := Columns[I].Width + adjustment;
400 <            end;
401 <        end;
379 >      for I := 0 to  ColCount - 1 do
380 >        if (I < FixedCols) or Columns[I - FixedCols].Visible then
381 >         ColSum := ColSum + ColWidths[I];
382 >
383 >      if Colsum <> ClientWidth then
384 >      begin
385 >        ResizeColCount := 0;
386 >        for I := 0 to Columns.Count -1 do
387 >          if TDBDynamicGridColumn(Columns[I]).AutoSizeColumn and Columns[I].Visible then
388 >          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 >
394 >          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 >              if TDBDynamicGridColumn(Columns[I]).AutoSizeColumn and Columns[I].Visible then
401 >              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      end;
410      PositionTotals;
411      UpdateEditorPanelBounds;
# Line 374 | Line 417 | end;
417   procedure TDBDynamicGrid.DoEditorHide;
418   begin
419    inherited DoEditorHide;
420 <  if (FExpandedRow >= 0) and (FExpandedRow < RowCount) then
421 <    RowHeights[FExpandedRow] := DefaultRowHeight;
422 <  FExpandedRow := -1;
423 <  if CanFocus then SetFocus;
424 <  if assigned(FOnEditorPanelHide) then
425 <     OnEditorPanelHide(self);
426 <  DoOnResize;
420 >  if Editor = FEditorPanel then
421 >  begin
422 >    if FMouseDown then
423 >      Application.QueueAsyncCall(@PerformEditorHide,FExpandedRow)
424 >    else
425 >      PerformEditorHide(FExpandedRow);
426 >    FExpandedRow := -1;
427 >  end;
428   end;
429  
430   procedure TDBDynamicGrid.DoEditorShow;
431   begin
432 +  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    if Editor = FEditorPanel then
439    begin
440      if ExpandEditorPanelBelowRow then
# Line 397 | Line 447 | begin
447      FEditorPanel.PerformTab(true);  {Select First Control}
448      if assigned(FOnEditorPanelShow) then
449         OnEditorPanelShow(self);
450 +    if assigned(Editor) and Editor.Visible then
451 +      Editor.SetFocus;
452    end
453    else
454      inherited DoEditorShow;
# Line 461 | Line 513 | begin
513      inherited KeyDown(Key, Shift);
514   end;
515  
516 + 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   procedure TDBDynamicGrid.DoShowEditorPanel(Data: PtrInt);
528   begin
529    if AppDestroying in Application.Flags then Exit;
# Line 492 | Line 555 | end;
555   procedure TDBDynamicGrid.KeyDownHandler(Sender: TObject; var Key: Word;
556    Shift: TShiftState);
557   var Done: boolean;
558 +    AControl: TControl;
559   begin
560    if Visible and assigned(FEditorPanel) and FEditorPanel.Visible and FWeHaveFocus then
561    begin
562      Done := false;
563 +    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 +                         and (Key in [VK_RETURN,VK_UP,VK_DOWN]) then Exit; {Ignore keys in a CustomMemo}
572 +
573 +    if (AControl <> nil) and (AControl is TCustomGrid)
574 +                         and (Key in [VK_RETURN,VK_UP,VK_DOWN,VK_TAB]) then Exit; {Ignore keys in a Custom Grid}
575 +
576 +    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 +
583      if assigned(FOnKeyDownHander) then
584        OnKeyDownHander(Sender,Key,Shift,Done);
585      if Done then Exit;
# Line 518 | Line 602 | begin
602    end
603   end;
604  
605 + 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   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 <  FreeNotification(FEditorPanel);
626 >  if FEditorPanel <> nil then
627 >     FreeNotification(FEditorPanel);
628   end;
629  
630   procedure TDBDynamicGrid.ChangeBounds(ALeft, ATop, AWidth, AHeight: integer;
# Line 552 | Line 652 | begin
652    inherited Loaded;
653    if assigned(FEditorPanel) and not (csDesigning in ComponentState)then
654      FEditorPanel.Visible := false;
655 <  DoGridResize
655 >  if Visible then
656 >    DoGridResize
657   end;
658  
659   procedure TDBDynamicGrid.DoOnResize;
# Line 576 | Line 677 | procedure TDBDynamicGrid.MouseDown(Butto
677    Y: Integer);
678   var Coord: TGridCoord;
679   begin
680 <  inherited MouseDown(Button, Shift, X, Y);
680 >  FMouseDown := true;
681 >  try
682 >    inherited MouseDown(Button, Shift, X, Y);
683 >  finally
684 >    FMouseDown := false;
685 >  end;
686  
687    Coord := MouseCoord(X,Y);
688    if (Coord.X = 0) and (Coord.Y > 0) then
# Line 585 | Line 691 | end;
691  
692   procedure TDBDynamicGrid.Notification(AComponent: TComponent;
693    Operation: TOperation);
694 + var i: integer;
695   begin
696    inherited Notification(AComponent, Operation);
697 <  if (Operation = opRemove) and
698 <     (AComponent = FEditorPanel) then FEditorPanel := nil;
697 >  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   end;
710  
711   procedure TDBDynamicGrid.TopLeftChanged;
# Line 601 | Line 718 | procedure TDBDynamicGrid.UpdateActive;
718   begin
719    inherited UpdateActive;
720  
721 +  if not (csLoading in ComponentState) and assigned(DataLink)
722 +                       and assigned(DataLink.DataSet) and DataLink.DataSet.Active then
723 +    DoGridResize;
724 +
725    if not (csLoading in ComponentState) and assigned(DataLink) and
726 +     assigned(FEditorPanel) and not FEditorPanel.Visible and
727       assigned(DataLink.DataSet) and (DataLink.DataSet.State = dsInsert) then
728       Application.QueueAsyncCall(@DoShowEditorPanel,0);
729   end;
# Line 634 | Line 756 | end;
756   procedure TDBDynamicGrid.HideEditorPanel;
757   begin
758    if Editor = FEditorPanel then
759 <    EditorMode := false;
759 >      EditorMode := false;
760   end;
761  
762   procedure TDBDynamicGrid.ShowEditorPanel;
763 + var aEditor: TWinControl;
764   begin
765 <  if csDesigning in ComponentState then Exit;
766 <  Editor := FEditorPanel;
765 >  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 >  aEditor := FEditorPanel;
770 >  if assigned(FOnSelectPanelEditor) then
771 >    OnSelectPanelEditor(self,aEditor);
772 >  if FEditorPanel <> aEditor then
773 >    SetEditorPanel(aEditor);
774 >  Editor := aEditor;
775    EditorMode := true;
776   end;
777  
# Line 679 | Line 810 | begin
810    Result := inherited Width
811   end;
812  
813 + type
814 +  THackedGrid = class(TIBDynamicGrid)
815 +  public
816 +    property FixedCols;
817 +  end;
818 +
819   { TDBLookupCellEditor }
820  
821 + 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   procedure TDBLookupCellEditor.WndProc(var TheMessage: TLMessage);
828   begin
829    if TheMessage.msg=LM_KILLFOCUS then begin
# Line 698 | Line 841 | procedure TDBLookupCellEditor.CloseUp;
841   begin
842    UpdateData(nil); {Force Record Update}
843    if FGrid<>nil then
844 <    (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, Text);
844 >  Begin
845 >    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 >    (FGrid as TIBDynamicGrid).UpdateData;
853 >  end;
854    inherited CloseUp;
855   end;
856  
# Line 710 | Line 862 | begin
862      inherited KeyDown(Key, Shift);
863   end;
864  
865 + procedure TDBLookupCellEditor.Loaded;
866 + begin
867 +  inherited Loaded;
868 +  Text := '';
869 + end;
870 +
871   procedure TDBLookupCellEditor.msg_GetValue(var Msg: TGridMessage);
872   begin
873    CheckAndInsert;
874    Msg.Col := FCol;
875    Msg.Row := FRow;
876 <  Msg.Value:= Trim(Text);
876 >  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   end;
886  
887   procedure TDBLookupCellEditor.msg_SetGrid(var Msg: TGridMessage);
# Line 730 | Line 896 | begin
896    FCol := Msg.Col;
897    FRow := Msg.Row;
898    FEditText := Msg.Value;
733  SelStart := Length(Text);
899    TIBDynamicGrid(FGrid).SetupEditor(self,FCol);
900   end;
901  
# Line 779 | Line 944 | begin
944      Editor.OnAutoInsert := OnAutoInsert;
945      Editor.OnCanAutoInsert := OnCanAutoInsert;
946      Editor.OnDrawItem := OnDrawItem;
947 +    Editor.OnCloseUp := OnCloseUp;
948  
949      {Setup Data Links}
950      if KeyField <> '' then
# Line 803 | Line 969 | begin
969      if DataFieldName <> '' then
970          Editor.DataSource := TDBGrid(Grid).DataSource;
971    end;
972 <  Editor.Text := Editor.FEditText;
972 >  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 >  Editor.SelStart := Length(Editor.Text);
980   end;
981  
982   procedure TIBDynamicGridColumn.SetInitialSortColumn(AValue: boolean);
# Line 827 | Line 1000 | end;
1000   destructor TIBDynamicGridColumn.Destroy;
1001   begin
1002    if assigned(FDBLookupProperties) then FDBLookupProperties.Free;
1003 +  Application.RemoveAsyncCalls(self);
1004    inherited Destroy;
1005   end;
1006  
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
1007  
1008   { TIBDynamicGrid }
1009  
# Line 872 | Line 1018 | begin
1018        OnColumnHeaderClick(self,Index);
1019  
1020      FLastColIndex := Index;
1021 <    if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active then
1021 >    FFieldPosition := 0;
1022 >    if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active
1023 >       and (DataSource.DataSet is TIBParserDataSet) then
1024      begin
1025 +      if FLastColIndex < Columns.Count then
1026 +      {try and cache field position while dataset still open}
1027 +        FFieldPosition := TIBParserDataSet(DataSource.DataSet).Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1028        DataSource.DataSet.Active := false;
1029        Application.QueueAsyncCall(@DoReopen,0)
1030      end;
# Line 901 | Line 1052 | end;
1052   procedure TIBDynamicGrid.SetDataSource(AValue: TDataSource);
1053   begin
1054    inherited DataSource := AValue;
1055 <  FDataLink.DataSource := AValue;
1055 >  IBControlLinkChanged;
1056   end;
1057  
1058   procedure TIBDynamicGrid.SetEditorBorderStyle(AValue: TBorderStyle);
# Line 921 | Line 1072 | begin
1072    for i := 0 to Columns.Count - 1 do
1073    begin
1074      if TIBDynamicGridColumn(columns[i]).InitialSortColumn then
1075 +    begin
1076 +      FFieldPosition := 0;
1077        FLastColIndex := i
1078 +    end
1079    end
1080   end;
1081  
# Line 938 | Line 1092 | end;
1092  
1093   procedure TIBDynamicGrid.UpdateSQL(Sender: TObject; Parser: TSelectSQLParser);
1094   var OrderBy: string;
941    FieldPosition: integer;
1095   begin
1096 <    if (Sender = TObject(FDataLink)) and assigned(DataSource) and assigned(DataSource.DataSet)
1096 >    if assigned(DataSource) and assigned(DataSource.DataSet)
1097        and (DataSource.DataSet is TIBCustomDataSet) then
1098      begin
1099 <      FieldPosition := Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1100 <      if FieldPosition = 0 then Exit;
1101 <
1102 <      if Descending then
1103 <        Parser.OrderByClause := IntToStr(FieldPosition) + ' desc'
1104 <      else
1105 <        Parser.OrderByClause := IntToStr(FieldPosition) + ' asc';
1099 >      if (FFieldPosition = 0) and (FLastColIndex >= 0) and (FLastColIndex < Columns.Count) then
1100 >        {Not cached - let's hope we can find it before the dataset is opened.
1101 >         Won't work if dynamic columns}
1102 >        FFieldPosition := Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1103 >      if FFieldPosition > 0 then
1104 >      begin
1105 >        if Descending then
1106 >          Parser.OrderByClause := IntToStr(FFieldPosition) + ' desc'
1107 >        else
1108 >          Parser.OrderByClause := IntToStr(FFieldPosition) + ' asc';
1109 >      end;
1110  
1111        if assigned(FOnUpdateSortOrder) then
1112        begin
# Line 972 | Line 1129 | begin
1129  
1130   end;
1131  
1132 < 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);
1132 > procedure TIBDynamicGrid.RestorePosition;
1133   begin
990  if AppDestroying in Application.Flags then Exit;
991
1134    if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active then
1135    begin
1136 +    if assigned(FOnRestorePosition) then
1137 +      OnRestorePosition(self,@FBookmark);
1138      if (Length(FBookmark) > 0) and
1139        DataSource.DataSet.Locate(FIndexFieldNames,FBookmark,[]) then Exit;
1140  
# Line 999 | Line 1143 | begin
1143    end;
1144   end;
1145  
1146 + procedure TIBDynamicGrid.SavePosition;
1147 + var i: integer;
1148 +    F: TField;
1149 + begin
1150 +  if FIndexFieldsList = nil then Exit;
1151 +
1152 +  SetLength(FBookmark,FIndexFieldsList.Count);
1153 +  for i := 0 to FIndexFieldsList.Count - 1 do
1154 +  begin
1155 +    F := DataSource.DataSet.FindField(FIndexFieldsList[i]);
1156 +    if assigned(F) then
1157 +       FBookmark[i] := F.AsVariant;
1158 +  end;
1159 + end;
1160 +
1161   procedure TIBDynamicGrid.DoReOpen(Data: PtrInt);
1162   begin
1163    DataSource.DataSet.Active := true;
1164   end;
1165  
1166 + procedure TIBDynamicGrid.IBControlLinkChanged;
1167 + begin
1168 +  if (DataSource <> nil) and (DataSource.DataSet <> nil) and (DataSource.DataSet is TIBParserDataSet) then
1169 +    FIBControlLink.IBDataSet := TIBCustomDataSet(DataSource.DataSet)
1170 +  else
1171 +    FIBControlLink.IBDataSet := nil;
1172 + end;
1173 +
1174   procedure TIBDynamicGrid.SetupEditor(aEditor: TDBLookupCellEditor; aCol: integer
1175    );
1176   var C: TIBDynamicGridColumn;
1177   begin
1178    C := ColumnFromGridColumn(aCol) as TIBDynamicGridColumn;
1179 <  C.SetupEditor(aEditor);
1179 >  if (c <> nil) then
1180 >    C.SetupEditor(aEditor);
1181   end;
1182  
1183   procedure TIBDynamicGrid.DoEditorHide;
# Line 1025 | Line 1193 | end;
1193   procedure TIBDynamicGrid.Loaded;
1194   begin
1195    inherited Loaded;
1196 +  IBControlLinkChanged;
1197    ProcessColumns;
1198   end;
1199  
# Line 1054 | Line 1223 | begin
1223    AllowOutboundEvents := false;
1224    try
1225      Coord := MouseCoord(X,Y);
1226 <  if AllowColumnSort and  (Coord.X <> -1) and
1226 >  if AllowColumnSort and  (Coord.X <> -1) and (FixedRows > 0) and
1227     (Coord.Y = 0) and (MouseCoord(X+5,Y).X = Coord.X) {not on boundary}
1228                     and (MouseCoord(X-5,Y).X = Coord.X) then
1229      ColumnHeaderClick(Coord.X-1);
# Line 1063 | Line 1232 | begin
1232    end;
1233   end;
1234  
1235 + procedure TIBDynamicGrid.MoveSelection;
1236 + begin
1237 +  inherited MoveSelection;
1238 +  SavePosition;
1239 + end;
1240 +
1241   procedure TIBDynamicGrid.LinkActive(Value: Boolean);
1242   begin
1243 +  IBControlLinkChanged;
1244    inherited LinkActive(Value);
1245    if (FActive <> Value) and Value then
1246 <    Application.QueueAsyncCall(@RestorePosition,0);
1246 >    RestorePosition;
1247    FActive := Value
1248   end;
1249  
1250   procedure TIBDynamicGrid.Notification(AComponent: TComponent;
1251    Operation: TOperation);
1252 + var i: integer;
1253   begin
1254    inherited Notification(AComponent, Operation);
1255 <  if (Operation = opRemove) and
1256 <     (FDataLink <> nil) and (AComponent = DataSource) then DataSource := nil;
1255 >  if (Operation = opRemove) then
1256 >  begin
1257 >    if (FIBControlLink <> nil) and (AComponent = DataSource) then
1258 >      FIBControlLink.IBDataSet := nil
1259 >    else
1260 >    if AComponent is TDataSource then
1261 >    begin
1262 >      for i := 0 to Columns.Count - 1 do
1263 >        if TIBDynamicGridColumn(Columns[I]).DBLookupProperties.ListSource = AComponent then
1264 >          TIBDynamicGridColumn(Columns[I]).DBLookupProperties.ListSource := nil;
1265 >    end
1266 >  end
1267   end;
1268  
1269   procedure TIBDynamicGrid.UpdateActive;
1270   begin
1271    inherited UpdateActive;
1272 <  if assigned(FDataLink) and assigned(FDataLink.DataSet) and
1273 <     FDataLink.DataSet.Active and (FDataLink.DataSet.State = dsInsert) then
1274 <    DataSetScrolled(nil);
1272 >  if assigned(DataLink) and assigned(DataLink.DataSet) and
1273 >     DataLink.DataSet.Active and (DataLink.DataSet.State = dsInsert) then
1274 >   SavePosition;
1275   end;
1276  
1277   constructor TIBDynamicGrid.Create(TheComponent: TComponent);
1278   begin
1279    inherited Create(TheComponent);
1280    FAllowColumnSort := true;
1281 <  FDataLink := TDynamicGridDataLink.Create(self);
1281 >  FIBControlLink := TIBGridControlLink.Create(self);
1282    FIndexFieldsList := TStringList.Create;
1283    FIndexFieldsList.Delimiter := ';';
1284    FIndexFieldsList.StrictDelimiter := true;
# Line 1103 | Line 1290 | end;
1290  
1291   destructor TIBDynamicGrid.Destroy;
1292   begin
1293 <  if assigned(FDataLink) then FDataLink.Free;
1293 >  if assigned(FIBControlLink) then FIBControlLink.Free;
1294    if assigned(FIndexFieldsList) then FIndexFieldsList.Free;
1295    if assigned(FDBLookupCellEditor) then FDBLookupCellEditor.Free;
1296 +  Application.RemoveAsyncCalls(self);
1297    inherited Destroy;
1298   end;
1299  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines