source: branches/2.20_branch/Components/MultiColumnListBox.pas

Last change on this file was 214, checked in by RBRi, 18 years ago

using StringUtilsUnit

  • Property svn:eol-style set to native
File size: 19.8 KB
Line 
1unit MultiColumnListBox;
2
3interface
4
5uses
6 Messages, SysUtils, Classes, Graphics, Forms, Dialogs,
7 StdCtrls, ComCtrls, CustomHeaderControl; // menus for SPCC v2.5+
8
9const
10 mclbImageMarker = #11;
11
12type
13 TMultiColumnListBox = class(TControl)
14 protected
15 FHeader: TCustomHeaderControl;
16 FLIstBox: TListBox;
17 FImageList: TImageList;
18
19 FSavedSelectedObject: TObject;
20
21 FBorderStyle: TBorderStyle;
22 Procedure SetBorderStyle( NewValue: TBorderStyle );
23
24 function GetHeaderPenColor: TColor;
25 procedure SetHeaderPenColor( NewValue: TColor );
26 function GetListPenColor: TColor;
27 procedure SetListPenColor( NewValue: TColor );
28
29 function GetEnabled: boolean; //override;
30 function GetExtendedSelect: boolean;
31 function GetHeaderFont: TFont;
32 function GetHeaderHeight: integer;
33 function GetHeaderParentFont: boolean;
34 function GetItemHeight: integer;
35 function GetListFont: TFont;
36 function GetListParentFont: boolean;
37 function GetMultiSelect: boolean;
38 function GetParentColor: boolean;
39 function GetParentShowHint: boolean;
40 function GetThePopupMenu: TPopupMenu;
41 function GetShowHint: boolean;
42// procedure SetEnabled(NewState:Boolean); override;
43 procedure SetExtendedSelect(const Value: boolean);
44 procedure SetHeaderFont(const Value: TFont);
45 procedure SetHeaderHeight(const Value: integer);
46 procedure SetHeaderParentFont(const Value: boolean);
47 procedure SetItemHeight(const Value: integer);
48 procedure SetListFont(const Value: TFont);
49 procedure SetListParentFont(const Value: boolean);
50 procedure SetMultiSelect(const Value: boolean);
51 procedure SetParentShowHint(const Value: boolean);
52 procedure SetPopupMenu(const Value: TPopupMenu);
53 procedure SetShowHint(const Value: boolean);
54 procedure SetSelectedObject(const Value: TObject);
55 function GetOnClick: TNotifyEvent;
56 procedure SetOnClick(const Value: TNotifyEvent);
57 function GetOnDblClick: TNotifyEvent;
58 procedure SetOnDblClick(const Value: TNotifyEvent);
59 procedure SetSelectedItem(const Value: string);
60 function GetTopObject: TObject;
61 procedure SetTopObject(const Value: TObject);
62
63 function GetItems: TStrings;
64 procedure SetItems( Items: TStrings );
65 function GetHeaderSections: TCustomHeaderSections;
66 procedure SetHeaderSections( Sections: TCustomHeaderSections );
67 function GetSelectedItem: string;
68 function GetSelectedObject: TObject;
69 function GetItemIndex: integer;
70 procedure SetItemIndex( const Value: integer );
71 procedure SetImageList( ImageList: TImageList );
72 procedure Notification( AComponent: TComponent;
73 Operation: TOperation); override;
74
75 procedure SetOnItemFocus( Value: TItemFocusEvent );
76 function GetOnItemFocus: TItemFocusEvent;
77 function GetOnItemSelect: TItemSelectEvent;
78 procedure SetOnItemSelect( Value: TItemSelectEvent );
79
80 function GetOnEnter: TNotifyEvent;
81 procedure SetOnEnter( Value: TNotifyEvent );
82 function GetOnExit: TNotifyEvent;
83 procedure SetOnExit( Value: TNotifyEvent );
84
85 procedure SetSelected( Index: longint; Value: boolean );
86 function GetSelected( Index: longint ): boolean;
87
88 Procedure SetColor(NewColor:TColor); Override;
89
90 procedure Layout;
91 procedure DrawListBoxItem( Sender: TObject;
92 Index: longint;
93 Rect: TRect;
94 State: TOwnerDrawState );
95 procedure ChangeHeader( HeaderControl: TCustomHeaderControl;
96 Section: TCustomHeaderSection );
97 procedure Resize; override;
98 procedure SetupShow; override;
99 procedure SetupComponent; override;
100
101 Procedure ReadSCUResource(Const ResName:TResourceName;Var Data;DataLen:LongInt);Override;
102 Function WriteSCUResource(Stream:TResourceStream):Boolean;Override;
103
104 function GetTabStop:boolean;
105 procedure SetTabStop(Value:boolean);
106
107 procedure WMFocussing( Var Msg: TMessage ); message WM_FOCUSSING;
108 public
109 destructor Destroy; override;
110
111 property ItemIndex: integer read GetItemIndex write SetItemIndex;
112 property SelectedItem: string read GetSelectedItem write SetSelectedItem;
113 property SelectedObject: TObject read GetSelectedObject write SetSelectedObject;
114 property TopObject: TObject read GetTopObject write SetTopObject;
115
116 procedure SetSelectedItemTo( Text: string );
117 property Selected[ Index: longint ]: boolean read GetSelected write SetSelected;
118
119 property Parent;
120
121 published
122 property Items: TStrings
123 read GetItems
124 write SetItems;
125 property HeaderColumns: TCustomHeaderSections
126 read GetHeaderSections
127 write SetHeaderSections;
128 property ImageList: TImageList
129 read FImageList
130 write SetImageList;
131
132 Property BorderStyle:TBorderStyle read FBorderStyle write SetBorderStyle;
133
134 property ListPenColor: TColor read GetListPenColor write SetListPenColor;
135 property HeaderPenColor: TColor read GetHeaderPenColor write SetHeaderPenColor;
136
137 property ListFont: TFont read GetListFont write SetListFont;
138 property ListParentFont: boolean read GetListParentFont write SetListParentFont;
139
140 property HeaderFont: TFont read GetHeaderFont write SetHeaderFont;
141 property HeaderParentFont: boolean read GetHeaderParentFont write SetHeaderParentFont;
142
143 property ShowHint: boolean read GetShowHint write SetShowHint;
144 property ParentShowHint: boolean read GetParentShowHint write SetParentShowHint;
145
146 property PopupMenu: TPopupMenu read GetThePopupMenu write SetPopupMenu;
147
148 property HeaderHeight: integer read GetHeaderHeight write SetHeaderHeight;
149 property ItemHeight: integer read GetItemHeight write SetItemHeight;
150
151 property MultiSelect: boolean read GetMultiSelect write SetMultiSelect;
152 property ExtendedSelect: boolean read GetExtendedSelect write SetExtendedSelect;
153
154 property Enabled; //: boolean read GetEnabled write SetEnabled;
155
156 property Align;
157 property Color;
158 property ParentColor;
159 property TabStop: boolean read GetTabStop write SetTabStop;
160 property TabOrder;
161
162 // Events
163 property OnClick: TNotifyEvent read GetOnClick write SetOnClick;
164 property OnDblClick: TNotifyEvent read GetOnDblClick write SetOnDblClick;
165 property OnItemFocus: TItemFocusEvent read GetOnItemFocus write SetOnItemFocus;
166 property OnItemSelect: TItemSelectEvent read GetOnItemSelect write SetOnItemSelect;
167 property OnEnter: TNotifyEvent read GetOnEnter write SetOnEnter;
168 property OnExit: TNotifyEvent read GetOnExit write SetOnExit;
169 end;
170
171exports
172 TMultiColumnListBox, 'User', 'MultiColumnListBox.bmp';
173
174implementation
175
176uses
177 StringUtilsUnit;
178
179{ TMultiColumnListBox }
180
181procedure TMultiColumnListBox.SetupComponent;
182var
183 Section: TCustomHeaderSection;
184begin
185 inherited SetupComponent;
186
187 Width := 100;
188 Height := 100;
189
190 ParentCOlor := true;
191
192 Name := 'MultiColumnListBox';
193
194 FTabStop := false;
195
196 FHeader := TCustomHeaderControl.Create( Self );
197 FHeader.Parent := self;
198 FHeader.Height := 22;
199 FHeader.BevelWidth := 1;
200 FHeader.TabStop := false;
201 Include( FHeader.ComponentState, csDetail );
202
203 // Create a couple of default header sections
204 // so it's obvious that it's there.
205 Section := FHeader.Sections.Add;
206 Section.Text := 'Column 1';
207 Section.AllowClick := false;
208 Section := FHeader.Sections.Add;
209 Section.Text := 'Column 2';
210
211 FListBox := TListBox.Create( Self );
212 FListBox.Parent := self;
213// FListBox.ItemHeight := 16;
214
215 FListBox.Style := lbOwnerDrawFixed;
216
217 FListBox.OnDrawItem := DrawListBoxItem;
218
219 FListBox.TabStop := true;
220 Include( FListBox.ComponentState, csDetail );
221 FListBox.ParentColor := true;
222
223// FListBox.BorderStyle := bsNone; // we draw it ourselves
224
225 FHeader.OnSectionResize := ChangeHeader;
226
227 FImageList := nil;
228
229// FAlwaysFocusChild := FListBox;
230
231 Layout;
232
233end;
234
235procedure TMultiColumnListBox.SetupShow;
236begin
237 Layout;
238end;
239
240destructor TMultiColumnListBox.Destroy;
241begin
242 inherited Destroy;
243end;
244
245Procedure TMultiColumnListBox.ReadSCUResource( Const ResName: TResourceName;
246 Var Data;DataLen: LongInt );
247begin
248 if ResName = rnHeaders then
249 FHeader.ReadSCUResource( ResName, Data, DataLen )
250 else
251 inherited ReadSCUResource( ResName, Data, DataLen );
252
253end;
254
255Function TMultiColumnListBox.WriteSCUResource( Stream: TResourceStream ): Boolean;
256begin
257 Result := Inherited WriteSCUResource(Stream);
258 If Not Result Then
259 Exit;
260 FHeader.WriteScuResource( Stream );
261end;
262
263procedure TMultiColumnListBox.WMFocussing( Var Msg: TMessage );
264begin
265 // focus listbox instead
266 Msg.Result := LONGWORD( FListBox );
267 msg.Handled := true;
268end;
269
270function TMultiColumnListBox.GetTabStop:boolean;
271begin
272 result:=FListBox.TabStop;
273end;
274
275procedure TMultiColumnListBox.SetTabStop(Value:boolean);
276begin
277 FListBox.TabStop:=Value;
278end;
279
280procedure TMultiColumnListBox.DrawListBoxItem( Sender: TObject;
281 Index: longint;
282 Rect: TRect;
283 State: TOwnerDrawState );
284var
285 ColumnIndex: integer;
286 X: integer;
287 ItemToDraw: string;
288 Line: string;
289 BitmapIndex: integer;
290 ColumnWidth: integer;
291 ItemRect: TRect;
292 Dest: TRect;
293 LineClipRect: TRect;
294 tmpColumns : TStringList;
295 i : longint;
296begin
297 LineClipRect := FListBox.Canvas.ClipRect;
298
299 ColumnIndex := 0;
300
301 Dest := rect;
302 dec( Dest.top ); // minor adjustments since we seem to get a slightly
303 inc( Dest.left ); // incorrect area to draw on...
304
305 X := Dest.Left;
306 Line := FListBox.Items[ Index ];
307
308 with FListBox.Canvas do
309 begin
310 Pen.Color := FListBox.PenColor;
311 Brush.Color := FListBox.Color;
312 IF State * [odSelected] <> [] THEN
313 begin
314 Brush.Color := clHighLight;
315 Pen.Color := Color;
316 end;
317
318 FillRect( Dest, Brush.Color );
319 end;
320
321 tmpColumns := TStringList.Create;
322 StrExtractStrings(tmpColumns, Line, [#9], #0);
323
324 for i := 0 to tmpColumns.Count - 1 do
325 begin
326 ItemToDraw := tmpColumns[i];
327 if ColumnIndex < FHeader.Sections.Count then
328 ColumnWidth := FHeader.Sections[ ColumnIndex ].Width
329 else
330 ColumnWidth := 50;
331
332 ItemRect := Dest;
333 ItemRect.Left := X;
334 ItemRect.Right := X + ColumnWidth - 2;
335 FListBox.Canvas.ClipRect := IntersectRect( LineClipRect,
336 ItemRect );
337
338 if StrLeft( ItemToDraw, 1 ) = mclbImageMarker then
339 begin
340 Delete( ItemToDraw, 1, 1 );
341 try
342 BitmapIndex := StrToInt( ItemToDraw );
343 except
344 BitmapIndex := -1;
345 end;
346 if Assigned( FImageList ) then
347 if ( BitmapIndex >= 0 )
348 and ( BitmapIndex < FImageList.Count ) then
349 begin
350 FImageList.Draw( FListBox.Canvas,
351 X, Dest.Bottom,
352 BitmapIndex );
353 end
354 else
355 begin
356 tmpColumns.Destroy;
357 raise Exception.Create( 'Bitmap index out of range in MultiColumnListBox' )
358 end
359 else
360 begin
361 tmpColumns.Destroy;
362 raise Exception.Create( 'No imagelist assigned in MultiColumnListBox' );
363 end
364 end
365 else
366 begin
367 FListBox.Canvas.TextOut( X, Dest.Bottom,
368 ItemToDraw );
369 end;
370 inc( X, ColumnWidth );
371 inc( ColumnIndex );
372 end;
373 tmpColumns.Destroy;
374end;
375
376procedure TMultiColumnListBox.SetItems( Items: TStrings );
377begin
378 FListBox.Items.Assign( Items );
379end;
380
381function TMultiColumnListBox.GetHeaderSections: TCustomHeaderSections;
382begin
383 Result := FHeader.Sections;
384end;
385
386function TMultiColumnListBox.GetItems: TStrings;
387begin
388 Result := FListBox.Items;
389end;
390
391procedure TMultiColumnListBox.Layout;
392var
393 LastSection: TCustomHeaderSection;
394begin
395 FHeader.Align := alTop;
396
397 //FListBox.Align := alClient;
398{
399 if FBorderStyle = bsNone then
400 begin
401}
402 FListBox.Left := 0;
403 FListBox.Width := Width;
404 FListBox.Bottom := 0;
405 FListBox.Height := Height - FHeader.Height + 2; // hide the top edge under header
406 FListBox.SendToBack;
407{
408 end
409 else
410 begin
411 FListBox.Left := 2;
412 FListBox.Width := Width - 4;
413 FListBox.Bottom := 2;
414 FListBox.Height := Height - FHeader.Height - 4;
415 end;
416}
417
418 if HeaderColumns.Count > 0 then
419 begin
420 // Resize the last column to fit, if possible
421 LastSection := HeaderColumns[ HeaderColumns.Count - 1 ];
422 if LastSection.Left < Width then
423 LastSection.Width := Width - LastSection.Left;
424 end;
425
426end;
427
428procedure TMultiColumnListBox.SetBorderStyle( NewValue: TBorderStyle );
429begin
430 if NewValue = FBorderStyle then
431 exit;
432 FBorderStyle := NewValue;
433 Layout;
434 Invalidate;
435end;
436
437procedure TMultiColumnListBox.SetImageList(ImageList: TImageList);
438begin
439 if FImageList <> nil then
440 // Tell the old imagelist not to inform us any more
441 FImageList.Notification( Self, opRemove );
442
443 FImageList := ImageList;
444
445 if FImageList <> nil then
446 begin
447 // request notification when other is freed
448 FImageList.FreeNotification( Self );
449 end;
450end;
451
452procedure TMultiColumnListBox.SetHeaderSections(Sections: TCustomHeaderSections);
453begin
454 FHeader.Sections.Assign( Sections );
455end;
456
457procedure TMultiColumnListBox.Notification( AComponent: TComponent;
458 Operation: TOperation);
459begin
460 inherited Notification( AComponent, Operation );
461 if AComponent = FImageList then
462 if Operation = opRemove then
463 // Image list is being destroyed
464 FImageList := nil;
465end;
466
467procedure TMultiColumnListBox.ChangeHeader(HeaderControl: TCustomHeaderControl;
468 Section: TCustomHeaderSection);
469begin
470 Layout;
471 FListBox.Invalidate;
472end;
473
474function TMultiColumnListBox.GetSelectedItem: string;
475begin
476 Result := '';
477 if FListBox.ItemIndex <> -1 then
478 Result := FListBox.Items[ FListBox.ItemIndex ];
479end;
480
481function TMultiColumnListBox.GetSelectedObject: TObject;
482begin
483 Result := nil;
484 if FListBox.ItemIndex <> -1 then
485 Result := FListBox.Items.Objects[ FListBox.ItemIndex ];
486
487end;
488
489procedure TMultiColumnListBox.SetItemIndex(const Value: integer );
490begin
491 FListBox.ItemIndex := Value;
492end;
493
494function TMultiColumnListBox.GetItemIndex: integer;
495begin
496 Result := FListBox.ItemIndex;
497end;
498
499function TMultiColumnListBox.GetHeaderPenColor: TColor;
500begin
501 Result := FHeader.PenColor;
502end;
503
504procedure TMultiColumnListBox.SetHeaderPenColor( NewValue: TColor );
505begin
506 FHeader.PenColor := NewValue;
507end;
508
509function TMultiColumnListBox.GetListPenColor: TColor;
510begin
511 Result := FListBox.PenColor;
512end;
513
514procedure TMultiColumnListBox.SetListPenColor( NewValue: TColor );
515begin
516 FListBox.PenColor := NewValue;
517end;
518
519function TMultiColumnListBox.GetEnabled: boolean;
520begin
521 Result := FListBox.Enabled;
522end;
523
524function TMultiColumnListBox.GetExtendedSelect: boolean;
525begin
526 Result := FListBox.ExtendedSelect;
527end;
528
529function TMultiColumnListBox.GetHeaderFont: TFont;
530begin
531 Result := FHeader.Font;
532end;
533
534function TMultiColumnListBox.GetHeaderHeight: integer;
535begin
536 Result := FHeader.Height;
537end;
538
539function TMultiColumnListBox.GetHeaderParentFont: boolean;
540begin
541 Result := FHeader.ParentFont;
542end;
543
544function TMultiColumnListBox.GetItemHeight: integer;
545begin
546 Result := FListBox.ItemHeight;
547end;
548
549function TMultiColumnListBox.GetListFont: TFont;
550begin
551 Result := FListBox.Font;
552end;
553
554function TMultiColumnListBox.GetListParentFont: boolean;
555begin
556 Result := FListBox.ParentFont;
557end;
558
559function TMultiColumnListBox.GetMultiSelect: boolean;
560begin
561 Result := FListBox.MultiSelect;
562end;
563
564function TMultiColumnListBox.GetParentColor: boolean;
565begin
566 Result := FListBox.ParentColor;
567end;
568
569function TMultiColumnListBox.GetParentShowHint: boolean;
570begin
571 Result := FListBox.ParentShowHint;
572end;
573
574function TMultiColumnListBox.GetThePopupMenu: TPopupMenu;
575begin
576 Result := FListBox.PopupMenu;
577end;
578
579function TMultiColumnListBox.GetShowHint: boolean;
580begin
581 Result := FListBox.ShowHint;
582end;
583
584{
585procedure TMultiColumnListBox.SetEnabled(NewState:Boolean);
586begin
587 FListBox.Enabled := NewState;
588 FHeader.Enabled := NewState;
589end;
590}
591
592procedure TMultiColumnListBox.SetExtendedSelect(const Value: boolean);
593begin
594 FListBox.ExtendedSelect := Value;
595end;
596
597procedure TMultiColumnListBox.SetHeaderFont(const Value: TFont);
598begin
599 FHeader.Font := Value;
600end;
601
602procedure TMultiColumnListBox.SetHeaderHeight(const Value: integer);
603begin
604 FHeader.Height := Value;
605end;
606
607procedure TMultiColumnListBox.SetHeaderParentFont(const Value: boolean);
608begin
609 FHeader.ParentFont := Value;
610end;
611
612procedure TMultiColumnListBox.SetItemHeight(const Value: integer);
613begin
614 FListBox.ItemHeight := Value;
615end;
616
617procedure TMultiColumnListBox.SetListFont(const Value: TFont);
618begin
619 FListBox.Font := Value;
620end;
621
622procedure TMultiColumnListBox.SetListParentFont(const Value: boolean);
623begin
624 FListBox.ParentFont := Value;
625end;
626
627procedure TMultiColumnListBox.SetMultiSelect(const Value: boolean);
628begin
629 FListBox.MultiSelect := Value;
630end;
631
632procedure TMultiColumnListBox.SetParentShowHint(const Value: boolean);
633begin
634 FListBox.ParentShowHint := Value;
635 FHeader.ParentShowHint := Value;
636end;
637
638procedure TMultiColumnListBox.SetPopupMenu(const Value: TPopupMenu);
639begin
640 FListBox.PopupMenu := Value;
641 FHeader.PopupMenu := Value;
642end;
643
644procedure TMultiColumnListBox.SetShowHint(const Value: boolean);
645begin
646 FListBox.ShowHint := Value;
647 FHeader.ShowHint := Value;
648end;
649
650procedure TMultiColumnListBox.SetSelectedObject(const Value: TObject);
651var
652 Index: integer;
653begin
654 Index := FListBox.Items.IndexOfObject( Value );
655 FListBox.ItemIndex := Index;
656end;
657
658function TMultiColumnListBox.GetOnClick: TNotifyEvent;
659begin
660 Result := FListBox.OnClick;
661end;
662
663procedure TMultiColumnListBox.SetOnClick(const Value: TNotifyEvent);
664begin
665 FListBox.OnClick := Value;
666end;
667
668function TMultiColumnListBox.GetOnDblClick: TNotifyEvent;
669begin
670 Result := FListBox.OnDblClick;
671end;
672
673procedure TMultiColumnListBox.SetOnDblClick(const Value: TNotifyEvent);
674begin
675 FListBox.OnDblClick := Value;
676end;
677
678procedure TMultiColumnListBox.SetSelectedItem(const Value: string);
679var
680 Index: integer;
681begin
682 Index := FListBox.Items.IndexOf( Value );
683 FListBox.ItemIndex := Index;
684end;
685
686procedure TMultiColumnListBox.SetSelectedItemTo(Text: string );
687begin
688 if ItemIndex = -1 then
689 raise Exception.Create( 'MultiColumnListBox: no item selected to set!' );
690
691 Items[ ItemIndex ] := Text;
692end;
693
694procedure TMultiColumnListBox.Resize;
695begin
696 Layout;
697end;
698
699
700function TMultiColumnListBox.GetTopObject: TObject;
701begin
702 Result := nil;
703 if ( FListBox.TopIndex >0 )
704 and ( FListBox.TopIndex < FListBox.Items.Count ) then
705 Result := FListBox.Items.Objects[ FLIstBox.TopIndex ];
706
707end;
708
709procedure TMultiColumnListBox.SetTopObject(const Value: TObject);
710var
711 Index: integer;
712begin
713 Index := FListBox.Items.IndexOfObject( Value );
714 if Index <> -1 then
715 FListBox.TopIndex := Index;
716end;
717
718procedure TMultiColumnListBox.SetOnItemFocus( Value: TItemFocusEvent );
719begin
720 FListBox.OnItemFocus := Value;
721end;
722
723function TMultiColumnListBox.GetOnItemFocus: TItemFocusEvent;
724begin
725 Result := FListBox.OnItemFocus;
726end;
727
728function TMultiColumnListBox.GetOnItemSelect: TItemSelectEvent;
729begin
730 Result := FListBox.OnItemSelect;
731end;
732
733procedure TMultiColumnListBox.SetOnItemSelect( Value: TItemSelectEvent );
734begin
735 FListBox.OnItemSelect := Value;
736end;
737
738function TMultiColumnListBox.GetOnEnter: TNotifyEvent;
739begin
740 Result := FListBox.OnEnter;
741end;
742
743procedure TMultiColumnListBox.SetOnEnter( Value: TNotifyEvent );
744begin
745 FListBox.OnEnter := Value;
746end;
747
748function TMultiColumnListBox.GetOnExit: TNotifyEvent;
749begin
750 Result := FListBox.OnExit;
751end;
752
753procedure TMultiColumnListBox.SetOnExit( Value: TNotifyEvent );
754begin
755 FListBox.OnExit := Value;
756end;
757
758procedure TMultiColumnListBox.SetSelected( Index: longint; Value: boolean );
759begin
760 FListBox.Selected[ Index ] := Value;
761end;
762
763function TMultiColumnListBox.GetSelected( Index: longint ): boolean;
764begin
765 Result := FListBox.Selected[ Index ];
766end;
767
768Procedure TMultiColumnListBox.SetColor(NewColor:TColor);
769begin
770 inherited SetColor( NewColor );
771end;
772
773Initialization
774 {Register classes}
775 RegisterClasses([TMultiColumnListBox]);
776end.
Note: See TracBrowser for help on using the repository browser.