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 27 by tony, Tue Apr 14 13:10:23 2015 UTC vs.
Revision 39 by tony, Tue May 17 08:14:52 2016 UTC

# Line 23 | Line 23
23   *  Contributor(s): ______________________________________.
24   *
25   *)
26 +
27   unit IBDynamicGrid;
28  
29   {$mode objfpc}{$H+}
# Line 91 | 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 117 | 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 147 | 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 177 | Line 181 | end;
181      FWeHaveFocus: boolean;
182      FHidingEditorPanel: boolean;
183      FAllowHide: boolean;
184 +    FMouseDown: boolean;
185 +    function ActiveControl: TControl;
186      procedure DoShowEditorPanel(Data: PtrInt);
187      procedure PositionTotals;
188      procedure KeyDownHandler(Sender: TObject; var Key: Word; Shift: TShiftState);
189 +    procedure PerformEditorHide(Data: PtrInt);
190      procedure SetEditorPanel(AValue: TWinControl);
191    protected
192      procedure ChangeBounds(ALeft, ATop, AWidth, AHeight: integer; KeepBase: boolean); override;
# Line 253 | Line 260 | end;
260      FBookmark: TLocationArray;
261      FDBLookupCellEditor: TDBLookupCellEditor;
262      FActive: boolean;
263 +    FFieldPosition: integer;
264      procedure ColumnHeaderClick(Index: integer);
265      function GetDataSource: TDataSource;
266      function GetEditorBorderStyle: TBorderStyle;
# Line 298 | Line 306 | end;
306  
307   implementation
308  
309 < uses Math, IBQuery, LCLType;
309 > uses Math, IBQuery, LCLType, Variants;
310  
311   { TIBGridControlLink }
312  
# Line 358 | Line 366 | begin
366    FResizing := true;
367    try
368      ColSum := 0;
361    for I := 0 to  ColCount - 1 do
362       ColSum := ColSum + ColWidths[I];
369  
370 <    if Colsum <> ClientWidth then
370 >    if (ColCount = 1) and TDBDynamicGridColumn(Columns[0]).AutoSizeColumn then
371 >      Columns[0].Width := ClientWidth
372 >    else
373      begin
374 <      ResizeColCount := 0;
375 <      for I := 0 to Columns.Count -1 do
376 <        if TDBDynamicGridColumn(Columns[I]).AutoSizeColumn then
377 <        begin
378 <          Inc(ResizeColCount);
379 <          Colsum := Colsum + TDBDynamicGridColumn(Columns[I]).DesignWidth - Columns[I].Width;
380 <          Columns[I].Width := TDBDynamicGridColumn(Columns[I]).DesignWidth;
381 <        end;
382 <
383 <        if (Colsum < ClientWidth) and (ResizeColCount > 0) then
384 <        begin
385 <          adjustment := (ClientWidth - ColSum) div ResizeColCount;
386 <          n := (ClientWidth - ColSum) mod ResizeColCount;
387 <
388 <          for I := 0 to Columns.Count -1 do
389 <            if TDBDynamicGridColumn(Columns[I]).AutoSizeColumn then
390 <            begin
391 <              if I = 0 then
392 <                Columns[I].Width := Columns[I].Width + adjustment + n
393 <              else
394 <                Columns[I].Width := Columns[I].Width + adjustment;
395 <            end;
396 <        end;
374 >      for I := 0 to  ColCount - 1 do
375 >        if (I < FixedCols) or Columns[I - FixedCols].Visible then
376 >         ColSum := ColSum + ColWidths[I];
377 >
378 >      if Colsum <> ClientWidth then
379 >      begin
380 >        ResizeColCount := 0;
381 >        for I := 0 to Columns.Count -1 do
382 >          if TDBDynamicGridColumn(Columns[I]).AutoSizeColumn and Columns[I].Visible then
383 >          begin
384 >            Inc(ResizeColCount);
385 >            Colsum := Colsum + TDBDynamicGridColumn(Columns[I]).DesignWidth - Columns[I].Width;
386 >            Columns[I].Width := TDBDynamicGridColumn(Columns[I]).DesignWidth;
387 >          end;
388 >
389 >          if (Colsum < ClientWidth) and (ResizeColCount > 0) then
390 >          begin
391 >            adjustment := (ClientWidth - ColSum) div ResizeColCount;
392 >            n := (ClientWidth - ColSum) mod ResizeColCount;
393 >
394 >            for I := 0 to Columns.Count -1 do
395 >              if TDBDynamicGridColumn(Columns[I]).AutoSizeColumn and Columns[I].Visible then
396 >              begin
397 >                if I = 0 then
398 >                  Columns[I].Width := Columns[I].Width + adjustment + n
399 >                else
400 >                  Columns[I].Width := Columns[I].Width + adjustment;
401 >              end;
402 >          end;
403 >      end;
404      end;
405      PositionTotals;
406      UpdateEditorPanelBounds;
# Line 399 | Line 414 | begin
414    inherited DoEditorHide;
415    if Editor = FEditorPanel then
416    begin
417 <    if (FExpandedRow >= 0) and (FExpandedRow < RowCount) then
418 <      RowHeights[FExpandedRow] := DefaultRowHeight;
417 >    if FMouseDown then
418 >      Application.QueueAsyncCall(@PerformEditorHide,FExpandedRow)
419 >    else
420 >      PerformEditorHide(FExpandedRow);
421      FExpandedRow := -1;
405    if CanFocus then SetFocus;
406    if assigned(FOnEditorPanelHide) then
407       OnEditorPanelHide(self);
408    DoOnResize;
409    ResetSizes;
410    Invalidate;
422    end;
423   end;
424  
425   procedure TDBDynamicGrid.DoEditorShow;
426   begin
427 +  if assigned(DataSource) and assigned(DataSource.DataSet) and
428 +             DataSource.DataSet.Active then
429 +  begin
430 +    if (DataSource.DataSet.RecordCount = 0) and (DataSource.DataSet.State <> dsInsert) then
431 +      DataSource.DataSet.Append
432 +  end;
433    if Editor = FEditorPanel then
434    begin
435      if ExpandEditorPanelBelowRow then
# Line 425 | Line 442 | begin
442      FEditorPanel.PerformTab(true);  {Select First Control}
443      if assigned(FOnEditorPanelShow) then
444         OnEditorPanelShow(self);
445 +    if assigned(Editor) and Editor.Visible then
446 +      Editor.SetFocus;
447    end
448    else
449      inherited DoEditorShow;
# Line 489 | Line 508 | begin
508      inherited KeyDown(Key, Shift);
509   end;
510  
511 + function TDBDynamicGrid.ActiveControl: TControl;
512 + var AParent: TWinControl;
513 + begin
514 +  Result := nil;
515 +  AParent := Parent;
516 +  while (AParent <> nil) and  not (AParent is TCustomForm) do
517 +    AParent := AParent.Parent;
518 +  if (AParent <> nil) and (AParent is TCustomForm)then
519 +      Result := TCustomForm(AParent).ActiveControl;
520 + end;
521 +
522   procedure TDBDynamicGrid.DoShowEditorPanel(Data: PtrInt);
523   begin
524    if AppDestroying in Application.Flags then Exit;
# Line 520 | Line 550 | end;
550   procedure TDBDynamicGrid.KeyDownHandler(Sender: TObject; var Key: Word;
551    Shift: TShiftState);
552   var Done: boolean;
553 +    AControl: TControl;
554   begin
555    if Visible and assigned(FEditorPanel) and FEditorPanel.Visible and FWeHaveFocus then
556    begin
557      Done := false;
558 +    AControl := ActiveControl;
559 +    if (AControl <> nil) and (AControl is TCustomComboBox)
560 +                         and ((Key in [VK_UP,VK_DOWN]) or
561 +                         (TCustomComboBox(AControl).DroppedDown and (Key = VK_RETURN)) or
562 +                         ((TCustomComboBox(AControl).Text <> '') and (Key =  VK_ESCAPE))) then
563 +      Exit; {ignore these keys if we are in a  combobox}
564 +
565 +    if (AControl <> nil) and (AControl is TCustomMemo)
566 +                         and (Key in [VK_RETURN,VK_UP,VK_DOWN]) then Exit; {Ignore Return in a CustomMemo}
567 +
568 +    if (AControl <> nil) and (AControl is TCustomGrid)
569 +                         and (Key in [VK_RETURN,VK_UP,VK_DOWN,VK_TAB]) then Exit; {Ignore Return in a CustomMemo}
570 +
571      if assigned(FOnKeyDownHander) then
572        OnKeyDownHander(Sender,Key,Shift,Done);
573      if Done then Exit;
# Line 546 | Line 590 | begin
590    end
591   end;
592  
593 + procedure TDBDynamicGrid.PerformEditorHide(Data: PtrInt);
594 + var ExpandedRow: integer;
595 + begin
596 +  if AppDestroying in Application.Flags then Exit;
597 +  ExpandedRow := integer(Data);
598 +  if (ExpandedRow >= 0) and (ExpandedRow < RowCount) then
599 +    RowHeights[ExpandedRow] := DefaultRowHeight;
600 +  if CanFocus then SetFocus;
601 +  DoOnResize;
602 +  ResetSizes;
603 +  DoOnChangeBounds;
604 +  if assigned(FOnEditorPanelHide) then
605 +     OnEditorPanelHide(self);
606 + end;
607 +
608   procedure TDBDynamicGrid.SetEditorPanel(AValue: TWinControl);
609   begin
610    if FEditorPanel = AValue then Exit;
611    if FEditorPanel <> nil then
612       RemoveFreeNotification(FEditorPanel);
613    FEditorPanel := AValue;
614 <  FreeNotification(FEditorPanel);
614 >  if FEditorPanel <> nil then
615 >     FreeNotification(FEditorPanel);
616   end;
617  
618   procedure TDBDynamicGrid.ChangeBounds(ALeft, ATop, AWidth, AHeight: integer;
# Line 580 | Line 640 | begin
640    inherited Loaded;
641    if assigned(FEditorPanel) and not (csDesigning in ComponentState)then
642      FEditorPanel.Visible := false;
643 <  DoGridResize
643 >  if Visible then
644 >    DoGridResize
645   end;
646  
647   procedure TDBDynamicGrid.DoOnResize;
# Line 604 | Line 665 | procedure TDBDynamicGrid.MouseDown(Butto
665    Y: Integer);
666   var Coord: TGridCoord;
667   begin
668 <  inherited MouseDown(Button, Shift, X, Y);
668 >  FMouseDown := true;
669 >  try
670 >    inherited MouseDown(Button, Shift, X, Y);
671 >  finally
672 >    FMouseDown := false;
673 >  end;
674  
675    Coord := MouseCoord(X,Y);
676    if (Coord.X = 0) and (Coord.Y > 0) then
# Line 613 | Line 679 | end;
679  
680   procedure TDBDynamicGrid.Notification(AComponent: TComponent;
681    Operation: TOperation);
682 + var i: integer;
683   begin
684    inherited Notification(AComponent, Operation);
685 <  if (Operation = opRemove) and
686 <     (AComponent = FEditorPanel) then FEditorPanel := nil;
685 >  if (Operation = opRemove) and not (csDestroying in ComponentState) then
686 >  begin
687 >    if AComponent = FEditorPanel then
688 >      FEditorPanel := nil
689 >    else
690 >    if AComponent is TControl then
691 >    begin
692 >      for i := 0 to Columns.Count - 1 do
693 >        if TDBDynamicGridColumn(Columns[I]).ColumnTotalsControl = AComponent then
694 >          TDBDynamicGridColumn(Columns[I]).ColumnTotalsControl := nil;
695 >    end;
696 >  end
697   end;
698  
699   procedure TDBDynamicGrid.TopLeftChanged;
# Line 630 | Line 707 | begin
707    inherited UpdateActive;
708  
709    if not (csLoading in ComponentState) and assigned(DataLink) and
710 +     assigned(FEditorPanel) and not FEditorPanel.Visible and
711       assigned(DataLink.DataSet) and (DataLink.DataSet.State = dsInsert) then
712       Application.QueueAsyncCall(@DoShowEditorPanel,0);
713   end;
# Line 662 | Line 740 | end;
740   procedure TDBDynamicGrid.HideEditorPanel;
741   begin
742    if Editor = FEditorPanel then
743 <    EditorMode := false;
743 >      EditorMode := false;
744   end;
745  
746   procedure TDBDynamicGrid.ShowEditorPanel;
# Line 710 | Line 788 | begin
788    Result := inherited Width
789   end;
790  
791 + type
792 +  THackedGrid = class(TIBDynamicGrid)
793 +  public
794 +    property FixedCols;
795 +  end;
796 +
797   { TDBLookupCellEditor }
798  
799 + function TDBLookupCellEditor.EditingKeyField: boolean;
800 + begin
801 +  with TIBDynamicGridColumn(TDBGrid(FGrid).Columns[FCol - THackedGrid(FGrid).FixedCols]) do
802 +    Result := CompareText(FieldName, DBLookupProperties.DataFieldName) = 0;
803 + end;
804 +
805   procedure TDBLookupCellEditor.WndProc(var TheMessage: TLMessage);
806   begin
807    if TheMessage.msg=LM_KILLFOCUS then begin
# Line 730 | Line 820 | begin
820    UpdateData(nil); {Force Record Update}
821    if FGrid<>nil then
822    Begin
823 <    (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, Trim(Text));
823 >    if EditingKeyField then
824 >    begin
825 >      if not VarIsNull(KeyValue) then
826 >       (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, KeyValue)
827 >    end
828 >    else
829 >      (FGrid as TIBDynamicGrid).EditorTextChanged(FCol, FRow, Trim(Text));
830      (FGrid as TIBDynamicGrid).UpdateData;
831    end;
832    inherited CloseUp;
# Line 755 | Line 851 | begin
851    CheckAndInsert;
852    Msg.Col := FCol;
853    Msg.Row := FRow;
854 <  Msg.Value:= Trim(Text);
854 >  if EditingKeyField then
855 >  begin
856 >    if not VarIsNull(KeyValue) then
857 >      Msg.Value:= KeyValue
858 >    else
859 >      Msg.Value:= ''
860 >  end
861 >  else
862 >    Msg.Value:= Trim(Text);
863   end;
864  
865   procedure TDBLookupCellEditor.msg_SetGrid(var Msg: TGridMessage);
# Line 770 | Line 874 | begin
874    FCol := Msg.Col;
875    FRow := Msg.Row;
876    FEditText := Msg.Value;
773  SelStart := Length(Text);
877    TIBDynamicGrid(FGrid).SetupEditor(self,FCol);
878   end;
879  
# Line 819 | Line 922 | begin
922      Editor.OnAutoInsert := OnAutoInsert;
923      Editor.OnCanAutoInsert := OnCanAutoInsert;
924      Editor.OnDrawItem := OnDrawItem;
925 +    Editor.OnCloseUp := OnCloseUp;
926  
927      {Setup Data Links}
928      if KeyField <> '' then
# Line 843 | Line 947 | begin
947      if DataFieldName <> '' then
948          Editor.DataSource := TDBGrid(Grid).DataSource;
949    end;
950 <  Editor.Text := Editor.FEditText;
950 >  if Editor.EditingKeyField then
951 >  begin
952 >    if not Field.IsNull then
953 >      Editor.KeyValue := Editor.FEditText
954 >  end
955 >  else
956 >    Editor.Text := Editor.FEditText;
957 >  Editor.SelStart := Length(Editor.Text);
958   end;
959  
960   procedure TIBDynamicGridColumn.SetInitialSortColumn(AValue: boolean);
# Line 884 | Line 995 | begin
995        OnColumnHeaderClick(self,Index);
996  
997      FLastColIndex := Index;
998 <    if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active then
998 >    FFieldPosition := 0;
999 >    if assigned(DataSource) and assigned(DataSource.DataSet) and DataSource.DataSet.Active
1000 >       and (DataSource.DataSet is TIBParserDataSet) then
1001      begin
1002 +      if FLastColIndex < Columns.Count then
1003 +      {try and cache field position while dataset still open}
1004 +        FFieldPosition := TIBParserDataSet(DataSource.DataSet).Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1005        DataSource.DataSet.Active := false;
1006        Application.QueueAsyncCall(@DoReopen,0)
1007      end;
# Line 933 | Line 1049 | begin
1049    for i := 0 to Columns.Count - 1 do
1050    begin
1051      if TIBDynamicGridColumn(columns[i]).InitialSortColumn then
1052 +    begin
1053 +      FFieldPosition := 0;
1054        FLastColIndex := i
1055 +    end
1056    end
1057   end;
1058  
# Line 950 | Line 1069 | end;
1069  
1070   procedure TIBDynamicGrid.UpdateSQL(Sender: TObject; Parser: TSelectSQLParser);
1071   var OrderBy: string;
953    FieldPosition: integer;
1072   begin
1073      if assigned(DataSource) and assigned(DataSource.DataSet)
1074        and (DataSource.DataSet is TIBCustomDataSet) then
1075      begin
1076 <      if (FLastColIndex < 0) or (FLastColIndex >= Columns.Count) then Exit;
1077 <      FieldPosition := Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1078 <      if FieldPosition = 0 then Exit;
1079 <
1080 <      if Descending then
1081 <        Parser.OrderByClause := IntToStr(FieldPosition) + ' desc'
1082 <      else
1083 <        Parser.OrderByClause := IntToStr(FieldPosition) + ' asc';
1076 >      if (FFieldPosition = 0) and (FLastColIndex >= 0) and (FLastColIndex < Columns.Count) then
1077 >        {Not cached - let's hope we can find it before the dataset is opened.
1078 >         Won't work if dynamic columns}
1079 >        FFieldPosition := Parser.GetFieldPosition(Columns[FLastColIndex].FieldName);
1080 >      if FFieldPosition > 0 then
1081 >      begin
1082 >        if Descending then
1083 >          Parser.OrderByClause := IntToStr(FFieldPosition) + ' desc'
1084 >        else
1085 >          Parser.OrderByClause := IntToStr(FFieldPosition) + ' asc';
1086 >      end;
1087  
1088        if assigned(FOnUpdateSortOrder) then
1089        begin
# Line 1049 | Line 1170 | end;
1170   procedure TIBDynamicGrid.Loaded;
1171   begin
1172    inherited Loaded;
1173 +  IBControlLinkChanged;
1174    ProcessColumns;
1175   end;
1176  
# Line 1104 | Line 1226 | end;
1226  
1227   procedure TIBDynamicGrid.Notification(AComponent: TComponent;
1228    Operation: TOperation);
1229 + var i: integer;
1230   begin
1231    inherited Notification(AComponent, Operation);
1232 <  if (Operation = opRemove) and
1233 <     (FIBControlLink <> nil) and (AComponent = DataSource) then FIBControlLink.IBDataSet := nil;
1232 >  if (Operation = opRemove) then
1233 >  begin
1234 >    if (FIBControlLink <> nil) and (AComponent = DataSource) then
1235 >      FIBControlLink.IBDataSet := nil
1236 >    else
1237 >    if AComponent is TDataSource then
1238 >    begin
1239 >      for i := 0 to Columns.Count - 1 do
1240 >        if TIBDynamicGridColumn(Columns[I]).DBLookupProperties.ListSource = AComponent then
1241 >          TIBDynamicGridColumn(Columns[I]).DBLookupProperties.ListSource := nil;
1242 >    end
1243 >  end
1244   end;
1245  
1246   procedure TIBDynamicGrid.UpdateActive;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines