* ListBox.cs:
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ListView.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2004-2005 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //      Ravindra Kumar (rkumar@novell.com)
24 //      Jordi Mas i Hernandez, jordi@ximian.com
25 //
26 // TODO:
27 //   - Keys to be handled ENTER/PAGE UP/PAGE DOWN/HOME/END/ARROWS/CTRL/SHIFT
28 //   - Item text editing
29 //   - Column resizing/reodering
30 //   - Feedback for item activation, change in cursor types as mouse moves.
31 //   - HideSelection
32 //   - Focused item (broken and not drawn)
33 //   - LabelEdit
34 //   - Manual column resizing
35 //   - Drag and drop
36 //   - Clipping 
37
38
39 // NOT COMPLETE
40
41
42 using System.Collections;
43 using System.ComponentModel;
44 using System.ComponentModel.Design;
45 using System.Drawing;
46 using System.Runtime.InteropServices;
47
48 namespace System.Windows.Forms
49 {
50         [DefaultEvent ("SelectedIndexChanged")]
51         [DefaultProperty ("Items")]
52         [Designer ("System.Windows.Forms.Design.ListViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
53         public class ListView : Control
54         {
55                 private ItemActivation activation = ItemActivation.Standard;
56                 private ListViewAlignment alignment = ListViewAlignment.Top;
57                 private bool allow_column_reorder = false;
58                 private bool auto_arrange = true;
59                 private bool check_boxes = false;
60                 private CheckedIndexCollection checked_indices;
61                 private CheckedListViewItemCollection checked_items;
62                 private ColumnHeader clicked_column;
63                 private ListViewItem clicked_item;
64                 private ListViewItem last_clicked_item;
65                 private ColumnHeaderCollection columns;
66                 private bool ctrl_pressed;
67                 private bool shift_pressed;
68                 private bool draw_headers = true; // Used for painting. Do we need to draw column headers ?
69                 private ListViewItem focused_item;
70                 private bool full_row_select = false;
71                 private bool grid_lines = false;
72                 private ColumnHeaderStyle header_style = ColumnHeaderStyle.Clickable;
73                 private bool hide_selection = true;
74                 private bool hover_selection = false;
75                 private IComparer item_sorter;
76                 private ListViewItemCollection items;
77                 private bool label_edit = false;
78                 private bool label_wrap = true;
79                 private bool multiselect = true;
80                 private bool scrollable = true;
81                 private SelectedIndexCollection selected_indices;
82                 private SelectedListViewItemCollection selected_items;
83                 private SortOrder sort_order = SortOrder.None;
84                 private ImageList state_image_list;
85                 private bool updating = false;
86                 private View view = View.LargeIcon;
87                 private int layout_wd;    // We might draw more than our client area
88                 private int layout_ht;    // therefore we need to have these two.
89                 //private TextBox editor;   // Used for editing an item text
90                 private ScrollBar h_scroll; // used for scrolling horizontally
91                 private ScrollBar v_scroll; // used for scrolling vertically
92                 private int h_marker;           // Position markers for scrolling
93                 private int v_marker;
94
95                 // internal variables
96                 internal ImageList large_image_list;
97                 internal ImageList small_image_list;
98                 internal Size text_size = Size.Empty;
99
100                 #region Events
101                 public event LabelEditEventHandler AfterLabelEdit;
102
103                 [Browsable (false)]
104                 [EditorBrowsable (EditorBrowsableState.Never)]
105                 public new event EventHandler BackgroundImageChanged;
106
107                 public event LabelEditEventHandler BeforeLabelEdit;
108                 public event ColumnClickEventHandler ColumnClick;
109                 public event EventHandler ItemActivate;
110                 public event ItemCheckEventHandler ItemCheck;
111                 public event ItemDragEventHandler ItemDrag;
112
113                 [Browsable (false)]
114                 [EditorBrowsable (EditorBrowsableState.Never)]
115                 public new event PaintEventHandler Paint;
116
117                 public event EventHandler SelectedIndexChanged;
118
119                 [Browsable (false)]
120                 [EditorBrowsable (EditorBrowsableState.Never)]
121                 public new event EventHandler TextChanged;
122                 #endregion // Events
123
124                 #region Public Constructors
125                 public ListView ()
126                 {
127                         background_color = ThemeEngine.Current.ColorWindow;
128                         checked_indices = new CheckedIndexCollection (this);
129                         checked_items = new CheckedListViewItemCollection (this);
130                         columns = new ColumnHeaderCollection (this);
131                         foreground_color = SystemColors.WindowText;
132                         items = new ListViewItemCollection (this);
133                         selected_indices = new SelectedIndexCollection (this);
134                         selected_items = new SelectedListViewItemCollection (this);
135
136                         border_style = BorderStyle.Fixed3D;
137
138                         // we are mostly scrollable
139                         h_scroll = new HScrollBar ();
140                         v_scroll = new VScrollBar ();
141                         h_marker = v_marker = 0;
142
143                         // scroll bars are disabled initially
144                         h_scroll.Visible = false;
145                         h_scroll.ValueChanged += new EventHandler(HorizontalScroller);
146                         v_scroll.Visible = false;
147                         v_scroll.ValueChanged += new EventHandler(VerticalScroller);
148
149                         // event handlers
150                         base.DoubleClick += new EventHandler(ListView_DoubleClick);
151                         base.KeyDown += new KeyEventHandler(ListView_KeyDown);
152                         base.KeyUp += new KeyEventHandler(ListView_KeyUp);
153                         base.MouseDown += new MouseEventHandler(ListView_MouseDown);
154                         base.MouseHover += new EventHandler(ListView_MouseHover);
155                         base.MouseUp += new MouseEventHandler(ListView_MouseUp);
156                         base.MouseMove += new MouseEventHandler(ListView_MouseMove);
157                         base.Paint += new PaintEventHandler (ListView_Paint);
158                         SizeChanged += new EventHandler (ListView_SizeChanged);
159
160                         this.SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
161                 }
162                 #endregion      // Public Constructors
163
164                 #region Private Internal Properties
165                 internal Size CheckBoxSize {
166                         get {
167                                 if (this.check_boxes) {
168                                         if (this.state_image_list != null)
169                                                 return this.state_image_list.ImageSize;
170                                         else
171                                                 return ThemeEngine.Current.ListViewCheckBoxSize;
172                                 }
173                                 return Size.Empty;
174                         }
175                 }
176
177                 internal bool CanMultiselect {
178                         get {
179                                 if (this.multiselect &&
180                                         (this.ctrl_pressed || this.shift_pressed))
181                                         return true;
182                                 else
183                                         return false;
184                         }
185                 }
186                 #endregion      // Private Internal Properties
187
188                 #region  Protected Properties
189                 protected override CreateParams CreateParams {
190                         get { return base.CreateParams; }
191                 }
192
193                 protected override Size DefaultSize {
194                         get { return ThemeEngine.Current.ListViewDefaultSize; }
195                 }
196                 #endregion      // Protected Properties
197
198                 #region Public Instance Properties
199                 [DefaultValue (ItemActivation.Standard)]
200                 public ItemActivation Activation {
201                         get { return activation; }
202                         set { 
203                                 if (value != ItemActivation.Standard && value != ItemActivation.OneClick && 
204                                         value != ItemActivation.TwoClick) {
205                                         throw new InvalidEnumArgumentException (string.Format
206                                                 ("Enum argument value '{0}' is not valid for Activation", value));
207                                 }
208                                   
209                                 activation = value;
210                         }
211                 }
212
213                 [DefaultValue (ListViewAlignment.Top)]
214                 [Localizable (true)]
215                 public ListViewAlignment Alignment {
216                         get { return alignment; }
217                         set {
218                                 if (value != ListViewAlignment.Default && value != ListViewAlignment.Left && 
219                                         value != ListViewAlignment.SnapToGrid && value != ListViewAlignment.Top) {
220                                         throw new InvalidEnumArgumentException (string.Format 
221                                                 ("Enum argument value '{0}' is not valid for Alignment", value));
222                                 }
223                                 
224                                 if (this.alignment != value) {
225                                         alignment = value;
226                                         // alignment does not matter in Details/List views
227                                         if (this.view == View.LargeIcon ||
228                                             this.View == View.SmallIcon)
229                                                 this.Redraw (true);
230                                 }
231                         }
232                 }
233
234                 [DefaultValue (false)]
235                 public bool AllowColumnReorder {
236                         get { return allow_column_reorder; }
237                         set {
238                                 if (this.allow_column_reorder != value) {
239                                         allow_column_reorder = value;
240                                         // column reorder does not matter in Details view
241                                         if (this.view != View.Details)
242                                                 this.Redraw (true);
243                                 }
244                         }
245                 }
246
247                 [DefaultValue (true)]
248                 public bool AutoArrange {
249                         get { return auto_arrange; }
250                         set {
251                                 if (auto_arrange != value) {
252                                         auto_arrange = value;
253                                         // autoarrange does not matter in Details/List views
254                                         if (this.view == View.LargeIcon || this.View == View.SmallIcon)
255                                                 this.Redraw (true);
256                                 }
257                         }
258                 }
259
260                 public override Color BackColor {
261                         get {
262                                 if (background_color.IsEmpty)
263                                         return ThemeEngine.Current.ColorWindow;
264                                 else
265                                         return background_color;
266                         }
267                         set { background_color = value; }
268                 }
269
270                 [Browsable (false)]
271                 [EditorBrowsable (EditorBrowsableState.Never)]
272                 public override Image BackgroundImage {
273                         get { return background_image; }
274                         set {
275                                 if (value == background_image)
276                                         return;
277
278                                 background_image = value;
279                                 if (BackgroundImageChanged != null)
280                                         BackgroundImageChanged (this, new EventArgs ());
281                         }
282                 }
283
284                 [DefaultValue (BorderStyle.Fixed3D)]
285                 [DispId (-504)]
286                 public BorderStyle BorderStyle {
287                         get { return border_style; }
288                         set {
289                                 if (value != BorderStyle.Fixed3D && value != BorderStyle.FixedSingle  && 
290                                         value != BorderStyle.None) {
291                                         throw new InvalidEnumArgumentException (string.Format 
292                                                 ("Enum argument value '{0}' is not valid for BorderStyle", value));
293                                 }
294                                 
295                                 if (border_style != value) {
296                                         border_style = value;
297                                         this.Redraw (true);
298                                 }
299                         }
300                 }
301
302                 [DefaultValue (false)]
303                 public bool CheckBoxes {
304                         get { return check_boxes; }
305                         set {
306                                 if (check_boxes != value) {
307                                         check_boxes = value;
308                                         this.Redraw (true);
309                                 }
310                         }
311                 }
312
313                 [Browsable (false)]
314                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
315                 public CheckedIndexCollection CheckedIndices {
316                         get { return checked_indices; }
317                 }
318
319                 [Browsable (false)]
320                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
321                 public CheckedListViewItemCollection CheckedItems {
322                         get { return checked_items; }
323                 }
324
325                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
326                 [Localizable (true)]
327                 [MergableProperty (false)]
328                 public ColumnHeaderCollection Columns {
329                         get { return columns; }
330                 }
331
332                 [Browsable (false)]
333                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
334                 public ListViewItem FocusedItem {
335                         get { return focused_item; }
336                 }
337
338                 public override Color ForeColor {
339                         get {
340                                 if (foreground_color.IsEmpty)
341                                         return ThemeEngine.Current.ColorWindowText;
342                                 else
343                                         return foreground_color;
344                         }
345                         set { foreground_color = value; }
346                 }
347
348                 [DefaultValue (false)]
349                 public bool FullRowSelect {
350                         get { return full_row_select; }
351                         set { full_row_select = value; }
352                 }
353
354                 [DefaultValue (false)]
355                 public bool GridLines {
356                         get { return grid_lines; }
357                         set {
358                                 if (grid_lines != value) {
359                                         grid_lines = value;
360                                         this.Redraw (false);
361                                 }
362                         }
363                 }
364
365                 [DefaultValue (ColumnHeaderStyle.Clickable)]
366                 public ColumnHeaderStyle HeaderStyle {
367                         get { return header_style; }
368                         set {
369                                 if (value != ColumnHeaderStyle.Clickable && value != ColumnHeaderStyle.Nonclickable  && 
370                                         value != ColumnHeaderStyle.None) {
371                                         throw new InvalidEnumArgumentException (string.Format 
372                                                 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
373                                 }
374                                 
375                                 if (header_style != value) {
376                                         header_style = value;
377                                         // header style matters only in Details view
378                                         if (this.view == View.Details)
379                                                 this.Redraw (false);
380                                 }
381                         }
382                 }
383
384                 [DefaultValue (true)]
385                 public bool HideSelection {
386                         get { return hide_selection; }
387                         set {
388                                 if (hide_selection != value) {
389                                         hide_selection = value;
390                                         this.Redraw (false);
391                                 }
392                         }
393                 }
394
395                 [DefaultValue (false)]
396                 public bool HoverSelection {
397                         get { return hover_selection; }
398                         set { hover_selection = value; }
399                 }
400
401                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
402                 [Localizable (true)]
403                 [MergableProperty (false)]              
404                 public ListViewItemCollection Items {
405                         get { return items; }
406                 }
407
408                 [DefaultValue (false)]
409                 public bool LabelEdit {
410                         get { return label_edit; }
411                         set { label_edit = value; }
412                 }
413
414                 [DefaultValue (true)]
415                 [Localizable (true)]
416                 public bool LabelWrap {
417                         get { return label_wrap; }
418                         set {
419                                 if (label_wrap != value) {
420                                         label_wrap = value;
421                                         this.Redraw (true);
422                                 }
423                         }
424                 }
425
426                 [DefaultValue (null)]
427                 public ImageList LargeImageList {
428                         get { return large_image_list; }
429                         set {
430                                 large_image_list = value;
431                                 this.Redraw (true);
432                         }
433                 }
434
435                 [Browsable (false)]
436                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
437                 public IComparer ListViewItemSorter {
438                         get { return item_sorter; }
439                         set { item_sorter = value; }
440                 }
441
442                 [DefaultValue (true)]
443                 public bool MultiSelect {
444                         get { return multiselect; }
445                         set { multiselect = value; }
446                 }
447
448                 [DefaultValue (true)]
449                 public bool Scrollable {
450                         get { return scrollable; }
451                         set {
452                                 if (scrollable != value) {
453                                         scrollable = value;
454                                         this.Redraw (true);
455                                 }
456                         }
457                 }
458
459                 [Browsable (false)]
460                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
461                 public SelectedIndexCollection SelectedIndices {
462                         get { return selected_indices; }
463                 }
464
465                 [Browsable (false)]
466                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
467                 public SelectedListViewItemCollection SelectedItems {
468                         get { return selected_items; }
469                 }
470
471                 [DefaultValue (null)]
472                 public ImageList SmallImageList {
473                         get { return small_image_list; }
474                         set {
475                                 small_image_list = value;
476                                 this.Redraw (true);
477                         }
478                 }
479
480                 [DefaultValue (SortOrder.None)]
481                 public SortOrder Sorting {
482                         get { return sort_order; }
483                         set { 
484                                 if (value != SortOrder.Ascending && value != SortOrder.Descending  && 
485                                         value != SortOrder.None) {
486                                         throw new InvalidEnumArgumentException (string.Format
487                                                 ("Enum argument value '{0}' is not valid for Sorting", value));
488                                 }
489                                 
490                                 if (sort_order != value)  {                     
491                                         sort_order = value; 
492                                         this.Redraw (false);
493                                 }
494                         }
495                 }
496
497                 [DefaultValue (null)]
498                 public ImageList StateImageList {
499                         get { return state_image_list; }
500                         set {
501                                 state_image_list = value;
502                                 this.Redraw (true);
503                         }
504                 }
505
506                 [Bindable (false)]
507                 [Browsable (false)]
508                 [EditorBrowsable (EditorBrowsableState.Never)]
509                 public override string Text {
510                         get { return text; } 
511                         set {
512                                 if (value == text)
513                                         return;
514
515                                 text = value;
516                                 this.Redraw (true);
517
518                                 if (TextChanged != null)
519                                         TextChanged (this, new EventArgs ());
520                         }
521                 }
522
523                 [Browsable (false)]
524                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
525                 public ListViewItem TopItem {
526                         get {
527                                 // there is no item
528                                 if (this.items.Count == 0)
529                                         return null;
530                                 // if contents are not scrolled
531                                 // it is the first item
532                                 else if (h_marker == 0 && v_marker == 0)
533                                         return this.items [0];
534                                 // do a hit test for the scrolled position
535                                 else {
536                                         foreach (ListViewItem item in this.items) {
537                                                 if (item.EntireRect.Contains (h_marker, v_marker))
538                                                         return item;
539                                         }
540                                         return null;
541                                 }
542                         }
543                 }
544
545                 [DefaultValue (View.LargeIcon)]
546                 public View View {
547                         get { return view; }
548                         set { 
549                                 if (value != View.Details && value != View.LargeIcon  && 
550                                         value != View.List  && value != View.SmallIcon  ) {
551                                         throw new InvalidEnumArgumentException (string.Format
552                                                 ("Enum argument value '{0}' is not valid for View", value));
553                                 }
554                                 
555                                 if (view != value) {
556                                         view = value; 
557                                         Redraw (true);
558                                 }
559                         }
560                 }
561                 #endregion      // Public Instance Properties
562
563                 #region Internal Methods Properties
564                 internal int TotalWidth {
565                         get { return Math.Max (this.Width, this.layout_wd); }
566                 }
567
568                 internal int TotalHeight {
569                         get { return Math.Max (this.Height, this.layout_ht); }
570                 }
571
572                 internal void Redraw (bool recalculate)
573                 {
574                         // Avoid calculations when control is being updated
575                         if (this.updating)
576                                 return;
577
578                         if (recalculate)
579                                 CalculateListView (this.alignment);
580
581                         Refresh ();
582                 }
583
584                 internal Size GetChildColumnSize (int index)
585                 {
586                         Size ret_size = Size.Empty;
587                         ColumnHeader col = this.columns [index];
588
589                         if (col.Width == -2) { // autosize = max(items, columnheader)
590                                 Size size = Size.Ceiling (this.DeviceContext.MeasureString
591                                                           (col.Text, this.Font));
592                                 ret_size = BiggestItem (index);
593                                 if (size.Width > ret_size.Width)
594                                         ret_size = size;
595                         }
596                         else { // -1 and all the values < -2 are put under one category
597                                 ret_size = BiggestItem (index);
598                                 // fall back to empty columns' width if no subitem is available for a column
599                                 if (ret_size.IsEmpty) {
600                                         ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth;
601                                         if (col.Text.Length > 0)
602                                                 ret_size.Height = Size.Ceiling (this.DeviceContext.MeasureString
603                                                                                 (col.Text, this.Font)).Height;
604                                         else
605                                                 ret_size.Height = this.Font.Height;
606                                 }
607                         }
608
609                         // adjust the size for icon and checkbox for 0th column
610                         if (index == 0) {
611                                 ret_size.Width += (this.CheckBoxSize.Width + 4);
612                                 if (this.small_image_list != null)
613                                         ret_size.Width += this.small_image_list.ImageSize.Width;
614                         }
615                         return ret_size;
616                 }
617
618                 // Returns the size of biggest item text in a column.
619                 private Size BiggestItem (int col)
620                 {
621                         Size temp = Size.Empty;
622                         Size ret_size = Size.Empty;
623
624                         // 0th column holds the item text, we check the size of
625                         // the various subitems falling in that column and get
626                         // the biggest one's size.
627                         foreach (ListViewItem item in items) {
628                                 if (col >= item.SubItems.Count)
629                                         continue;
630
631                                 temp = Size.Ceiling (this.DeviceContext.MeasureString
632                                                      (item.SubItems [col].Text, this.Font));
633                                 if (temp.Width > ret_size.Width)
634                                         ret_size = temp;
635                         }
636
637                         // adjustment for space
638                         if (!ret_size.IsEmpty)
639                                 ret_size.Width += 4;
640
641                         return ret_size;
642                 }
643
644                 // Sets the size of the biggest item text as per the view
645                 private void CalcTextSize ()
646                 {                       
647                         // clear the old value
648                         text_size = Size.Empty;
649
650                         if (items.Count == 0)
651                                 return;
652
653                         text_size = BiggestItem (0);
654
655                         if (view == View.LargeIcon && this.label_wrap) {
656                                 Size temp = Size.Empty;
657                                 if (this.check_boxes)
658                                         temp.Width += 2 * this.CheckBoxSize.Width;
659                                 if (large_image_list != null)
660                                         temp.Width += large_image_list.ImageSize.Width;
661                                 if (temp.Width == 0)
662                                         temp.Width = 43;
663                                 // wrapping is done for two lines only
664                                 if (text_size.Width > temp.Width) {
665                                         text_size.Width = temp.Width;
666                                         text_size.Height *= 2;
667                                 }
668                         }
669                         else if (view == View.List) {
670                                 // in list view max text shown in determined by the
671                                 // control width, even if scolling is enabled.
672                                 int max_wd = this.Width - (this.CheckBoxSize.Width - 2);
673                                 if (this.small_image_list != null)
674                                         max_wd -= this.small_image_list.ImageSize.Width;
675
676                                 if (text_size.Width > max_wd)
677                                         text_size.Width = max_wd;
678                         }
679
680                         // we do the default settings, if we have got 0's
681                         if (text_size.Height <= 0)
682                                 text_size.Height = this.Font.Height;
683                         if (text_size.Width <= 0)
684                                 text_size.Width = this.Width;
685
686                         // little adjustment
687                         text_size.Width += 4;
688                         text_size.Height += 2;
689                 }
690
691                 private void CalculateScrollBars ()
692                 {
693                         if (!this.scrollable || this.items.Count <= 0) {
694                                 h_scroll.Visible = false;
695                                 v_scroll.Visible = false;
696                                 return;
697                         }
698
699                         // making a scroll bar visible might make
700                         // other scroll bar visible
701                         if (layout_wd > this.Width) {
702                                 h_scroll.Visible = true;
703                                 if ((layout_ht + h_scroll.Height) > Height)
704                                         v_scroll.Visible = true;
705                         } else if (layout_ht > Height) {
706                                 v_scroll.Visible = true;
707                                 if ((layout_wd + v_scroll.Width) > Width)
708                                         h_scroll.Visible = true;
709                         }
710
711                         if (h_scroll.Visible) {
712                                 h_scroll.Location = new Point (0, Height - h_scroll.Height);
713                                 h_scroll.Minimum = 0;
714
715                                 // if v_scroll is visible, adjust the maximum of the
716                                 // h_scroll to account for the width of v_scroll
717                                 if (v_scroll.Visible) {
718                                         h_scroll.Maximum = layout_wd + v_scroll.Width;
719                                         h_scroll.Width = Width - v_scroll.Width;
720                                 }
721                                 else {
722                                         h_scroll.Maximum = layout_wd;
723                                         h_scroll.Width = Width;
724                                 }
725    
726                                 h_scroll.LargeChange = Width;
727                                 h_scroll.SmallChange = Font.Height;
728                         }
729
730                         // vertical scrollbar
731                         if (v_scroll.Visible) {
732                                 v_scroll.Location = new Point (Width - v_scroll.Width, 0);
733                                 v_scroll.Minimum = 0;
734
735                                 // if h_scroll is visible, adjust the maximum of the
736                                 // v_scroll to account for the height of h_scroll
737                                 if (h_scroll.Visible) {
738                                         v_scroll.Maximum = layout_ht + h_scroll.Height;
739                                         v_scroll.Height = Height - h_scroll.Height;
740                                 } else {
741                                         v_scroll.Maximum = layout_ht;
742                                         v_scroll.Height = Height;
743                                 }
744
745                                 v_scroll.LargeChange = Height;
746                                 v_scroll.SmallChange = Font.Height;
747                         }
748                 }
749
750                 // Sets the location of every item on
751                 // the ListView as per the view
752                 private void CalculateListView (ListViewAlignment align)
753                 {
754                         int current_pos_x = 0; // our x-position marker
755                         int current_pos_y = 0; // our y-position marker
756                         int item_ht;
757                         int item_wd;
758                         int max;         // max x_pos or y_pos depending on the alignment
759                         int current = 0; // current row or column
760                         int vertical_spacing = ThemeEngine.Current.ListViewVerticalSpacing;
761                         int horizontal_spacing = ThemeEngine.Current.ListViewHorizontalSpacing;
762
763                         CalcTextSize ();
764
765                         switch (view) {
766
767                         case View.Details:
768                                 // ColumnHeaders are not drawn if headerstyle is none
769                                 int ht = (this.header_style == ColumnHeaderStyle.None) ? 
770                                         2 : this.Font.Height + 5;
771                                 if (columns.Count > 0) {
772                                         foreach (ColumnHeader col in columns) {
773                                                 col.X = current_pos_x;
774                                                 col.Y = 0;
775                                                 col.CalcColumnHeader ();
776                                                 current_pos_x += col.Wd;
777                                         }
778                                         this.layout_wd = current_pos_x;
779                                 }
780                                 // set the position marker for placing items
781                                 // vertically down
782                                 current_pos_y = ht;
783
784                                 if (items.Count > 0) {
785                                         foreach (ListViewItem item in items) {
786                                                 item.location.X = 0;
787                                                 item.location.Y = current_pos_y;
788                                                 item.CalcListViewItem ();
789                                                 current_pos_y += item.EntireRect.Height;
790                                         }
791                                         this.layout_ht = current_pos_y;
792
793                                         // some space for bottom gridline
794                                         if (this.grid_lines)
795                                                 this.layout_ht += 2;
796                                 }
797                                 break;
798
799                         case View.SmallIcon:
800                                 vertical_spacing = 0;
801                                 horizontal_spacing = 0;
802                                 goto case View.LargeIcon;
803
804                         case View.LargeIcon:
805                                 if (items.Count > 0) {
806                                         items [0].CalcListViewItem ();
807                                         item_ht = items [0].EntireRect.Height;
808                                         item_wd = items [0].EntireRect.Width;
809
810                                         // top (default) and snaptogrid alignments are handled same way
811                                         if (align == ListViewAlignment.Left) {
812                                                 max = this.Height;
813                                                 foreach (ListViewItem item in items) {
814                                                         item.location.X = current_pos_x +
815                                                                 horizontal_spacing;
816                                                         item.location.Y = current_pos_y;
817                                                         item.CalcListViewItem ();
818                                                         current_pos_y += item_ht;
819
820                                                         current ++; // just to know about the last element
821                                                         // we just did the last item
822                                                         if (current == items.Count) {
823                                                                 if (max < current_pos_y)
824                                                                         max = current_pos_y;
825                                                                 current_pos_x = item.EntireRect.Right;
826                                                                 break;
827                                                         }
828                                                         else {
829                                                                 // is there enough space for another row ?
830                                                                 if ((current_pos_y + vertical_spacing
831                                                                      + item_ht) <= this.Height)
832                                                                         current_pos_y += vertical_spacing;
833                                                                 else {
834                                                                         // start another column
835                                                                         // make current_pos_y as the
836                                                                         // max value and reset
837                                                                         // current_pos_y value.
838                                                                         max = current_pos_y;
839                                                                         current_pos_x += item_wd;
840                                                                         current_pos_y = 0;
841                                                                 }
842                                                         }
843                                                 }
844                                                 // adjust the layout dimensions
845                                                 this.layout_ht = max;
846                                                 this.layout_wd = current_pos_x;
847                                         }
848                                         else { // other default/top alignment
849                                                 max = this.Width;
850                                                 foreach (ListViewItem item in items) {
851                                                         item.location.X = current_pos_x +
852                                                                 horizontal_spacing;
853
854                                                         item.location.Y = current_pos_y;
855                                                         item.CalcListViewItem ();
856                                                         current_pos_x += item_wd;
857
858                                                         current ++; // just to know about the last element
859                                                         // we just did the last item
860                                                         if (current == items.Count) {
861                                                                 if (max < current_pos_x)
862                                                                         max = current_pos_x;
863                                                                 current_pos_y = item.EntireRect.Bottom;
864                                                                 break;
865                                                         }
866                                                         else {
867                                                                 // is there enough space for another column?
868                                                                 if ((current_pos_x + horizontal_spacing
869                                                                      + item_wd) <= this.Width)
870                                                                         continue;
871                                                                 else {
872                                                                         // start another row
873                                                                         // make current_pos_x as the
874                                                                         // max value and reset
875                                                                         // current_pos_x value.
876                                                                         max = current_pos_x;
877                                                                         current_pos_y += (item_ht +
878                                                                                           vertical_spacing);
879                                                                         current_pos_x = 0;
880                                                                 }
881                                                         }
882                                                 }
883                                                 // adjust the layout dimensions
884                                                 this.layout_wd = max;
885                                                 this.layout_ht = current_pos_y;
886                                         }
887                                 }
888                                 break;
889
890                         case View.List:
891                                 if (items.Count > 0) {
892                                         items [0].CalcListViewItem ();
893                                         item_ht = items [0].EntireRect.Height;
894                                         item_wd = items [0].EntireRect.Width;
895
896                                         max = this.Height / item_ht;
897                                         if (max == 0)
898                                                 max = 1; // we draw at least one row
899
900                                         foreach (ListViewItem item in items) {
901                                                 item.location.X = current_pos_x;
902                                                 item.location.Y = current_pos_y;
903                                                 item.CalcListViewItem ();
904                                                 current ++;
905                                                 if (current == max) {
906                                                         current_pos_x += item_wd;
907                                                         current_pos_y = 0;
908                                                         current = 0;
909                                                 }
910                                                 else
911                                                         current_pos_y += item_ht;
912                                         }
913
914                                         // adjust the layout dimensions
915                                         this.layout_ht = max * item_ht;
916                                         if (current == 0) // we have fully filled layout
917                                                 this.layout_wd = current_pos_x;
918                                         else
919                                                 this.layout_wd = current_pos_x + item_wd;
920                                 }
921                                 break;
922                         }
923
924                         CalculateScrollBars ();
925                 }               
926                 
927
928                 // Event Handlers
929                 private void ListView_DoubleClick (object sender, EventArgs e)
930                 {
931                         if (this.activation == ItemActivation.Standard
932                             && this.ItemActivate != null)
933                                 this.ItemActivate (this, e);
934                 }
935
936                 private void ListView_KeyDown (object sender, KeyEventArgs ke)
937                 {
938                         int index = -1;
939                         if (ke.Handled)
940                                 return;
941
942                         ke.Handled = true;
943
944                         switch (ke.KeyCode) {
945
946                         case Keys.ControlKey:
947                                 this.ctrl_pressed = true;
948                                 break;
949
950                         case Keys.Down:                         
951                                 // FIXME:TODO
952                                 break;
953
954                         case Keys.End:
955                                 this.v_scroll.Value = this.v_scroll.Maximum;
956                                 break;
957
958                         case Keys.Home:
959                                 this.v_scroll.Value = this.v_scroll.Minimum;
960                                 break;
961
962                         case Keys.Left:
963                                 index = -1;
964                                 if (this.last_clicked_item != null)
965                                         index = this.last_clicked_item.Index;
966                                 else
967                                         break;
968
969                                 if (index > 0)
970                                         index -= 1;
971
972                                 this.last_clicked_item = this.items [index];
973                                 this.last_clicked_item.Selected = true;
974                                 this.EnsureVisible (index);
975                                 break;
976
977                         case Keys.Right:
978                                 if (this.last_clicked_item != null)
979                                         index = this.last_clicked_item.Index + 1;
980                                 else
981                                         index = 1;
982
983                                 if (index == this.items.Count)
984                                         break;
985
986                                 this.last_clicked_item = this.items [index];
987                                 this.last_clicked_item.Selected = true;
988                                 this.EnsureVisible (index);
989                                 break;
990
991                         case Keys.ShiftKey:
992                                 this.shift_pressed = true;
993                                 break;
994
995                         case Keys.Up:                           
996                                 // FIXME:TODO
997                                 break;
998
999                         default:
1000                                 ke.Handled = false;
1001                                 break;
1002                         }
1003                 }
1004
1005                 private void ListView_KeyUp (object sender, KeyEventArgs ke)
1006                 {
1007                         if (!ke.Handled) {
1008                                 if (ke.KeyCode == Keys.ControlKey)
1009                                         this.ctrl_pressed = false;
1010
1011                                 if (ke.KeyCode == Keys.ShiftKey)
1012                                         this.shift_pressed = false;
1013                                 ke.Handled = true;
1014                         }
1015                 }
1016
1017                 private void ListView_MouseDown (object sender, MouseEventArgs me)
1018                 {
1019                         if (items.Count == 0)
1020                                 return;
1021
1022                         Point hit = Point.Empty;
1023                         if (this.HeaderStyle != ColumnHeaderStyle.None) {
1024                                 // take horizontal scrolling into account
1025                                 hit = new Point (me.X + h_marker, me.Y);
1026
1027                                 // hit test on columns
1028                                 if (this.view == View.Details && this.columns.Count > 0) {
1029                                         foreach (ColumnHeader col in this.columns) {
1030                                                 if (col.Rect.Contains (hit)) {
1031                                                         this.clicked_column = col;
1032                                                         this.Capture = true;
1033                                                         break;
1034                                                 }
1035                                         }
1036
1037                                         if (this.clicked_column != null) {
1038                                                 this.clicked_column.pressed = true;
1039                                                 this.draw_headers = true;
1040                                                 this.Redraw (false);
1041                                                 return;
1042                                         }
1043                                 }
1044                         }
1045
1046                         // hit test on items
1047                         // we need to take scrolling into account
1048                         hit = new Point (me.X + h_marker, me.Y + v_marker);
1049                         foreach (ListViewItem item in this.items) {
1050                                 if (item.CheckRect.Contains (hit)) {
1051                                         CheckState curr_state = item.Checked ?
1052                                                 CheckState.Checked : CheckState.Unchecked;
1053                                         if (item.Checked)
1054                                                 item.Checked = false;
1055                                         else
1056                                                 item.Checked = true;
1057
1058                                         CheckState new_state = item.Checked ?
1059                                                 CheckState.Checked : CheckState.Unchecked;
1060                                         this.Redraw (false);
1061
1062                                         // Raise the ItemCheck event
1063                                         ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index,
1064                                                                                          curr_state,
1065                                                                                          new_state);
1066                                         this.OnItemCheck (ice);
1067                                         break;
1068                                 }
1069
1070                                 if (this.view == View.Details &&
1071                                     this.FullRowSelect == false) {
1072                                         if (item.LabelRect.Contains (hit)) {
1073                                                 this.clicked_item = item;
1074                                                 break;
1075                                         }
1076                                 }
1077                                 else {
1078                                         if (item.EntireRect.Contains (hit)) {
1079                                                 this.clicked_item = item;
1080                                                 break;
1081                                         }
1082                                 }
1083                         }
1084                         
1085                         // set the FocusedItem to be the current clicked_item
1086                         this.focused_item = this.clicked_item;
1087
1088                         if (this.clicked_item != null) {
1089                                 this.clicked_item.Selected = true;
1090                                 // Raise the event
1091                                 this.OnSelectedIndexChanged (new EventArgs ());
1092
1093                                 this.Redraw (false);
1094                         }               
1095                 }
1096
1097                 private void ListView_MouseHover (object sender, EventArgs e)
1098                 {
1099                         // handle the hover events only when the mouse
1100                         // is not captured.
1101                         if (this.hover_selection == false || this.Capture)
1102                                 return;
1103
1104                         // hit test for the items
1105                         Point hit = this.PointToClient (Control.MousePosition);
1106                         ListViewItem item = this.GetItemAt (hit.X, hit.Y);
1107
1108                         if (item != null) {
1109                                 item.Selected = true;
1110                                 // Raise the event
1111                                 this.OnSelectedIndexChanged (new EventArgs ());
1112
1113                                 this.Redraw (false);
1114                         }
1115                 }
1116
1117                 private void ListView_MouseMove (object sender, MouseEventArgs me)
1118                 {
1119                         // Column header is always at the top. It can
1120                         // scroll only horizontally. So, we have to take
1121                         // only horizontal scrolling into account
1122                         Point hit = new Point (me.X + h_marker, me.Y);
1123
1124                         // non-null clicked_col means mouse down has happened
1125                         // on a column
1126                         if (this.clicked_column != null) {
1127                                 if (this.clicked_column.pressed == false &&
1128                                     this.clicked_column.Rect.Contains (hit)) {
1129                                         this.clicked_column.pressed = true;
1130                                         this.draw_headers = true;
1131                                         this.Redraw (false);
1132                                 }
1133                                 else if (this.clicked_column.pressed && 
1134                                          ! this.clicked_column.Rect.Contains (hit)) {
1135                                         this.clicked_column.pressed = false;
1136                                         this.draw_headers = true;
1137                                         this.Redraw (false);
1138                                 }
1139                         }
1140                 }
1141
1142                 private void ListView_MouseUp (object sender, MouseEventArgs me)
1143                 {
1144                         this.Capture = false;
1145                         if (items.Count == 0)
1146                                 return;
1147
1148                         Point hit = new Point (me.X, me.Y);
1149
1150                         if (this.clicked_column != null) {
1151                                 if (this.clicked_column.pressed) {
1152                                         this.clicked_column.pressed = false;
1153                                         this.draw_headers = true;
1154                                         this.Redraw (false);
1155
1156                                         // Raise the ColumnClick event
1157                                         this.OnColumnClick (new ColumnClickEventArgs
1158                                                             (this.clicked_column.Index));
1159                                 }
1160                         }
1161
1162                         // Raise the ItemActivate event
1163                         Rectangle rect = Rectangle.Empty;
1164                         if (this.clicked_item != null) {
1165                                 if (this.view == View.Details && !this.full_row_select)
1166                                         rect = this.clicked_item.LabelRect;
1167                                 else
1168                                         rect = this.clicked_item.EntireRect;
1169
1170                                 // We handle double click in a separate handler
1171                                 if (this.activation != ItemActivation.Standard &&
1172                                     rect.Contains (hit)) {
1173                                         if (this.activation == ItemActivation.OneClick)
1174                                                 this.ItemActivate (this, EventArgs.Empty);
1175
1176                                         // ItemActivate is raised on the second click on the same item
1177                                         else if (this.activation == ItemActivation.TwoClick) {
1178                                                 if (this.last_clicked_item == this.clicked_item) {
1179                                                         this.ItemActivate (this, EventArgs.Empty);
1180                                                         this.last_clicked_item = null;
1181                                                 }
1182                                                 else
1183                                                         this.last_clicked_item = this.clicked_item;
1184                                         }
1185                                 }
1186                         }
1187
1188                         this.clicked_column = null;
1189                         this.clicked_item = null;
1190                 }
1191
1192                 private void ListView_Paint (object sender, PaintEventArgs pe)
1193                 {
1194                         if (this.Width <= 0 || this.Height <=  0 ||
1195                             this.Visible == false || this.updating == true)
1196                                 return;
1197
1198                         CalculateScrollBars ();
1199
1200                         ThemeEngine.Current.DrawListView (pe.Graphics,
1201                                         pe.ClipRectangle, this);
1202
1203                         // We paint on the screen as per the location set
1204                         // by the two scrollbars. In case of details view
1205                         // since column headers can scroll only horizontally
1206                         // and items can scroll in both directions, paiting is
1207                         // done separtely for the column header and the items.
1208
1209                         Rectangle srcRect = this.ClientRectangle;
1210                         Rectangle dstRect = this.ClientRectangle;
1211
1212                         // set the visible starting point
1213                         if (scrollable) {
1214                                 srcRect.X += h_marker;
1215                                 srcRect.Y += v_marker;
1216
1217                                 if (h_scroll.Visible) {
1218                                         srcRect.Height -= h_scroll.Height;
1219                                         dstRect.Height -= h_scroll.Height;
1220                                 }
1221
1222                                 if (v_scroll.Visible) {
1223                                         srcRect.Width -= v_scroll.Width;
1224                                         dstRect.Width -= v_scroll.Width;
1225                                 }
1226                         }
1227
1228                         // We paint the column headers always at the top, in case
1229                         // of vertical scrolling. Therefore, we advance the painting
1230                         // by the amount equal to the column height.
1231                         /*
1232                         if (this.view == View.Details &&
1233                             this.Columns.Count > 0 &&
1234                             this.header_style != ColumnHeaderStyle.None &&
1235                             v_marker > 0 ) {
1236
1237                                 int col_ht = this.Columns [0].Ht;
1238
1239                                 if (this.draw_headers) {
1240                                         this.draw_headers = false;
1241                                         // Move the source rect by the amount of horizontal
1242                                         // scrolling done so far.
1243                                         Rectangle headerSrc = new Rectangle (h_marker, 0,
1244                                                                              srcRect.Width, col_ht);
1245                                         // dest rect is always stable at 0,0
1246                                         Rectangle headerDst = new Rectangle (0, 0, srcRect.Width, col_ht);
1247                                         pe.Graphics.DrawImage (this.ImageBuffer, headerDst,
1248                                                                headerSrc, GraphicsUnit.Pixel);
1249                                 }
1250
1251                                 dstRect.Y += col_ht;
1252                                 srcRect.Y += col_ht;
1253                         }
1254                         */
1255                         
1256                         // Draw the border of the list view
1257                         // The border is painted here separately, because
1258                         // our imagebuffer might be scrollable
1259                         ThemeEngine.Current.CPDrawBorderStyle (pe.Graphics,
1260                                                                this.ClientRectangle,
1261                                                                this.BorderStyle);
1262
1263                         // Raise the Paint event
1264                         if (Paint != null)
1265                                 Paint (this, pe);
1266                 }
1267
1268                 private void ListView_SizeChanged (object sender, EventArgs e)
1269                 {
1270                         CalculateScrollBars ();
1271                 }
1272
1273                 private void HorizontalScroller (object sender, EventArgs e)
1274                 {
1275                         // Avoid unnecessary flickering, when button is
1276                         // kept pressed at the end
1277                         if (h_marker != h_scroll.Value) {
1278                                 h_marker = h_scroll.Value;
1279                                 // draw the headers again
1280                                 this.draw_headers = true;
1281                                 this.Refresh ();
1282                         }
1283                 }
1284
1285                 private void VerticalScroller (object sender, EventArgs e)
1286                 {
1287                         // Avoid unnecessary flickering, when button is
1288                         // kept pressed at the end
1289                         if (v_marker != v_scroll.Value) {
1290                                 v_marker = v_scroll.Value;
1291                                 this.Refresh ();
1292                         }
1293                 }
1294                 #endregion      // Internal Methods Properties
1295
1296                 #region Protected Methods
1297                 protected override void CreateHandle ()
1298                 {
1299                         base.CreateHandle ();
1300                 }
1301
1302                 protected override void Dispose (bool disposing)
1303                 {
1304                         base.Dispose (disposing);
1305                 }
1306
1307                 protected override bool IsInputKey (Keys keyData)
1308                 {
1309                         return base.IsInputKey (keyData);
1310                 }
1311
1312                 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
1313                 {
1314                         if (AfterLabelEdit != null)
1315                                 AfterLabelEdit (this, e);
1316                 }
1317
1318                 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
1319                 {
1320                         if (BeforeLabelEdit != null)
1321                                 BeforeLabelEdit (this, e);
1322                 }
1323
1324                 protected virtual void OnColumnClick (ColumnClickEventArgs e)
1325                 {
1326                         if (ColumnClick != null)
1327                                 ColumnClick (this, e);
1328                 }
1329
1330                 protected override void OnEnabledChanged (EventArgs e)
1331                 {
1332                         base.OnEnabledChanged (e);
1333                 }
1334
1335                 protected override void OnFontChanged (EventArgs e)
1336                 {
1337                         base.OnFontChanged (e);
1338                         Redraw (true);
1339                 }
1340
1341                 protected override void OnHandleCreated (EventArgs e)
1342                 {
1343                         base.OnHandleCreated (e);
1344                         SuspendLayout ();
1345                         Controls.AddImplicit (this.v_scroll);
1346                         Controls.AddImplicit (this.h_scroll);
1347                         ResumeLayout ();
1348                 }
1349
1350                 protected override void OnHandleDestroyed (EventArgs e)
1351                 {
1352                         base.OnHandleDestroyed (e);
1353                 }
1354
1355                 protected virtual void OnItemActivate (EventArgs e)
1356                 {
1357                         if (ItemActivate != null)
1358                                 ItemActivate (this, e);
1359                 }
1360
1361                 protected virtual void OnItemCheck (ItemCheckEventArgs ice)
1362                 {
1363                         if (ItemCheck != null)
1364                                 ItemCheck (this, ice);
1365                 }
1366
1367                 protected virtual void OnItemDrag (ItemDragEventArgs e)
1368                 {
1369                         if (ItemDrag != null)
1370                                 ItemDrag (this, e);
1371                 }
1372
1373                 protected virtual void OnSelectedIndexChanged (EventArgs e)
1374                 {
1375                         if (SelectedIndexChanged != null)
1376                                 SelectedIndexChanged (this, e);
1377                 }
1378
1379                 protected override void OnSystemColorsChanged (EventArgs e)
1380                 {
1381                         base.OnSystemColorsChanged (e);
1382                 }
1383
1384                 protected void RealizeProperties ()
1385                 {
1386                         // FIXME: TODO
1387                 }
1388
1389                 protected void UpdateExtendedStyles ()
1390                 {
1391                         // FIXME: TODO
1392                 }
1393
1394                 protected override void WndProc (ref Message m)
1395                 {
1396                         base.WndProc (ref m);
1397                 }
1398                 #endregion // Protected Methods
1399
1400                 #region Public Instance Methods
1401                 public void ArrangeIcons ()
1402                 {
1403                         ArrangeIcons (this.alignment);
1404                 }
1405
1406                 public void ArrangeIcons (ListViewAlignment alignment)
1407                 {
1408                         // Icons are arranged only if view is set to LargeIcon or SmallIcon
1409                         if (view == View.LargeIcon || view == View.SmallIcon) {
1410                                 this.CalculateListView (alignment);
1411                                 // we have done the calculations already
1412                                 this.Redraw (false);
1413                         }
1414                 }
1415
1416                 public void BeginUpdate ()
1417                 {
1418                         // flag to avoid painting
1419                         updating = true;
1420                 }
1421
1422                 public void Clear ()
1423                 {
1424                         columns.Clear ();
1425                         items.Clear ();
1426                         this.Redraw (true);
1427                 }
1428
1429                 public void EndUpdate ()
1430                 {
1431                         // flag to avoid painting
1432                         updating = false;
1433
1434                         // probably, now we need a redraw with recalculations
1435                         this.Redraw (true);
1436                 }
1437
1438                 public void EnsureVisible (int index)
1439                 {
1440                         if (index < 0 || index >= this.items.Count || this.scrollable == false)
1441                                 return;
1442
1443                         // dimensions of visible area
1444                         int view_wd = this.Width - (this.v_scroll.Visible ? this.v_scroll.Width : 0);
1445                         int view_ht = this.Height - (this.h_scroll.Visible ? this.h_scroll.Height : 0);
1446                         // visible area is decided by the h_marker and v_marker
1447                         Rectangle view_rect = new Rectangle (h_marker, v_marker, view_wd, view_ht);
1448
1449                         // an item's bounding rect
1450                         Rectangle rect = this.items [index].EntireRect;
1451
1452                         // we don't need to do anything if item is visible.
1453                         // visible area is represented by (0,0,view_wd,view_ht)
1454                         if (view_rect.Contains (rect))
1455                                 return;
1456
1457                         // Scroll Left or Up
1458                         if ((rect.Left < view_rect.Left) || (rect.Top < view_rect.Top)) {
1459                                 if (rect.Left < view_rect.Left)
1460                                         this.h_scroll.Value -= (view_rect.Left - rect.Left);
1461                                 if (rect.Top < view_rect.Top)
1462                                         this.v_scroll.Value -= (view_rect.Top - rect.Top);
1463                         }
1464                         // Scroll Right or Down
1465                         else {
1466                                 if (rect.Right > view_rect.Right)
1467                                         this.h_scroll.Value += (rect.Right - view_rect.Right);
1468                                 if (rect.Bottom > view_rect.Bottom)
1469                                         this.v_scroll.Value += (rect.Bottom - view_rect.Bottom);
1470                         }
1471                 }
1472                 
1473                 public ListViewItem GetItemAt (int x, int y)
1474                 {
1475                         foreach (ListViewItem item in items) {
1476                                 if (item.Bounds.Contains (x, y))
1477                                         return item;
1478                         }
1479                         return null;
1480                 }
1481
1482                 public Rectangle GetItemRect (int index)
1483                 {
1484                         return GetItemRect (index, ItemBoundsPortion.Entire);
1485                 }
1486
1487                 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
1488                 {
1489                         if (index < 0 || index >= items.Count)
1490                                 throw new IndexOutOfRangeException ("Invalid Index");
1491
1492                         return items [index].GetBounds (portion);
1493                 }
1494
1495                 public void Sort ()
1496                 {
1497                         if (sort_order != SortOrder.None)
1498                                 items.list.Sort (item_sorter);
1499
1500                         if (sort_order == SortOrder.Descending)
1501                                 items.list.Reverse ();
1502
1503                         this.Redraw (true);
1504                 }
1505
1506                 public override string ToString ()
1507                 {
1508                         int count = this.Items.Count;
1509
1510                         if (count == 0)
1511                                 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
1512                         else
1513                                 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
1514                 }
1515                 #endregion      // Public Instance Methods
1516
1517
1518                 #region Subclasses
1519                 public class CheckedIndexCollection : IList, ICollection, IEnumerable
1520                 {
1521                         internal ArrayList list;
1522                         private ListView owner;
1523
1524                         #region Public Constructor
1525                         public CheckedIndexCollection (ListView owner)
1526                         {
1527                                 list = new ArrayList ();
1528                                 this.owner = owner;
1529                         }
1530                         #endregion      // Public Constructor
1531
1532                         #region Public Properties
1533                         [Browsable (false)]
1534                         public virtual int Count {
1535                                 get { return list.Count; }
1536                         }
1537
1538                         public virtual bool IsReadOnly {
1539                                 get { return true; }
1540                         }
1541
1542                         public int this [int index] {
1543                                 get {
1544                                         if (index < 0 || index >= list.Count)
1545                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
1546                                         return (int) list [index];
1547                                 }
1548                         }
1549
1550                         bool ICollection.IsSynchronized {
1551                                 get { return list.IsSynchronized; }
1552                         }
1553
1554                         object ICollection.SyncRoot {
1555                                 get { return list.SyncRoot; }
1556                         }
1557
1558                         bool IList.IsFixedSize {
1559                                 get { return list.IsFixedSize; }
1560                         }
1561
1562                         object IList.this [int index] {
1563                                 get { return this [index]; }
1564                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
1565                         }
1566                         #endregion      // Public Properties
1567
1568                         #region Public Methods
1569                         public bool Contains (int checkedIndex)
1570                         {
1571                                 return list.Contains (checkedIndex);
1572                         }
1573
1574                         public virtual IEnumerator GetEnumerator ()
1575                         {
1576                                 return list.GetEnumerator ();
1577                         }
1578
1579                         void ICollection.CopyTo (Array dest, int index)
1580                         {
1581                                 list.CopyTo (dest, index);
1582                         }
1583
1584                         int IList.Add (object value)
1585                         {
1586                                 throw new NotSupportedException ("Add operation is not supported.");
1587                         }
1588
1589                         void IList.Clear ()
1590                         {
1591                                 throw new NotSupportedException ("Clear operation is not supported.");
1592                         }
1593
1594                         bool IList.Contains (object checkedIndex)
1595                         {
1596                                 return list.Contains (checkedIndex);
1597                         }
1598
1599                         int IList.IndexOf (object checkedIndex)
1600                         {
1601                                 return list.IndexOf (checkedIndex);
1602                         }
1603
1604                         void IList.Insert (int index, object value)
1605                         {
1606                                 throw new NotSupportedException ("Insert operation is not supported.");
1607                         }
1608
1609                         void IList.Remove (object value)
1610                         {
1611                                 throw new NotSupportedException ("Remove operation is not supported.");
1612                         }
1613
1614                         void IList.RemoveAt (int index)
1615                         {
1616                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
1617                         }
1618
1619                         public int IndexOf (int checkedIndex)
1620                         {
1621                                 return list.IndexOf (checkedIndex);
1622                         }
1623                         #endregion      // Public Methods
1624
1625                 }       // CheckedIndexCollection
1626
1627                 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
1628                 {
1629                         internal ArrayList list;
1630                         private ListView owner;
1631
1632                         #region Public Constructor
1633                         public CheckedListViewItemCollection (ListView owner)
1634                         {
1635                                 list = new ArrayList ();
1636                                 this.owner = owner;
1637                         }
1638                         #endregion      // Public Constructor
1639
1640                         #region Public Properties
1641                         [Browsable (false)]
1642                         public virtual int Count {
1643                                 get { return list.Count; }
1644                         }
1645
1646                         public virtual bool IsReadOnly {
1647                                 get { return true; }
1648                         }
1649
1650                         public ListViewItem this [int index] {
1651                                 get {
1652                                         if (index < 0 || index >= list.Count)
1653                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
1654                                         return (ListViewItem) list [index];
1655                                 }
1656                         }
1657
1658                         bool ICollection.IsSynchronized {
1659                                 get { return list.IsSynchronized; }
1660                         }
1661
1662                         object ICollection.SyncRoot {
1663                                 get { return list.SyncRoot; }
1664                         }
1665
1666                         bool IList.IsFixedSize {
1667                                 get { return list.IsFixedSize; }
1668                         }
1669
1670                         object IList.this [int index] {
1671                                 get { return this [index]; }
1672                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
1673                         }
1674                         #endregion      // Public Properties
1675
1676                         #region Public Methods
1677                         public bool Contains (ListViewItem item)
1678                         {
1679                                 return list.Contains (item);
1680                         }
1681
1682                         public virtual void CopyTo (Array dest, int index)
1683                         {
1684                                 list.CopyTo (dest, index);
1685                         }
1686
1687                         public virtual IEnumerator GetEnumerator ()
1688                         {
1689                                 return list.GetEnumerator ();
1690                         }
1691
1692                         int IList.Add (object value)
1693                         {
1694                                 throw new NotSupportedException ("Add operation is not supported.");
1695                         }
1696
1697                         void IList.Clear ()
1698                         {
1699                                 throw new NotSupportedException ("Clear operation is not supported.");
1700                         }
1701
1702                         bool IList.Contains (object item)
1703                         {
1704                                 return list.Contains (item);
1705                         }
1706
1707                         int IList.IndexOf (object item)
1708                         {
1709                                 return list.IndexOf (item);
1710                         }
1711
1712                         void IList.Insert (int index, object value)
1713                         {
1714                                 throw new NotSupportedException ("Insert operation is not supported.");
1715                         }
1716
1717                         void IList.Remove (object value)
1718                         {
1719                                 throw new NotSupportedException ("Remove operation is not supported.");
1720                         }
1721
1722                         void IList.RemoveAt (int index)
1723                         {
1724                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
1725                         }
1726
1727                         public int IndexOf (ListViewItem item)
1728                         {
1729                                 return list.IndexOf (item);
1730                         }
1731                         #endregion      // Public Methods
1732
1733                 }       // CheckedListViewItemCollection
1734
1735                 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
1736                 {
1737                         internal ArrayList list;
1738                         private ListView owner;
1739
1740                         #region Public Constructor
1741                         public ColumnHeaderCollection (ListView owner)
1742                         {
1743                                 list = new ArrayList ();
1744                                 this.owner = owner;
1745                         }
1746                         #endregion      // Public Constructor
1747
1748                         #region Public Properties
1749                         [Browsable (false)]
1750                         public virtual int Count {
1751                                 get { return list.Count; }
1752                         }
1753
1754                         public virtual bool IsReadOnly {
1755                                 get { return false; }
1756                         }
1757
1758                         public virtual ColumnHeader this [int index] {
1759                                 get {
1760                                         if (index < 0 || index >= list.Count)
1761                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
1762                                         return (ColumnHeader) list [index];
1763                                 }
1764                         }
1765
1766                         bool ICollection.IsSynchronized {
1767                                 get { return list.IsSynchronized; }
1768                         }
1769
1770                         object ICollection.SyncRoot {
1771                                 get { return list.SyncRoot; }
1772                         }
1773
1774                         bool IList.IsFixedSize {
1775                                 get { return list.IsFixedSize; }
1776                         }
1777
1778                         object IList.this [int index] {
1779                                 get { return this [index]; }
1780                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
1781                         }
1782                         #endregion      // Public Properties
1783
1784                         #region Public Methods
1785                         public virtual int Add (ColumnHeader value)
1786                         {
1787                                 int idx;
1788                                 value.owner = this.owner;
1789                                 idx = list.Add (value);
1790                                 owner.Redraw (true); 
1791                                 return idx;
1792                         }
1793
1794                         public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
1795                         {
1796                                 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
1797                                 this.Add (colHeader);                                                                   
1798                                 return colHeader;
1799                         }
1800
1801                         public virtual void AddRange (ColumnHeader [] values)
1802                         {
1803                                 foreach (ColumnHeader colHeader in values) {
1804                                         colHeader.owner = this.owner;
1805                                         Add (colHeader);
1806                                 }
1807                                 
1808                                 owner.Redraw (true); 
1809                         }
1810
1811                         public virtual void Clear ()
1812                         {
1813                                 list.Clear ();
1814                                 owner.Redraw (true);
1815                         }
1816
1817                         public bool Contains (ColumnHeader value)
1818                         {
1819                                 return list.Contains (value);
1820                         }
1821
1822                         public virtual IEnumerator GetEnumerator ()
1823                         {
1824                                 return list.GetEnumerator ();
1825                         }
1826
1827                         void ICollection.CopyTo (Array dest, int index)
1828                         {
1829                                 list.CopyTo (dest, index);
1830                         }
1831
1832                         int IList.Add (object value)
1833                         {
1834                                 if (! (value is ColumnHeader)) {
1835                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
1836                                 }
1837
1838                                 return this.Add ((ColumnHeader) value);
1839                         }
1840
1841                         bool IList.Contains (object value)
1842                         {
1843                                 if (! (value is ColumnHeader)) {
1844                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
1845                                 }
1846
1847                                 return this.Contains ((ColumnHeader) value);
1848                         }
1849
1850                         int IList.IndexOf (object value)
1851                         {
1852                                 if (! (value is ColumnHeader)) {
1853                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
1854                                 }
1855
1856                                 return this.IndexOf ((ColumnHeader) value);
1857                         }
1858
1859                         void IList.Insert (int index, object value)
1860                         {
1861                                 if (! (value is ColumnHeader)) {
1862                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
1863                                 }
1864
1865                                 this.Insert (index, (ColumnHeader) value);
1866                         }
1867
1868                         void IList.Remove (object value)
1869                         {
1870                                 if (! (value is ColumnHeader)) {
1871                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
1872                                 }
1873
1874                                 this.Remove ((ColumnHeader) value);
1875                         }
1876
1877                         public int IndexOf (ColumnHeader value)
1878                         {
1879                                 return list.IndexOf (value);
1880                         }
1881
1882                         public void Insert (int index, ColumnHeader value)
1883                         {
1884                                 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
1885                                 // but it's really only greater.
1886                                 if (index < 0 || index > list.Count)
1887                                         throw new ArgumentOutOfRangeException ("Index out of range.");
1888
1889                                 value.owner = this.owner;
1890                                 list.Insert (index, value);
1891                                 owner.Redraw (true);
1892                         }
1893
1894                         public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
1895                         {
1896                                 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
1897                                 this.Insert (index, colHeader);
1898                         }
1899
1900                         public virtual void Remove (ColumnHeader column)
1901                         {
1902                                 // TODO: Update Column internal index ?
1903                                 list.Remove (column);
1904                                 owner.Redraw (true);
1905                         }
1906
1907                         public virtual void RemoveAt (int index)
1908                         {
1909                                 if (index < 0 || index >= list.Count)
1910                                         throw new ArgumentOutOfRangeException ("Index out of range.");
1911
1912                                 // TODO: Update Column internal index ?
1913                                 list.RemoveAt (index);
1914                                 owner.Redraw (true);
1915                         }
1916                         #endregion      // Public Methods
1917                         
1918
1919                 }       // ColumnHeaderCollection
1920
1921                 public class ListViewItemCollection : IList, ICollection, IEnumerable
1922                 {
1923                         internal ArrayList list;
1924                         private ListView owner;
1925
1926                         #region Public Constructor
1927                         public ListViewItemCollection (ListView owner)
1928                         {
1929                                 list = new ArrayList ();
1930                                 this.owner = owner;
1931                         }
1932                         #endregion      // Public Constructor
1933
1934                         #region Public Properties
1935                         [Browsable (false)]
1936                         public virtual int Count {
1937                                 get { return list.Count; }
1938                         }
1939
1940                         public virtual bool IsReadOnly {
1941                                 get { return false; }
1942                         }
1943
1944                         public virtual ListViewItem this [int displayIndex] {
1945                                 get {
1946                                         if (displayIndex < 0 || displayIndex >= list.Count)
1947                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
1948                                         return (ListViewItem) list [displayIndex];
1949                                 }
1950
1951                                 set {
1952                                         if (displayIndex < 0 || displayIndex >= list.Count)
1953                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
1954
1955                                         if (list.Contains (value))
1956                                                 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
1957
1958                                         value.owner = this.owner;
1959                                         list [displayIndex] = value;
1960
1961                                         owner.Redraw (true);
1962                                 }
1963                         }
1964
1965                         bool ICollection.IsSynchronized {
1966                                 get { return list.IsSynchronized; }
1967                         }
1968
1969                         object ICollection.SyncRoot {
1970                                 get { return list.SyncRoot; }
1971                         }
1972
1973                         bool IList.IsFixedSize {
1974                                 get { return list.IsFixedSize; }
1975                         }
1976
1977                         object IList.this [int index] {
1978                                 get { return this [index]; }
1979                                 set {
1980                                         if (value is ListViewItem)
1981                                                 this [index] = (ListViewItem) value;
1982                                         else
1983                                                 this [index] = new ListViewItem (value.ToString ());
1984                                 }
1985                         }
1986                         #endregion      // Public Properties
1987
1988                         #region Public Methods
1989                         public virtual ListViewItem Add (ListViewItem value)
1990                         {
1991                                 if (list.Contains (value))
1992                                         throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
1993
1994                                 value.owner = this.owner;
1995                                 list.Add (value);
1996
1997                                 if (owner.Sorting != SortOrder.None)
1998                                         owner.Sort ();
1999
2000                                 owner.Redraw (true);
2001
2002                                 return value;
2003                         }
2004
2005                         public virtual ListViewItem Add (string text)
2006                         {
2007                                 ListViewItem item = new ListViewItem (text);
2008                                 return this.Add (item);
2009                         }
2010
2011                         public virtual ListViewItem Add (string text, int imageIndex)
2012                         {
2013                                 ListViewItem item = new ListViewItem (text, imageIndex);
2014                                 return this.Add (item);
2015                         }
2016
2017                         public void AddRange (ListViewItem [] values)
2018                         {
2019                                 list.Clear ();
2020
2021                                 foreach (ListViewItem item in values) {
2022                                         item.owner = this.owner;
2023                                         list.Add (item);
2024                                 }
2025
2026                                 if (owner.Sorting != SortOrder.None)
2027                                         owner.Sort ();
2028
2029                                 owner.Redraw (true);
2030                         }
2031
2032                         public virtual void Clear ()
2033                         {
2034                                 list.Clear ();
2035                         }
2036
2037                         public bool Contains (ListViewItem item)
2038                         {
2039                                 return list.Contains (item);
2040                         }
2041
2042                         public virtual void CopyTo (Array dest, int index)
2043                         {
2044                                 list.CopyTo (dest, index);
2045                         }
2046
2047                         public virtual IEnumerator GetEnumerator ()
2048                         {
2049                                 return list.GetEnumerator ();
2050                         }
2051
2052                         int IList.Add (object item)
2053                         {
2054                                 int result;
2055                                 ListViewItem li;
2056
2057                                 if (item is ListViewItem) {
2058                                         li = (ListViewItem) item;
2059                                         if (list.Contains (li))
2060                                                 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2061                                 }
2062                                 else
2063                                         li = new ListViewItem (item.ToString ());
2064
2065                                 li.owner = this.owner;
2066                                 result = list.Add (li);
2067                                 owner.Redraw (true);
2068
2069                                 return result;
2070                         }
2071
2072                         bool IList.Contains (object item)
2073                         {
2074                                 return list.Contains (item);
2075                         }
2076
2077                         int IList.IndexOf (object item)
2078                         {
2079                                 return list.IndexOf (item);
2080                         }
2081
2082                         void IList.Insert (int index, object item)
2083                         {
2084                                 if (item is ListViewItem)
2085                                         this.Insert (index, (ListViewItem) item);
2086                                 else
2087                                         this.Insert (index, item.ToString ());
2088                         }
2089
2090                         void IList.Remove (object item)
2091                         {
2092                                 if (list.Contains (item)) {
2093                                         list.Remove (item);
2094                                         owner.Redraw (true);
2095                                 }
2096                         }
2097
2098                         public int IndexOf (ListViewItem item)
2099                         {
2100                                 return list.IndexOf (item);
2101                         }
2102
2103                         public ListViewItem Insert (int index, ListViewItem item)
2104                         {
2105                                 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2106                                 // but it's really only greater.
2107                                 if (index < 0 || index > list.Count)
2108                                         throw new ArgumentOutOfRangeException ("Index out of range.");
2109
2110                                 if (list.Contains (item))
2111                                         throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2112
2113                                 item.owner = this.owner;
2114                                 list.Insert (index, item);
2115                                 owner.Redraw (true);
2116                                 return item;
2117                         }
2118
2119                         public ListViewItem Insert (int index, string text)
2120                         {
2121                                 return this.Insert (index, new ListViewItem (text));
2122                         }
2123
2124                         public ListViewItem Insert (int index, string text, int imageIndex)
2125                         {
2126                                 return this.Insert (index, new ListViewItem (text, imageIndex));
2127                         }
2128
2129                         public virtual void Remove (ListViewItem item)
2130                         {
2131                                 if (list.Contains (item)) {
2132                                         list.Remove (item);
2133                                         owner.Redraw (true);
2134                                 }
2135                         }
2136
2137                         public virtual void RemoveAt (int index)
2138                         {
2139                                 if (index < 0 || index >= list.Count)
2140                                         throw new ArgumentOutOfRangeException ("Index out of range.");
2141
2142                                 list.RemoveAt (index);
2143                                 owner.Redraw (false);
2144                         }
2145                         #endregion      // Public Methods
2146
2147                 }       // ListViewItemCollection
2148
2149                 public class SelectedIndexCollection : IList, ICollection, IEnumerable
2150                 {
2151                         internal ArrayList list;
2152                         private ListView owner;
2153
2154                         #region Public Constructor
2155                         public SelectedIndexCollection (ListView owner)
2156                         {
2157                                 list = new ArrayList ();
2158                                 this.owner = owner;
2159                         }
2160                         #endregion      // Public Constructor
2161
2162                         #region Public Properties
2163                         [Browsable (false)]
2164                         public virtual int Count {
2165                                 get { return list.Count; }
2166                         }
2167
2168                         public virtual bool IsReadOnly {
2169                                 get { return true; }
2170                         }
2171
2172                         public int this [int index] {
2173                                 get {
2174                                         if (index < 0 || index >= list.Count)
2175                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
2176                                         return (int) list [index];
2177                                 }
2178                         }
2179
2180                         bool ICollection.IsSynchronized {
2181                                 get { return list.IsSynchronized; }
2182                         }
2183
2184                         object ICollection.SyncRoot {
2185                                 get { return list.SyncRoot; }
2186                         }
2187
2188                         bool IList.IsFixedSize {
2189                                 get { return list.IsFixedSize; }
2190                         }
2191
2192                         object IList.this [int index] {
2193                                 get { return this [index]; }
2194                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2195                         }
2196                         #endregion      // Public Properties
2197
2198                         #region Public Methods
2199                         public bool Contains (int selectedIndex)
2200                         {
2201                                 return list.Contains (selectedIndex);
2202                         }
2203
2204                         public virtual void CopyTo (Array dest, int index)
2205                         {
2206                                 list.CopyTo (dest, index);
2207                         }
2208
2209                         public virtual IEnumerator GetEnumerator ()
2210                         {
2211                                 return list.GetEnumerator ();
2212                         }
2213
2214                         int IList.Add (object value)
2215                         {
2216                                 throw new NotSupportedException ("Add operation is not supported.");
2217                         }
2218
2219                         void IList.Clear ()
2220                         {
2221                                 throw new NotSupportedException ("Clear operation is not supported.");
2222                         }
2223
2224                         bool IList.Contains (object selectedIndex)
2225                         {
2226                                 return list.Contains (selectedIndex);
2227                         }
2228
2229                         int IList.IndexOf (object selectedIndex)
2230                         {
2231                                 return list.IndexOf (selectedIndex);
2232                         }
2233
2234                         void IList.Insert (int index, object value)
2235                         {
2236                                 throw new NotSupportedException ("Insert operation is not supported.");
2237                         }
2238
2239                         void IList.Remove (object value)
2240                         {
2241                                 throw new NotSupportedException ("Remove operation is not supported.");
2242                         }
2243
2244                         void IList.RemoveAt (int index)
2245                         {
2246                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
2247                         }
2248
2249                         public int IndexOf (int selectedIndex)
2250                         {
2251                                 return list.IndexOf (selectedIndex);
2252                         }
2253                         #endregion      // Public Methods
2254
2255                 }       // SelectedIndexCollection
2256
2257                 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
2258                 {
2259                         internal ArrayList list;
2260                         private ListView owner;
2261
2262                         #region Public Constructor
2263                         public SelectedListViewItemCollection (ListView owner)
2264                         {
2265                                 list = new ArrayList ();
2266                                 this.owner = owner;
2267                         }
2268                         #endregion      // Public Constructor
2269
2270                         #region Public Properties
2271                         [Browsable (false)]
2272                         public virtual int Count {
2273                                 get { return list.Count; }
2274                         }
2275
2276                         public virtual bool IsReadOnly {
2277                                 get { return true; }
2278                         }
2279
2280                         public ListViewItem this [int index] {
2281                                 get {
2282                                         if (index < 0 || index >= list.Count)
2283                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
2284                                         return (ListViewItem) list [index];
2285                                 }
2286                         }
2287
2288                         bool ICollection.IsSynchronized {
2289                                 get { return list.IsSynchronized; }
2290                         }
2291
2292                         object ICollection.SyncRoot {
2293                                 get { return list.SyncRoot; }
2294                         }
2295
2296                         bool IList.IsFixedSize {
2297                                 get { return list.IsFixedSize; }
2298                         }
2299
2300                         object IList.this [int index] {
2301                                 get { return this [index]; }
2302                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2303                         }
2304                         #endregion      // Public Properties
2305
2306                         #region Public Methods
2307                         public virtual void Clear ()
2308                         {
2309                                 // mark the items as unselected before clearing the list
2310                                 for (int i = 0; i < list.Count; i++)
2311                                         ((ListViewItem) list [i]).selected = false;
2312
2313                                 list.Clear ();
2314                         }
2315
2316                         public bool Contains (ListViewItem item)
2317                         {
2318                                 return list.Contains (item);
2319                         }
2320
2321                         public virtual void CopyTo (Array dest, int index)
2322                         {
2323                                 list.CopyTo (dest, index);
2324                         }
2325
2326                         public virtual IEnumerator GetEnumerator ()
2327                         {
2328                                 return list.GetEnumerator ();
2329                         }
2330
2331                         int IList.Add (object value)
2332                         {
2333                                 throw new NotSupportedException ("Add operation is not supported.");
2334                         }
2335
2336                         bool IList.Contains (object item)
2337                         {
2338                                 return list.Contains (item);
2339                         }
2340
2341                         int IList.IndexOf (object item)
2342                         {
2343                                 return list.IndexOf (item);
2344                         }
2345
2346                         void IList.Insert (int index, object value)
2347                         {
2348                                 throw new NotSupportedException ("Insert operation is not supported.");
2349                         }
2350
2351                         void IList.Remove (object value)
2352                         {
2353                                 throw new NotSupportedException ("Remove operation is not supported.");
2354                         }
2355
2356                         void IList.RemoveAt (int index)
2357                         {
2358                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
2359                         }
2360
2361                         public int IndexOf (ListViewItem item)
2362                         {
2363                                 return list.IndexOf (item);
2364                         }
2365                         #endregion      // Public Methods
2366
2367                 }       // SelectedListViewItemCollection
2368
2369                 #endregion // Subclasses
2370         }
2371 }