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

Comparing ibx/trunk/ibcontrols/IBDynamicGrid.pas (file contents):
Revision 21 by tony, Thu Feb 26 10:33:34 2015 UTC vs.
Revision 41 by tony, Sat Jul 16 12:25:48 2016 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 Math, IBQuery, LCLType, Variants;
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 CustomMemo}
575 +
576      if assigned(FOnKeyDownHander) then
577        OnKeyDownHander(Sender,Key,Shift,Done);
578      if Done then Exit;
# Line 518 | Line 595 | begin
595    end
596   end;
597  
598 + procedure TDBDynamicGrid.PerformEditorHide(Data: PtrInt);
599 + var ExpandedRow: integer;
600 + begin
601 +  if AppDestroying in Application.Flags then Exit;
602 +  ExpandedRow := integer(Data);
603 +  if (ExpandedRow >= 0) and (ExpandedRow < RowCount) then
604 +    RowHeights[ExpandedRow] := DefaultRowHeight;
605 +  if CanFocus then SetFocus;
606 +  DoOnResize;
607 +  ResetSizes;
608 +  DoOnChangeBounds;
609 +  if assigned(FOnEditorPanelHide) then
610 +     OnEditorPanelHide(self);
611 + end;
612 +
613   procedure TDBDynamicGrid.SetEditorPanel(AValue: TWinControl);
614   begin
615    if FEditorPanel = AValue then Exit;
616    if FEditorPanel <> nil then
617       RemoveFreeNotification(FEditorPanel);
618    FEditorPanel := AValue;
619 <  FreeNotification(FEditorPanel);
619 >  if FEditorPanel <> nil then
620 >     FreeNotification(FEditorPanel);
621   end;
622  
623   procedure TDBDynamicGrid.ChangeBounds(ALeft, ATop, AWidth, AHeight: integer;
# Line 552 | Line 645 | begin
645    inherited Loaded;
646    if assigned(FEditorPanel) and not (csDesigning in ComponentState)then
647      FEditorPanel.Visible := false;
648 <  DoGridResize
648 >  if Visible then
649 >    DoGridResize
650   end;
651  
652   procedure TDBDynamicGrid.DoOnResize;
# Line 576 | Line 670 | procedure TDBDynamicGrid.MouseDown(Butto
670    Y: Integer);
671   var Coord: TGridCoord;
672   begin
673 <  inherited MouseDown(Button, Shift, X, Y);
673 >  FMouseDown := true;
674 >  try
675 >    inherited MouseDown(Button, Shift, X, Y);
676 >  finally
677 >    FMouseDown := false;
678 >  end;
679  
680    Coord := MouseCoord(X,Y);
681    if (Coord.X = 0) and (Coord.Y > 0) then
# Line 585 | Line 684 | end;
684  
685   procedure TDBDynamicGrid.Notification(AComponent: TComponent;
686    Operation: TOperation);
687 + var i: integer;
688   begin
689    inherited Notification(AComponent, Operation);
690 <  if (Operation = opRemove) and
691 <     (AComponent = FEditorPanel) then FEditorPanel := nil;
690 >  if (Operation = opRemove) and not (csDestroying in ComponentState) then
691 >  begin
692 >    if AComponent = FEditorPanel then
693 >      FEditorPanel := nil
694 >    else
695 >    if AComponent is TControl then
696 >    begin
697 >      for i := 0 to Columns.Count - 1 do
698 >        if TDBDynamicGridColumn(Columns[I]).ColumnTotalsControl = AComponent then
699 >          TDBDynamicGridColumn(Columns[I]).ColumnTotalsControl := nil;
700 >    end;
701 >  end
702   end;
703  
704   procedure TDBDynamicGrid.TopLeftChanged;
# Line 601 | Line 711 | procedure TDBDynamicGrid.UpdateActive;
711   begin
712    inherited UpdateActive;
713  
714 +  if not (csLoading in ComponentState) and assigned(DataLink)
715 +                       and assigned(DataLink.DataSet) and DataLink.DataSet.Active then
716 +    DoGridResize;
717 +
718    if not (csLoading in ComponentState) and assigned(DataLink) and
719 +     assigned(FEditorPanel) and not FEditorPanel.Visible and
720       assigned(DataLink.DataSet) and (DataLink.DataSet.State = dsInsert) then
721       Application.QueueAsyncCall(@DoShowEditorPanel,0);
722   end;
# Line 634 | Line 749 | end;
749   procedure TDBDynamicGrid.HideEditorPanel;
750   begin
751    if Editor = FEditorPanel then
752 <    EditorMode := false;
752 >      EditorMode := false;
753   end;
754  
755   procedure TDBDynamicGrid.ShowEditorPanel;
756 + var aEditor: TWinControl;
757   begin
758 <  if csDesigning in ComponentState then Exit;
759 <  Editor := FEditorPanel;
758 >  if (csDesigning in ComponentState) or
759 >   (DataSource = nil) or (DataSource.DataSet = nil)
760 >     or ((DataSource.DataSet.RecordCount = 0) and (DataSource.DataSet.State <> dsInsert)) then
761 >     Exit;
762 >  aEditor := FEditorPanel;
763 >  if assigned(FOnSelectPanelEditor) then
764 >    OnSelectPanelEditor(self,aEditor);
765 >  if FEditorPanel <> aEditor then
766 >    SetEditorPanel(aEditor);
767 >  Editor := aEditor;
768    EditorMode := true;
769   end;
770  
# Line 679 | Line 803 | begin
803    Result := inherited Width
804   end;
805  
806 + type
807 +  THackedGrid = class(TIBDynamicGrid)
808 +  public
809 +    property FixedCols;
810 +  end;
811 +
812   { TDBLookupCellEditor }
813  
814 + function TDBLookupCellEditor.EditingKeyField: boolean;
815 + begin
816 +  with TIBDynamicGridColumn(TDBGrid(FGrid).Columns[FCol - THackedGrid(FGrid).FixedCols]) do
817 +    Result := CompareText(FieldName, DBLookupProperties.DataFieldName) = 0;
818 + end;
819 +
820   procedure TDBLookupCellEditor.WndProc(var TheMessage: TLMessage);
821   begin
822    if TheMessage.msg=LM_KILLFOCUS then begin
# Line 698 | Line 834 | procedure TDBLookupCellEditor.CloseUp;
834   begin
835    UpdateData(nil); {Force Record Update}
836    if FGrid<>nil then
837 <    (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, Text);
837 >  Begin
838 >    if EditingKeyField then
839 >    begin
840 >      if not VarIsNull(KeyValue) then
841 >       (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, KeyValue)
842 >    end
843 >    else
844 >      (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, Trim(Text));
845 >    (FGrid as TIBDynamicGrid).UpdateData;
846 >  end;
847    inherited CloseUp;
848   end;
849  
# Line 710 | Line 855 | begin
855      inherited KeyDown(Key, Shift);
856   end;
857  
858 + procedure TDBLookupCellEditor.Loaded;
859 + begin
860 +  inherited Loaded;
861 +  Text := '';
862 + end;
863 +
864   procedure TDBLookupCellEditor.msg_GetValue(var Msg: TGridMessage);
865   begin
866    CheckAndInsert;
867    Msg.Col := FCol;
868    Msg.Row := FRow;
869 <  Msg.Value:= Trim(Text);
869 >  if EditingKeyField then
870 >  begin
871 >    if not VarIsNull(KeyValue) then
872 >      Msg.Value:= KeyValue
873 >    else
874 >      Msg.Value:= ''
875 >  end
876 >  else
877 >    Msg.Value:= Trim(Text);
878   end;
879  
880   procedure TDBLookupCellEditor.msg_SetGrid(var Msg: TGridMessage);
# Line 730 | Line 889 | begin
889    FCol := Msg.Col;
890    FRow := Msg.Row;
891    FEditText := Msg.Value;
733  SelStart := Length(Text);
892    TIBDynamicGrid(FGrid).SetupEditor(self,FCol);
893   end;
894  
# Line 779 | Line 937 | begin
937      Editor.OnAutoInsert := OnAutoInsert;
938      Editor.OnCanAutoInsert := OnCanAutoInsert;
939      Editor.OnDrawItem := OnDrawItem;
940 +    Editor.OnCloseUp := OnCloseUp;
941  
942      {Setup Data Links}
943      if KeyField <> '' then
# Line 803 | Line 962 | begin
962      if DataFieldName <> '' then
963          Editor.DataSource := TDBGrid(Grid).DataSource;
964    end;
965 <  Editor.Text := Editor.FEditText;
965 >  if Editor.EditingKeyField then
966 >  begin
967 >    if not Field.IsNull then
968 >      Editor.KeyValue := Editor.FEditText
969 >  end
970 >  else
971 >    Editor.Text := Editor.FEditText;
972 >  Editor.SelStart := Length(Editor.Text);
973   end;
974  
975   procedure TIBDynamicGridColumn.SetInitialSortColumn(AValue: boolean);
# Line 830 | Line 996 | begin
996    inherited Destroy;
997   end;
998  
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
999  
1000   { TIBDynamicGrid }
1001  
# Line 872 | Line 1010 | begin
1010        OnColumnHeaderClick(self,Index);
1011  
1012      FLastColIndex := Index;
1013 <    if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active then
1013 >    FFieldPosition := 0;
1014 >    if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active
1015 >       and (DataSource.DataSet is TIBParserDataSet) then
1016      begin
1017 +      if FLastColIndex < Columns.Count then
1018 +      {try and cache field position while dataset still open}
1019 +        FFieldPosition := TIBParserDataSet(DataSource.DataSet).Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1020        DataSource.DataSet.Active := false;
1021        Application.QueueAsyncCall(@DoReopen,0)
1022      end;
# Line 901 | Line 1044 | end;
1044   procedure TIBDynamicGrid.SetDataSource(AValue: TDataSource);
1045   begin
1046    inherited DataSource := AValue;
1047 <  FDataLink.DataSource := AValue;
1047 >  IBControlLinkChanged;
1048   end;
1049  
1050   procedure TIBDynamicGrid.SetEditorBorderStyle(AValue: TBorderStyle);
# Line 921 | Line 1064 | begin
1064    for i := 0 to Columns.Count - 1 do
1065    begin
1066      if TIBDynamicGridColumn(columns[i]).InitialSortColumn then
1067 +    begin
1068 +      FFieldPosition := 0;
1069        FLastColIndex := i
1070 +    end
1071    end
1072   end;
1073  
# Line 938 | Line 1084 | end;
1084  
1085   procedure TIBDynamicGrid.UpdateSQL(Sender: TObject; Parser: TSelectSQLParser);
1086   var OrderBy: string;
941    FieldPosition: integer;
1087   begin
1088 <    if (Sender = TObject(FDataLink)) and assigned(DataSource) and assigned(DataSource.DataSet)
1088 >    if assigned(DataSource) and assigned(DataSource.DataSet)
1089        and (DataSource.DataSet is TIBCustomDataSet) then
1090      begin
1091 <      FieldPosition := Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1092 <      if FieldPosition = 0 then Exit;
1093 <
1094 <      if Descending then
1095 <        Parser.OrderByClause := IntToStr(FieldPosition) + ' desc'
1096 <      else
1097 <        Parser.OrderByClause := IntToStr(FieldPosition) + ' asc';
1091 >      if (FFieldPosition = 0) and (FLastColIndex >= 0) and (FLastColIndex < Columns.Count) then
1092 >        {Not cached - let's hope we can find it before the dataset is opened.
1093 >         Won't work if dynamic columns}
1094 >        FFieldPosition := Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1095 >      if FFieldPosition > 0 then
1096 >      begin
1097 >        if Descending then
1098 >          Parser.OrderByClause := IntToStr(FFieldPosition) + ' desc'
1099 >        else
1100 >          Parser.OrderByClause := IntToStr(FFieldPosition) + ' asc';
1101 >      end;
1102  
1103        if assigned(FOnUpdateSortOrder) then
1104        begin
# Line 972 | Line 1121 | begin
1121  
1122   end;
1123  
1124 < procedure TIBDynamicGrid.DataSetScrolled(Sender: TObject);
976 < var i: integer;
977 <    F: TField;
1124 > procedure TIBDynamicGrid.RestorePosition;
1125   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
1126    if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active then
1127    begin
1128 +    if assigned(FOnRestorePosition) then
1129 +      OnRestorePosition(self,@FBookmark);
1130      if (Length(FBookmark) > 0) and
1131        DataSource.DataSet.Locate(FIndexFieldNames,FBookmark,[]) then Exit;
1132  
# Line 999 | Line 1135 | begin
1135    end;
1136   end;
1137  
1138 + procedure TIBDynamicGrid.SavePosition;
1139 + var i: integer;
1140 +    F: TField;
1141 + begin
1142 +  if FIndexFieldsList = nil then Exit;
1143 +
1144 +  SetLength(FBookmark,FIndexFieldsList.Count);
1145 +  for i := 0 to FIndexFieldsList.Count - 1 do
1146 +  begin
1147 +    F := DataSource.DataSet.FindField(FIndexFieldsList[i]);
1148 +    if assigned(F) then
1149 +       FBookmark[i] := F.AsVariant;
1150 +  end;
1151 + end;
1152 +
1153   procedure TIBDynamicGrid.DoReOpen(Data: PtrInt);
1154   begin
1155    DataSource.DataSet.Active := true;
1156   end;
1157  
1158 + procedure TIBDynamicGrid.IBControlLinkChanged;
1159 + begin
1160 +  if (DataSource <> nil) and (DataSource.DataSet <> nil) and (DataSource.DataSet is TIBParserDataSet) then
1161 +    FIBControlLink.IBDataSet := TIBCustomDataSet(DataSource.DataSet)
1162 +  else
1163 +    FIBControlLink.IBDataSet := nil;
1164 + end;
1165 +
1166   procedure TIBDynamicGrid.SetupEditor(aEditor: TDBLookupCellEditor; aCol: integer
1167    );
1168   var C: TIBDynamicGridColumn;
1169   begin
1170    C := ColumnFromGridColumn(aCol) as TIBDynamicGridColumn;
1171 <  C.SetupEditor(aEditor);
1171 >  if (c <> nil) then
1172 >    C.SetupEditor(aEditor);
1173   end;
1174  
1175   procedure TIBDynamicGrid.DoEditorHide;
# Line 1025 | Line 1185 | end;
1185   procedure TIBDynamicGrid.Loaded;
1186   begin
1187    inherited Loaded;
1188 +  IBControlLinkChanged;
1189    ProcessColumns;
1190   end;
1191  
# Line 1054 | Line 1215 | begin
1215    AllowOutboundEvents := false;
1216    try
1217      Coord := MouseCoord(X,Y);
1218 <  if AllowColumnSort and  (Coord.X <> -1) and
1218 >  if AllowColumnSort and  (Coord.X <> -1) and (FixedRows > 0) and
1219     (Coord.Y = 0) and (MouseCoord(X+5,Y).X = Coord.X) {not on boundary}
1220                     and (MouseCoord(X-5,Y).X = Coord.X) then
1221      ColumnHeaderClick(Coord.X-1);
# Line 1063 | Line 1224 | begin
1224    end;
1225   end;
1226  
1227 + procedure TIBDynamicGrid.MoveSelection;
1228 + begin
1229 +  inherited MoveSelection;
1230 +  SavePosition;
1231 + end;
1232 +
1233   procedure TIBDynamicGrid.LinkActive(Value: Boolean);
1234   begin
1235 +  IBControlLinkChanged;
1236    inherited LinkActive(Value);
1237    if (FActive <> Value) and Value then
1238 <    Application.QueueAsyncCall(@RestorePosition,0);
1238 >    RestorePosition;
1239    FActive := Value
1240   end;
1241  
1242   procedure TIBDynamicGrid.Notification(AComponent: TComponent;
1243    Operation: TOperation);
1244 + var i: integer;
1245   begin
1246    inherited Notification(AComponent, Operation);
1247 <  if (Operation = opRemove) and
1248 <     (FDataLink <> nil) and (AComponent = DataSource) then DataSource := nil;
1247 >  if (Operation = opRemove) then
1248 >  begin
1249 >    if (FIBControlLink <> nil) and (AComponent = DataSource) then
1250 >      FIBControlLink.IBDataSet := nil
1251 >    else
1252 >    if AComponent is TDataSource then
1253 >    begin
1254 >      for i := 0 to Columns.Count - 1 do
1255 >        if TIBDynamicGridColumn(Columns[I]).DBLookupProperties.ListSource = AComponent then
1256 >          TIBDynamicGridColumn(Columns[I]).DBLookupProperties.ListSource := nil;
1257 >    end
1258 >  end
1259   end;
1260  
1261   procedure TIBDynamicGrid.UpdateActive;
1262   begin
1263    inherited UpdateActive;
1264 <  if assigned(FDataLink) and assigned(FDataLink.DataSet) and
1265 <     FDataLink.DataSet.Active and (FDataLink.DataSet.State = dsInsert) then
1266 <    DataSetScrolled(nil);
1264 >  if assigned(DataLink) and assigned(DataLink.DataSet) and
1265 >     DataLink.DataSet.Active and (DataLink.DataSet.State = dsInsert) then
1266 >   SavePosition;
1267   end;
1268  
1269   constructor TIBDynamicGrid.Create(TheComponent: TComponent);
1270   begin
1271    inherited Create(TheComponent);
1272    FAllowColumnSort := true;
1273 <  FDataLink := TDynamicGridDataLink.Create(self);
1273 >  FIBControlLink := TIBGridControlLink.Create(self);
1274    FIndexFieldsList := TStringList.Create;
1275    FIndexFieldsList.Delimiter := ';';
1276    FIndexFieldsList.StrictDelimiter := true;
# Line 1103 | Line 1282 | end;
1282  
1283   destructor TIBDynamicGrid.Destroy;
1284   begin
1285 <  if assigned(FDataLink) then FDataLink.Free;
1285 >  if assigned(FIBControlLink) then FIBControlLink.Free;
1286    if assigned(FIndexFieldsList) then FIndexFieldsList.Free;
1287    if assigned(FDBLookupCellEditor) then FDBLookupCellEditor.Free;
1288    inherited Destroy;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines