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 31 by tony, Tue Jul 14 15:31:25 2015 UTC vs.
Revision 41 by tony, Sat Jul 16 12:25:48 2016 UTC

# Line 23 | Line 23
23   *  Contributor(s): ______________________________________.
24   *
25   *)
26 +
27   unit IBDynamicGrid;
28  
29   {$mode objfpc}{$H+}
# Line 149 | 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;
# Line 165 | 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 175 | 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 220 | 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}
# Line 256 | Line 265 | end;
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;
# Line 301 | Line 311 | end;
311  
312   implementation
313  
314 < uses Math, IBQuery, LCLType;
314 > uses Math, IBQuery, LCLType, Variants;
315  
316   { TIBGridControlLink }
317  
# Line 361 | Line 371 | begin
371    FResizing := true;
372    try
373      ColSum := 0;
364    for I := 0 to  ColCount - 1 do
365       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 402 | Line 419 | begin
419    inherited DoEditorHide;
420    if Editor = FEditorPanel then
421    begin
422 <    if (FExpandedRow >= 0) and (FExpandedRow < RowCount) then
423 <      RowHeights[FExpandedRow] := DefaultRowHeight;
422 >    if FMouseDown then
423 >      Application.QueueAsyncCall(@PerformEditorHide,FExpandedRow)
424 >    else
425 >      PerformEditorHide(FExpandedRow);
426      FExpandedRow := -1;
408    if CanFocus then SetFocus;
409    DoOnResize;
410    ResetSizes;
411    DoOnChangeBounds;
412    if assigned(FOnEditorPanelHide) then
413       OnEditorPanelHide(self);
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 428 | 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 547 | Line 568 | begin
568        Exit; {ignore these keys if we are in a  combobox}
569  
570      if (AControl <> nil) and (AControl is TCustomMemo)
571 <                         and (Key = VK_RETURN) then Exit; {Ignore Return in a CustomMemo}
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 570 | 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 604 | 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 628 | 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 637 | 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 653 | 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 686 | 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) or
759     (DataSource = nil) or (DataSource.DataSet = nil)
760       or ((DataSource.DataSet.RecordCount = 0) and (DataSource.DataSet.State <> dsInsert)) then
761       Exit;
762 <  Editor := FEditorPanel;
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 734 | 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 754 | Line 835 | begin
835    UpdateData(nil); {Force Record Update}
836    if FGrid<>nil then
837    Begin
838 <    (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, Trim(Text));
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;
# Line 779 | Line 866 | 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 867 | 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  
# Line 909 | 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 958 | 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 975 | Line 1084 | end;
1084  
1085   procedure TIBDynamicGrid.UpdateSQL(Sender: TObject; Parser: TSelectSQLParser);
1086   var OrderBy: string;
978    FieldPosition: integer;
1087   begin
1088      if assigned(DataSource) and assigned(DataSource.DataSet)
1089        and (DataSource.DataSet is TIBCustomDataSet) then
1090      begin
1091 <      if (FLastColIndex < 0) or (FLastColIndex >= Columns.Count) then Exit;
1092 <      FieldPosition := Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1093 <      if FieldPosition = 0 then Exit;
1094 <
1095 <      if Descending then
1096 <        Parser.OrderByClause := IntToStr(FieldPosition) + ' desc'
1097 <      else
1098 <        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 1130 | Line 1241 | 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 <     (FIBControlLink <> nil) and (AComponent = DataSource) then FIBControlLink.IBDataSet := 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;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines