source: trunk/Demo/Packages/Common/UListViewSort.pas

Last change on this file was 60, checked in by chronos, 12 years ago
File size: 9.9 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;
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
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;
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 property ListView: TListView read FListView write SetListView;
53 property OnCompareItem: TCompareEvent read FOnCompareItem
54 write FOnCompareItem;
55 property OnFilter: TListFilterEvent read FOnFilter
56 write FOnFilter;
57 property OnCustomDraw: TLVCustomDrawItemEvent read FOnCustomDraw
58 write FOnCustomDraw;
59 property Column: Integer read FColumn write SetColumn;
60 property Order: TSortOrder read FOrder write SetOrder;
61 end;
62
63implementation
64
65{ TListViewSort }
66
67
68procedure TListViewSort.ColumnClick(Sender: TObject; Column: TListColumn);
69begin
70 if Column.Index = Self.Column then begin
71 if FOrder = soUp then FOrder := soDown
72 else if FOrder = soDown then FOrder := soUp
73 else FOrder := soUp;
74 end else Self.Column := Column.Index;
75 Refresh;
76 UpdateColumns;
77end;
78
79procedure TListViewSort.SetOrder(const Value: TSortOrder);
80begin
81 FOrder := Value;
82 UpdateColumns;
83end;
84
85procedure TListViewSort.SetColumn(const Value: Integer);
86begin
87 FColumn := Value;
88 UpdateColumns;
89end;
90
91procedure TListViewSort.SetListView(const Value: TListView);
92begin
93 FListView := Value;
94 FListView.OnColumnClick := ColumnClick;
95 FListView.OnCustomDrawItem := ListViewCustomDrawItem;
96 FListView.OnClick := ListViewClick;
97end;
98
99procedure TListViewSort.Sort(Compare: TCompareEvent);
100begin
101 if (List.Count > 0) then
102 List.Sort(Compare);
103end;
104
105procedure TListViewSort.Refresh;
106begin
107 if Assigned(FOnFilter) then FOnFilter(Self)
108 else if Assigned(Source) then
109 List.Assign(Source) else
110 List.Clear;
111 if ListView.Items.Count <> List.Count then
112 ListView.Items.Count := List.Count;
113 if Assigned(FOnCompareItem) then Sort(FOnCompareItem);
114 //ListView.Items[-1]; // Workaround for not show first row if selected
115 ListView.Refresh;
116 // Workaround for not working item selection on first row
117 //if not Assigned(ListView.Selected) then begin
118 // ListView.Items.Count := 0;
119 // ListView.Items.Count := List.Count;
120 //end;
121 //if ListView.Items.Count > 0 then
122 // ListView.Items[0].Selected := True;
123 //ListView.Selected := nil;
124 UpdateColumns;
125end;
126
127const
128 //W_64: Integer = 64; {Width of thumbnail in ICON view mode}
129 H_64: Integer = 64; {Height of thumbnail size}
130 CheckWidth: Integer = 14; {Width of check mark box}
131 CheckHeight: Integer = 14; {Height of checkmark}
132 CheckBiasTop: Integer = 2; {This aligns the checkbox to be in centered}
133 CheckBiasLeft: Integer = 3; {In the row of the list item display}
134
135function TListViewSort.CompareBoolean(Value1, Value2: Boolean): Integer;
136begin
137 if Value1 > Value2 then Result := 1
138 else if Value1 < Value2 then Result := -1
139 else Result := 0;
140end;
141
142function TListViewSort.CompareInteger(Value1, Value2: Integer): Integer;
143begin
144 if Value1 > Value2 then Result := 1
145 else if Value1 < Value2 then Result := -1
146 else Result := 0;
147end;
148
149function TListViewSort.CompareString(Value1, Value2: string): Integer;
150begin
151 Result := AnsiCompareStr(Value1, Value2);
152// if Value1 > Value2 then Result := -1
153// else if Value1 < Value2 then Result := 1
154// else Result := 0;
155end;
156
157function TListViewSort.CompareTime(Time1, Time2: TDateTime): Integer;
158begin
159 Result := DateUtils.CompareDateTime(Time1, Time2);
160end;
161
162constructor TListViewSort.Create;
163begin
164 List := TListObject.Create;
165 List.OwnsObjects := False;
166end;
167
168destructor TListViewSort.Destroy;
169begin
170 List.Free;
171 inherited;
172end;
173
174procedure TListViewSort.DrawCheckMark(Item: TListItem; Checked:
175 Boolean);
176var
177 TP1: TPoint;
178 XBias, YBias: Integer;
179 OldColor: TColor;
180 BiasTop, BiasLeft: Integer;
181 Rect1: TRect;
182 lRect: TRect;
183 ItemLeft: Integer;
184begin
185 XBias := 0;
186 YBias := 0;
187 BiasTop := 0;
188 BiasLeft := 0;
189 Item.Left := 0;
190 GetCheckBias(XBias, YBias, BiasTop, BiasLeft, ListView);
191 OldColor := ListView.Canvas.Pen.Color;
192 //TP1 := Item.GetPosition;
193 lRect := Item.DisplayRect(drBounds); // Windows 7 workaround
194 TP1.X := lRect.Left;
195 TP1.Y := lRect.Top;
196 //ShowMessage(IntToStr(Item.Index) + ', ' + IntToStr(GetScrollPos(Item.ListView.Handle, SB_VERT)) + ' ' +
197 // IntToHex(Integer(Item), 8) + ', ' + IntToStr(TP1.X) + ', ' + IntToStr(TP1.Y));
198
199// if Checked then
200 ListView.Canvas.Brush.Color := clWhite;
201 ItemLeft := Item.Left;
202 ItemLeft := 23; // Windows 7 workaround
203
204 Rect1.Left := ItemLeft - CheckWidth - BiasLeft + 1 + XBias;
205 //ShowMessage(IntToStr(Tp1.Y) + ', ' + IntToStr(BiasTop) + ', ' + IntToStr(XBias));
206 Rect1.Top := Tp1.Y + BiasTop + 1 + YBias;
207 Rect1.Right := ItemLeft - BiasLeft - 1 + XBias;
208 Rect1.Bottom := Tp1.Y + BiasTop + CheckHeight - 1 + YBias;
209 //ShowMessage(IntToStr(Rect1.Left) + ', ' + IntToStr(Rect1.Top) + ', ' + IntToStr(Rect1.Right) + ', ' + IntToStr(Rect1.Bottom));
210
211 ListView.Canvas.FillRect(Rect1);
212 //if Checked then ListView.Canvas.Brush.Color := clBlack
213 ListView.Canvas.Brush.Color := clBlack;
214 ListView.Canvas.FrameRect(Rect1);
215 ListView.Canvas.FrameRect(Rect(Rect1.Left - 1, Rect1.Top - 1,
216 Rect1.Right + 1, Rect1.Bottom + 1));
217 if Checked then begin
218 ListView.Canvas.Pen.Color := clBlack;
219 ListView.Canvas.MoveTo(ItemLeft - BiasLeft - 2 + XBias - 2,
220 Tp1.Y + BiasTop + 3 + YBias);
221 ListView.Canvas.LineTo(ItemLeft - BiasLeft - (CheckWidth div 2) + XBias,
222 Tp1.Y + BiasTop + (CheckHeight - 4) + YBias);
223 ListView.Canvas.LineTo(ItemLeft - BiasLeft - (CheckWidth - 3) + XBias,
224 Tp1.Y + BiasTop + (CheckHeight div 2) + YBias - 1);
225
226 ListView.Canvas.MoveTo(ItemLeft - BiasLeft - 2 - 1 + XBias - 2,
227 Tp1.Y + BiasTop + 3 + YBias);
228 ListView.Canvas.LineTo(ItemLeft - BiasLeft - (CheckWidth div 2) - 1 + XBias,
229 Tp1.Y + BiasTop + (CheckHeight - 4) + YBias);
230 ListView.Canvas.LineTo(ItemLeft - BiasLeft - (CheckWidth - 3) - 1 + XBias,
231 Tp1.Y + BiasTop + (CheckHeight div 2) + YBias - 1);
232 end;
233 //ListView.Canvas.Brush.Color := ListView.Color;
234 ListView.Canvas.Brush.Color := clWindow;
235 ListView.Canvas.Pen.Color := OldColor;
236end;
237
238procedure TListViewSort.GetCheckBias(var XBias, YBias, BiasTop, BiasLeft: Integer;
239 const ListView: TListView);
240begin
241 XBias := 0;
242 YBias := 0;
243 if ListView.ViewStyle = vsICON then
244 begin
245 YBias := H_64 - CheckHeight;
246 XBias := 0;
247 end;
248 BiasTop := CheckBiasTop;
249 BiasLeft := CheckBiasLeft;
250 if ListView.ViewStyle <> vsReport then
251 begin
252 BiasTop := 0;
253 BiasLeft := 0;
254 end;
255end;
256
257procedure TListViewSort.ListViewCustomDrawItem(Sender: TCustomListView;
258 Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
259begin
260 if Assigned(Item) then begin
261 if ListView.Checkboxes then
262 DrawCheckMark(Item, Item.Checked);
263 if Assigned(FOnCustomDraw) then
264 FOnCustomDraw(Sender, Item, State, DefaultDraw);
265 end;
266end;
267
268procedure TListViewSort.ListViewClick(Sender: TObject);
269var
270 Item: TListItem;
271 Pos: TPoint;
272 DefaultDraw: Boolean;
273begin
274 Pos := ListView.ScreenToClient(Mouse.CursorPos);
275 Item := ListView.GetItemAt(Pos.X, Pos.Y);
276 //ShowMessage(IntToStr(Item.Index) + ', ' + IntToStr(Pos.X) + ', ' + IntToStr(Pos.Y));
277 if Assigned(Item) and (Pos.X < 20) then begin
278
279 Item.Checked := not Item.Checked;
280 //ShowMessage(IntToStr(Item.Index) + ', ' +BoolToStr(Item.Checked));
281 if Assigned(ListView.OnChange) then
282 ListView.OnChange(Self, Item, ctState);
283 DefaultDraw := False;
284 ListViewCustomDrawItem(ListView, Item, [], DefaultDraw);
285 //ListView.UpdateItems(Item.Index, Item.Index);
286 end;
287end;
288
289procedure TListViewSort.UpdateColumns;
290{$IFDEF Windows}
291const
292 HDF_SORTUP = $0400;
293 HDF_SORTDOWN = $0200;
294 SortOrder: array[TSortOrder] of Word = (0, HDF_SORTUP, HDF_SORTDOWN);
295var
296 Item: THDItem;
297 I: Integer;
298begin
299 if Assigned(FListView) then begin
300 FHeaderHandle := ListView_GetHeader(FListView.Handle);
301 for I := 0 to FListView.Columns.Count - 1 do begin
302 FillChar(Item, SizeOf(THDItem), 0);
303 Item.Mask := HDI_FORMAT;
304 Header_GetItem(FHeaderHandle, I, Item);
305 Item.fmt := Item.fmt and not (HDF_SORTDOWN or HDF_SORTUP);
306 if (Column <> -1) and (I = Column) then
307 Item.fmt := Item.fmt or SortOrder[FOrder];
308 Header_SetItem(FHeaderHandle, I, Item);
309 end;
310 end;
311end;
312{$ELSE}
313begin
314end;
315{$ENDIF}
316
317end.
Note: See TracBrowser for help on using the repository browser.