Ignore:
Timestamp:
Jun 4, 2024, 12:22:49 AM (5 months ago)
Author:
chronos
Message:
  • Modified: Removed U prefix from unit names.
  • Modified: Updated Common package.
File:
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/Packages/Common/ListViewSort.pas

    r74 r75  
    1 unit UListViewSort;
    2 
    3 // Date: 2010-11-03
    4 
    5 {$mode delphi}
     1unit ListViewSort;
     2
     3// Date: 2019-05-17
    64
    75interface
    86
    97uses
    10   {$IFDEF Windows}Windows, CommCtrl, {$ENDIF}Classes, Graphics, ComCtrls, SysUtils,
    11   Controls, DateUtils, Dialogs, SpecializedList, Forms, Grids, StdCtrls, ExtCtrls;
     8  {$IFDEF Windows}Windows, CommCtrl, LMessages, {$ENDIF}Classes, Graphics, ComCtrls, SysUtils,
     9  Controls, DateUtils, Dialogs, Forms, Grids, StdCtrls, ExtCtrls,
     10  LclIntf, LclType, LResources, Generics.Collections, Generics.Defaults;
    1211
    1312type
     
    1817  TCompareEvent = function (Item1, Item2: TObject): Integer of object;
    1918  TListFilterEvent = procedure (ListViewSort: TListViewSort) of object;
     19
     20  TObjects = TObjectList<TObject>;
     21
     22  { TListViewSort }
    2023
    2124  TListViewSort = class(TComponent)
     
    2831    FColumn: Integer;
    2932    FOrder: TSortOrder;
     33    FOldListViewWindowProc: TWndMethod;
     34    FOnColumnWidthChanged: TNotifyEvent;
     35    procedure DoColumnBeginResize(const AColIndex: Integer);
     36    procedure DoColumnResized(const AColIndex: Integer);
     37    procedure DoColumnResizing(const AColIndex, AWidth: Integer);
    3038    procedure SetListView(const Value: TListView);
    3139    procedure ColumnClick(Sender: TObject; Column: TListColumn);
     
    4048    procedure SetColumn(const Value: Integer);
    4149    procedure SetOrder(const Value: TSortOrder);
     50    {$IFDEF WINDOWS}
     51    procedure NewListViewWindowProc(var AMsg: TMessage);
     52    {$ENDIF}
    4253  public
    43     List: TListObject;
    44     Source: TListObject;
     54    Source: TObjects;
     55    List: TObjects;
    4556    constructor Create(AOwner: TComponent); override;
    4657    destructor Destroy; override;
     
    5869    property OnCustomDraw: TLVCustomDrawItemEvent read FOnCustomDraw
    5970      write FOnCustomDraw;
     71    property OnColumnWidthChanged: TNotifyEvent read FOnColumnWidthChanged
     72      write FOnColumnWidthChanged;
    6073    property Column: Integer read FColumn write SetColumn;
    6174    property Order: TSortOrder read FOrder write SetOrder;
     
    6881    FOnChange: TNotifyEvent;
    6982    FStringGrid1: TStringGrid;
    70     procedure DoOnKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
     83    procedure DoOnChange;
     84    procedure GridDoOnKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
     85    procedure GridDoOnResize(Sender: TObject);
    7186  public
    7287    constructor Create(AOwner: TComponent); override;
    7388    procedure UpdateFromListView(ListView: TListView);
    7489    function TextEntered: Boolean;
     90    function TextEnteredCount: Integer;
     91    function TextEnteredColumn(Index: Integer): Boolean;
    7592    function GetColValue(Index: Integer): string;
     93    procedure Reset;
    7694    property StringGrid: TStringGrid read FStringGrid1 write FStringGrid1;
    7795  published
     
    7997    property Align;
    8098    property Anchors;
     99    property BorderSpacing;
     100  end;
     101
     102  { TListViewEx }
     103
     104  TListViewEx = class(TWinControl)
     105  private
     106    FFilter: TListViewFilter;
     107    FListView: TListView;
     108    FListViewSort: TListViewSort;
     109    procedure ResizeHanlder;
     110  public
     111    constructor Create(TheOwner: TComponent); override;
     112    destructor Destroy; override;
     113  published
     114    property ListView: TListView read FListView write FListView;
     115    property ListViewSort: TListViewSort read FListViewSort write FListViewSort;
     116    property Filter: TListViewFilter read FFilter write FFilter;
     117    property Visible;
    81118  end;
    82119
     
    88125procedure Register;
    89126begin
    90   RegisterComponents('Common', [TListViewSort, TListViewFilter]);
     127  RegisterComponents('Common', [TListViewSort, TListViewFilter, TListViewEx]);
     128end;
     129
     130{ TListViewEx }
     131
     132procedure TListViewEx.ResizeHanlder;
     133begin
     134end;
     135
     136constructor TListViewEx.Create(TheOwner: TComponent);
     137begin
     138  inherited Create(TheOwner);
     139  Filter := TListViewFilter.Create(Self);
     140  Filter.Parent := Self;
     141  Filter.Align := alBottom;
     142  ListView := TListView.Create(Self);
     143  ListView.Parent := Self;
     144  ListView.Align := alClient;
     145  ListViewSort := TListViewSort.Create(Self);
     146  ListViewSort.ListView := ListView;
     147end;
     148
     149destructor TListViewEx.Destroy;
     150begin
     151  inherited;
    91152end;
    92153
    93154{ TListViewFilter }
    94155
    95 procedure TListViewFilter.DoOnKeyUp(Sender: TObject; var Key: Word;
     156procedure TListViewFilter.DoOnChange;
     157begin
     158  if Assigned(FOnChange) then FOnChange(Self);
     159end;
     160
     161procedure TListViewFilter.GridDoOnKeyUp(Sender: TObject; var Key: Word;
    96162  Shift: TShiftState);
    97163begin
    98   if Assigned(FOnChange) then
    99     FOnChange(Self);
     164  DoOnChange;
     165end;
     166
     167procedure TListViewFilter.GridDoOnResize(Sender: TObject);
     168begin
     169  FStringGrid1.DefaultRowHeight := FStringGrid1.Height;
    100170end;
    101171
     
    113183  FStringGrid1.Options := [goFixedHorzLine, goFixedVertLine, goVertLine,
    114184    goHorzLine, goRangeSelect, goEditing, goAlwaysShowEditor, goSmoothScroll];
    115   FStringGrid1.OnKeyUp := DoOnKeyUp;
     185  FStringGrid1.OnKeyUp := GridDoOnKeyUp;
     186  FStringGrid1.OnResize := GridDoOnResize;
    116187end;
    117188
     
    119190var
    120191  I: Integer;
    121   NewColumn: TGridColumn;
     192  R: TRect;
    122193begin
    123194  with FStringGrid1 do begin
    124     Columns.Clear;
    125195    while Columns.Count > ListView.Columns.Count do Columns.Delete(Columns.Count - 1);
    126     while Columns.Count < ListView.Columns.Count do NewColumn := Columns.Add;
     196    while Columns.Count < ListView.Columns.Count do Columns.Add;
    127197    for I := 0 to ListView.Columns.Count - 1 do begin
    128198      Columns[I].Width := ListView.Columns[I].Width;
     199      if Selection.Left = I then begin
     200        R := CellRect(I, 0);
     201        Editor.Left := R.Left + 2;
     202        Editor.Width := R.Width - 4;
     203      end;
    129204    end;
    130205  end;
     
    132207
    133208function TListViewFilter.TextEntered: Boolean;
     209begin
     210  Result := TextEnteredCount > 0;
     211end;
     212
     213function TListViewFilter.TextEnteredCount: Integer;
    134214var
    135215  I: Integer;
    136216begin
    137   Result := False;
     217  Result := 0;
    138218  for I := 0 to FStringGrid1.ColCount - 1 do begin
    139219    if FStringGrid1.Cells[I, 0] <> '' then begin
    140       Result := True;
    141       Break;
     220      Inc(Result);
    142221    end;
    143222  end;
     223end;
     224
     225function TListViewFilter.TextEnteredColumn(Index: Integer): Boolean;
     226begin
     227  Result := FStringGrid1.Cells[Index, 0] <> '';
    144228end;
    145229
     
    151235end;
    152236
     237procedure TListViewFilter.Reset;
     238var
     239  I: Integer;
     240begin
     241  with StringGrid do
     242  for I := 0 to ColCount - 1 do
     243    Cells[I, 0] := '';
     244  DoOnChange;
     245end;
     246
    153247{ TListViewSort }
    154248
     249{$IFDEF WINDOWS}
     250procedure TListViewSort.NewListViewWindowProc(var AMsg: TMessage);
     251var
     252  vColWidth: Integer;
     253  vMsgNotify: TLMNotify absolute AMsg;
     254  Code: Integer;
     255begin
     256  // call the old WindowProc of ListView
     257  FOldListViewWindowProc(AMsg);
     258
     259  // Currently we care only with WM_NOTIFY message
     260  if AMsg.Msg = WM_NOTIFY then
     261  begin
     262    Code := NMHDR(PHDNotify(vMsgNotify.NMHdr)^.Hdr).Code;
     263    case Code of
     264      HDN_ENDTRACKA, HDN_ENDTRACKW:
     265        DoColumnResized(PHDNotify(vMsgNotify.NMHdr)^.Item);
     266
     267      HDN_BEGINTRACKA, HDN_BEGINTRACKW:
     268        DoColumnBeginResize(PHDNotify(vMsgNotify.NMHdr)^.Item);
     269
     270      HDN_TRACKA, HDN_TRACKW:
     271        begin
     272          vColWidth := -1;
     273          if (PHDNotify(vMsgNotify.NMHdr)^.PItem<>nil)
     274             and (PHDNotify(vMsgNotify.NMHdr)^.PItem^.Mask and HDI_WIDTH <> 0)
     275          then
     276            vColWidth := PHDNotify(vMsgNotify.NMHdr)^.PItem^.cxy;
     277
     278          DoColumnResizing(PHDNotify(vMsgNotify.NMHdr)^.Item, vColWidth);
     279        end;
     280    end;
     281  end;
     282end;
     283{$ENDIF}
     284
     285procedure TListViewSort.DoColumnBeginResize(const AColIndex: Integer);
     286begin
     287end;
     288
     289procedure TListViewSort.DoColumnResizing(const AColIndex, AWidth: Integer);
     290begin
     291end;
     292
     293procedure TListViewSort.DoColumnResized(const AColIndex: Integer);
     294begin
     295  if Assigned(FOnColumnWidthChanged) then
     296    FOnColumnWidthChanged(Self);
     297end;
    155298
    156299procedure TListViewSort.ColumnClick(Sender: TObject; Column: TListColumn);
     
    179322procedure TListViewSort.SetListView(const Value: TListView);
    180323begin
     324  if FListView = Value then Exit;
     325  if Assigned(FListView) then
     326    ListView.WindowProc := FOldListViewWindowProc;
    181327  FListView := Value;
    182328  FListView.OnColumnClick := ColumnClick;
    183329  FListView.OnCustomDrawItem := ListViewCustomDrawItem;
    184330  FListView.OnClick := ListViewClick;
     331  FOldListViewWindowProc := FListView.WindowProc;
     332  {$IFDEF WINDOWS}
     333  FListView.WindowProc := NewListViewWindowProc;
     334  {$ENDIF}
     335end;
     336
     337var
     338  ListViewSortCompare: TCompareEvent;
     339
     340function ListViewCompare(constref Item1, Item2: TObject): Integer;
     341begin
     342  Result := ListViewSortCompare(Item1, Item2);
    185343end;
    186344
    187345procedure TListViewSort.Sort(Compare: TCompareEvent);
    188346begin
     347  // TODO: Because TFLGObjectList compare handler is not class method,
     348  // it is necessary to use simple function compare handler with local variable
     349  ListViewSortCompare := Compare;
    189350  if (List.Count > 0) then
    190     List.Sort(Compare);
     351    List.Sort(TComparer<TObject>.Construct(ListViewCompare));
    191352end;
    192353
     
    194355begin
    195356  if Assigned(FOnFilter) then FOnFilter(Self)
    196   else if Assigned(Source) then
    197     List.Assign(Source) else
     357  else if Assigned(Source) then begin
    198358    List.Clear;
     359    List.AddRange(Source);
     360  end else List.Clear;
    199361  if ListView.Items.Count <> List.Count then
    200362    ListView.Items.Count := List.Count;
    201   if Assigned(FOnCompareItem) then Sort(FOnCompareItem);
     363  if Assigned(FOnCompareItem) and (Order <> soNone) then Sort(FOnCompareItem);
    202364  //ListView.Items[-1]; // Workaround for not show first row if selected
    203365  ListView.Refresh;
     
    251413begin
    252414  inherited;
    253   List := TListObject.Create;
     415  List := TObjects.Create;
    254416  List.OwnsObjects := False;
    255417end;
     
    257419destructor TListViewSort.Destroy;
    258420begin
    259   List.Free;
     421  FreeAndNil(List);
    260422  inherited;
    261423end;
     
    266428  TP1: TPoint;
    267429  XBias, YBias: Integer;
    268   OldColor: TColor;
     430  PenColor: TColor;
     431  BrushColor: TColor;
    269432  BiasTop, BiasLeft: Integer;
    270433  Rect1: TRect;
     
    278441  Item.Left := 0;
    279442  GetCheckBias(XBias, YBias, BiasTop, BiasLeft, ListView);
    280   OldColor := ListView.Canvas.Pen.Color;
     443  PenColor := ListView.Canvas.Pen.Color;
     444  BrushColor := ListView.Canvas.Brush.Color;
    281445  //TP1 := Item.GetPosition;
    282446  lRect := Item.DisplayRect(drBounds); // Windows 7 workaround
     
    290454  ItemLeft := Item.Left;
    291455  ItemLeft := 23; // Windows 7 workaround
    292  
     456
    293457  Rect1.Left := ItemLeft - CheckWidth - BiasLeft + 1 + XBias;
    294458  //ShowMessage(IntToStr(Tp1.Y) + ', ' + IntToStr(BiasTop) + ', ' + IntToStr(XBias));
     
    321485  end;
    322486  //ListView.Canvas.Brush.Color := ListView.Color;
    323   ListView.Canvas.Brush.Color := clWindow;
    324   ListView.Canvas.Pen.Color := OldColor;
     487  ListView.Canvas.Brush.Color := BrushColor;
     488  ListView.Canvas.Pen.Color := PenColor;
    325489end;
    326490
     
    389553    FHeaderHandle := ListView_GetHeader(FListView.Handle);
    390554    for I := 0 to FListView.Columns.Count - 1 do begin
     555      {$push}{$warn 5057 off}
    391556      FillChar(Item, SizeOf(THDItem), 0);
     557      {$pop}
    392558      Item.Mask := HDI_FORMAT;
    393559      Header_GetItem(FHeaderHandle, I, Item);
Note: See TracChangeset for help on using the changeset viewer.