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 45 by tony, Tue Dec 6 10:33:46 2016 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 Return 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 Return in a Custom Grid}
575 +
576 +    if (AControl <> nil) and ((AControl is TDateEdit) or (AControl is TEBEdit))
577 +                         and (Key in [VK_RETURN,VK_UP,VK_DOWN,
578 +                               VK_ESCAPE,VK_LEFT,VK_RIGHT]) then Exit; {Ignore Return in a Data edit}
579 +
580      if assigned(FOnKeyDownHander) then
581        OnKeyDownHander(Sender,Key,Shift,Done);
582      if Done then Exit;
# Line 518 | Line 599 | begin
599    end
600   end;
601  
602 + procedure TDBDynamicGrid.PerformEditorHide(Data: PtrInt);
603 + var ExpandedRow: integer;
604 + begin
605 +  if AppDestroying in Application.Flags then Exit;
606 +  ExpandedRow := integer(Data);
607 +  if (ExpandedRow >= 0) and (ExpandedRow < RowCount) then
608 +    RowHeights[ExpandedRow] := DefaultRowHeight;
609 +  if CanFocus then SetFocus;
610 +  DoOnResize;
611 +  ResetSizes;
612 +  DoOnChangeBounds;
613 +  if assigned(FOnEditorPanelHide) then
614 +     OnEditorPanelHide(self);
615 + end;
616 +
617   procedure TDBDynamicGrid.SetEditorPanel(AValue: TWinControl);
618   begin
619    if FEditorPanel = AValue then Exit;
620    if FEditorPanel <> nil then
621       RemoveFreeNotification(FEditorPanel);
622    FEditorPanel := AValue;
623 <  FreeNotification(FEditorPanel);
623 >  if FEditorPanel <> nil then
624 >     FreeNotification(FEditorPanel);
625   end;
626  
627   procedure TDBDynamicGrid.ChangeBounds(ALeft, ATop, AWidth, AHeight: integer;
# Line 552 | Line 649 | begin
649    inherited Loaded;
650    if assigned(FEditorPanel) and not (csDesigning in ComponentState)then
651      FEditorPanel.Visible := false;
652 <  DoGridResize
652 >  if Visible then
653 >    DoGridResize
654   end;
655  
656   procedure TDBDynamicGrid.DoOnResize;
# Line 576 | Line 674 | procedure TDBDynamicGrid.MouseDown(Butto
674    Y: Integer);
675   var Coord: TGridCoord;
676   begin
677 <  inherited MouseDown(Button, Shift, X, Y);
677 >  FMouseDown := true;
678 >  try
679 >    inherited MouseDown(Button, Shift, X, Y);
680 >  finally
681 >    FMouseDown := false;
682 >  end;
683  
684    Coord := MouseCoord(X,Y);
685    if (Coord.X = 0) and (Coord.Y > 0) then
# Line 585 | Line 688 | end;
688  
689   procedure TDBDynamicGrid.Notification(AComponent: TComponent;
690    Operation: TOperation);
691 + var i: integer;
692   begin
693    inherited Notification(AComponent, Operation);
694 <  if (Operation = opRemove) and
695 <     (AComponent = FEditorPanel) then FEditorPanel := nil;
694 >  if (Operation = opRemove) and not (csDestroying in ComponentState) then
695 >  begin
696 >    if AComponent = FEditorPanel then
697 >      FEditorPanel := nil
698 >    else
699 >    if AComponent is TControl then
700 >    begin
701 >      for i := 0 to Columns.Count - 1 do
702 >        if TDBDynamicGridColumn(Columns[I]).ColumnTotalsControl = AComponent then
703 >          TDBDynamicGridColumn(Columns[I]).ColumnTotalsControl := nil;
704 >    end;
705 >  end
706   end;
707  
708   procedure TDBDynamicGrid.TopLeftChanged;
# Line 601 | Line 715 | procedure TDBDynamicGrid.UpdateActive;
715   begin
716    inherited UpdateActive;
717  
718 +  if not (csLoading in ComponentState) and assigned(DataLink)
719 +                       and assigned(DataLink.DataSet) and DataLink.DataSet.Active then
720 +    DoGridResize;
721 +
722    if not (csLoading in ComponentState) and assigned(DataLink) and
723 +     assigned(FEditorPanel) and not FEditorPanel.Visible and
724       assigned(DataLink.DataSet) and (DataLink.DataSet.State = dsInsert) then
725       Application.QueueAsyncCall(@DoShowEditorPanel,0);
726   end;
# Line 634 | Line 753 | end;
753   procedure TDBDynamicGrid.HideEditorPanel;
754   begin
755    if Editor = FEditorPanel then
756 <    EditorMode := false;
756 >      EditorMode := false;
757   end;
758  
759   procedure TDBDynamicGrid.ShowEditorPanel;
760 + var aEditor: TWinControl;
761   begin
762 <  if csDesigning in ComponentState then Exit;
763 <  Editor := FEditorPanel;
762 >  if (csDesigning in ComponentState) or
763 >   (DataSource = nil) or (DataSource.DataSet = nil)
764 >     or ((DataSource.DataSet.RecordCount = 0) and (DataSource.DataSet.State <> dsInsert)) then
765 >     Exit;
766 >  aEditor := FEditorPanel;
767 >  if assigned(FOnSelectPanelEditor) then
768 >    OnSelectPanelEditor(self,aEditor);
769 >  if FEditorPanel <> aEditor then
770 >    SetEditorPanel(aEditor);
771 >  Editor := aEditor;
772    EditorMode := true;
773   end;
774  
# Line 679 | Line 807 | begin
807    Result := inherited Width
808   end;
809  
810 + type
811 +  THackedGrid = class(TIBDynamicGrid)
812 +  public
813 +    property FixedCols;
814 +  end;
815 +
816   { TDBLookupCellEditor }
817  
818 + function TDBLookupCellEditor.EditingKeyField: boolean;
819 + begin
820 +  with TIBDynamicGridColumn(TDBGrid(FGrid).Columns[FCol - THackedGrid(FGrid).FixedCols]) do
821 +    Result := CompareText(FieldName, DBLookupProperties.DataFieldName) = 0;
822 + end;
823 +
824   procedure TDBLookupCellEditor.WndProc(var TheMessage: TLMessage);
825   begin
826    if TheMessage.msg=LM_KILLFOCUS then begin
# Line 698 | Line 838 | procedure TDBLookupCellEditor.CloseUp;
838   begin
839    UpdateData(nil); {Force Record Update}
840    if FGrid<>nil then
841 <    (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, Text);
841 >  Begin
842 >    if EditingKeyField then
843 >    begin
844 >      if not VarIsNull(KeyValue) then
845 >       (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, KeyValue)
846 >    end
847 >    else
848 >      (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, Trim(Text));
849 >    (FGrid as TIBDynamicGrid).UpdateData;
850 >  end;
851    inherited CloseUp;
852   end;
853  
# Line 710 | Line 859 | begin
859      inherited KeyDown(Key, Shift);
860   end;
861  
862 + procedure TDBLookupCellEditor.Loaded;
863 + begin
864 +  inherited Loaded;
865 +  Text := '';
866 + end;
867 +
868   procedure TDBLookupCellEditor.msg_GetValue(var Msg: TGridMessage);
869   begin
870    CheckAndInsert;
871    Msg.Col := FCol;
872    Msg.Row := FRow;
873 <  Msg.Value:= Trim(Text);
873 >  if EditingKeyField then
874 >  begin
875 >    if not VarIsNull(KeyValue) then
876 >      Msg.Value:= KeyValue
877 >    else
878 >      Msg.Value:= ''
879 >  end
880 >  else
881 >    Msg.Value:= Trim(Text);
882   end;
883  
884   procedure TDBLookupCellEditor.msg_SetGrid(var Msg: TGridMessage);
# Line 730 | Line 893 | begin
893    FCol := Msg.Col;
894    FRow := Msg.Row;
895    FEditText := Msg.Value;
733  SelStart := Length(Text);
896    TIBDynamicGrid(FGrid).SetupEditor(self,FCol);
897   end;
898  
# Line 779 | Line 941 | begin
941      Editor.OnAutoInsert := OnAutoInsert;
942      Editor.OnCanAutoInsert := OnCanAutoInsert;
943      Editor.OnDrawItem := OnDrawItem;
944 +    Editor.OnCloseUp := OnCloseUp;
945  
946      {Setup Data Links}
947      if KeyField <> '' then
# Line 803 | Line 966 | begin
966      if DataFieldName <> '' then
967          Editor.DataSource := TDBGrid(Grid).DataSource;
968    end;
969 <  Editor.Text := Editor.FEditText;
969 >  if Editor.EditingKeyField then
970 >  begin
971 >    if not Field.IsNull then
972 >      Editor.KeyValue := Editor.FEditText
973 >  end
974 >  else
975 >    Editor.Text := Editor.FEditText;
976 >  Editor.SelStart := Length(Editor.Text);
977   end;
978  
979   procedure TIBDynamicGridColumn.SetInitialSortColumn(AValue: boolean);
# Line 830 | Line 1000 | begin
1000    inherited Destroy;
1001   end;
1002  
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
1003  
1004   { TIBDynamicGrid }
1005  
# Line 872 | Line 1014 | begin
1014        OnColumnHeaderClick(self,Index);
1015  
1016      FLastColIndex := Index;
1017 <    if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active then
1017 >    FFieldPosition := 0;
1018 >    if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active
1019 >       and (DataSource.DataSet is TIBParserDataSet) then
1020      begin
1021 +      if FLastColIndex < Columns.Count then
1022 +      {try and cache field position while dataset still open}
1023 +        FFieldPosition := TIBParserDataSet(DataSource.DataSet).Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1024        DataSource.DataSet.Active := false;
1025        Application.QueueAsyncCall(@DoReopen,0)
1026      end;
# Line 901 | Line 1048 | end;
1048   procedure TIBDynamicGrid.SetDataSource(AValue: TDataSource);
1049   begin
1050    inherited DataSource := AValue;
1051 <  FDataLink.DataSource := AValue;
1051 >  IBControlLinkChanged;
1052   end;
1053  
1054   procedure TIBDynamicGrid.SetEditorBorderStyle(AValue: TBorderStyle);
# Line 921 | Line 1068 | begin
1068    for i := 0 to Columns.Count - 1 do
1069    begin
1070      if TIBDynamicGridColumn(columns[i]).InitialSortColumn then
1071 +    begin
1072 +      FFieldPosition := 0;
1073        FLastColIndex := i
1074 +    end
1075    end
1076   end;
1077  
# Line 938 | Line 1088 | end;
1088  
1089   procedure TIBDynamicGrid.UpdateSQL(Sender: TObject; Parser: TSelectSQLParser);
1090   var OrderBy: string;
941    FieldPosition: integer;
1091   begin
1092 <    if (Sender = TObject(FDataLink)) and assigned(DataSource) and assigned(DataSource.DataSet)
1092 >    if assigned(DataSource) and assigned(DataSource.DataSet)
1093        and (DataSource.DataSet is TIBCustomDataSet) then
1094      begin
1095 <      FieldPosition := Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1096 <      if FieldPosition = 0 then Exit;
1097 <
1098 <      if Descending then
1099 <        Parser.OrderByClause := IntToStr(FieldPosition) + ' desc'
1100 <      else
1101 <        Parser.OrderByClause := IntToStr(FieldPosition) + ' asc';
1095 >      if (FFieldPosition = 0) and (FLastColIndex >= 0) and (FLastColIndex < Columns.Count) then
1096 >        {Not cached - let's hope we can find it before the dataset is opened.
1097 >         Won't work if dynamic columns}
1098 >        FFieldPosition := Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1099 >      if FFieldPosition > 0 then
1100 >      begin
1101 >        if Descending then
1102 >          Parser.OrderByClause := IntToStr(FFieldPosition) + ' desc'
1103 >        else
1104 >          Parser.OrderByClause := IntToStr(FFieldPosition) + ' asc';
1105 >      end;
1106  
1107        if assigned(FOnUpdateSortOrder) then
1108        begin
# Line 972 | Line 1125 | begin
1125  
1126   end;
1127  
1128 < procedure TIBDynamicGrid.DataSetScrolled(Sender: TObject);
976 < var i: integer;
977 <    F: TField;
1128 > procedure TIBDynamicGrid.RestorePosition;
1129   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);
989 begin
990  if AppDestroying in Application.Flags then Exit;
991
1130    if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active then
1131    begin
1132 +    if assigned(FOnRestorePosition) then
1133 +      OnRestorePosition(self,@FBookmark);
1134      if (Length(FBookmark) > 0) and
1135        DataSource.DataSet.Locate(FIndexFieldNames,FBookmark,[]) then Exit;
1136  
# Line 999 | Line 1139 | begin
1139    end;
1140   end;
1141  
1142 + procedure TIBDynamicGrid.SavePosition;
1143 + var i: integer;
1144 +    F: TField;
1145 + begin
1146 +  if FIndexFieldsList = nil then Exit;
1147 +
1148 +  SetLength(FBookmark,FIndexFieldsList.Count);
1149 +  for i := 0 to FIndexFieldsList.Count - 1 do
1150 +  begin
1151 +    F := DataSource.DataSet.FindField(FIndexFieldsList[i]);
1152 +    if assigned(F) then
1153 +       FBookmark[i] := F.AsVariant;
1154 +  end;
1155 + end;
1156 +
1157   procedure TIBDynamicGrid.DoReOpen(Data: PtrInt);
1158   begin
1159    DataSource.DataSet.Active := true;
1160   end;
1161  
1162 + procedure TIBDynamicGrid.IBControlLinkChanged;
1163 + begin
1164 +  if (DataSource <> nil) and (DataSource.DataSet <> nil) and (DataSource.DataSet is TIBParserDataSet) then
1165 +    FIBControlLink.IBDataSet := TIBCustomDataSet(DataSource.DataSet)
1166 +  else
1167 +    FIBControlLink.IBDataSet := nil;
1168 + end;
1169 +
1170   procedure TIBDynamicGrid.SetupEditor(aEditor: TDBLookupCellEditor; aCol: integer
1171    );
1172   var C: TIBDynamicGridColumn;
1173   begin
1174    C := ColumnFromGridColumn(aCol) as TIBDynamicGridColumn;
1175 <  C.SetupEditor(aEditor);
1175 >  if (c <> nil) then
1176 >    C.SetupEditor(aEditor);
1177   end;
1178  
1179   procedure TIBDynamicGrid.DoEditorHide;
# Line 1025 | Line 1189 | end;
1189   procedure TIBDynamicGrid.Loaded;
1190   begin
1191    inherited Loaded;
1192 +  IBControlLinkChanged;
1193    ProcessColumns;
1194   end;
1195  
# Line 1054 | Line 1219 | begin
1219    AllowOutboundEvents := false;
1220    try
1221      Coord := MouseCoord(X,Y);
1222 <  if AllowColumnSort and  (Coord.X <> -1) and
1222 >  if AllowColumnSort and  (Coord.X <> -1) and (FixedRows > 0) and
1223     (Coord.Y = 0) and (MouseCoord(X+5,Y).X = Coord.X) {not on boundary}
1224                     and (MouseCoord(X-5,Y).X = Coord.X) then
1225      ColumnHeaderClick(Coord.X-1);
# Line 1063 | Line 1228 | begin
1228    end;
1229   end;
1230  
1231 + procedure TIBDynamicGrid.MoveSelection;
1232 + begin
1233 +  inherited MoveSelection;
1234 +  SavePosition;
1235 + end;
1236 +
1237   procedure TIBDynamicGrid.LinkActive(Value: Boolean);
1238   begin
1239 +  IBControlLinkChanged;
1240    inherited LinkActive(Value);
1241    if (FActive <> Value) and Value then
1242 <    Application.QueueAsyncCall(@RestorePosition,0);
1242 >    RestorePosition;
1243    FActive := Value
1244   end;
1245  
1246   procedure TIBDynamicGrid.Notification(AComponent: TComponent;
1247    Operation: TOperation);
1248 + var i: integer;
1249   begin
1250    inherited Notification(AComponent, Operation);
1251 <  if (Operation = opRemove) and
1252 <     (FDataLink <> nil) and (AComponent = DataSource) then DataSource := nil;
1251 >  if (Operation = opRemove) then
1252 >  begin
1253 >    if (FIBControlLink <> nil) and (AComponent = DataSource) then
1254 >      FIBControlLink.IBDataSet := nil
1255 >    else
1256 >    if AComponent is TDataSource then
1257 >    begin
1258 >      for i := 0 to Columns.Count - 1 do
1259 >        if TIBDynamicGridColumn(Columns[I]).DBLookupProperties.ListSource = AComponent then
1260 >          TIBDynamicGridColumn(Columns[I]).DBLookupProperties.ListSource := nil;
1261 >    end
1262 >  end
1263   end;
1264  
1265   procedure TIBDynamicGrid.UpdateActive;
1266   begin
1267    inherited UpdateActive;
1268 <  if assigned(FDataLink) and assigned(FDataLink.DataSet) and
1269 <     FDataLink.DataSet.Active and (FDataLink.DataSet.State = dsInsert) then
1270 <    DataSetScrolled(nil);
1268 >  if assigned(DataLink) and assigned(DataLink.DataSet) and
1269 >     DataLink.DataSet.Active and (DataLink.DataSet.State = dsInsert) then
1270 >   SavePosition;
1271   end;
1272  
1273   constructor TIBDynamicGrid.Create(TheComponent: TComponent);
1274   begin
1275    inherited Create(TheComponent);
1276    FAllowColumnSort := true;
1277 <  FDataLink := TDynamicGridDataLink.Create(self);
1277 >  FIBControlLink := TIBGridControlLink.Create(self);
1278    FIndexFieldsList := TStringList.Create;
1279    FIndexFieldsList.Delimiter := ';';
1280    FIndexFieldsList.StrictDelimiter := true;
# Line 1103 | Line 1286 | end;
1286  
1287   destructor TIBDynamicGrid.Destroy;
1288   begin
1289 <  if assigned(FDataLink) then FDataLink.Free;
1289 >  if assigned(FIBControlLink) then FIBControlLink.Free;
1290    if assigned(FIndexFieldsList) then FIndexFieldsList.Free;
1291    if assigned(FDBLookupCellEditor) then FDBLookupCellEditor.Free;
1292    inherited Destroy;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines