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