2005-05-24 Peter Bartok <pbartok@novell.com>
[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                         this.Controls.Add (this.v_scroll);
1345                         this.Controls.Add (this.h_scroll);                      
1346                 }
1347
1348                 protected override void OnHandleDestroyed (EventArgs e)
1349                 {
1350                         base.OnHandleDestroyed (e);
1351                 }
1352
1353                 protected virtual void OnItemActivate (EventArgs e)
1354                 {
1355                         if (ItemActivate != null)
1356                                 ItemActivate (this, e);
1357                 }
1358
1359                 protected virtual void OnItemCheck (ItemCheckEventArgs ice)
1360                 {
1361                         if (ItemCheck != null)
1362                                 ItemCheck (this, ice);
1363                 }
1364
1365                 protected virtual void OnItemDrag (ItemDragEventArgs e)
1366                 {
1367                         if (ItemDrag != null)
1368                                 ItemDrag (this, e);
1369                 }
1370
1371                 protected virtual void OnSelectedIndexChanged (EventArgs e)
1372                 {
1373                         if (SelectedIndexChanged != null)
1374                                 SelectedIndexChanged (this, e);
1375                 }
1376
1377                 protected override void OnSystemColorsChanged (EventArgs e)
1378                 {
1379                         base.OnSystemColorsChanged (e);
1380                 }
1381
1382                 protected void RealizeProperties ()
1383                 {
1384                         // FIXME: TODO
1385                 }
1386
1387                 protected void UpdateExtendedStyles ()
1388                 {
1389                         // FIXME: TODO
1390                 }
1391
1392                 protected override void WndProc (ref Message m)
1393                 {
1394                         base.WndProc (ref m);
1395                 }
1396                 #endregion // Protected Methods
1397
1398                 #region Public Instance Methods
1399                 public void ArrangeIcons ()
1400                 {
1401                         ArrangeIcons (this.alignment);
1402                 }
1403
1404                 public void ArrangeIcons (ListViewAlignment alignment)
1405                 {
1406                         // Icons are arranged only if view is set to LargeIcon or SmallIcon
1407                         if (view == View.LargeIcon || view == View.SmallIcon) {
1408                                 this.CalculateListView (alignment);
1409                                 // we have done the calculations already
1410                                 this.Redraw (false);
1411                         }
1412                 }
1413
1414                 public void BeginUpdate ()
1415                 {
1416                         // flag to avoid painting
1417                         updating = true;
1418                 }
1419
1420                 public void Clear ()
1421                 {
1422                         columns.Clear ();
1423                         items.Clear ();
1424                         this.Redraw (true);
1425                 }
1426
1427                 public void EndUpdate ()
1428                 {
1429                         // flag to avoid painting
1430                         updating = false;
1431
1432                         // probably, now we need a redraw with recalculations
1433                         this.Redraw (true);
1434                 }
1435
1436                 public void EnsureVisible (int index)
1437                 {
1438                         if (index < 0 || index >= this.items.Count || this.scrollable == false)
1439                                 return;
1440
1441                         // dimensions of visible area
1442                         int view_wd = this.Width - (this.v_scroll.Visible ? this.v_scroll.Width : 0);
1443                         int view_ht = this.Height - (this.h_scroll.Visible ? this.h_scroll.Height : 0);
1444                         // visible area is decided by the h_marker and v_marker
1445                         Rectangle view_rect = new Rectangle (h_marker, v_marker, view_wd, view_ht);
1446
1447                         // an item's bounding rect
1448                         Rectangle rect = this.items [index].EntireRect;
1449
1450                         // we don't need to do anything if item is visible.
1451                         // visible area is represented by (0,0,view_wd,view_ht)
1452                         if (view_rect.Contains (rect))
1453                                 return;
1454
1455                         // Scroll Left or Up
1456                         if ((rect.Left < view_rect.Left) || (rect.Top < view_rect.Top)) {
1457                                 if (rect.Left < view_rect.Left)
1458                                         this.h_scroll.Value -= (view_rect.Left - rect.Left);
1459                                 if (rect.Top < view_rect.Top)
1460                                         this.v_scroll.Value -= (view_rect.Top - rect.Top);
1461                         }
1462                         // Scroll Right or Down
1463                         else {
1464                                 if (rect.Right > view_rect.Right)
1465                                         this.h_scroll.Value += (rect.Right - view_rect.Right);
1466                                 if (rect.Bottom > view_rect.Bottom)
1467                                         this.v_scroll.Value += (rect.Bottom - view_rect.Bottom);
1468                         }
1469                 }
1470                 
1471                 public ListViewItem GetItemAt (int x, int y)
1472                 {
1473                         foreach (ListViewItem item in items) {
1474                                 if (item.Bounds.Contains (x, y))
1475                                         return item;
1476                         }
1477                         return null;
1478                 }
1479
1480                 public Rectangle GetItemRect (int index)
1481                 {
1482                         return GetItemRect (index, ItemBoundsPortion.Entire);
1483                 }
1484
1485                 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
1486                 {
1487                         if (index < 0 || index >= items.Count)
1488                                 throw new IndexOutOfRangeException ("Invalid Index");
1489
1490                         return items [index].GetBounds (portion);
1491                 }
1492
1493                 public void Sort ()
1494                 {
1495                         if (sort_order != SortOrder.None)
1496                                 items.list.Sort (item_sorter);
1497
1498                         if (sort_order == SortOrder.Descending)
1499                                 items.list.Reverse ();
1500
1501                         this.Redraw (true);
1502                 }
1503
1504                 public override string ToString ()
1505                 {
1506                         int count = this.Items.Count;
1507
1508                         if (count == 0)
1509                                 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
1510                         else
1511                                 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
1512                 }
1513                 #endregion      // Public Instance Methods
1514
1515
1516                 #region Subclasses
1517                 public class CheckedIndexCollection : IList, ICollection, IEnumerable
1518                 {
1519                         internal ArrayList list;
1520                         private ListView owner;
1521
1522                         #region Public Constructor
1523                         public CheckedIndexCollection (ListView owner)
1524                         {
1525                                 list = new ArrayList ();
1526                                 this.owner = owner;
1527                         }
1528                         #endregion      // Public Constructor
1529
1530                         #region Public Properties
1531                         [Browsable (false)]
1532                         public virtual int Count {
1533                                 get { return list.Count; }
1534                         }
1535
1536                         public virtual bool IsReadOnly {
1537                                 get { return true; }
1538                         }
1539
1540                         public int this [int index] {
1541                                 get {
1542                                         if (index < 0 || index >= list.Count)
1543                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
1544                                         return (int) list [index];
1545                                 }
1546                         }
1547
1548                         bool ICollection.IsSynchronized {
1549                                 get { return list.IsSynchronized; }
1550                         }
1551
1552                         object ICollection.SyncRoot {
1553                                 get { return list.SyncRoot; }
1554                         }
1555
1556                         bool IList.IsFixedSize {
1557                                 get { return list.IsFixedSize; }
1558                         }
1559
1560                         object IList.this [int index] {
1561                                 get { return this [index]; }
1562                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
1563                         }
1564                         #endregion      // Public Properties
1565
1566                         #region Public Methods
1567                         public bool Contains (int checkedIndex)
1568                         {
1569                                 return list.Contains (checkedIndex);
1570                         }
1571
1572                         public virtual IEnumerator GetEnumerator ()
1573                         {
1574                                 return list.GetEnumerator ();
1575                         }
1576
1577                         void ICollection.CopyTo (Array dest, int index)
1578                         {
1579                                 list.CopyTo (dest, index);
1580                         }
1581
1582                         int IList.Add (object value)
1583                         {
1584                                 throw new NotSupportedException ("Add operation is not supported.");
1585                         }
1586
1587                         void IList.Clear ()
1588                         {
1589                                 throw new NotSupportedException ("Clear operation is not supported.");
1590                         }
1591
1592                         bool IList.Contains (object checkedIndex)
1593                         {
1594                                 return list.Contains (checkedIndex);
1595                         }
1596
1597                         int IList.IndexOf (object checkedIndex)
1598                         {
1599                                 return list.IndexOf (checkedIndex);
1600                         }
1601
1602                         void IList.Insert (int index, object value)
1603                         {
1604                                 throw new NotSupportedException ("Insert operation is not supported.");
1605                         }
1606
1607                         void IList.Remove (object value)
1608                         {
1609                                 throw new NotSupportedException ("Remove operation is not supported.");
1610                         }
1611
1612                         void IList.RemoveAt (int index)
1613                         {
1614                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
1615                         }
1616
1617                         public int IndexOf (int checkedIndex)
1618                         {
1619                                 return list.IndexOf (checkedIndex);
1620                         }
1621                         #endregion      // Public Methods
1622
1623                 }       // CheckedIndexCollection
1624
1625                 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
1626                 {
1627                         internal ArrayList list;
1628                         private ListView owner;
1629
1630                         #region Public Constructor
1631                         public CheckedListViewItemCollection (ListView owner)
1632                         {
1633                                 list = new ArrayList ();
1634                                 this.owner = owner;
1635                         }
1636                         #endregion      // Public Constructor
1637
1638                         #region Public Properties
1639                         [Browsable (false)]
1640                         public virtual int Count {
1641                                 get { return list.Count; }
1642                         }
1643
1644                         public virtual bool IsReadOnly {
1645                                 get { return true; }
1646                         }
1647
1648                         public ListViewItem this [int index] {
1649                                 get {
1650                                         if (index < 0 || index >= list.Count)
1651                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
1652                                         return (ListViewItem) list [index];
1653                                 }
1654                         }
1655
1656                         bool ICollection.IsSynchronized {
1657                                 get { return list.IsSynchronized; }
1658                         }
1659
1660                         object ICollection.SyncRoot {
1661                                 get { return list.SyncRoot; }
1662                         }
1663
1664                         bool IList.IsFixedSize {
1665                                 get { return list.IsFixedSize; }
1666                         }
1667
1668                         object IList.this [int index] {
1669                                 get { return this [index]; }
1670                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
1671                         }
1672                         #endregion      // Public Properties
1673
1674                         #region Public Methods
1675                         public bool Contains (ListViewItem item)
1676                         {
1677                                 return list.Contains (item);
1678                         }
1679
1680                         public virtual void CopyTo (Array dest, int index)
1681                         {
1682                                 list.CopyTo (dest, index);
1683                         }
1684
1685                         public virtual IEnumerator GetEnumerator ()
1686                         {
1687                                 return list.GetEnumerator ();
1688                         }
1689
1690                         int IList.Add (object value)
1691                         {
1692                                 throw new NotSupportedException ("Add operation is not supported.");
1693                         }
1694
1695                         void IList.Clear ()
1696                         {
1697                                 throw new NotSupportedException ("Clear operation is not supported.");
1698                         }
1699
1700                         bool IList.Contains (object item)
1701                         {
1702                                 return list.Contains (item);
1703                         }
1704
1705                         int IList.IndexOf (object item)
1706                         {
1707                                 return list.IndexOf (item);
1708                         }
1709
1710                         void IList.Insert (int index, object value)
1711                         {
1712                                 throw new NotSupportedException ("Insert operation is not supported.");
1713                         }
1714
1715                         void IList.Remove (object value)
1716                         {
1717                                 throw new NotSupportedException ("Remove operation is not supported.");
1718                         }
1719
1720                         void IList.RemoveAt (int index)
1721                         {
1722                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
1723                         }
1724
1725                         public int IndexOf (ListViewItem item)
1726                         {
1727                                 return list.IndexOf (item);
1728                         }
1729                         #endregion      // Public Methods
1730
1731                 }       // CheckedListViewItemCollection
1732
1733                 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
1734                 {
1735                         internal ArrayList list;
1736                         private ListView owner;
1737
1738                         #region Public Constructor
1739                         public ColumnHeaderCollection (ListView owner)
1740                         {
1741                                 list = new ArrayList ();
1742                                 this.owner = owner;
1743                         }
1744                         #endregion      // Public Constructor
1745
1746                         #region Public Properties
1747                         [Browsable (false)]
1748                         public virtual int Count {
1749                                 get { return list.Count; }
1750                         }
1751
1752                         public virtual bool IsReadOnly {
1753                                 get { return false; }
1754                         }
1755
1756                         public virtual ColumnHeader this [int index] {
1757                                 get {
1758                                         if (index < 0 || index >= list.Count)
1759                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
1760                                         return (ColumnHeader) list [index];
1761                                 }
1762                         }
1763
1764                         bool ICollection.IsSynchronized {
1765                                 get { return list.IsSynchronized; }
1766                         }
1767
1768                         object ICollection.SyncRoot {
1769                                 get { return list.SyncRoot; }
1770                         }
1771
1772                         bool IList.IsFixedSize {
1773                                 get { return list.IsFixedSize; }
1774                         }
1775
1776                         object IList.this [int index] {
1777                                 get { return this [index]; }
1778                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
1779                         }
1780                         #endregion      // Public Properties
1781
1782                         #region Public Methods
1783                         public virtual int Add (ColumnHeader value)
1784                         {
1785                                 int idx;
1786                                 value.owner = this.owner;
1787                                 idx = list.Add (value);
1788                                 owner.Redraw (true); 
1789                                 return idx;
1790                         }
1791
1792                         public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
1793                         {
1794                                 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
1795                                 this.Add (colHeader);                                                                   
1796                                 return colHeader;
1797                         }
1798
1799                         public virtual void AddRange (ColumnHeader [] values)
1800                         {
1801                                 foreach (ColumnHeader colHeader in values) {
1802                                         colHeader.owner = this.owner;
1803                                         Add (colHeader);
1804                                 }
1805                                 
1806                                 owner.Redraw (true); 
1807                         }
1808
1809                         public virtual void Clear ()
1810                         {
1811                                 list.Clear ();
1812                                 owner.Redraw (true);
1813                         }
1814
1815                         public bool Contains (ColumnHeader value)
1816                         {
1817                                 return list.Contains (value);
1818                         }
1819
1820                         public virtual IEnumerator GetEnumerator ()
1821                         {
1822                                 return list.GetEnumerator ();
1823                         }
1824
1825                         void ICollection.CopyTo (Array dest, int index)
1826                         {
1827                                 list.CopyTo (dest, index);
1828                         }
1829
1830                         int IList.Add (object value)
1831                         {
1832                                 if (! (value is ColumnHeader)) {
1833                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
1834                                 }
1835
1836                                 return this.Add ((ColumnHeader) value);
1837                         }
1838
1839                         bool IList.Contains (object value)
1840                         {
1841                                 if (! (value is ColumnHeader)) {
1842                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
1843                                 }
1844
1845                                 return this.Contains ((ColumnHeader) value);
1846                         }
1847
1848                         int IList.IndexOf (object value)
1849                         {
1850                                 if (! (value is ColumnHeader)) {
1851                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
1852                                 }
1853
1854                                 return this.IndexOf ((ColumnHeader) value);
1855                         }
1856
1857                         void IList.Insert (int index, object value)
1858                         {
1859                                 if (! (value is ColumnHeader)) {
1860                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
1861                                 }
1862
1863                                 this.Insert (index, (ColumnHeader) value);
1864                         }
1865
1866                         void IList.Remove (object value)
1867                         {
1868                                 if (! (value is ColumnHeader)) {
1869                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
1870                                 }
1871
1872                                 this.Remove ((ColumnHeader) value);
1873                         }
1874
1875                         public int IndexOf (ColumnHeader value)
1876                         {
1877                                 return list.IndexOf (value);
1878                         }
1879
1880                         public void Insert (int index, ColumnHeader value)
1881                         {
1882                                 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
1883                                 // but it's really only greater.
1884                                 if (index < 0 || index > list.Count)
1885                                         throw new ArgumentOutOfRangeException ("Index out of range.");
1886
1887                                 value.owner = this.owner;
1888                                 list.Insert (index, value);
1889                                 owner.Redraw (true);
1890                         }
1891
1892                         public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
1893                         {
1894                                 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
1895                                 this.Insert (index, colHeader);
1896                         }
1897
1898                         public virtual void Remove (ColumnHeader column)
1899                         {
1900                                 // TODO: Update Column internal index ?
1901                                 list.Remove (column);
1902                                 owner.Redraw (true);
1903                         }
1904
1905                         public virtual void RemoveAt (int index)
1906                         {
1907                                 if (index < 0 || index >= list.Count)
1908                                         throw new ArgumentOutOfRangeException ("Index out of range.");
1909
1910                                 // TODO: Update Column internal index ?
1911                                 list.RemoveAt (index);
1912                                 owner.Redraw (true);
1913                         }
1914                         #endregion      // Public Methods
1915                         
1916
1917                 }       // ColumnHeaderCollection
1918
1919                 public class ListViewItemCollection : IList, ICollection, IEnumerable
1920                 {
1921                         internal ArrayList list;
1922                         private ListView owner;
1923
1924                         #region Public Constructor
1925                         public ListViewItemCollection (ListView owner)
1926                         {
1927                                 list = new ArrayList ();
1928                                 this.owner = owner;
1929                         }
1930                         #endregion      // Public Constructor
1931
1932                         #region Public Properties
1933                         [Browsable (false)]
1934                         public virtual int Count {
1935                                 get { return list.Count; }
1936                         }
1937
1938                         public virtual bool IsReadOnly {
1939                                 get { return false; }
1940                         }
1941
1942                         public virtual ListViewItem this [int displayIndex] {
1943                                 get {
1944                                         if (displayIndex < 0 || displayIndex >= list.Count)
1945                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
1946                                         return (ListViewItem) list [displayIndex];
1947                                 }
1948
1949                                 set {
1950                                         if (displayIndex < 0 || displayIndex >= list.Count)
1951                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
1952
1953                                         if (list.Contains (value))
1954                                                 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
1955
1956                                         value.owner = this.owner;
1957                                         list [displayIndex] = value;
1958
1959                                         owner.Redraw (true);
1960                                 }
1961                         }
1962
1963                         bool ICollection.IsSynchronized {
1964                                 get { return list.IsSynchronized; }
1965                         }
1966
1967                         object ICollection.SyncRoot {
1968                                 get { return list.SyncRoot; }
1969                         }
1970
1971                         bool IList.IsFixedSize {
1972                                 get { return list.IsFixedSize; }
1973                         }
1974
1975                         object IList.this [int index] {
1976                                 get { return this [index]; }
1977                                 set {
1978                                         if (value is ListViewItem)
1979                                                 this [index] = (ListViewItem) value;
1980                                         else
1981                                                 this [index] = new ListViewItem (value.ToString ());
1982                                 }
1983                         }
1984                         #endregion      // Public Properties
1985
1986                         #region Public Methods
1987                         public virtual ListViewItem Add (ListViewItem value)
1988                         {
1989                                 if (list.Contains (value))
1990                                         throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
1991
1992                                 value.owner = this.owner;
1993                                 list.Add (value);
1994
1995                                 if (owner.Sorting != SortOrder.None)
1996                                         owner.Sort ();
1997
1998                                 owner.Redraw (true);
1999
2000                                 return value;
2001                         }
2002
2003                         public virtual ListViewItem Add (string text)
2004                         {
2005                                 ListViewItem item = new ListViewItem (text);
2006                                 return this.Add (item);
2007                         }
2008
2009                         public virtual ListViewItem Add (string text, int imageIndex)
2010                         {
2011                                 ListViewItem item = new ListViewItem (text, imageIndex);
2012                                 return this.Add (item);
2013                         }
2014
2015                         public void AddRange (ListViewItem [] values)
2016                         {
2017                                 list.Clear ();
2018
2019                                 foreach (ListViewItem item in values) {
2020                                         item.owner = this.owner;
2021                                         list.Add (item);
2022                                 }
2023
2024                                 if (owner.Sorting != SortOrder.None)
2025                                         owner.Sort ();
2026
2027                                 owner.Redraw (true);
2028                         }
2029
2030                         public virtual void Clear ()
2031                         {
2032                                 list.Clear ();
2033                         }
2034
2035                         public bool Contains (ListViewItem item)
2036                         {
2037                                 return list.Contains (item);
2038                         }
2039
2040                         public virtual void CopyTo (Array dest, int index)
2041                         {
2042                                 list.CopyTo (dest, index);
2043                         }
2044
2045                         public virtual IEnumerator GetEnumerator ()
2046                         {
2047                                 return list.GetEnumerator ();
2048                         }
2049
2050                         int IList.Add (object item)
2051                         {
2052                                 int result;
2053                                 ListViewItem li;
2054
2055                                 if (item is ListViewItem) {
2056                                         li = (ListViewItem) item;
2057                                         if (list.Contains (li))
2058                                                 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2059                                 }
2060                                 else
2061                                         li = new ListViewItem (item.ToString ());
2062
2063                                 li.owner = this.owner;
2064                                 result = list.Add (li);
2065                                 owner.Redraw (true);
2066
2067                                 return result;
2068                         }
2069
2070                         bool IList.Contains (object item)
2071                         {
2072                                 return list.Contains (item);
2073                         }
2074
2075                         int IList.IndexOf (object item)
2076                         {
2077                                 return list.IndexOf (item);
2078                         }
2079
2080                         void IList.Insert (int index, object item)
2081                         {
2082                                 if (item is ListViewItem)
2083                                         this.Insert (index, (ListViewItem) item);
2084                                 else
2085                                         this.Insert (index, item.ToString ());
2086                         }
2087
2088                         void IList.Remove (object item)
2089                         {
2090                                 if (list.Contains (item)) {
2091                                         list.Remove (item);
2092                                         owner.Redraw (true);
2093                                 }
2094                         }
2095
2096                         public int IndexOf (ListViewItem item)
2097                         {
2098                                 return list.IndexOf (item);
2099                         }
2100
2101                         public ListViewItem Insert (int index, ListViewItem item)
2102                         {
2103                                 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2104                                 // but it's really only greater.
2105                                 if (index < 0 || index > list.Count)
2106                                         throw new ArgumentOutOfRangeException ("Index out of range.");
2107
2108                                 if (list.Contains (item))
2109                                         throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2110
2111                                 item.owner = this.owner;
2112                                 list.Insert (index, item);
2113                                 owner.Redraw (true);
2114                                 return item;
2115                         }
2116
2117                         public ListViewItem Insert (int index, string text)
2118                         {
2119                                 return this.Insert (index, new ListViewItem (text));
2120                         }
2121
2122                         public ListViewItem Insert (int index, string text, int imageIndex)
2123                         {
2124                                 return this.Insert (index, new ListViewItem (text, imageIndex));
2125                         }
2126
2127                         public virtual void Remove (ListViewItem item)
2128                         {
2129                                 if (list.Contains (item)) {
2130                                         list.Remove (item);
2131                                         owner.Redraw (true);
2132                                 }
2133                         }
2134
2135                         public virtual void RemoveAt (int index)
2136                         {
2137                                 if (index < 0 || index >= list.Count)
2138                                         throw new ArgumentOutOfRangeException ("Index out of range.");
2139
2140                                 list.RemoveAt (index);
2141                                 owner.Redraw (false);
2142                         }
2143                         #endregion      // Public Methods
2144
2145                 }       // ListViewItemCollection
2146
2147                 public class SelectedIndexCollection : IList, ICollection, IEnumerable
2148                 {
2149                         internal ArrayList list;
2150                         private ListView owner;
2151
2152                         #region Public Constructor
2153                         public SelectedIndexCollection (ListView owner)
2154                         {
2155                                 list = new ArrayList ();
2156                                 this.owner = owner;
2157                         }
2158                         #endregion      // Public Constructor
2159
2160                         #region Public Properties
2161                         [Browsable (false)]
2162                         public virtual int Count {
2163                                 get { return list.Count; }
2164                         }
2165
2166                         public virtual bool IsReadOnly {
2167                                 get { return true; }
2168                         }
2169
2170                         public int this [int index] {
2171                                 get {
2172                                         if (index < 0 || index >= list.Count)
2173                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
2174                                         return (int) list [index];
2175                                 }
2176                         }
2177
2178                         bool ICollection.IsSynchronized {
2179                                 get { return list.IsSynchronized; }
2180                         }
2181
2182                         object ICollection.SyncRoot {
2183                                 get { return list.SyncRoot; }
2184                         }
2185
2186                         bool IList.IsFixedSize {
2187                                 get { return list.IsFixedSize; }
2188                         }
2189
2190                         object IList.this [int index] {
2191                                 get { return this [index]; }
2192                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2193                         }
2194                         #endregion      // Public Properties
2195
2196                         #region Public Methods
2197                         public bool Contains (int selectedIndex)
2198                         {
2199                                 return list.Contains (selectedIndex);
2200                         }
2201
2202                         public virtual void CopyTo (Array dest, int index)
2203                         {
2204                                 list.CopyTo (dest, index);
2205                         }
2206
2207                         public virtual IEnumerator GetEnumerator ()
2208                         {
2209                                 return list.GetEnumerator ();
2210                         }
2211
2212                         int IList.Add (object value)
2213                         {
2214                                 throw new NotSupportedException ("Add operation is not supported.");
2215                         }
2216
2217                         void IList.Clear ()
2218                         {
2219                                 throw new NotSupportedException ("Clear operation is not supported.");
2220                         }
2221
2222                         bool IList.Contains (object selectedIndex)
2223                         {
2224                                 return list.Contains (selectedIndex);
2225                         }
2226
2227                         int IList.IndexOf (object selectedIndex)
2228                         {
2229                                 return list.IndexOf (selectedIndex);
2230                         }
2231
2232                         void IList.Insert (int index, object value)
2233                         {
2234                                 throw new NotSupportedException ("Insert operation is not supported.");
2235                         }
2236
2237                         void IList.Remove (object value)
2238                         {
2239                                 throw new NotSupportedException ("Remove operation is not supported.");
2240                         }
2241
2242                         void IList.RemoveAt (int index)
2243                         {
2244                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
2245                         }
2246
2247                         public int IndexOf (int selectedIndex)
2248                         {
2249                                 return list.IndexOf (selectedIndex);
2250                         }
2251                         #endregion      // Public Methods
2252
2253                 }       // SelectedIndexCollection
2254
2255                 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
2256                 {
2257                         internal ArrayList list;
2258                         private ListView owner;
2259
2260                         #region Public Constructor
2261                         public SelectedListViewItemCollection (ListView owner)
2262                         {
2263                                 list = new ArrayList ();
2264                                 this.owner = owner;
2265                         }
2266                         #endregion      // Public Constructor
2267
2268                         #region Public Properties
2269                         [Browsable (false)]
2270                         public virtual int Count {
2271                                 get { return list.Count; }
2272                         }
2273
2274                         public virtual bool IsReadOnly {
2275                                 get { return true; }
2276                         }
2277
2278                         public ListViewItem this [int index] {
2279                                 get {
2280                                         if (index < 0 || index >= list.Count)
2281                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
2282                                         return (ListViewItem) list [index];
2283                                 }
2284                         }
2285
2286                         bool ICollection.IsSynchronized {
2287                                 get { return list.IsSynchronized; }
2288                         }
2289
2290                         object ICollection.SyncRoot {
2291                                 get { return list.SyncRoot; }
2292                         }
2293
2294                         bool IList.IsFixedSize {
2295                                 get { return list.IsFixedSize; }
2296                         }
2297
2298                         object IList.this [int index] {
2299                                 get { return this [index]; }
2300                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2301                         }
2302                         #endregion      // Public Properties
2303
2304                         #region Public Methods
2305                         public virtual void Clear ()
2306                         {
2307                                 // mark the items as unselected before clearing the list
2308                                 for (int i = 0; i < list.Count; i++)
2309                                         ((ListViewItem) list [i]).selected = false;
2310
2311                                 list.Clear ();
2312                         }
2313
2314                         public bool Contains (ListViewItem item)
2315                         {
2316                                 return list.Contains (item);
2317                         }
2318
2319                         public virtual void CopyTo (Array dest, int index)
2320                         {
2321                                 list.CopyTo (dest, index);
2322                         }
2323
2324                         public virtual IEnumerator GetEnumerator ()
2325                         {
2326                                 return list.GetEnumerator ();
2327                         }
2328
2329                         int IList.Add (object value)
2330                         {
2331                                 throw new NotSupportedException ("Add operation is not supported.");
2332                         }
2333
2334                         bool IList.Contains (object item)
2335                         {
2336                                 return list.Contains (item);
2337                         }
2338
2339                         int IList.IndexOf (object item)
2340                         {
2341                                 return list.IndexOf (item);
2342                         }
2343
2344                         void IList.Insert (int index, object value)
2345                         {
2346                                 throw new NotSupportedException ("Insert operation is not supported.");
2347                         }
2348
2349                         void IList.Remove (object value)
2350                         {
2351                                 throw new NotSupportedException ("Remove operation is not supported.");
2352                         }
2353
2354                         void IList.RemoveAt (int index)
2355                         {
2356                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
2357                         }
2358
2359                         public int IndexOf (ListViewItem item)
2360                         {
2361                                 return list.IndexOf (item);
2362                         }
2363                         #endregion      // Public Methods
2364
2365                 }       // SelectedListViewItemCollection
2366
2367                 #endregion // Subclasses
2368         }
2369 }