source: trunk/Packages/Common/UListViewSort.pas

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