source: tags/1.2.0/Packages/Common/UListViewSort.pas

Last change on this file was 74, checked in by chronos, 8 years ago
  • Fixed: Wrong column indexes in list of import sources.
  • Fixed: Do not sort items in TListSort component if soNone order is set.
File size: 12.7 KB
Line 
1unit UListViewSort;
2
3// Date: 2010-11-03
4
5{$mode delphi}
6
7interface
8
9uses
10 {$IFDEF Windows}Windows, CommCtrl, {$ENDIF}Classes, Graphics, ComCtrls, SysUtils,
11 Controls, DateUtils, Dialogs, SpecializedList, Forms, Grids, StdCtrls, ExtCtrls;
12
13type
14 TSortOrder = (soNone, soUp, soDown);
15
16 TListViewSort = class;
17
18 TCompareEvent = function (Item1, Item2: TObject): Integer of object;
19 TListFilterEvent = procedure (ListViewSort: TListViewSort) of object;
20
21 TListViewSort = class(TComponent)
22 private
23 FListView: TListView;
24 FOnCompareItem: TCompareEvent;
25 FOnFilter: TListFilterEvent;
26 FOnCustomDraw: TLVCustomDrawItemEvent;
27 {$IFDEF Windows}FHeaderHandle: HWND;{$ENDIF}
28 FColumn: Integer;
29 FOrder: TSortOrder;
30 procedure SetListView(const Value: TListView);
31 procedure ColumnClick(Sender: TObject; Column: TListColumn);
32 procedure Sort(Compare: TCompareEvent);
33 procedure DrawCheckMark(Item: TListItem; Checked: Boolean);
34 procedure GetCheckBias(var XBias, YBias, BiasTop, BiasLeft: Integer;
35 const ListView: TListView);
36 procedure ListViewCustomDrawItem(Sender: TCustomListView;
37 Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
38 procedure ListViewClick(Sender: TObject);
39 procedure UpdateColumns;
40 procedure SetColumn(const Value: Integer);
41 procedure SetOrder(const Value: TSortOrder);
42 public
43 List: TListObject;
44 Source: TListObject;
45 constructor Create(AOwner: TComponent); override;
46 destructor Destroy; override;
47 function CompareTime(Time1, Time2: TDateTime): Integer;
48 function CompareInteger(Value1, Value2: Integer): Integer;
49 function CompareString(Value1, Value2: string): Integer;
50 function CompareBoolean(Value1, Value2: Boolean): Integer;
51 procedure Refresh;
52 published
53 property ListView: TListView read FListView write SetListView;
54 property OnCompareItem: TCompareEvent read FOnCompareItem
55 write FOnCompareItem;
56 property OnFilter: TListFilterEvent read FOnFilter
57 write FOnFilter;
58 property OnCustomDraw: TLVCustomDrawItemEvent read FOnCustomDraw
59 write FOnCustomDraw;
60 property Column: Integer read FColumn write SetColumn;
61 property Order: TSortOrder read FOrder write SetOrder;
62 end;
63
64 { TListViewFilter }
65
66 TListViewFilter = class(TWinControl)
67 private
68 FOnChange: TNotifyEvent;
69 FStringGrid1: TStringGrid;
70 procedure DoOnKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
71 public
72 constructor Create(AOwner: TComponent); override;
73 procedure UpdateFromListView(ListView: TListView);
74 function TextEntered: Boolean;
75 function TextEnteredCount: Integer;
76 function TextEnteredColumn(Index: Integer): Boolean;
77 function GetColValue(Index: Integer): string;
78 property StringGrid: TStringGrid read FStringGrid1 write FStringGrid1;
79 published
80 property OnChange: TNotifyEvent read FOnChange write FOnChange;
81 property Align;
82 property Anchors;
83 end;
84
85procedure Register;
86
87
88implementation
89
90procedure Register;
91begin
92 RegisterComponents('Common', [TListViewSort, TListViewFilter]);
93end;
94
95{ TListViewFilter }
96
97procedure TListViewFilter.DoOnKeyUp(Sender: TObject; var Key: Word;
98 Shift: TShiftState);
99begin
100 if Assigned(FOnChange) then
101 FOnChange(Self);
102end;
103
104constructor TListViewFilter.Create(AOwner: TComponent);
105begin
106 inherited Create(AOwner);
107 FStringGrid1 := TStringGrid.Create(Self);
108 FStringGrid1.Align := alClient;
109 FStringGrid1.Parent := Self;
110 FStringGrid1.Visible := True;
111 FStringGrid1.ScrollBars := ssNone;
112 FStringGrid1.FixedCols := 0;
113 FStringGrid1.FixedRows := 0;
114 FStringGrid1.RowCount := 1;
115 FStringGrid1.Options := [goFixedHorzLine, goFixedVertLine, goVertLine,
116 goHorzLine, goRangeSelect, goEditing, goAlwaysShowEditor, goSmoothScroll];
117 FStringGrid1.OnKeyUp := DoOnKeyUp;
118end;
119
120procedure TListViewFilter.UpdateFromListView(ListView: TListView);
121var
122 I: Integer;
123begin
124 with FStringGrid1 do begin
125 //Columns.Clear;
126 while Columns.Count > ListView.Columns.Count do Columns.Delete(Columns.Count - 1);
127 while Columns.Count < ListView.Columns.Count do Columns.Add;
128 for I := 0 to ListView.Columns.Count - 1 do begin
129 Columns[I].Width := ListView.Columns[I].Width;
130 end;
131 end;
132end;
133
134function TListViewFilter.TextEntered: Boolean;
135begin
136 Result := TextEnteredCount > 0;
137end;
138
139function TListViewFilter.TextEnteredCount: Integer;
140var
141 I: Integer;
142begin
143 Result := 0;
144 for I := 0 to FStringGrid1.ColCount - 1 do begin
145 if FStringGrid1.Cells[I, 0] <> '' then begin
146 Inc(Result);
147 end;
148 end;
149end;
150
151function TListViewFilter.TextEnteredColumn(Index: Integer): Boolean;
152begin
153 Result := FStringGrid1.Cells[Index, 0] <> '';
154end;
155
156function TListViewFilter.GetColValue(Index: Integer): string;
157begin
158 if (Index >= 0) and (Index < StringGrid.Columns.Count) then
159 Result := StringGrid.Cells[Index, 0]
160 else Result := '';
161end;
162
163{ TListViewSort }
164
165
166procedure TListViewSort.ColumnClick(Sender: TObject; Column: TListColumn);
167begin
168 if Column.Index = Self.Column then begin
169 if FOrder = soUp then FOrder := soDown
170 else if FOrder = soDown then FOrder := soUp
171 else FOrder := soUp;
172 end else Self.Column := Column.Index;
173 Refresh;
174 UpdateColumns;
175end;
176
177procedure TListViewSort.SetOrder(const Value: TSortOrder);
178begin
179 FOrder := Value;
180 UpdateColumns;
181end;
182
183procedure TListViewSort.SetColumn(const Value: Integer);
184begin
185 FColumn := Value;
186 UpdateColumns;
187end;
188
189procedure TListViewSort.SetListView(const Value: TListView);
190begin
191 FListView := Value;
192 FListView.OnColumnClick := ColumnClick;
193 FListView.OnCustomDrawItem := ListViewCustomDrawItem;
194 FListView.OnClick := ListViewClick;
195end;
196
197procedure TListViewSort.Sort(Compare: TCompareEvent);
198begin
199 if (List.Count > 0) then
200 List.Sort(Compare);
201end;
202
203procedure TListViewSort.Refresh;
204begin
205 if Assigned(FOnFilter) then FOnFilter(Self)
206 else if Assigned(Source) then
207 List.Assign(Source) else
208 List.Clear;
209 if ListView.Items.Count <> List.Count then
210 ListView.Items.Count := List.Count;
211 if Assigned(FOnCompareItem) and (Order <> soNone) then Sort(FOnCompareItem);
212 //ListView.Items[-1]; // Workaround for not show first row if selected
213 ListView.Refresh;
214 // Workaround for not working item selection on first row
215 //if not Assigned(ListView.Selected) then begin
216 // ListView.Items.Count := 0;
217 // ListView.Items.Count := List.Count;
218 //end;
219 //if ListView.Items.Count > 0 then
220 // ListView.Items[0].Selected := True;
221 //ListView.Selected := nil;
222 UpdateColumns;
223end;
224
225const
226 //W_64: Integer = 64; {Width of thumbnail in ICON view mode}
227 H_64: Integer = 64; {Height of thumbnail size}
228 CheckWidth: Integer = 14; {Width of check mark box}
229 CheckHeight: Integer = 14; {Height of checkmark}
230 CheckBiasTop: Integer = 2; {This aligns the checkbox to be in centered}
231 CheckBiasLeft: Integer = 3; {In the row of the list item display}
232
233function TListViewSort.CompareBoolean(Value1, Value2: Boolean): Integer;
234begin
235 if Value1 > Value2 then Result := 1
236 else if Value1 < Value2 then Result := -1
237 else Result := 0;
238end;
239
240function TListViewSort.CompareInteger(Value1, Value2: Integer): Integer;
241begin
242 if Value1 > Value2 then Result := 1
243 else if Value1 < Value2 then Result := -1
244 else Result := 0;
245end;
246
247function TListViewSort.CompareString(Value1, Value2: string): Integer;
248begin
249 Result := AnsiCompareStr(Value1, Value2);
250// if Value1 > Value2 then Result := -1
251// else if Value1 < Value2 then Result := 1
252// else Result := 0;
253end;
254
255function TListViewSort.CompareTime(Time1, Time2: TDateTime): Integer;
256begin
257 Result := DateUtils.CompareDateTime(Time1, Time2);
258end;
259
260constructor TListViewSort.Create(AOwner: TComponent);
261begin
262 inherited;
263 List := TListObject.Create;
264 List.OwnsObjects := False;
265end;
266
267destructor TListViewSort.Destroy;
268begin
269 List.Free;
270 inherited;
271end;
272
273procedure TListViewSort.DrawCheckMark(Item: TListItem; Checked:
274 Boolean);
275var
276 TP1: TPoint;
277 XBias, YBias: Integer;
278 OldColor: TColor;
279 BiasTop, BiasLeft: Integer;
280 Rect1: TRect;
281 lRect: TRect;
282 ItemLeft: Integer;
283begin
284 XBias := 0;
285 YBias := 0;
286 BiasTop := 0;
287 BiasLeft := 0;
288 Item.Left := 0;
289 GetCheckBias(XBias, YBias, BiasTop, BiasLeft, ListView);
290 OldColor := ListView.Canvas.Pen.Color;
291 //TP1 := Item.GetPosition;
292 lRect := Item.DisplayRect(drBounds); // Windows 7 workaround
293 TP1.X := lRect.Left;
294 TP1.Y := lRect.Top;
295 //ShowMessage(IntToStr(Item.Index) + ', ' + IntToStr(GetScrollPos(Item.ListView.Handle, SB_VERT)) + ' ' +
296 // IntToHex(Integer(Item), 8) + ', ' + IntToStr(TP1.X) + ', ' + IntToStr(TP1.Y));
297
298// if Checked then
299 ListView.Canvas.Brush.Color := clWhite;
300 ItemLeft := Item.Left;
301 ItemLeft := 23; // Windows 7 workaround
302
303 Rect1.Left := ItemLeft - CheckWidth - BiasLeft + 1 + XBias;
304 //ShowMessage(IntToStr(Tp1.Y) + ', ' + IntToStr(BiasTop) + ', ' + IntToStr(XBias));
305 Rect1.Top := Tp1.Y + BiasTop + 1 + YBias;
306 Rect1.Right := ItemLeft - BiasLeft - 1 + XBias;
307 Rect1.Bottom := Tp1.Y + BiasTop + CheckHeight - 1 + YBias;
308 //ShowMessage(IntToStr(Rect1.Left) + ', ' + IntToStr(Rect1.Top) + ', ' + IntToStr(Rect1.Right) + ', ' + IntToStr(Rect1.Bottom));
309
310 ListView.Canvas.FillRect(Rect1);
311 //if Checked then ListView.Canvas.Brush.Color := clBlack
312 ListView.Canvas.Brush.Color := clBlack;
313 ListView.Canvas.FrameRect(Rect1);
314 ListView.Canvas.FrameRect(Rect(Rect1.Left - 1, Rect1.Top - 1,
315 Rect1.Right + 1, Rect1.Bottom + 1));
316 if Checked then begin
317 ListView.Canvas.Pen.Color := clBlack;
318 ListView.Canvas.MoveTo(ItemLeft - BiasLeft - 2 + XBias - 2,
319 Tp1.Y + BiasTop + 3 + YBias);
320 ListView.Canvas.LineTo(ItemLeft - BiasLeft - (CheckWidth div 2) + XBias,
321 Tp1.Y + BiasTop + (CheckHeight - 4) + YBias);
322 ListView.Canvas.LineTo(ItemLeft - BiasLeft - (CheckWidth - 3) + XBias,
323 Tp1.Y + BiasTop + (CheckHeight div 2) + YBias - 1);
324
325 ListView.Canvas.MoveTo(ItemLeft - BiasLeft - 2 - 1 + XBias - 2,
326 Tp1.Y + BiasTop + 3 + YBias);
327 ListView.Canvas.LineTo(ItemLeft - BiasLeft - (CheckWidth div 2) - 1 + XBias,
328 Tp1.Y + BiasTop + (CheckHeight - 4) + YBias);
329 ListView.Canvas.LineTo(ItemLeft - BiasLeft - (CheckWidth - 3) - 1 + XBias,
330 Tp1.Y + BiasTop + (CheckHeight div 2) + YBias - 1);
331 end;
332 //ListView.Canvas.Brush.Color := ListView.Color;
333 ListView.Canvas.Brush.Color := clWindow;
334 ListView.Canvas.Pen.Color := OldColor;
335end;
336
337procedure TListViewSort.GetCheckBias(var XBias, YBias, BiasTop, BiasLeft: Integer;
338 const ListView: TListView);
339begin
340 XBias := 0;
341 YBias := 0;
342 if ListView.ViewStyle = vsICON then
343 begin
344 YBias := H_64 - CheckHeight;
345 XBias := 0;
346 end;
347 BiasTop := CheckBiasTop;
348 BiasLeft := CheckBiasLeft;
349 if ListView.ViewStyle <> vsReport then
350 begin
351 BiasTop := 0;
352 BiasLeft := 0;
353 end;
354end;
355
356procedure TListViewSort.ListViewCustomDrawItem(Sender: TCustomListView;
357 Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
358begin
359 if Assigned(Item) then begin
360 if ListView.Checkboxes then
361 DrawCheckMark(Item, Item.Checked);
362 if Assigned(FOnCustomDraw) then
363 FOnCustomDraw(Sender, Item, State, DefaultDraw);
364 end;
365end;
366
367procedure TListViewSort.ListViewClick(Sender: TObject);
368var
369 Item: TListItem;
370 Pos: TPoint;
371 DefaultDraw: Boolean;
372begin
373 Pos := ListView.ScreenToClient(Mouse.CursorPos);
374 Item := ListView.GetItemAt(Pos.X, Pos.Y);
375 //ShowMessage(IntToStr(Item.Index) + ', ' + IntToStr(Pos.X) + ', ' + IntToStr(Pos.Y));
376 if Assigned(Item) and (Pos.X < 20) then begin
377
378 Item.Checked := not Item.Checked;
379 //ShowMessage(IntToStr(Item.Index) + ', ' +BoolToStr(Item.Checked));
380 if Assigned(ListView.OnChange) then
381 ListView.OnChange(Self, Item, ctState);
382 DefaultDraw := False;
383 ListViewCustomDrawItem(ListView, Item, [], DefaultDraw);
384 //ListView.UpdateItems(Item.Index, Item.Index);
385 end;
386end;
387
388procedure TListViewSort.UpdateColumns;
389{$IFDEF Windows}
390const
391 HDF_SORTUP = $0400;
392 HDF_SORTDOWN = $0200;
393 SortOrder: array[TSortOrder] of Word = (0, HDF_SORTUP, HDF_SORTDOWN);
394var
395 Item: THDItem;
396 I: Integer;
397begin
398 if Assigned(FListView) then begin
399 FHeaderHandle := ListView_GetHeader(FListView.Handle);
400 for I := 0 to FListView.Columns.Count - 1 do begin
401 FillChar(Item, SizeOf(THDItem), 0);
402 Item.Mask := HDI_FORMAT;
403 Header_GetItem(FHeaderHandle, I, Item);
404 Item.fmt := Item.fmt and not (HDF_SORTDOWN or HDF_SORTUP);
405 if (Column <> -1) and (I = Column) then
406 Item.fmt := Item.fmt or SortOrder[FOrder];
407 Header_SetItem(FHeaderHandle, I, Item);
408 end;
409 end;
410end;
411{$ELSE}
412begin
413end;
414{$ENDIF}
415
416end.
Note: See TracBrowser for help on using the repository browser.