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