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 23 by tony, Fri Mar 13 10:26:52 2015 UTC vs.
Revision 49 by tony, Thu Feb 2 16:20:12 2017 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 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 830 | Line 1003 | begin
1003    inherited Destroy;
1004   end;
1005  
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
1006  
1007   { TIBDynamicGrid }
1008  
# Line 872 | Line 1017 | begin
1017        OnColumnHeaderClick(self,Index);
1018  
1019      FLastColIndex := Index;
1020 <    if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active then
1020 >    FFieldPosition := 0;
1021 >    if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active
1022 >       and (DataSource.DataSet is TIBParserDataSet) then
1023      begin
1024 +      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        DataSource.DataSet.Active := false;
1028        Application.QueueAsyncCall(@DoReopen,0)
1029      end;
# Line 901 | Line 1051 | end;
1051   procedure TIBDynamicGrid.SetDataSource(AValue: TDataSource);
1052   begin
1053    inherited DataSource := AValue;
1054 <  FDataLink.DataSource := AValue;
1054 >  IBControlLinkChanged;
1055   end;
1056  
1057   procedure TIBDynamicGrid.SetEditorBorderStyle(AValue: TBorderStyle);
# Line 921 | Line 1071 | begin
1071    for i := 0 to Columns.Count - 1 do
1072    begin
1073      if TIBDynamicGridColumn(columns[i]).InitialSortColumn then
1074 +    begin
1075 +      FFieldPosition := 0;
1076        FLastColIndex := i
1077 +    end
1078    end
1079   end;
1080  
# Line 938 | Line 1091 | end;
1091  
1092   procedure TIBDynamicGrid.UpdateSQL(Sender: TObject; Parser: TSelectSQLParser);
1093   var OrderBy: string;
941    FieldPosition: integer;
1094   begin
1095 <    if (Sender = TObject(FDataLink)) and assigned(DataSource) and assigned(DataSource.DataSet)
1095 >    if assigned(DataSource) and assigned(DataSource.DataSet)
1096        and (DataSource.DataSet is TIBCustomDataSet) then
1097      begin
1098 <      FieldPosition := Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1099 <      if FieldPosition = 0 then Exit;
1100 <
1101 <      if Descending then
1102 <        Parser.OrderByClause := IntToStr(FieldPosition) + ' desc'
1103 <      else
1104 <        Parser.OrderByClause := IntToStr(FieldPosition) + ' asc';
1098 >      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 >      begin
1104 >        if Descending then
1105 >          Parser.OrderByClause := IntToStr(FFieldPosition) + ' desc'
1106 >        else
1107 >          Parser.OrderByClause := IntToStr(FFieldPosition) + ' asc';
1108 >      end;
1109  
1110        if assigned(FOnUpdateSortOrder) then
1111        begin
# Line 972 | Line 1128 | begin
1128  
1129   end;
1130  
1131 < 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);
1131 > procedure TIBDynamicGrid.RestorePosition;
1132   begin
990  if AppDestroying in Application.Flags then Exit;
991
1133    if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active then
1134    begin
1135 +    if assigned(FOnRestorePosition) then
1136 +      OnRestorePosition(self,@FBookmark);
1137      if (Length(FBookmark) > 0) and
1138        DataSource.DataSet.Locate(FIndexFieldNames,FBookmark,[]) then Exit;
1139  
# Line 999 | Line 1142 | begin
1142    end;
1143   end;
1144  
1145 + 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   procedure TIBDynamicGrid.DoReOpen(Data: PtrInt);
1161   begin
1162    DataSource.DataSet.Active := true;
1163   end;
1164  
1165 + 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   procedure TIBDynamicGrid.SetupEditor(aEditor: TDBLookupCellEditor; aCol: integer
1174    );
1175   var C: TIBDynamicGridColumn;
1176   begin
1177    C := ColumnFromGridColumn(aCol) as TIBDynamicGridColumn;
1178 <  C.SetupEditor(aEditor);
1178 >  if (c <> nil) then
1179 >    C.SetupEditor(aEditor);
1180   end;
1181  
1182   procedure TIBDynamicGrid.DoEditorHide;
# Line 1025 | Line 1192 | end;
1192   procedure TIBDynamicGrid.Loaded;
1193   begin
1194    inherited Loaded;
1195 +  IBControlLinkChanged;
1196    ProcessColumns;
1197   end;
1198  
# Line 1054 | Line 1222 | begin
1222    AllowOutboundEvents := false;
1223    try
1224      Coord := MouseCoord(X,Y);
1225 <  if AllowColumnSort and  (Coord.X <> -1) and
1225 >  if AllowColumnSort and  (Coord.X <> -1) and (FixedRows > 0) and
1226     (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);
# Line 1063 | Line 1231 | begin
1231    end;
1232   end;
1233  
1234 + procedure TIBDynamicGrid.MoveSelection;
1235 + begin
1236 +  inherited MoveSelection;
1237 +  SavePosition;
1238 + end;
1239 +
1240   procedure TIBDynamicGrid.LinkActive(Value: Boolean);
1241   begin
1242 +  IBControlLinkChanged;
1243    inherited LinkActive(Value);
1244    if (FActive <> Value) and Value then
1245 <    Application.QueueAsyncCall(@RestorePosition,0);
1245 >    RestorePosition;
1246    FActive := Value
1247   end;
1248  
1249   procedure TIBDynamicGrid.Notification(AComponent: TComponent;
1250    Operation: TOperation);
1251 + var i: integer;
1252   begin
1253    inherited Notification(AComponent, Operation);
1254 <  if (Operation = opRemove) and
1255 <     (FDataLink <> nil) and (AComponent = DataSource) then DataSource := nil;
1254 >  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   end;
1267  
1268   procedure TIBDynamicGrid.UpdateActive;
1269   begin
1270    inherited UpdateActive;
1271 <  if assigned(FDataLink) and assigned(FDataLink.DataSet) and
1272 <     FDataLink.DataSet.Active and (FDataLink.DataSet.State = dsInsert) then
1273 <    DataSetScrolled(nil);
1271 >  if assigned(DataLink) and assigned(DataLink.DataSet) and
1272 >     DataLink.DataSet.Active and (DataLink.DataSet.State = dsInsert) then
1273 >   SavePosition;
1274   end;
1275  
1276   constructor TIBDynamicGrid.Create(TheComponent: TComponent);
1277   begin
1278    inherited Create(TheComponent);
1279    FAllowColumnSort := true;
1280 <  FDataLink := TDynamicGridDataLink.Create(self);
1280 >  FIBControlLink := TIBGridControlLink.Create(self);
1281    FIndexFieldsList := TStringList.Create;
1282    FIndexFieldsList.Delimiter := ';';
1283    FIndexFieldsList.StrictDelimiter := true;
# Line 1103 | Line 1289 | end;
1289  
1290   destructor TIBDynamicGrid.Destroy;
1291   begin
1292 <  if assigned(FDataLink) then FDataLink.Free;
1292 >  if assigned(FIBControlLink) then FIBControlLink.Free;
1293    if assigned(FIndexFieldsList) then FIndexFieldsList.Free;
1294    if assigned(FDBLookupCellEditor) then FDBLookupCellEditor.Free;
1295    inherited Destroy;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines