* ListView.cs: When changing the size in VirtualMode, also Reset the
[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 //      Mike Kestner (mkestner@novell.com)
26 //      Daniel Nauck (dna(at)mono-project(dot)de)
27 //      Carlos Alberto Cortez <calberto.cortez@gmail.com>
28 //
29
30
31 // NOT COMPLETE
32
33
34 using System.Collections;
35 using System.ComponentModel;
36 using System.ComponentModel.Design;
37 using System.Drawing;
38 using System.Runtime.InteropServices;
39 using System.Globalization;
40 #if NET_2_0
41 using System.Collections.Generic;
42 #endif
43
44 namespace System.Windows.Forms
45 {
46         [DefaultEvent ("SelectedIndexChanged")]
47         [DefaultProperty ("Items")]
48         [Designer ("System.Windows.Forms.Design.ListViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
49 #if NET_2_0
50         [ClassInterface (ClassInterfaceType.AutoDispatch)]
51         [ComVisible (true)]
52         [Docking (DockingBehavior.Ask)]
53 #endif
54         public class ListView : Control
55         {
56                 private ItemActivation activation = ItemActivation.Standard;
57                 private ListViewAlignment alignment = ListViewAlignment.Top;
58                 private bool allow_column_reorder;
59                 private bool auto_arrange = true;
60                 private bool check_boxes;
61                 private readonly CheckedIndexCollection checked_indices;
62                 private readonly CheckedListViewItemCollection checked_items;
63                 private readonly ColumnHeaderCollection columns;
64                 internal int focused_item_index = -1;
65                 private bool full_row_select;
66                 private bool grid_lines;
67                 private ColumnHeaderStyle header_style = ColumnHeaderStyle.Clickable;
68                 private bool hide_selection = true;
69                 private bool hover_selection;
70                 private IComparer item_sorter;
71                 private readonly ListViewItemCollection items;
72 #if NET_2_0
73                 private readonly ListViewGroupCollection groups;
74                 private bool owner_draw;
75                 private bool show_groups = true;
76 #endif
77                 private bool label_edit;
78                 private bool label_wrap = true;
79                 private bool multiselect = true;
80                 private bool scrollable = true;
81                 private bool hover_pending;
82                 private readonly SelectedIndexCollection selected_indices;
83                 private readonly SelectedListViewItemCollection selected_items;
84                 private SortOrder sort_order = SortOrder.None;
85                 private ImageList state_image_list;
86                 internal bool updating;
87                 private View view = View.LargeIcon;
88                 private int layout_wd;    // We might draw more than our client area
89                 private int layout_ht;    // therefore we need to have these two.
90                 HeaderControl header_control;
91                 internal ItemControl item_control;
92                 internal ScrollBar h_scroll; // used for scrolling horizontally
93                 internal ScrollBar v_scroll; // used for scrolling vertically
94                 internal int h_marker;          // Position markers for scrolling
95                 internal int v_marker;
96                 private int keysearch_tickcnt;
97                 private string keysearch_text;
98                 static private readonly int keysearch_keydelay = 1000;
99                 private int[] reordered_column_indices;
100                 private int[] reordered_items_indices;
101                 private Point [] items_location;
102                 private ItemMatrixLocation [] items_matrix_location;
103                 private Size item_size; // used for caching item size
104                 private int custom_column_width; // used when using Columns with SmallIcon/List views
105                 private int hot_item_index = -1;
106 #if NET_2_0
107                 private bool hot_tracking;
108                 private ListViewInsertionMark insertion_mark;
109                 private bool show_item_tooltips;
110                 private ToolTip item_tooltip;
111                 private Size tile_size;
112                 private bool virtual_mode;
113                 private int virtual_list_size;
114                 private bool right_to_left_layout;
115 #endif
116
117                 // internal variables
118                 internal ImageList large_image_list;
119                 internal ImageList small_image_list;
120                 internal Size text_size = Size.Empty;
121
122                 #region Events
123                 static object AfterLabelEditEvent = new object ();
124                 static object BeforeLabelEditEvent = new object ();
125                 static object ColumnClickEvent = new object ();
126                 static object ItemActivateEvent = new object ();
127                 static object ItemCheckEvent = new object ();
128                 static object ItemDragEvent = new object ();
129                 static object SelectedIndexChangedEvent = new object ();
130 #if NET_2_0
131                 static object DrawColumnHeaderEvent = new object();
132                 static object DrawItemEvent = new object();
133                 static object DrawSubItemEvent = new object();
134                 static object ItemCheckedEvent = new object ();
135                 static object ItemMouseHoverEvent = new object ();
136                 static object ItemSelectionChangedEvent = new object ();
137                 static object CacheVirtualItemsEvent = new object ();
138                 static object RetrieveVirtualItemEvent = new object ();
139                 static object RightToLeftLayoutChangedEvent = new object ();
140                 static object SearchForVirtualItemEvent = new object ();
141                 static object VirtualItemsSelectionRangeChangedEvent = new object ();
142 #endif
143
144                 public event LabelEditEventHandler AfterLabelEdit {
145                         add { Events.AddHandler (AfterLabelEditEvent, value); }
146                         remove { Events.RemoveHandler (AfterLabelEditEvent, value); }
147                 }
148
149 #if !NET_2_0
150                 [Browsable (false)]
151                 [EditorBrowsable (EditorBrowsableState.Never)]
152                 public new event EventHandler BackgroundImageChanged {
153                         add { base.BackgroundImageChanged += value; }
154                         remove { base.BackgroundImageChanged -= value; }
155                 }
156 #endif
157
158 #if NET_2_0
159                 [Browsable (false)]
160                 [EditorBrowsable (EditorBrowsableState.Never)]
161                 public new event EventHandler BackgroundImageLayoutChanged {
162                         add { base.BackgroundImageLayoutChanged += value; }
163                         remove { base.BackgroundImageLayoutChanged -= value; }
164                 }
165 #endif
166
167                 public event LabelEditEventHandler BeforeLabelEdit {
168                         add { Events.AddHandler (BeforeLabelEditEvent, value); }
169                         remove { Events.RemoveHandler (BeforeLabelEditEvent, value); }
170                 }
171
172                 public event ColumnClickEventHandler ColumnClick {
173                         add { Events.AddHandler (ColumnClickEvent, value); }
174                         remove { Events.RemoveHandler (ColumnClickEvent, value); }
175                 }
176
177 #if NET_2_0
178                 public event DrawListViewColumnHeaderEventHandler DrawColumnHeader {
179                         add { Events.AddHandler(DrawColumnHeaderEvent, value); }
180                         remove { Events.RemoveHandler(DrawColumnHeaderEvent, value); }
181                 }
182
183                 public event DrawListViewItemEventHandler DrawItem {
184                         add { Events.AddHandler(DrawItemEvent, value); }
185                         remove { Events.RemoveHandler(DrawItemEvent, value); }
186                 }
187
188                 public event DrawListViewSubItemEventHandler DrawSubItem {
189                         add { Events.AddHandler(DrawSubItemEvent, value); }
190                         remove { Events.RemoveHandler(DrawSubItemEvent, value); }
191                 }
192 #endif
193
194                 public event EventHandler ItemActivate {
195                         add { Events.AddHandler (ItemActivateEvent, value); }
196                         remove { Events.RemoveHandler (ItemActivateEvent, value); }
197                 }
198
199                 public event ItemCheckEventHandler ItemCheck {
200                         add { Events.AddHandler (ItemCheckEvent, value); }
201                         remove { Events.RemoveHandler (ItemCheckEvent, value); }
202                 }
203
204 #if NET_2_0
205                 public event ItemCheckedEventHandler ItemChecked {
206                         add { Events.AddHandler (ItemCheckedEvent, value); }
207                         remove { Events.RemoveHandler (ItemCheckedEvent, value); }
208                 }
209 #endif
210
211                 public event ItemDragEventHandler ItemDrag {
212                         add { Events.AddHandler (ItemDragEvent, value); }
213                         remove { Events.RemoveHandler (ItemDragEvent, value); }
214                 }
215
216 #if NET_2_0
217                 public event ListViewItemMouseHoverEventHandler ItemMouseHover {
218                         add { Events.AddHandler (ItemMouseHoverEvent, value); }
219                         remove { Events.RemoveHandler (ItemMouseHoverEvent, value); }
220                 }
221
222                 public event ListViewItemSelectionChangedEventHandler ItemSelectionChanged {
223                         add { Events.AddHandler (ItemSelectionChangedEvent, value); }
224                         remove { Events.RemoveHandler (ItemSelectionChangedEvent, value); }
225                 }
226
227                 [Browsable (false)]
228                 [EditorBrowsable (EditorBrowsableState.Never)]
229                 public new event EventHandler PaddingChanged {
230                         add { base.PaddingChanged += value; }
231                         remove { base.PaddingChanged -= value; }
232                 }
233 #endif
234
235                 [Browsable (false)]
236                 [EditorBrowsable (EditorBrowsableState.Never)]
237                 public new event PaintEventHandler Paint {
238                         add { base.Paint += value; }
239                         remove { base.Paint -= value; }
240                 }
241
242                 public event EventHandler SelectedIndexChanged {
243                         add { Events.AddHandler (SelectedIndexChangedEvent, value); }
244                         remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
245                 }
246
247                 [Browsable (false)]
248                 [EditorBrowsable (EditorBrowsableState.Never)]
249                 public new event EventHandler TextChanged {
250                         add { base.TextChanged += value; }
251                         remove { base.TextChanged -= value; }
252                 }
253
254 #if NET_2_0
255                 public event CacheVirtualItemsEventHandler CacheVirtualItems {
256                         add { Events.AddHandler (CacheVirtualItemsEvent, value); }
257                         remove { Events.RemoveHandler (CacheVirtualItemsEvent, value); }
258                 }
259
260                 public event RetrieveVirtualItemEventHandler RetrieveVirtualItem {
261                         add { Events.AddHandler (RetrieveVirtualItemEvent, value); }
262                         remove { Events.RemoveHandler (RetrieveVirtualItemEvent, value); }
263                 }
264
265                 public event EventHandler RightToLeftLayoutChanged {
266                         add { Events.AddHandler (RightToLeftLayoutChangedEvent, value); }
267                         remove { Events.RemoveHandler (RightToLeftLayoutChangedEvent, value); }
268                 }
269
270                 public event SearchForVirtualItemEventHandler SearchForVirtualItem {
271                         add { Events.AddHandler (SearchForVirtualItemEvent, value); }
272                         remove { Events.AddHandler (SearchForVirtualItemEvent, value); }
273                 }
274                 
275                 public event ListViewVirtualItemsSelectionRangeChangedEventHandler VirtualItemsSelectionRangeChanged {
276                         add { Events.AddHandler (VirtualItemsSelectionRangeChangedEvent, value); }
277                         remove { Events.RemoveHandler (VirtualItemsSelectionRangeChangedEvent, value); }
278                 }
279 #endif
280
281                 #endregion // Events
282
283                 #region Public Constructors
284                 public ListView ()
285                 {
286                         background_color = ThemeEngine.Current.ColorWindow;
287 #if NET_2_0
288                         groups = new ListViewGroupCollection (this);
289 #endif
290                         items = new ListViewItemCollection (this);
291                         checked_indices = new CheckedIndexCollection (this);
292                         checked_items = new CheckedListViewItemCollection (this);
293                         columns = new ColumnHeaderCollection (this);
294                         foreground_color = SystemColors.WindowText;
295                         selected_indices = new SelectedIndexCollection (this);
296                         selected_items = new SelectedListViewItemCollection (this);
297                         items_location = new Point [16];
298                         items_matrix_location = new ItemMatrixLocation [16];
299                         reordered_items_indices = new int [16];
300 #if NET_2_0
301                         item_tooltip = new ToolTip ();
302                         item_tooltip.Active = false;
303                         insertion_mark = new ListViewInsertionMark (this);
304 #endif
305
306                         InternalBorderStyle = BorderStyle.Fixed3D;
307
308                         header_control = new HeaderControl (this);
309                         header_control.Visible = false;
310                         Controls.AddImplicit (header_control);
311
312                         item_control = new ItemControl (this);
313                         Controls.AddImplicit (item_control);
314
315                         h_scroll = new ImplicitHScrollBar ();
316                         Controls.AddImplicit (this.h_scroll);
317
318                         v_scroll = new ImplicitVScrollBar ();
319                         Controls.AddImplicit (this.v_scroll);
320
321                         h_marker = v_marker = 0;
322                         keysearch_tickcnt = 0;
323
324                         // scroll bars are disabled initially
325                         h_scroll.Visible = false;
326                         h_scroll.ValueChanged += new EventHandler(HorizontalScroller);
327                         v_scroll.Visible = false;
328                         v_scroll.ValueChanged += new EventHandler(VerticalScroller);
329
330                         // event handlers
331                         base.KeyDown += new KeyEventHandler(ListView_KeyDown);
332                         SizeChanged += new EventHandler (ListView_SizeChanged);
333                         GotFocus += new EventHandler (FocusChanged);
334                         LostFocus += new EventHandler (FocusChanged);
335                         MouseWheel += new MouseEventHandler(ListView_MouseWheel);
336                         MouseEnter += new EventHandler (ListView_MouseEnter);
337
338 #if NET_2_0
339                         BackgroundImageTiled = false;
340 #endif
341
342                         this.SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick
343 #if NET_2_0
344                                 | ControlStyles.UseTextForAccessibility
345 #endif
346                                 , false);
347                 }
348                 #endregion      // Public Constructors
349
350                 #region Private Internal Properties
351                 internal Size CheckBoxSize {
352                         get {
353                                 if (this.check_boxes) {
354                                         if (this.state_image_list != null)
355                                                 return this.state_image_list.ImageSize;
356                                         else
357                                                 return ThemeEngine.Current.ListViewCheckBoxSize;
358                                 }
359                                 return Size.Empty;
360                         }
361                 }
362
363                 internal Size ItemSize {
364                         get {
365                                 if (view != View.Details)
366                                         return item_size;
367
368                                 Size size = new Size ();
369                                 size.Height = item_size.Height;
370                                 for (int i = 0; i < columns.Count; i++)
371                                         size.Width += columns [i].Wd;
372
373                                 return size;
374                         }
375                         set {
376                                 item_size = value;
377                         }
378                 }
379
380                 internal int HotItemIndex {
381                         get {
382                                 return hot_item_index;
383                         }
384                         set {
385                                 hot_item_index = value;
386                         }
387                 }
388
389                 internal override bool ScaleChildrenInternal {
390                         get { return false; }
391                 }
392
393                 internal bool UseCustomColumnWidth {
394                         get {
395                                 return (view == View.List || view == View.SmallIcon) && columns.Count > 0;
396                         }
397                 }
398
399                 #endregion      // Private Internal Properties
400
401                 #region  Protected Properties
402                 protected override CreateParams CreateParams {
403                         get { return base.CreateParams; }
404                 }
405
406                 protected override Size DefaultSize {
407                         get { return ThemeEngine.Current.ListViewDefaultSize; }
408                 }
409 #if NET_2_0
410                 protected override bool DoubleBuffered {
411                         get {
412                                 return base.DoubleBuffered;
413                         }
414                         set {
415                                 base.DoubleBuffered = value;
416                         }
417                 }
418 #endif
419                 #endregion      // Protected Properties
420
421                 #region Public Instance Properties
422                 [DefaultValue (ItemActivation.Standard)]
423                 public ItemActivation Activation {
424                         get { return activation; }
425                         set { 
426                                 if (value != ItemActivation.Standard && value != ItemActivation.OneClick && 
427                                         value != ItemActivation.TwoClick) {
428                                         throw new InvalidEnumArgumentException (string.Format
429                                                 ("Enum argument value '{0}' is not valid for Activation", value));
430                                 }
431 #if NET_2_0
432                                 if (hot_tracking && value != ItemActivation.OneClick)
433                                         throw new ArgumentException ("When HotTracking is on, activation must be ItemActivation.OneClick");
434 #endif
435                                 
436                                 activation = value;
437                         }
438                 }
439
440                 [DefaultValue (ListViewAlignment.Top)]
441                 [Localizable (true)]
442                 public ListViewAlignment Alignment {
443                         get { return alignment; }
444                         set {
445                                 if (value != ListViewAlignment.Default && value != ListViewAlignment.Left && 
446                                         value != ListViewAlignment.SnapToGrid && value != ListViewAlignment.Top) {
447                                         throw new InvalidEnumArgumentException (string.Format 
448                                                 ("Enum argument value '{0}' is not valid for Alignment", value));
449                                 }
450                                 
451                                 if (this.alignment != value) {
452                                         alignment = value;
453                                         // alignment does not matter in Details/List views
454                                         if (this.view == View.LargeIcon || this.View == View.SmallIcon)
455                                                 this.Redraw (true);
456                                 }
457                         }
458                 }
459
460                 [DefaultValue (false)]
461                 public bool AllowColumnReorder {
462                         get { return allow_column_reorder; }
463                         set { allow_column_reorder = value; }
464                 }
465
466                 [DefaultValue (true)]
467                 public bool AutoArrange {
468                         get { return auto_arrange; }
469                         set {
470                                 if (auto_arrange != value) {
471                                         auto_arrange = value;
472                                         // autoarrange does not matter in Details/List views
473                                         if (this.view == View.LargeIcon || this.View == View.SmallIcon)
474                                                 this.Redraw (true);
475                                 }
476                         }
477                 }
478
479                 public override Color BackColor {
480                         get {
481                                 if (background_color.IsEmpty)
482                                         return ThemeEngine.Current.ColorWindow;
483                                 else
484                                         return background_color;
485                         }
486                         set { 
487                                 background_color = value;
488                                 item_control.BackColor = value;
489                         }
490                 }
491
492 #if !NET_2_0
493                 [Browsable (false)]
494                 [EditorBrowsable (EditorBrowsableState.Never)]
495                 public override Image BackgroundImage {
496                         get { return base.BackgroundImage; }
497                         set { base.BackgroundImage = value; }
498                 }
499 #endif
500
501 #if NET_2_0
502                 [Browsable (false)]
503                 [EditorBrowsable (EditorBrowsableState.Never)]
504                 public override ImageLayout BackgroundImageLayout {
505                         get {
506                                 return base.BackgroundImageLayout;
507                         }
508                         set {
509                                 base.BackgroundImageLayout = value;
510                         }
511                 }
512
513                 [DefaultValue (false)]
514                 public bool BackgroundImageTiled {
515                         get {
516                                 return item_control.BackgroundImageLayout == ImageLayout.Tile;
517                         }
518                         set {
519                                 ImageLayout new_image_layout = value ? ImageLayout.Tile : ImageLayout.None;
520                                 if (new_image_layout == item_control.BackgroundImageLayout)
521                                         return;
522
523                                 item_control.BackgroundImageLayout = new_image_layout;
524                         }
525                 }
526 #endif
527
528                 [DefaultValue (BorderStyle.Fixed3D)]
529                 [DispId (-504)]
530                 public BorderStyle BorderStyle {
531                         get { return InternalBorderStyle; }
532                         set { InternalBorderStyle = value; }
533                 }
534
535                 [DefaultValue (false)]
536                 public bool CheckBoxes {
537                         get { return check_boxes; }
538                         set {
539                                 if (check_boxes != value) {
540 #if NET_2_0
541                                         if (value && View == View.Tile)
542                                                 throw new NotSupportedException ("CheckBoxes are not"
543                                                         + " supported in Tile view. Choose a different"
544                                                         + " view or set CheckBoxes to false.");
545 #endif
546
547                                         check_boxes = value;
548                                         this.Redraw (true);
549                                 }
550                         }
551                 }
552
553                 [Browsable (false)]
554                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
555                 public CheckedIndexCollection CheckedIndices {
556                         get { return checked_indices; }
557                 }
558
559                 [Browsable (false)]
560                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
561                 public CheckedListViewItemCollection CheckedItems {
562                         get { return checked_items; }
563                 }
564
565 #if NET_2_0
566                 [Editor ("System.Windows.Forms.Design.ColumnHeaderCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
567 #endif
568                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
569                 [Localizable (true)]
570                 [MergableProperty (false)]
571                 public ColumnHeaderCollection Columns {
572                         get { return columns; }
573                 }
574
575                 [Browsable (false)]
576                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
577                 public ListViewItem FocusedItem {
578                         get {
579                                 if (focused_item_index == -1)
580                                         return null;
581
582                                 return items [focused_item_index];
583                         }
584 #if NET_2_0
585                         set {
586                                 if (value == null || value.ListView != this || 
587                                                 !IsHandleCreated)
588                                         return;
589
590                                 SetFocusedItem (value.Index);
591                         }
592 #endif
593                 }
594
595                 public override Color ForeColor {
596                         get {
597                                 if (foreground_color.IsEmpty)
598                                         return ThemeEngine.Current.ColorWindowText;
599                                 else
600                                         return foreground_color;
601                         }
602                         set { foreground_color = value; }
603                 }
604
605                 [DefaultValue (false)]
606                 public bool FullRowSelect {
607                         get { return full_row_select; }
608                         set { 
609                                 if (full_row_select != value) {
610                                         full_row_select = value;
611                                         InvalidateSelection ();
612                                 }
613                         }
614                 }
615
616                 [DefaultValue (false)]
617                 public bool GridLines {
618                         get { return grid_lines; }
619                         set {
620                                 if (grid_lines != value) {
621                                         grid_lines = value;
622                                         this.Redraw (false);
623                                 }
624                         }
625                 }
626
627                 [DefaultValue (ColumnHeaderStyle.Clickable)]
628                 public ColumnHeaderStyle HeaderStyle {
629                         get { return header_style; }
630                         set {
631                                 if (header_style == value)
632                                         return;
633
634                                 switch (value) {
635                                 case ColumnHeaderStyle.Clickable:
636                                 case ColumnHeaderStyle.Nonclickable:
637                                 case ColumnHeaderStyle.None:
638                                         break;
639                                 default:
640                                         throw new InvalidEnumArgumentException (string.Format 
641                                                 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
642                                 }
643                                 
644                                 header_style = value;
645                                 if (view == View.Details)
646                                         Redraw (true);
647                         }
648                 }
649
650                 [DefaultValue (true)]
651                 public bool HideSelection {
652                         get { return hide_selection; }
653                         set {
654                                 if (hide_selection != value) {
655                                         hide_selection = value;
656                                         InvalidateSelection ();
657                                 }
658                         }
659                 }
660
661 #if NET_2_0
662                 [DefaultValue (false)]
663                 public bool HotTracking {
664                         get {
665                                 return hot_tracking;
666                         }
667                         set {
668                                 if (hot_tracking == value)
669                                         return;
670                                 
671                                 hot_tracking = value;
672                                 if (hot_tracking) {
673                                         hover_selection = true;
674                                         activation = ItemActivation.OneClick;
675                                 }
676                         }
677                 }
678 #endif
679
680                 [DefaultValue (false)]
681                 public bool HoverSelection {
682                         get { return hover_selection; }
683                         set { 
684 #if NET_2_0
685                                 if (hot_tracking && value == false)
686                                         throw new ArgumentException ("When HotTracking is on, hover selection must be true");
687 #endif
688                                 hover_selection = value; 
689                         }
690                 }
691
692 #if NET_2_0
693                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
694                 [Browsable (false)]
695                 public ListViewInsertionMark InsertionMark {
696                         get {
697                                 return insertion_mark;
698                         }
699                 }
700 #endif
701
702 #if NET_2_0
703                 [Editor ("System.Windows.Forms.Design.ListViewItemCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
704 #endif
705                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
706                 [Localizable (true)]
707                 [MergableProperty (false)]
708                 public ListViewItemCollection Items {
709                         get { return items; }
710                 }
711
712                 [DefaultValue (false)]
713                 public bool LabelEdit {
714                         get { return label_edit; }
715                         set { label_edit = value; }
716                 }
717
718                 [DefaultValue (true)]
719                 [Localizable (true)]
720                 public bool LabelWrap {
721                         get { return label_wrap; }
722                         set {
723                                 if (label_wrap != value) {
724                                         label_wrap = value;
725                                         this.Redraw (true);
726                                 }
727                         }
728                 }
729
730                 [DefaultValue (null)]
731                 public ImageList LargeImageList {
732                         get { return large_image_list; }
733                         set {
734                                 large_image_list = value;
735                                 this.Redraw (true);
736                         }
737                 }
738
739                 [Browsable (false)]
740                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
741                 public IComparer ListViewItemSorter {
742                         get {
743                                 if (View != View.SmallIcon && View != View.LargeIcon && item_sorter is ItemComparer)
744                                         return null;
745                                 return item_sorter;
746                         }
747                         set {
748                                 if (item_sorter != value) {
749                                         item_sorter = value;
750                                         Sort ();
751                                 }
752                         }
753                 }
754
755                 [DefaultValue (true)]
756                 public bool MultiSelect {
757                         get { return multiselect; }
758                         set { multiselect = value; }
759                 }
760
761
762 #if NET_2_0
763                 [DefaultValue(false)]
764                 public bool OwnerDraw {
765                         get { return owner_draw; }
766                         set { 
767                                 owner_draw = value;
768                                 Redraw (true);
769                         }
770                 }
771
772                 [Browsable (false)]
773                 [EditorBrowsable (EditorBrowsableState.Never)]
774                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
775                 public new Padding Padding {
776                         get {
777                                 return base.Padding;
778                         }
779                         set {
780                                 base.Padding = value;
781                         }
782                 }
783                 
784                 [MonoTODO ("RTL not supported")]
785                 [Localizable (true)]
786                 [DefaultValue (false)]
787                 public virtual bool RightToLeftLayout {
788                         get { return right_to_left_layout; }
789                         set { 
790                                 if (right_to_left_layout != value) {
791                                         right_to_left_layout = value;
792                                         OnRightToLeftLayoutChanged (EventArgs.Empty);
793                                 }
794                         }
795                 }
796 #endif
797
798                 [DefaultValue (true)]
799                 public bool Scrollable {
800                         get { return scrollable; }
801                         set {
802                                 if (scrollable != value) {
803                                         scrollable = value;
804                                         this.Redraw (true);
805                                 }
806                         }
807                 }
808
809                 [Browsable (false)]
810                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
811                 public SelectedIndexCollection SelectedIndices {
812                         get { return selected_indices; }
813                 }
814
815                 [Browsable (false)]
816                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
817                 public SelectedListViewItemCollection SelectedItems {
818                         get { return selected_items; }
819                 }
820
821 #if NET_2_0
822                 [DefaultValue(true)]
823                 public bool ShowGroups {
824                         get { return show_groups; }
825                         set {
826                                 if (show_groups != value) {
827                                         show_groups = value;
828                                         Redraw(true);
829                                 }
830                         }
831                 }
832
833                 [LocalizableAttribute (true)]
834                 [MergableProperty (false)]
835                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
836                 [Editor ("System.Windows.Forms.Design.ListViewGroupCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
837                 public ListViewGroupCollection Groups {
838                         get { return groups; }
839                 }
840
841                 [DefaultValue (false)]
842                 public bool ShowItemToolTips {
843                         get {
844                                 return show_item_tooltips;
845                         }
846                         set {
847                                 show_item_tooltips = value;
848                                 item_tooltip.Active = false;
849                         }
850                 }
851 #endif
852
853                 [DefaultValue (null)]
854                 public ImageList SmallImageList {
855                         get { return small_image_list; }
856                         set {
857                                 small_image_list = value;
858                                 this.Redraw (true);
859                         }
860                 }
861
862                 [DefaultValue (SortOrder.None)]
863                 public SortOrder Sorting {
864                         get { return sort_order; }
865                         set { 
866                                 if (!Enum.IsDefined (typeof (SortOrder), value)) {
867                                         throw new InvalidEnumArgumentException ("value", (int) value,
868                                                 typeof (SortOrder));
869                                 }
870                                 
871                                 if (sort_order == value)
872                                         return;
873
874                                 sort_order = value;
875
876 #if NET_2_0
877                                 if (virtual_mode) // Sorting is not allowed in virtual mode
878                                         return;
879 #endif
880
881                                 if (value == SortOrder.None) {
882                                         if (item_sorter != null) {
883                                                 // ListViewItemSorter should never be reset for SmallIcon
884                                                 // and LargeIcon view
885                                                 if (View != View.SmallIcon && View != View.LargeIcon)
886 #if NET_2_0
887                                                         item_sorter = null;
888 #else
889                                                         // in .NET 1.1, only internal IComparer would be
890                                                         // set to null
891                                                         if (item_sorter is ItemComparer)
892                                                                 item_sorter = null;
893 #endif
894                                         }
895                                         this.Redraw (false);
896                                 } else {
897                                         if (item_sorter == null)
898                                                 item_sorter = new ItemComparer (value);
899                                         if (item_sorter is ItemComparer) {
900 #if NET_2_0
901                                                 item_sorter = new ItemComparer (value);
902 #else
903                                                 // in .NET 1.1, the sort order is not updated for
904                                                 // SmallIcon and LargeIcon views if no custom IComparer
905                                                 // is set
906                                                 if (View != View.SmallIcon && View != View.LargeIcon)
907                                                         item_sorter = new ItemComparer (value);
908 #endif
909                                         }
910                                         Sort ();
911                                 }
912                         }
913                 }
914
915                 private void OnImageListChanged (object sender, EventArgs args)
916                 {
917                         item_control.Invalidate ();
918                 }
919
920                 [DefaultValue (null)]
921                 public ImageList StateImageList {
922                         get { return state_image_list; }
923                         set {
924                                 if (state_image_list == value)
925                                         return;
926
927                                 if (state_image_list != null)
928                                         state_image_list.Images.Changed -= new EventHandler (OnImageListChanged);
929
930                                 state_image_list = value;
931
932                                 if (state_image_list != null)
933                                         state_image_list.Images.Changed += new EventHandler (OnImageListChanged);
934
935                                 this.Redraw (true);
936                         }
937                 }
938
939                 [Bindable (false)]
940                 [Browsable (false)]
941                 [EditorBrowsable (EditorBrowsableState.Never)]
942                 public override string Text {
943                         get { return base.Text; } 
944                         set {
945                                 if (value == base.Text)
946                                         return;
947
948                                 base.Text = value;
949                                 this.Redraw (true);
950                         }
951                 }
952
953 #if NET_2_0
954                 [Browsable (true)]
955                 public Size TileSize {
956                         get {
957                                 return tile_size;
958                         }
959                         set {
960                                 if (value.Width <= 0 || value.Height <= 0)
961                                         throw new ArgumentOutOfRangeException ("value");
962
963                                 tile_size = value;
964                                 Redraw (true);
965                         }
966                 }
967 #endif
968
969                 [Browsable (false)]
970                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
971                 public ListViewItem TopItem {
972                         get {
973 #if NET_2_0
974                                 if (view == View.LargeIcon || view == View.SmallIcon || view == View.Tile)
975                                         throw new InvalidOperationException ("Cannot get the top item in LargeIcon, SmallIcon or Tile view.");
976 #endif
977                                 // there is no item
978                                 if (this.items.Count == 0)
979                                         return null;
980                                 // if contents are not scrolled
981                                 // it is the first item
982                                 else if (h_marker == 0 && v_marker == 0)
983                                         return this.items [0];
984                                 // do a hit test for the scrolled position
985                                 else {
986                                         for (int i = 0; i < items.Count; i++) {
987                                                 Point item_loc = GetItemLocation (i);
988                                                 if (item_loc.X >= 0 && item_loc.Y >= 0)
989                                                         return items [i];
990                                         }
991                                         return null;
992                                 }
993                         }
994 #if NET_2_0
995                         set {
996                                 if (view == View.LargeIcon || view == View.SmallIcon || view == View.Tile)
997                                         throw new InvalidOperationException ("Cannot set the top item in LargeIcon, SmallIcon or Tile view.");
998
999                                 // .Net doesn't throw any exception in the cases below
1000                                 if (value == null || value.ListView != this)
1001                                         return;
1002
1003                                 EnsureVisible (value.Index);
1004                         }
1005 #endif
1006                 }
1007
1008 #if NET_2_0
1009                 [EditorBrowsable (EditorBrowsableState.Advanced)]
1010                 [DefaultValue (true)]
1011                 [Browsable (false)]
1012                 [MonoInternalNote ("Stub, not implemented")]
1013                 public bool UseCompatibleStateImageBehavior {
1014                         get {
1015                                 return false;
1016                         }
1017                         set {
1018                         }
1019                 }
1020 #endif
1021
1022                 [DefaultValue (View.LargeIcon)]
1023                 public View View {
1024                         get { return view; }
1025                         set { 
1026                                 if (!Enum.IsDefined (typeof (View), value))
1027                                         throw new InvalidEnumArgumentException ("value", (int) value,
1028                                                 typeof (View));
1029
1030                                 if (view != value) {
1031 #if NET_2_0
1032                                         if (CheckBoxes && value == View.Tile)
1033                                                 throw new NotSupportedException ("CheckBoxes are not"
1034                                                         + " supported in Tile view. Choose a different"
1035                                                         + " view or set CheckBoxes to false.");
1036 #endif
1037
1038                                         h_scroll.Value = v_scroll.Value = 0;
1039                                         view = value; 
1040                                         Redraw (true);
1041                                 }
1042                         }
1043                 }
1044
1045 #if NET_2_0
1046                 [DefaultValue (false)]
1047                 [RefreshProperties (RefreshProperties.Repaint)]
1048                 public bool VirtualMode {
1049                         get {
1050                                 return virtual_mode;
1051                         }
1052                         set {
1053                                 if (virtual_mode == value)
1054                                         return;
1055
1056                                 if (!virtual_mode && items.Count > 0)
1057                                         throw new InvalidOperationException ();
1058
1059                                 virtual_mode = value;
1060                                 Redraw (true);
1061                         }
1062                 }
1063
1064                 [DefaultValue (0)]
1065                 [RefreshProperties (RefreshProperties.Repaint)]
1066                 public int VirtualListSize {
1067                         get {
1068                                 return virtual_list_size;
1069                         }
1070                         set {
1071                                 if (value < 0)
1072                                         throw new ArgumentException ("value");
1073
1074                                 if (virtual_list_size == value)
1075                                         return;
1076
1077                                 virtual_list_size = value;
1078                                 if (virtual_mode) {
1079                                         selected_indices.Reset ();
1080                                         Redraw (true);
1081                                 }
1082                         }
1083                 }
1084 #endif
1085                 #endregion      // Public Instance Properties
1086
1087                 #region Internal Methods Properties
1088                 
1089                 internal int FirstVisibleIndex {
1090                         get {
1091                                 // there is no item
1092                                 if (this.items.Count == 0)
1093                                         return 0;
1094                                 
1095                                 if (h_marker == 0 && v_marker == 0)
1096                                         return 0;
1097                                 
1098                                 Size item_size = ItemSize;
1099                                 for (int i = 0; i < items.Count; i++) {
1100                                         Rectangle item_rect = new Rectangle (GetItemLocation (i), item_size);
1101                                         if (item_rect.Right >= 0 && item_rect.Bottom >= 0)
1102                                                 return i;
1103                                 }
1104
1105                                 return 0;
1106                         }
1107                 }
1108
1109                 
1110                 internal int LastVisibleIndex {
1111                         get {
1112                                 for (int i = FirstVisibleIndex; i < Items.Count; i++) {
1113                                         if (View == View.List || Alignment == ListViewAlignment.Left) {
1114                                                 if (GetItemLocation (i).X > item_control.ClientRectangle.Right)
1115                                                         return i - 1;
1116                                         } else {
1117                                                 if (GetItemLocation (i).Y > item_control.ClientRectangle.Bottom)
1118                                                         return i - 1;
1119                                         }
1120                                 }
1121                                 
1122                                 return Items.Count - 1;
1123                         }
1124                 }
1125
1126                 internal void OnSelectedIndexChanged ()
1127                 {
1128                         if (IsHandleCreated)
1129                                 OnSelectedIndexChanged (EventArgs.Empty);
1130                 }
1131
1132                 internal int TotalWidth {
1133                         get { return Math.Max (this.Width, this.layout_wd); }
1134                 }
1135
1136                 internal int TotalHeight {
1137                         get { return Math.Max (this.Height, this.layout_ht); }
1138                 }
1139
1140                 internal void Redraw (bool recalculate)
1141                 {
1142                         // Avoid calculations when control is being updated
1143                         if (updating)
1144                                 return;
1145 #if NET_2_0
1146                         // VirtualMode doesn't do any calculations until handle is created
1147                         if (virtual_mode && !IsHandleCreated)
1148                                 return;
1149 #endif
1150
1151
1152                         if (recalculate)
1153                                 CalculateListView (this.alignment);
1154
1155                         Refresh ();
1156                 }
1157
1158                 void InvalidateSelection ()
1159                 {
1160                         foreach (int selected_index in SelectedIndices)
1161                                 items [selected_index].Invalidate ();
1162                 }
1163
1164                 const int text_padding = 15;
1165
1166                 internal Size GetChildColumnSize (int index)
1167                 {
1168                         Size ret_size = Size.Empty;
1169                         ColumnHeader col = this.columns [index];
1170
1171                         if (col.Width == -2) { // autosize = max(items, columnheader)
1172                                 Size size = Size.Ceiling (TextRenderer.MeasureString
1173                                         (col.Text, this.Font));
1174                                 size.Width += text_padding;
1175                                 ret_size = BiggestItem (index);
1176                                 if (size.Width > ret_size.Width)
1177                                         ret_size = size;
1178                         }
1179                         else { // -1 and all the values < -2 are put under one category
1180                                 ret_size = BiggestItem (index);
1181                                 // fall back to empty columns' width if no subitem is available for a column
1182                                 if (ret_size.IsEmpty) {
1183                                         ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth;
1184                                         if (col.Text.Length > 0)
1185                                                 ret_size.Height = Size.Ceiling (TextRenderer.MeasureString
1186                                                                                 (col.Text, this.Font)).Height;
1187                                         else
1188                                                 ret_size.Height = this.Font.Height;
1189                                 }
1190                         }
1191
1192                         ret_size.Height += text_padding;
1193
1194                         // adjust the size for icon and checkbox for 0th column
1195                         if (index == 0) {
1196                                 ret_size.Width += (this.CheckBoxSize.Width + 4);
1197                                 if (this.small_image_list != null)
1198                                         ret_size.Width += this.small_image_list.ImageSize.Width;
1199                         }
1200                         return ret_size;
1201                 }
1202
1203                 // Returns the size of biggest item text in a column
1204                 // or the sum of the text and indent count if we are on 2.0
1205                 private Size BiggestItem (int col)
1206                 {
1207                         Size temp = Size.Empty;
1208                         Size ret_size = Size.Empty;
1209 #if NET_2_0
1210                         bool use_indent_count = small_image_list != null;
1211
1212                         // VirtualMode uses the first item text size
1213                         if (virtual_mode && items.Count > 0) {
1214                                 ListViewItem item = items [0];
1215                                 ret_size = Size.Ceiling (TextRenderer.MeasureString (item.SubItems[col].Text,
1216                                                         Font));
1217
1218                                 if (use_indent_count)
1219                                         ret_size.Width += item.IndentCount * small_image_list.ImageSize.Width;
1220                         } else {
1221 #endif
1222                                 // 0th column holds the item text, we check the size of
1223                                 // the various subitems falling in that column and get
1224                                 // the biggest one's size.
1225                                 foreach (ListViewItem item in items) {
1226                                         if (col >= item.SubItems.Count)
1227                                                 continue;
1228
1229                                         temp = Size.Ceiling (TextRenderer.MeasureString
1230                                                                 (item.SubItems [col].Text, Font));
1231
1232 #if NET_2_0
1233                                         if (use_indent_count)
1234                                                 temp.Width += item.IndentCount * small_image_list.ImageSize.Width;
1235 #endif
1236     
1237                                         if (temp.Width > ret_size.Width)
1238                                                 ret_size = temp;
1239                                 }
1240 #if NET_2_0
1241                         }
1242 #endif
1243
1244                         // adjustment for space in Details view
1245                         if (!ret_size.IsEmpty && view == View.Details)
1246                                 ret_size.Width += ThemeEngine.Current.ListViewItemPaddingWidth;
1247
1248                         return ret_size;
1249                 }
1250
1251                 const int max_wrap_padding = 30;
1252
1253                 // Sets the size of the biggest item text as per the view
1254                 private void CalcTextSize ()
1255                 {
1256                         // clear the old value
1257                         text_size = Size.Empty;
1258
1259                         if (items.Count == 0)
1260                                 return;
1261
1262                         text_size = BiggestItem (0);
1263
1264                         if (view == View.LargeIcon && this.label_wrap) {
1265                                 Size temp = Size.Empty;
1266                                 if (this.check_boxes)
1267                                         temp.Width += 2 * this.CheckBoxSize.Width;
1268                                 int icon_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
1269                                 temp.Width += icon_w + max_wrap_padding;
1270                                 // wrapping is done for two lines only
1271                                 if (text_size.Width > temp.Width) {
1272                                         text_size.Width = temp.Width;
1273                                         text_size.Height *= 2;
1274                                 }
1275                         }
1276                         else if (view == View.List) {
1277                                 // in list view max text shown in determined by the
1278                                 // control width, even if scolling is enabled.
1279                                 int max_wd = this.Width - (this.CheckBoxSize.Width - 2);
1280                                 if (this.small_image_list != null)
1281                                         max_wd -= this.small_image_list.ImageSize.Width;
1282
1283                                 if (text_size.Width > max_wd)
1284                                         text_size.Width = max_wd;
1285                         }
1286
1287                         // we do the default settings, if we have got 0's
1288                         if (text_size.Height <= 0)
1289                                 text_size.Height = this.Font.Height;
1290                         if (text_size.Width <= 0)
1291                                 text_size.Width = this.Width;
1292
1293                         // little adjustment
1294                         text_size.Width += 2;
1295                         text_size.Height += 2;
1296                 }
1297
1298                 private void Scroll (ScrollBar scrollbar, int delta)
1299                 {
1300                         if (delta == 0 || !scrollbar.Visible)
1301                                 return;
1302
1303                         int max;
1304                         if (scrollbar == h_scroll)
1305                                 max = h_scroll.Maximum - item_control.Width;
1306                         else
1307                                 max = v_scroll.Maximum - item_control.Height;
1308
1309                         int val = scrollbar.Value + delta;
1310                         if (val > max)
1311                                 val = max;
1312                         else if (val < scrollbar.Minimum)
1313                                 val = scrollbar.Minimum;
1314                         scrollbar.Value = val;
1315                 }
1316
1317                 private void CalculateScrollBars ()
1318                 {
1319                         if (!IsHandleCreated)
1320                                 return;
1321
1322                         Rectangle client_area = ClientRectangle;
1323                         int height = client_area.Height;
1324                         int width = client_area.Width;
1325                         
1326                         if (!scrollable) {
1327                                 h_scroll.Visible = false;
1328                                 v_scroll.Visible = false;
1329                                 item_control.Size = new Size (width, height);
1330                                 header_control.Width = width;
1331                                 return;
1332                         }
1333
1334                         // Don't calculate if the view is not displayable
1335                         if (client_area.Height < 0 || client_area.Width < 0)
1336                                 return;
1337
1338                         // making a scroll bar visible might make
1339                         // other scroll bar visible
1340                         if (layout_wd > client_area.Right) {
1341                                 h_scroll.Visible = true;
1342                                 if ((layout_ht + h_scroll.Height) > client_area.Bottom)
1343                                         v_scroll.Visible = true;
1344                                 else
1345                                         v_scroll.Visible = false;
1346                         } else if (layout_ht > client_area.Bottom) {
1347                                 v_scroll.Visible = true;
1348                                 if ((layout_wd + v_scroll.Width) > client_area.Right)
1349                                         h_scroll.Visible = true;
1350                                 else
1351                                         h_scroll.Visible = false;
1352                         } else {
1353                                 h_scroll.Visible = false;
1354                                 v_scroll.Visible = false;
1355                         }
1356
1357
1358                         if (h_scroll.is_visible) {
1359                                 h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
1360                                 h_scroll.Minimum = 0;
1361
1362                                 // if v_scroll is visible, adjust the maximum of the
1363                                 // h_scroll to account for the width of v_scroll
1364                                 if (v_scroll.Visible) {
1365                                         h_scroll.Maximum = layout_wd + v_scroll.Width;
1366                                         h_scroll.Width = client_area.Width - v_scroll.Width;
1367                                 }
1368                                 else {
1369                                         h_scroll.Maximum = layout_wd;
1370                                         h_scroll.Width = client_area.Width;
1371                                 }
1372
1373                                 h_scroll.LargeChange = client_area.Width;
1374                                 h_scroll.SmallChange = Font.Height;
1375                                 height -= h_scroll.Height;
1376                         }
1377
1378                         if (v_scroll.is_visible) {
1379                                 v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
1380                                 v_scroll.Minimum = 0;
1381
1382                                 // if h_scroll is visible, adjust the maximum of the
1383                                 // v_scroll to account for the height of h_scroll
1384                                 if (h_scroll.Visible) {
1385                                         v_scroll.Maximum = layout_ht + h_scroll.Height;
1386                                         v_scroll.Height = client_area.Height; // - h_scroll.Height already done 
1387                                 } else {
1388                                         v_scroll.Maximum = layout_ht;
1389                                         v_scroll.Height = client_area.Height;
1390                                 }
1391
1392                                 v_scroll.LargeChange = client_area.Height;
1393                                 v_scroll.SmallChange = Font.Height;
1394                                 width -= v_scroll.Width;
1395                         }
1396                         
1397                         item_control.Size = new Size (width, height);
1398
1399                         if (header_control.is_visible)
1400                                 header_control.Width = width;
1401                 }
1402
1403 #if NET_2_0
1404                 internal int GetReorderedColumnIndex (ColumnHeader column)
1405                 {
1406                         if (reordered_column_indices == null)
1407                                 return column.Index;
1408
1409                         for (int i = 0; i < Columns.Count; i++)
1410                                 if (reordered_column_indices [i] == column.Index)
1411                                         return i;
1412
1413                         return -1;
1414                 }
1415 #endif
1416
1417                 internal ColumnHeader GetReorderedColumn (int index)
1418                 {
1419                         if (reordered_column_indices == null)
1420                                 return Columns [index];
1421                         else
1422                                 return Columns [reordered_column_indices [index]];
1423                 }
1424
1425                 internal void ReorderColumn (ColumnHeader col, int index, bool fireEvent)
1426                 {
1427 #if NET_2_0
1428                         if (fireEvent) {
1429                                 ColumnReorderedEventHandler eh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
1430                                 if (eh != null){
1431                                         ColumnReorderedEventArgs args = new ColumnReorderedEventArgs (col.Index, index, col);
1432
1433                                         eh (this, args);
1434                                         if (args.Cancel) {
1435                                                 header_control.Invalidate ();
1436                                                 item_control.Invalidate ();
1437                                                 return;
1438                                         }
1439                                 }
1440                         }
1441 #endif
1442                         int column_count = Columns.Count;
1443
1444                         if (reordered_column_indices == null) {
1445                                 reordered_column_indices = new int [column_count];
1446                                 for (int i = 0; i < column_count; i++)
1447                                         reordered_column_indices [i] = i;
1448                         }
1449
1450                         if (reordered_column_indices [index] == col.Index)
1451                                 return;
1452
1453                         int[] curr = reordered_column_indices;
1454                         int [] result = new int [column_count];
1455                         int curr_idx = 0;
1456                         for (int i = 0; i < column_count; i++) {
1457                                 if (curr_idx < column_count && curr [curr_idx] == col.Index)
1458                                         curr_idx++;
1459
1460                                 if (i == index)
1461                                         result [i] = col.Index;
1462                                 else
1463                                         result [i] = curr [curr_idx++];
1464                         }
1465
1466                         ReorderColumns (result, true);
1467                 }
1468
1469                 internal void ReorderColumns (int [] display_indices, bool redraw)
1470                 {
1471                         reordered_column_indices = display_indices;
1472                         for (int i = 0; i < Columns.Count; i++) {
1473                                 ColumnHeader col = Columns [i];
1474                                 col.InternalDisplayIndex = reordered_column_indices [i];
1475                         }
1476                         if (redraw && view == View.Details && IsHandleCreated) {
1477                                 LayoutDetails ();
1478                                 header_control.Invalidate ();
1479                                 item_control.Invalidate ();
1480                         }
1481                 }
1482
1483                 internal void AddColumn (ColumnHeader newCol, int index, bool redraw)
1484                 {
1485                         int column_count = Columns.Count;
1486                         newCol.SetListView (this);
1487
1488                         int [] display_indices = new int [column_count];
1489                         for (int i = 0; i < column_count; i++) {
1490                                 ColumnHeader col = Columns [i];
1491                                 if (i == index) {
1492                                         display_indices [i] = index;
1493                                 } else {
1494                                         int display_index = col.InternalDisplayIndex;
1495                                         if (display_index < index) {
1496                                                 display_indices [i] = display_index;
1497                                         } else {
1498                                                 display_indices [i] = (display_index + 1);
1499                                         }
1500                                 }
1501                         }
1502
1503                         ReorderColumns (display_indices, redraw);
1504                         Invalidate ();
1505                 }
1506
1507                 Size LargeIconItemSize
1508                 {
1509                         get {
1510                                 int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
1511                                 int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
1512                                 int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
1513                                 int w = Math.Max (text_size.Width, image_w);
1514
1515                                 if (check_boxes)
1516                                         w += 2 + CheckBoxSize.Width;
1517
1518                                 return new Size (w, h);
1519                         }
1520                 }
1521
1522                 Size SmallIconItemSize {
1523                         get {
1524                                 int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
1525                                 int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
1526                                 int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
1527                                 int w = text_size.Width + image_w;
1528
1529                                 if (check_boxes)
1530                                         w += 2 + CheckBoxSize.Width;
1531
1532                                 return new Size (w, h);
1533                         }
1534                 }
1535
1536 #if NET_2_0
1537                 Size TileItemSize {
1538                         get {
1539                                 // Calculate tile size if needed
1540                                 // It appears that using Font.Size instead of a SizeF value can give us
1541                                 // a slightly better approach to the proportions defined in .Net
1542                                 if (tile_size == Size.Empty) {
1543                                         int image_w = LargeImageList == null ? 0 : LargeImageList.ImageSize.Width;
1544                                         int image_h = LargeImageList == null ? 0 : LargeImageList.ImageSize.Height;
1545                                         int w = (int)Font.Size * ThemeEngine.Current.ListViewTileWidthFactor + image_w + 4;
1546                                         int h = Math.Max ((int)Font.Size * ThemeEngine.Current.ListViewTileHeightFactor, image_h);
1547                                 
1548                                         tile_size = new Size (w, h);
1549                                 }
1550                         
1551                                 return tile_size;
1552                         }
1553                 }
1554 #endif
1555
1556                 int GetDetailsItemHeight ()
1557                 {
1558                         int item_height;
1559                         int checkbox_height = CheckBoxes ? CheckBoxSize.Height : 0;
1560                         int small_image_height = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
1561                         item_height = Math.Max (checkbox_height, text_size.Height);
1562                         item_height = Math.Max (item_height, small_image_height);
1563                         return item_height;
1564                 }
1565
1566                 void SetItemLocation (int index, int x, int y, int row, int col)
1567                 {
1568                         Point old_location = items_location [index];
1569                         if (old_location.X == x && old_location.Y == y)
1570                                 return;
1571
1572                         Size item_size = ItemSize;
1573                         Rectangle old_rect = new Rectangle (GetItemLocation (index), item_size);
1574
1575                         items_location [index] = new Point (x, y);
1576                         items_matrix_location [index] = new ItemMatrixLocation (row, col);
1577
1578                         //
1579                         // Initial position matches item's position in ListViewItemCollection
1580                         //
1581                         reordered_items_indices [index] = index;
1582
1583                         // Invalidate both previous and new bounds
1584                         item_control.Invalidate (old_rect);
1585                         item_control.Invalidate (new Rectangle (GetItemLocation (index), item_size));
1586                 }
1587
1588 #if NET_2_0
1589                 void ShiftItemsPositions (int from, int to, bool forward)
1590                 {
1591                         if (forward) {
1592                                 for (int i = to + 1; i > from; i--) {
1593                                         reordered_items_indices [i] = reordered_items_indices [i - 1];
1594
1595                                         ListViewItem item = items [reordered_items_indices [i]];
1596                                         item_control.Invalidate (item.Bounds);
1597                                         item.DisplayIndex = i;
1598                                         item_control.Invalidate (item.Bounds);
1599                                 }
1600                         } else {
1601                                 for (int i = from - 1; i < to; i++) {
1602                                         reordered_items_indices [i] = reordered_items_indices [i + 1];
1603
1604                                         ListViewItem item = items [reordered_items_indices [i]];
1605                                         item_control.Invalidate (item.Bounds);
1606                                         item.DisplayIndex = i;
1607                                         item_control.Invalidate (item.Bounds);
1608                                 }
1609                         }
1610                 }
1611
1612                 internal void ChangeItemLocation (int display_index, Point new_pos)
1613                 {
1614                         int new_display_index = GetDisplayIndexFromLocation (new_pos);
1615                         if (new_display_index == display_index)
1616                                 return;
1617
1618                         int item_index = reordered_items_indices [display_index];
1619                         ListViewItem item = items [item_index];
1620
1621                         bool forward = new_display_index < display_index;
1622                         int index_from, index_to;
1623                         if (forward) {
1624                                 index_from = new_display_index;
1625                                 index_to = display_index - 1;
1626                         } else {
1627                                 index_from = display_index + 1;
1628                                 index_to = new_display_index;
1629                         }
1630
1631                         ShiftItemsPositions (index_from, index_to, forward);
1632
1633                         reordered_items_indices [new_display_index] = item_index;
1634
1635                         item_control.Invalidate (item.Bounds);
1636                         item.DisplayIndex = new_display_index;
1637                         item_control.Invalidate (item.Bounds);
1638                 }
1639
1640                 int GetDisplayIndexFromLocation (Point loc)
1641                 {
1642                         int display_index = -1;
1643                         Rectangle item_area;
1644
1645                         // First item
1646                         if (loc.X < 0 || loc.Y < 0)
1647                                 return 0;
1648
1649                         // Adjustment to put in the next position refered by 'loc'
1650                         loc.X -= item_size.Width / 2;
1651                         if (loc.X < 0)
1652                                 loc.X = 0;
1653
1654                         for (int i = 0; i < items.Count; i++) {
1655                                 item_area = new Rectangle (GetItemLocation (i), item_size);
1656                                 item_area.Inflate (ThemeEngine.Current.ListViewHorizontalSpacing,
1657                                                 ThemeEngine.Current.ListViewVerticalSpacing);
1658
1659                                 if (item_area.Contains (loc)) {
1660                                         display_index = i;
1661                                         break;
1662                                 }
1663                         }
1664
1665                         // Put in in last position
1666                         if (display_index == -1)
1667                                 display_index = items.Count - 1;
1668
1669                         return display_index;
1670                 }
1671
1672                 // When using groups, the items with no group assigned
1673                 // belong to the DefaultGroup
1674                 int GetDefaultGroupItems ()
1675                 {
1676                         int count = 0;
1677                         foreach (ListViewItem item in items)
1678                                 if (item.Group == null)
1679                                         count++;
1680
1681                         return count;
1682                 }
1683 #endif
1684
1685                 int rows;
1686                 int cols;
1687                 int[,] item_index_matrix;
1688
1689                 void CalculateRowsAndCols (Size item_size, bool left_aligned, int x_spacing, int y_spacing)
1690                 {
1691                         Rectangle area = ClientRectangle;
1692
1693                         if (UseCustomColumnWidth)
1694                                 CalculateCustomColumnWidth ();
1695 #if NET_2_0
1696                         if (show_groups && groups.Count > 0 && view != View.List) {
1697                                 // When groups are used the alignment is always top-aligned
1698                                 rows = 0;
1699                                 cols = 0;
1700
1701                                 groups.DefaultGroup.ItemCount = GetDefaultGroupItems ();
1702                                 for (int i = 0; i < groups.InternalCount; i++) {
1703                                         ListViewGroup group = groups.GetInternalGroup (i);
1704                                         int items_in_group = group.ItemCount;
1705
1706                                         if (items_in_group == 0)
1707                                                 continue;
1708
1709                                         int group_cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(item_size.Width + x_spacing));
1710                                         if (group_cols <= 0)
1711                                                 group_cols = 1;
1712                                         int group_rows = (int) Math.Ceiling ((double)items_in_group / (double)group_cols);
1713
1714                                         group.starting_row = rows;
1715                                         group.rows = group_rows;
1716
1717                                         cols = Math.Max (group_cols, cols);
1718                                         rows += group_rows;
1719                                 }
1720                         } else
1721 #endif
1722                         {
1723                                 // Simple matrix if no groups are used
1724                                 if (left_aligned) {
1725                                         rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(item_size.Height + y_spacing));
1726                                         if (rows <= 0)
1727                                                 rows = 1;
1728                                         cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
1729                                 } else {
1730                                         if (UseCustomColumnWidth)
1731                                                 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width) / (double)(custom_column_width));
1732                                         else
1733                                                 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(item_size.Width + x_spacing));
1734
1735                                         if (cols < 1)
1736                                                 cols = 1;
1737
1738                                         rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
1739                                 }
1740                         }
1741
1742                         item_index_matrix = new int [rows, cols];
1743                 }
1744
1745                 // When using custom column width, we look for the minimum one
1746                 void CalculateCustomColumnWidth ()
1747                 {
1748                         int min_width = Int32.MaxValue;
1749                         for (int i = 0; i < columns.Count; i++) {
1750                                 int col_width = columns [i].Width;
1751
1752                                 if (col_width < min_width)
1753                                         min_width = col_width;
1754                         }
1755
1756                         custom_column_width = min_width;
1757                 }
1758
1759                 void LayoutIcons (Size item_size, bool left_aligned, int x_spacing, int y_spacing)
1760                 {
1761                         header_control.Visible = false;
1762                         header_control.Size = Size.Empty;
1763                         item_control.Visible = true;
1764                         item_control.Location = Point.Empty;
1765                         ItemSize = item_size; // Cache item size
1766
1767                         if (items.Count == 0)
1768                                 return;
1769
1770                         Size sz = item_size;
1771 #if NET_2_0
1772                         bool using_groups = show_groups && groups.Count > 0 && view != View.List;
1773 #endif
1774
1775                         CalculateRowsAndCols (sz, left_aligned, x_spacing, y_spacing);
1776
1777                         layout_wd = UseCustomColumnWidth ? cols * custom_column_width : cols * (sz.Width + x_spacing) - x_spacing;
1778                         layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
1779 #if NET_2_0
1780                         if (using_groups)
1781                                 CalculateGroupsLayout (sz, y_spacing, 0);
1782 #endif
1783
1784                         int row = 0, col = 0;
1785                         int x = 0, y = 0;
1786
1787                         for (int i = 0; i < items.Count; i++) {
1788                                 ListViewItem item = items [i];
1789 #if NET_2_0
1790                                 if (using_groups) {
1791                                         ListViewGroup group = item.Group;
1792                                         if (group == null)
1793                                                 group = groups.DefaultGroup;
1794
1795                                         Point group_items_loc = group.items_area_location;
1796                                         int current_item = group.current_item++;
1797                                         int starting_row = group.starting_row;
1798
1799                                         row = (current_item / cols);
1800                                         col = current_item % cols;
1801
1802                                         x = UseCustomColumnWidth ? col * custom_column_width : col * (item_size.Width + x_spacing);
1803                                         y = row * (item_size.Height + y_spacing) + group_items_loc.Y;
1804
1805                                         SetItemLocation (i, x, y, row + starting_row, col);
1806                                         item_index_matrix [row + starting_row, col] = i;
1807                                 } else
1808 #endif
1809                                 {
1810                                         x = UseCustomColumnWidth ? col * custom_column_width : col * (item_size.Width + x_spacing);
1811                                         y = row * (item_size.Height + y_spacing);
1812
1813                                         SetItemLocation (i, x, y, row, col);
1814                                         item_index_matrix [row, col] = i;
1815
1816                                         if (left_aligned) {
1817                                                 row++;
1818                                                 if (row == rows) {
1819                                                         row = 0;
1820                                                         col++;
1821                                                 }
1822                                         } else {
1823                                                 if (++col == cols) {
1824                                                         col = 0;
1825                                                         row++;
1826                                                 }
1827                                         }
1828                                 }
1829 #if NET_2_0
1830                                 if (!virtual_mode) 
1831 #endif
1832                                 {
1833                                         item.Layout ();
1834                                         item.DisplayIndex = i;
1835                                         item.SetPosition (new Point (x, y));
1836                                 }
1837
1838
1839                         }
1840
1841                         item_control.Size = new Size (layout_wd, layout_ht);
1842                 }
1843
1844 #if NET_2_0
1845                 void CalculateGroupsLayout (Size item_size, int y_spacing, int y_origin)
1846                 {
1847                         int y = y_origin;
1848                         bool details = view == View.Details;
1849
1850                         for (int i = 0; i < groups.InternalCount; i++) {
1851                                 ListViewGroup group = groups.GetInternalGroup (i);
1852                                 if (group.ItemCount == 0)
1853                                         continue;
1854
1855                                 group.current_item = 0; // Reset layout
1856                                 y += LayoutGroupHeader (group, y, item_size.Height, y_spacing, details ? group.ItemCount : group.rows);
1857                         }
1858
1859                         layout_ht = y; // Update height taking into account Groups' headers heights
1860                 }
1861
1862                 int LayoutGroupHeader (ListViewGroup group, int y_origin, int item_height, int y_spacing, int rows)
1863                 {
1864                         Rectangle client_area = ClientRectangle;
1865                         int header_height = text_size.Height + 10;
1866
1867                         group.HeaderBounds = new Rectangle (0, y_origin, client_area.Width - v_scroll.Width, header_height);
1868                         group.items_area_location = new Point (0, y_origin + header_height);
1869
1870                         int items_area_height = ((item_height + y_spacing) * rows);
1871                         return header_height + items_area_height + 10; // Add a small bottom margin
1872                 }
1873 #endif
1874
1875                 void LayoutHeader ()
1876                 {
1877                         int x = 0;
1878                         for (int i = 0; i < Columns.Count; i++) {
1879                                 ColumnHeader col = GetReorderedColumn (i);
1880                                 col.X = x;
1881                                 col.Y = 0;
1882                                 col.CalcColumnHeader ();
1883                                 x += col.Wd;
1884                         }
1885
1886                         layout_wd = x;
1887
1888                         if (x < ClientRectangle.Width)
1889                                 x = ClientRectangle.Width;
1890
1891                         if (header_style == ColumnHeaderStyle.None) {
1892                                 header_control.Visible = false;
1893                                 header_control.Size = Size.Empty;
1894                                 layout_wd = ClientRectangle.Width;
1895                         } else {
1896                                 header_control.Width = x;
1897                                 header_control.Height = columns.Count > 0 ? columns [0].Ht : Font.Height + 5;
1898                                 header_control.Visible = true;
1899                         }
1900                 }
1901
1902                 void LayoutDetails ()
1903                 {
1904                         LayoutHeader ();
1905
1906                         if (columns.Count == 0) {
1907                                 item_control.Visible = false;
1908                                 layout_wd = ClientRectangle.Width;
1909                                 layout_ht = ClientRectangle.Height;
1910                                 return;
1911                         }
1912
1913                         item_control.Visible = true;
1914                         item_control.Location = Point.Empty;
1915                         item_control.Width = ClientRectangle.Width;
1916
1917                         int item_height = GetDetailsItemHeight ();
1918                         ItemSize = new Size (0, item_height); // We only cache Height for details view
1919                         int y = header_control.Height;
1920 #if NET_2_0
1921                         bool using_groups = show_groups && groups.Count > 0 && view != View.List;
1922                         if (using_groups) 
1923                                 CalculateGroupsLayout (ItemSize, 2, y);
1924 #endif
1925
1926                         for (int i = 0; i < items.Count; i++) {
1927                                 ListViewItem item = items [i];
1928 #if NET_2_0
1929                                 if (!virtual_mode) // Virtual mode sets Layout until draw time
1930 #endif
1931                                 {
1932                                         item.Layout ();
1933                                         item.DisplayIndex = i;
1934                                 }
1935
1936 #if NET_2_0
1937                                 if (using_groups) {
1938                                         ListViewGroup group = item.Group;
1939                                         if (group == null)
1940                                                 group = groups.DefaultGroup;
1941
1942                                         int current_item = group.current_item++;
1943                                         Point group_items_loc = group.items_area_location;
1944
1945                                         y = current_item * (item_height + 2) + group_items_loc.Y;
1946                                         SetItemLocation (i, 0, y, 0, 0);
1947                                         item.SetPosition (new Point (0, y));
1948                                 } else
1949 #endif
1950                                 {
1951                                         SetItemLocation (i, 0, y, 0, 0);
1952                                         item.SetPosition (new Point (0, y));
1953                                         y += item_height;
1954                                 }
1955                         }
1956
1957                         // some space for bottom gridline
1958                         if (items.Count > 0 && grid_lines)
1959                                 y += 2;
1960
1961 #if NET_2_0
1962                         if (!using_groups) // With groups it has been previously computed
1963 #endif
1964                                 layout_ht = y;
1965                 }
1966
1967                 private void AdjustItemsPositionArray (int count)
1968                 {
1969                         if (items_location.Length >= count)
1970                                 return;
1971
1972                         // items_location, items_matrix_location and reordered_items_indices must keep the same length
1973                         count = Math.Max (count, items_location.Length * 2);
1974                         items_location = new Point [count];
1975                         items_matrix_location = new ItemMatrixLocation [count];
1976                         reordered_items_indices = new int [count];
1977                 }
1978
1979                 private void CalculateListView (ListViewAlignment align)
1980                 {
1981                         CalcTextSize ();
1982
1983                         AdjustItemsPositionArray (items.Count);
1984
1985                         switch (view) {
1986                         case View.Details:
1987                                 LayoutDetails ();
1988                                 break;
1989
1990                         case View.SmallIcon:
1991                                 LayoutIcons (SmallIconItemSize, alignment == ListViewAlignment.Left, 
1992                                                 ThemeEngine.Current.ListViewHorizontalSpacing, 2);
1993                                 break;
1994
1995                         case View.LargeIcon:
1996                                 LayoutIcons (LargeIconItemSize, alignment == ListViewAlignment.Left,
1997                                         ThemeEngine.Current.ListViewHorizontalSpacing,
1998                                         ThemeEngine.Current.ListViewVerticalSpacing);
1999                                 break;
2000
2001                         case View.List:
2002                                 LayoutIcons (SmallIconItemSize, true, 
2003                                                 ThemeEngine.Current.ListViewHorizontalSpacing, 2);
2004                                 break;
2005 #if NET_2_0
2006                         case View.Tile:
2007                                 LayoutIcons (TileItemSize, alignment == ListViewAlignment.Left, 
2008                                                 ThemeEngine.Current.ListViewHorizontalSpacing,
2009                                                 ThemeEngine.Current.ListViewVerticalSpacing);
2010                                 break;
2011 #endif
2012                         }
2013
2014                         CalculateScrollBars ();
2015                 }
2016
2017                 internal Point GetItemLocation (int index)
2018                 {
2019                         Point loc = items_location [index];
2020                         loc.X -= h_marker; // Adjust to scroll
2021                         loc.Y -= v_marker;
2022
2023                         return loc;
2024                 }
2025
2026                 internal int GetItemIndex (int display_index)
2027                 {
2028                         return reordered_items_indices [display_index];
2029                 }
2030
2031                 private bool KeySearchString (KeyEventArgs ke)
2032                 {
2033                         int current_tickcnt = Environment.TickCount;
2034                         if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
2035                                 keysearch_text = string.Empty;
2036                         }
2037                         
2038                         if (!Char.IsLetterOrDigit ((char)ke.KeyCode))
2039                                 return false;
2040
2041                         keysearch_text += (char)ke.KeyCode;
2042                         keysearch_tickcnt = current_tickcnt;
2043
2044                         int start = FocusedItem == null ? 0 : FocusedItem.Index;
2045                         int i = start;
2046                         while (true) {
2047                                 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (Items[i].Text, keysearch_text,
2048                                         CompareOptions.IgnoreCase)) {
2049                                         SetFocusedItem (i);
2050                                         items [i].Selected = true;
2051                                         EnsureVisible (i);
2052                                         break;
2053                                 }
2054                                 i = (i + 1 < Items.Count) ? i+1 : 0;
2055
2056                                 if (i == start)
2057                                         break;
2058                         }
2059                         return true;
2060                 }
2061
2062                 int GetAdjustedIndex (Keys key)
2063                 {
2064                         int result = -1;
2065
2066                         if (View == View.Details) {
2067                                 switch (key) {
2068                                 case Keys.Up:
2069                                         result = FocusedItem.Index - 1;
2070                                         break;
2071                                 case Keys.Down:
2072                                         result = FocusedItem.Index + 1;
2073                                         if (result == items.Count)
2074                                                 result = -1;
2075                                         break;
2076                                 case Keys.PageDown:
2077                                         int last_index = LastVisibleIndex;
2078                                         Rectangle item_rect = new Rectangle (GetItemLocation (last_index), ItemSize);
2079                                         if (item_rect.Bottom > item_control.ClientRectangle.Bottom)
2080                                                 last_index--;
2081                                         if (FocusedItem.Index == last_index) {
2082                                                 if (FocusedItem.Index < Items.Count - 1) {
2083                                                         int page_size = item_control.Height / ItemSize.Height - 1;
2084                                                         result = FocusedItem.Index + page_size - 1;
2085                                                         if (result >= Items.Count)
2086                                                                 result = Items.Count - 1;
2087                                                 }
2088                                         } else
2089                                                 result = last_index;
2090                                         break;
2091                                 case Keys.PageUp:
2092                                         int first_index = FirstVisibleIndex;
2093                                         if (GetItemLocation (first_index).Y < 0)
2094                                                 first_index++;
2095                                         if (FocusedItem.Index == first_index) {
2096                                                 if (first_index > 0) {
2097                                                         int page_size = item_control.Height / ItemSize.Height - 1;
2098                                                         result = first_index - page_size + 1;
2099                                                         if (result < 0)
2100                                                                 result = 0;
2101                                                 }
2102                                         } else
2103                                                 result = first_index;
2104                                         break;
2105                                 }
2106                                 return result;
2107                         }
2108
2109                         ItemMatrixLocation item_matrix_location = items_matrix_location [FocusedItem.Index];
2110                         int row = item_matrix_location.Row;
2111                         int col = item_matrix_location.Col;
2112
2113                         switch (key) {
2114                         case Keys.Left:
2115                                 if (col == 0)
2116                                         return -1;
2117                                 return item_index_matrix [row, col - 1];
2118
2119                         case Keys.Right:
2120                                 if (col == (cols - 1))
2121                                         return -1;
2122                                 while (item_index_matrix [row, col + 1] == 0) {
2123                                         row--;
2124                                         if (row < 0)
2125                                                 return -1;
2126                                 }
2127                                 return item_index_matrix [row, col + 1];
2128
2129                         case Keys.Up:
2130                                 if (row == 0)
2131                                         return -1;
2132                                 while (item_index_matrix [row - 1, col] == 0 && row != 1) {
2133                                         col--;
2134                                         if (col < 0)
2135                                                 return -1;
2136                                 }
2137                                 return item_index_matrix [row - 1, col];
2138
2139                         case Keys.Down:
2140                                 if (row == (rows - 1) || row == Items.Count - 1)
2141                                         return -1;
2142                                 while (item_index_matrix [row + 1, col] == 0) {
2143                                         col--;
2144                                         if (col < 0)
2145                                                 return -1;
2146                                 }
2147                                 return item_index_matrix [row + 1, col];
2148
2149                         default:
2150                                 return -1;
2151                         }
2152                 }
2153
2154                 ListViewItem selection_start;
2155
2156                 private bool SelectItems (ArrayList sel_items)
2157                 {
2158                         bool changed = false;
2159                         foreach (ListViewItem item in SelectedItems)
2160                                 if (!sel_items.Contains (item)) {
2161                                         item.Selected = false;
2162                                         changed = true;
2163                                 }
2164                         foreach (ListViewItem item in sel_items)
2165                                 if (!item.Selected) {
2166                                         item.Selected = true;
2167                                         changed = true;
2168                                 }
2169                         return changed;
2170                 }
2171
2172                 private void UpdateMultiSelection (int index, bool reselect)
2173                 {
2174                         bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
2175                         bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
2176                         ListViewItem item = items [index];
2177
2178                         if (shift_pressed && selection_start != null) {
2179                                 ArrayList list = new ArrayList ();
2180                                 int start_index = selection_start.Index;
2181                                 int start = Math.Min (start_index, index);
2182                                 int end = Math.Max (start_index, index);
2183                                 if (View == View.Details) {
2184                                         for (int i = start; i <= end; i++)
2185                                                 list.Add (items [i]);
2186                                 } else {
2187                                         ItemMatrixLocation start_item_matrix_location = items_matrix_location [start];
2188                                         ItemMatrixLocation end_item_matrix_location = items_matrix_location [end];
2189                                         int left = Math.Min (start_item_matrix_location.Col, end_item_matrix_location.Col);
2190                                         int right = Math.Max (start_item_matrix_location.Col, end_item_matrix_location.Col);
2191                                         int top = Math.Min (start_item_matrix_location.Row, end_item_matrix_location.Row);
2192                                         int bottom = Math.Max (start_item_matrix_location.Row, end_item_matrix_location.Row);
2193
2194                                         for (int i = 0; i < items.Count; i++) {
2195                                                 ItemMatrixLocation item_matrix_loc = items_matrix_location [i];
2196
2197                                                 if (item_matrix_loc.Row >= top && item_matrix_loc.Row <= bottom &&
2198                                                                 item_matrix_loc.Col >= left && item_matrix_loc.Col <= right)
2199                                                         list.Add (items [i]);
2200                                         }
2201                                 }
2202                                 SelectItems (list);
2203                         } else if (ctrl_pressed) {
2204                                 item.Selected = !item.Selected;
2205                                 selection_start = item;
2206                         } else {
2207                                 if (!reselect) {
2208                                         // do not unselect, and reselect the item
2209                                         foreach (int itemIndex in SelectedIndices) {
2210                                                 if (index == itemIndex)
2211                                                         continue;
2212                                                 items [itemIndex].Selected = false;
2213                                         }
2214                                 } else {
2215                                         SelectedItems.Clear ();
2216                                         item.Selected = true;
2217                                 }
2218                                 selection_start = item;
2219                         }
2220                 }
2221
2222                 internal override bool InternalPreProcessMessage (ref Message msg)
2223                 {
2224                         if (msg.Msg == (int)Msg.WM_KEYDOWN) {
2225                                 Keys key_data = (Keys)msg.WParam.ToInt32();
2226                                 
2227                                 HandleNavKeys (key_data);
2228                         } 
2229                         
2230                         return base.InternalPreProcessMessage (ref msg);
2231                 }
2232
2233                 bool HandleNavKeys (Keys key_data)
2234                 {
2235                         if (Items.Count == 0 || !item_control.Visible)
2236                                 return false;
2237
2238                         if (FocusedItem == null)
2239                                 SetFocusedItem (0);
2240
2241                         switch (key_data) {
2242                         case Keys.End:
2243                                 SelectIndex (Items.Count - 1);
2244                                 break;
2245
2246                         case Keys.Home:
2247                                 SelectIndex (0);
2248                                 break;
2249
2250                         case Keys.Left:
2251                         case Keys.Right:
2252                         case Keys.Up:
2253                         case Keys.Down:
2254                         case Keys.PageUp:
2255                         case Keys.PageDown:
2256                                 SelectIndex (GetAdjustedIndex (key_data));
2257                                 break;
2258
2259                         case Keys.Space:
2260                                 ToggleItemsCheckState ();
2261                                 break;
2262                         case Keys.Enter:
2263                                 if (selected_indices.Count > 0)
2264                                         OnItemActivate (EventArgs.Empty);
2265                                 break;
2266
2267                         default:
2268                                 return false;
2269                         }
2270
2271                         return true;
2272                 }
2273
2274                 void ToggleItemsCheckState ()
2275                 {
2276                         if (!CheckBoxes)
2277                                 return;
2278
2279                         // Don't modify check state if StateImageList has less than 2 elements
2280                         if (StateImageList != null && StateImageList.Images.Count < 2)
2281                                 return;
2282
2283                         if (SelectedIndices.Count > 0) {
2284                                 for (int i = 0; i < SelectedIndices.Count; i++) {
2285                                         ListViewItem item = Items [SelectedIndices [i]];
2286                                         item.Checked = !item.Checked;
2287                                 }
2288                                 return;
2289                         } 
2290                         
2291                         if (FocusedItem != null) {
2292                                 FocusedItem.Checked = !FocusedItem.Checked;
2293                                 SelectIndex (FocusedItem.Index);
2294                         }
2295                 }
2296
2297                 void SelectIndex (int index)
2298                 {
2299                         if (index == -1)
2300                                 return;
2301
2302                         if (MultiSelect)
2303                                 UpdateMultiSelection (index, true);
2304                         else if (!items [index].Selected)
2305                                 items [index].Selected = true;
2306
2307                         SetFocusedItem (index);
2308                         EnsureVisible (index);
2309                 }
2310
2311                 private void ListView_KeyDown (object sender, KeyEventArgs ke)
2312                 {
2313                         if (ke.Handled || Items.Count == 0 || !item_control.Visible)
2314                                 return;
2315
2316                         if (ke.Alt || ke.Control)
2317                                 return;
2318                                 
2319                         ke.Handled = KeySearchString (ke);
2320                 }
2321
2322                 private MouseEventArgs TranslateMouseEventArgs (MouseEventArgs args)
2323                 {
2324                         Point loc = PointToClient (Control.MousePosition);
2325                         return new MouseEventArgs (args.Button, args.Clicks, loc.X, loc.Y, args.Delta);
2326                 }
2327
2328                 internal class ItemControl : Control {
2329
2330                         ListView owner;
2331                         ListViewItem clicked_item;
2332                         ListViewItem last_clicked_item;
2333                         bool hover_processed = false;
2334                         bool checking = false;
2335                         ListViewItem prev_hovered_item;
2336 #if NET_2_0
2337                         ListViewItem prev_tooltip_item;
2338 #endif
2339                         int clicks;
2340                         Point drag_begin = new Point (-1, -1);
2341                         internal int dragged_item_index = -1;
2342                         
2343                         ListViewLabelEditTextBox edit_text_box;
2344                         internal ListViewItem edit_item;
2345                         LabelEditEventArgs edit_args;
2346
2347                         public ItemControl (ListView owner)
2348                         {
2349                                 this.owner = owner;
2350                                 DoubleClick += new EventHandler(ItemsDoubleClick);
2351                                 MouseDown += new MouseEventHandler(ItemsMouseDown);
2352                                 MouseMove += new MouseEventHandler(ItemsMouseMove);
2353                                 MouseHover += new EventHandler(ItemsMouseHover);
2354                                 MouseUp += new MouseEventHandler(ItemsMouseUp);
2355                         }
2356
2357                         void ItemsDoubleClick (object sender, EventArgs e)
2358                         {
2359                                 if (owner.activation == ItemActivation.Standard)
2360                                         owner.OnItemActivate (EventArgs.Empty);
2361                         }
2362
2363                         enum BoxSelect {
2364                                 None,
2365                                 Normal,
2366                                 Shift,
2367                                 Control
2368                         }
2369
2370                         BoxSelect box_select_mode = BoxSelect.None;
2371                         IList prev_selection;
2372                         Point box_select_start;
2373
2374                         Rectangle box_select_rect;
2375                         internal Rectangle BoxSelectRectangle {
2376                                 get { return box_select_rect; }
2377                                 set {
2378                                         if (box_select_rect == value)
2379                                                 return;
2380
2381                                         InvalidateBoxSelectRect ();
2382                                         box_select_rect = value;
2383                                         InvalidateBoxSelectRect ();
2384                                 }
2385                         }
2386
2387                         void InvalidateBoxSelectRect ()
2388                         {
2389                                 if (BoxSelectRectangle.Size.IsEmpty)
2390                                         return;
2391
2392                                 Rectangle edge = BoxSelectRectangle;
2393                                 edge.X -= 1;
2394                                 edge.Y -= 1;
2395                                 edge.Width += 2;
2396                                 edge.Height = 2;
2397                                 Invalidate (edge);
2398                                 edge.Y = BoxSelectRectangle.Bottom - 1;
2399                                 Invalidate (edge);
2400                                 edge.Y = BoxSelectRectangle.Y - 1;
2401                                 edge.Width = 2;
2402                                 edge.Height = BoxSelectRectangle.Height + 2;
2403                                 Invalidate (edge);
2404                                 edge.X = BoxSelectRectangle.Right - 1;
2405                                 Invalidate (edge);
2406                         }
2407
2408                         private Rectangle CalculateBoxSelectRectangle (Point pt)
2409                         {
2410                                 int left = Math.Min (box_select_start.X, pt.X);
2411                                 int right = Math.Max (box_select_start.X, pt.X);
2412                                 int top = Math.Min (box_select_start.Y, pt.Y);
2413                                 int bottom = Math.Max (box_select_start.Y, pt.Y);
2414                                 return Rectangle.FromLTRB (left, top, right, bottom);
2415                         }
2416
2417                         bool BoxIntersectsItem (int index)
2418                         {
2419                                 Rectangle r = new Rectangle (owner.GetItemLocation (index), owner.ItemSize);
2420                                 if (owner.View != View.Details) {
2421                                         r.X += r.Width / 4;
2422                                         r.Y += r.Height / 4;
2423                                         r.Width /= 2;
2424                                         r.Height /= 2;
2425                                 }
2426                                 return BoxSelectRectangle.IntersectsWith (r);
2427                         }
2428
2429                         bool BoxIntersectsText (int index)
2430                         {
2431                                 Rectangle r = owner.Items [index].TextBounds;
2432                                 return BoxSelectRectangle.IntersectsWith (r);
2433                         }
2434
2435                         ArrayList BoxSelectedItems {
2436                                 get {
2437                                         ArrayList result = new ArrayList ();
2438                                         for (int i = 0; i < owner.Items.Count; i++) {
2439                                                 bool intersects;
2440                                                 if (owner.View == View.Details && !owner.FullRowSelect)
2441                                                         intersects = BoxIntersectsText (i);
2442                                                 else
2443                                                         intersects = BoxIntersectsItem (i);
2444
2445                                                 if (intersects)
2446                                                         result.Add (owner.Items [i]);
2447                                         }
2448                                         return result;
2449                                 }
2450                         }
2451
2452                         private bool PerformBoxSelection (Point pt)
2453                         {
2454                                 if (box_select_mode == BoxSelect.None)
2455                                         return false;
2456
2457                                 BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
2458                                 
2459                                 ArrayList box_items = BoxSelectedItems;
2460
2461                                 ArrayList items;
2462
2463                                 switch (box_select_mode) {
2464
2465                                 case BoxSelect.Normal:
2466                                         items = box_items;
2467                                         break;
2468
2469                                 case BoxSelect.Control:
2470                                         items = new ArrayList ();
2471                                         foreach (int index in prev_selection)
2472                                                 if (!box_items.Contains (owner.Items [index]))
2473                                                         items.Add (owner.Items [index]);
2474                                         foreach (ListViewItem item in box_items)
2475                                                 if (!prev_selection.Contains (item.Index))
2476                                                         items.Add (item);
2477                                         break;
2478
2479                                 case BoxSelect.Shift:
2480                                         items = box_items;
2481                                         foreach (ListViewItem item in box_items)
2482                                                 prev_selection.Remove (item.Index);
2483                                         foreach (int index in prev_selection)
2484                                                 items.Add (owner.Items [index]);
2485                                         break;
2486
2487                                 default:
2488                                         throw new Exception ("Unexpected Selection mode: " + box_select_mode);
2489                                 }
2490
2491                                 SuspendLayout ();
2492                                 owner.SelectItems (items);
2493                                 ResumeLayout ();
2494
2495                                 return true;
2496                         }
2497
2498                         private void ItemsMouseDown (object sender, MouseEventArgs me)
2499                         {
2500                                 owner.OnMouseDown (owner.TranslateMouseEventArgs (me));
2501                                 if (owner.items.Count == 0)
2502                                         return;
2503
2504                                 bool box_selecting = false;
2505                                 Size item_size = owner.ItemSize;
2506                                 Point pt = new Point (me.X, me.Y);
2507                                 for (int i = 0; i < owner.items.Count; i++) {
2508                                         Rectangle item_rect = new Rectangle (owner.GetItemLocation (i), item_size);
2509                                         if (!item_rect.Contains (pt))
2510                                                 continue;
2511
2512                                         // Actual item in 'i' position
2513                                         ListViewItem item = owner.items [owner.reordered_items_indices [i]];
2514
2515                                         if (item.CheckRectReal.Contains (pt)) {
2516                                                 // Don't modify check state if we have only one image
2517                                                 // and if we are in 1.1 profile only take into account
2518                                                 // double clicks
2519                                                 if (owner.StateImageList != null && owner.StateImageList.Images.Count < 2 
2520 #if !NET_2_0
2521                                                                 && me.Clicks == 1
2522 #endif
2523                                                                 )
2524                                                         return;
2525
2526                                                 // Generate an extra ItemCheck event when we got two clicks
2527                                                 // (Match weird .Net behaviour)
2528                                                 if (me.Clicks == 2)
2529                                                         item.Checked = !item.Checked;
2530
2531                                                 item.Checked = !item.Checked;
2532                                                 checking = true;
2533                                                 return;
2534                                         }
2535                                         
2536                                         if (owner.View == View.Details) {
2537                                                 bool over_text = item.TextBounds.Contains (pt);
2538                                                 if (owner.FullRowSelect) {
2539                                                         clicked_item = owner.items [i];
2540                                                         bool over_item_column = (me.X > owner.Columns[0].X && me.X < owner.Columns[0].X + owner.Columns[0].Width);
2541                                                         if (!over_text && over_item_column && owner.MultiSelect)
2542                                                                 box_selecting = true;
2543                                                 } else if (over_text)
2544                                                         clicked_item = item;
2545                                                 else
2546                                                         owner.SetFocusedItem (i);
2547                                         } else
2548                                                 clicked_item = item;
2549
2550                                         break;
2551                                 }
2552
2553
2554                                 if (clicked_item != null) {
2555                                         bool changed = !clicked_item.Selected;
2556                                         if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed))
2557                                                 owner.SetFocusedItem (clicked_item.Index);
2558
2559                                         if (owner.MultiSelect) {
2560                                                 bool reselect = (!owner.LabelEdit || changed);
2561                                                 if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed))
2562                                                         owner.UpdateMultiSelection (clicked_item.Index, reselect);
2563                                         } else {
2564                                                 clicked_item.Selected = true;
2565                                         }
2566
2567 #if NET_2_0
2568                                         if (owner.VirtualMode && changed) {
2569                                                 // Broken event - It's not fired from Item.Selected also
2570                                                 ListViewVirtualItemsSelectionRangeChangedEventArgs args = 
2571                                                         new ListViewVirtualItemsSelectionRangeChangedEventArgs (0, owner.items.Count - 1, false);
2572
2573                                                 owner.OnVirtualItemsSelectionRangeChanged (args);
2574                                         }
2575 #endif
2576                                         // Report clicks only if the item was clicked. On MS the
2577                                         // clicks are only raised if you click an item
2578                                         clicks = me.Clicks;
2579                                         if (me.Clicks > 1) {
2580                                                 if (owner.CheckBoxes)
2581                                                         clicked_item.Checked = !clicked_item.Checked;
2582                                         } else if (me.Clicks == 1) {
2583                                                 if (owner.LabelEdit && !changed)
2584                                                         BeginEdit (clicked_item); // this is probably not the correct place to execute BeginEdit
2585                                         }
2586                                 } else {
2587                                         if (owner.MultiSelect)
2588                                                 box_selecting = true;
2589                                         else if (owner.SelectedItems.Count > 0)
2590                                                 owner.SelectedItems.Clear ();
2591                                 }
2592
2593                                 if (box_selecting) {
2594                                         Keys mods = XplatUI.State.ModifierKeys;
2595                                         if ((mods & Keys.Shift) != 0)
2596                                                 box_select_mode = BoxSelect.Shift;
2597                                         else if ((mods & Keys.Control) != 0)
2598                                                 box_select_mode = BoxSelect.Control;
2599                                         else
2600                                                 box_select_mode = BoxSelect.Normal;
2601                                         box_select_start = pt; 
2602                                         prev_selection = owner.SelectedIndices.List.Clone () as IList;
2603                                 }
2604                         }
2605
2606                         private void ItemsMouseMove (object sender, MouseEventArgs me)
2607                         {
2608                                 bool done = PerformBoxSelection (new Point (me.X, me.Y));
2609
2610                                 owner.OnMouseMove (owner.TranslateMouseEventArgs (me));
2611
2612                                 if (done)
2613                                         return;
2614                                 if ((me.Button != MouseButtons.Left && me.Button != MouseButtons.Right) &&
2615                                         !hover_processed && owner.Activation != ItemActivation.OneClick
2616 #if NET_2_0
2617                                         && !owner.ShowItemToolTips
2618 #endif
2619                                                 )
2620                                         return;
2621
2622                                 Point pt = PointToClient (Control.MousePosition);
2623                                 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
2624
2625                                 if (hover_processed && item != null && item != prev_hovered_item) {
2626                                         hover_processed = false;
2627                                         XplatUI.ResetMouseHover (Handle);
2628                                 }
2629
2630                                 // Need to invalidate the item in HotTracking to show/hide the underline style
2631                                 if (owner.Activation == ItemActivation.OneClick) {
2632                                         if (item == null && owner.HotItemIndex != -1) {
2633 #if NET_2_0
2634                                                 if (owner.HotTracking)
2635                                                         Invalidate (owner.Items [owner.HotItemIndex].Bounds); // Previous one
2636 #endif
2637
2638                                                 Cursor = Cursors.Default;
2639                                                 owner.HotItemIndex = -1;
2640                                         } else if (item != null && owner.HotItemIndex == -1) {
2641 #if NET_2_0
2642                                                 if (owner.HotTracking)
2643                                                         Invalidate (item.Bounds);
2644 #endif
2645
2646                                                 Cursor = Cursors.Hand;
2647                                                 owner.HotItemIndex = item.Index;
2648                                         }
2649                                 }
2650
2651                                 if (me.Button == MouseButtons.Left || me.Button == MouseButtons.Right) {
2652                                         if (drag_begin.X == -1 && drag_begin.Y == -1) {
2653                                                 if (item != null) {
2654                                                         drag_begin = new Point (me.X, me.Y);
2655                                                         dragged_item_index = item.Index;
2656                                                 }
2657
2658                                         } else {
2659                                                 Rectangle r = new Rectangle (drag_begin, SystemInformation.DragSize);
2660                                                 if (!r.Contains (me.X, me.Y)) {
2661                                                         ListViewItem dragged_item  = owner.items [dragged_item_index];
2662                                                         owner.OnItemDrag (new ItemDragEventArgs (me.Button, dragged_item));
2663
2664                                                         drag_begin = new Point (-1, -1);
2665                                                         dragged_item_index = -1;
2666                                                 }
2667                                         }
2668                                 }
2669
2670 #if NET_2_0
2671                                 if (owner.ShowItemToolTips) {
2672                                         if (item == null) {
2673                                                 owner.item_tooltip.Active = false;
2674                                                 prev_tooltip_item = null;
2675                                         } else if (item != prev_tooltip_item && item.ToolTipText.Length > 0) {
2676                                                 owner.item_tooltip.Active = true;
2677                                                 owner.item_tooltip.SetToolTip (owner, item.ToolTipText);
2678                                                 prev_tooltip_item = item;
2679                                         }
2680                                 }
2681 #endif
2682
2683                         }
2684
2685                         private void ItemsMouseHover (object sender, EventArgs e)
2686                         {
2687                                 if (owner.hover_pending) {
2688                                         owner.OnMouseHover (e);
2689                                         owner.hover_pending = false;
2690                                 }
2691
2692                                 if (Capture)
2693                                         return;
2694
2695                                 hover_processed = true;
2696                                 Point pt = PointToClient (Control.MousePosition);
2697                                 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
2698                                 if (item == null)
2699                                         return;
2700
2701                                 prev_hovered_item = item;
2702
2703                                 if (owner.HoverSelection) {
2704                                         if (owner.MultiSelect)
2705                                                 owner.UpdateMultiSelection (item.Index, true);
2706                                         else
2707                                                 item.Selected = true;
2708                                         
2709                                         owner.SetFocusedItem (item.Index);
2710                                         Select (); // Make sure we have the focus, since MouseHover doesn't give it to us
2711                                 }
2712
2713 #if NET_2_0
2714                                 owner.OnItemMouseHover (new ListViewItemMouseHoverEventArgs (item));
2715 #endif
2716                         }
2717
2718                         void HandleClicks (MouseEventArgs me)
2719                         {
2720                                 // if the click is not on an item,
2721                                 // clicks remains as 0
2722                                 if (clicks > 1) {
2723 #if !NET_2_0
2724                                         owner.OnDoubleClick (EventArgs.Empty);
2725                                 } else if (clicks == 1) {
2726                                         owner.OnClick (EventArgs.Empty);
2727 #else
2728                                         owner.OnDoubleClick (EventArgs.Empty);
2729                                         owner.OnMouseDoubleClick (me);
2730                                 } else if (clicks == 1) {
2731                                         owner.OnClick (EventArgs.Empty);
2732                                         owner.OnMouseClick (me);
2733 #endif
2734                                 }
2735
2736                                 clicks = 0;
2737                         }
2738
2739                         private void ItemsMouseUp (object sender, MouseEventArgs me)
2740                         {
2741                                 MouseEventArgs owner_me = owner.TranslateMouseEventArgs (me);
2742                                 HandleClicks (owner_me);
2743
2744                                 Capture = false;
2745                                 if (owner.Items.Count == 0) {
2746                                         ResetMouseState ();
2747                                         owner.OnMouseUp (owner_me);
2748                                         return;
2749                                 }
2750
2751                                 Point pt = new Point (me.X, me.Y);
2752
2753                                 Rectangle rect = Rectangle.Empty;
2754                                 if (clicked_item != null) {
2755                                         if (owner.view == View.Details && !owner.full_row_select)
2756                                                 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
2757                                         else
2758                                                 rect = clicked_item.Bounds;
2759
2760                                         if (rect.Contains (pt)) {
2761                                                 switch (owner.activation) {
2762                                                 case ItemActivation.OneClick:
2763                                                         owner.OnItemActivate (EventArgs.Empty);
2764                                                         break;
2765
2766                                                 case ItemActivation.TwoClick:
2767                                                         if (last_clicked_item == clicked_item) {
2768                                                                 owner.OnItemActivate (EventArgs.Empty);
2769                                                                 last_clicked_item = null;
2770                                                         } else
2771                                                                 last_clicked_item = clicked_item;
2772                                                         break;
2773                                                 default:
2774                                                         // DoubleClick activation is handled in another handler
2775                                                         break;
2776                                                 }
2777                                         }
2778                                 } else if (!checking && owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
2779                                         // Need this to clean up background clicks
2780                                         owner.SelectedItems.Clear ();
2781                                 }
2782
2783                                 ResetMouseState ();
2784                                 owner.OnMouseUp (owner_me);
2785                         }
2786
2787                         private void ResetMouseState ()
2788                         {                               
2789                                 clicked_item = null;
2790                                 box_select_start = Point.Empty;
2791                                 BoxSelectRectangle = Rectangle.Empty;
2792                                 prev_selection = null;
2793                                 box_select_mode = BoxSelect.None;
2794                                 checking = false;
2795
2796                                 // Clean these bits in case the mouse buttons were
2797                                 // released before firing ItemDrag
2798                                 dragged_item_index = -1;
2799                                 drag_begin = new Point (-1, -1);
2800                         }
2801                         
2802                         private void LabelEditFinished (object sender, EventArgs e)
2803                         {
2804                                 EndEdit (edit_item);
2805                         }
2806
2807                         private void LabelEditCancelled (object sender, EventArgs e)
2808                         {
2809                                 edit_args.SetLabel (null);
2810                                 EndEdit (edit_item);
2811                         }
2812
2813                         private void LabelTextChanged (object sender, EventArgs e)
2814                         {
2815                                 if (edit_args != null)
2816                                         edit_args.SetLabel (edit_text_box.Text);
2817                         }
2818
2819                         internal void BeginEdit (ListViewItem item)
2820                         {
2821                                 if (edit_item != null)
2822                                         EndEdit (edit_item);
2823                                 
2824                                 if (edit_text_box == null) {
2825                                         edit_text_box = new ListViewLabelEditTextBox ();
2826                                         edit_text_box.BorderStyle = BorderStyle.FixedSingle;
2827                                         edit_text_box.EditingCancelled += new EventHandler (LabelEditCancelled);
2828                                         edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
2829                                         edit_text_box.TextChanged += new EventHandler (LabelTextChanged);
2830                                         edit_text_box.Visible = false;
2831                                         Controls.Add (edit_text_box);
2832                                 }
2833                                 
2834                                 item.EnsureVisible();
2835                                 
2836                                 edit_text_box.Reset ();
2837                                 
2838                                 switch (owner.view) {
2839                                         case View.List:
2840                                         case View.SmallIcon:
2841                                         case View.Details:
2842                                                 edit_text_box.TextAlign = HorizontalAlignment.Left;
2843                                                 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
2844                                                 SizeF sizef = TextRenderer.MeasureString (item.Text, item.Font);
2845                                                 edit_text_box.Width = (int)sizef.Width + 4;
2846                                                 edit_text_box.MaxWidth = owner.ClientRectangle.Width - edit_text_box.Bounds.X;
2847                                                 edit_text_box.WordWrap = false;
2848                                                 edit_text_box.Multiline = false;
2849                                                 break;
2850                                         case View.LargeIcon:
2851                                                 edit_text_box.TextAlign = HorizontalAlignment.Center;
2852                                                 edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
2853                                                 sizef = TextRenderer.MeasureString (item.Text, item.Font);
2854                                                 edit_text_box.Width = (int)sizef.Width + 4;
2855                                                 edit_text_box.MaxWidth = item.GetBounds(ItemBoundsPortion.Entire).Width;
2856                                                 edit_text_box.MaxHeight = owner.ClientRectangle.Height - edit_text_box.Bounds.Y;
2857                                                 edit_text_box.WordWrap = true;
2858                                                 edit_text_box.Multiline = true;
2859                                                 break;
2860                                 }
2861
2862                                 edit_item = item;
2863
2864                                 edit_text_box.Text = item.Text;
2865                                 edit_text_box.Font = item.Font;
2866                                 edit_text_box.Visible = true;
2867                                 edit_text_box.Focus ();
2868                                 edit_text_box.SelectAll ();
2869
2870                                 edit_args = new LabelEditEventArgs (owner.Items.IndexOf (edit_item));
2871                                 owner.OnBeforeLabelEdit (edit_args);
2872
2873                                 if (edit_args.CancelEdit)
2874                                         EndEdit (item);
2875                         }
2876
2877                         internal void CancelEdit (ListViewItem item)
2878                         {
2879                                 // do nothing if there's no item being edited, or if the
2880                                 // item being edited is not the one passed in
2881                                 if (edit_item == null || edit_item != item)
2882                                         return;
2883
2884                                 edit_args.SetLabel (null);
2885                                 EndEdit (item);
2886                         }
2887
2888                         internal void EndEdit (ListViewItem item)
2889                         {
2890                                 // do nothing if there's no item being edited, or if the
2891                                 // item being edited is not the one passed in
2892                                 if (edit_item == null || edit_item != item)
2893                                         return;
2894
2895                                 if (edit_text_box != null) {
2896                                         if (edit_text_box.Visible)
2897                                                 edit_text_box.Visible = false;
2898                                         // ensure listview gets focus
2899                                         owner.Focus ();
2900                                 }
2901
2902                                 // Same as TreeView.EndEdit: need to have focus in synch
2903                                 Application.DoEvents ();
2904
2905                                 // 
2906                                 // Create a new instance, since we could get a call to BeginEdit
2907                                 // from the handler and have fields out of synch
2908                                 //
2909                                 LabelEditEventArgs args = new LabelEditEventArgs (item.Index, edit_args.Label);
2910                                 edit_item = null;
2911
2912                                 owner.OnAfterLabelEdit (args);
2913                                 if (!args.CancelEdit && args.Label != null)
2914                                         item.Text = args.Label;
2915                         }
2916
2917                         internal override void OnPaintInternal (PaintEventArgs pe)
2918                         {
2919                                 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
2920                         }
2921
2922                         protected override void WndProc (ref Message m)
2923                         {
2924                                 switch ((Msg)m.Msg) {
2925                                 case Msg.WM_KILLFOCUS:
2926                                         owner.Select (false, true);
2927                                         break;
2928                                 case Msg.WM_SETFOCUS:
2929                                         owner.Select (false, true);
2930                                         break;
2931                                 case Msg.WM_LBUTTONDOWN:
2932                                         if (!Focused)
2933                                                 owner.Select (false, true);
2934                                         break;
2935                                 case Msg.WM_RBUTTONDOWN:
2936                                         if (!Focused)
2937                                                 owner.Select (false, true);
2938                                         break;
2939                                 default:
2940                                         break;
2941                                 }
2942                                 base.WndProc (ref m);
2943                         }
2944                 }
2945                 
2946                 internal class ListViewLabelEditTextBox : TextBox
2947                 {
2948                         int max_width = -1;
2949                         int min_width = -1;
2950                         
2951                         int max_height = -1;
2952                         int min_height = -1;
2953                         
2954                         int old_number_lines = 1;
2955                         
2956                         SizeF text_size_one_char;
2957                         
2958                         public ListViewLabelEditTextBox ()
2959                         {
2960                                 min_height = DefaultSize.Height;
2961                                 text_size_one_char = TextRenderer.MeasureString ("B", Font);
2962                         }
2963                         
2964                         public int MaxWidth {
2965                                 set {
2966                                         if (value < min_width)
2967                                                 max_width = min_width;
2968                                         else
2969                                                 max_width = value;
2970                                 }
2971                         }
2972                         
2973                         public int MaxHeight {
2974                                 set {
2975                                         if (value < min_height)
2976                                                 max_height = min_height;
2977                                         else
2978                                                 max_height = value;
2979                                 }
2980                         }
2981                         
2982                         public new int Width {
2983                                 get {
2984                                         return base.Width;
2985                                 }
2986                                 set {
2987                                         min_width = value;
2988                                         base.Width = value;
2989                                 }
2990                         }
2991                         
2992                         public override Font Font {
2993                                 get {
2994                                         return base.Font;
2995                                 }
2996                                 set {
2997                                         base.Font = value;
2998                                         text_size_one_char = TextRenderer.MeasureString ("B", Font);
2999                                 }
3000                         }
3001                         
3002                         protected override void OnTextChanged (EventArgs e)
3003                         {
3004                                 SizeF text_size = TextRenderer.MeasureString (Text, Font);
3005                                 
3006                                 int new_width = (int)text_size.Width + 8;
3007                                 
3008                                 if (!Multiline)
3009                                         ResizeTextBoxWidth (new_width);
3010                                 else {
3011                                         if (Width != max_width)
3012                                                 ResizeTextBoxWidth (new_width);
3013                                         
3014                                         int number_lines = Lines.Length;
3015                                         
3016                                         if (number_lines != old_number_lines) {
3017                                                 int new_height = number_lines * (int)text_size_one_char.Height + 4;
3018                                                 old_number_lines = number_lines;
3019                                                 
3020                                                 ResizeTextBoxHeight (new_height);
3021                                         }
3022                                 }
3023                                 
3024                                 base.OnTextChanged (e);
3025                         }
3026                         
3027                         protected override bool IsInputKey (Keys key_data)
3028                         {
3029                                 if ((key_data & Keys.Alt) == 0) {
3030                                         switch (key_data & Keys.KeyCode) {
3031                                                 case Keys.Enter:
3032                                                         return true;
3033                                                 case Keys.Escape:
3034                                                         return true;
3035                                         }
3036                                 }
3037                                 return base.IsInputKey (key_data);
3038                         }
3039                         
3040                         protected override void OnKeyDown (KeyEventArgs e)
3041                         {
3042                                 if (!Visible)
3043                                         return;
3044
3045                                 switch (e.KeyCode) {
3046                                 case Keys.Return:
3047                                         Visible = false;
3048                                         e.Handled = true;
3049                                         OnEditingFinished (e);
3050                                         break;
3051                                 case Keys.Escape:
3052                                         Visible = false;
3053                                         e.Handled = true;
3054                                         OnEditingCancelled (e);
3055                                         break;
3056                                 }
3057                         }
3058                         
3059                         protected override void OnLostFocus (EventArgs e)
3060                         {
3061                                 if (Visible) {
3062                                         OnEditingFinished (e);
3063                                 }
3064                         }
3065
3066                         protected void OnEditingCancelled (EventArgs e)
3067                         {
3068                                 EventHandler eh = (EventHandler)(Events [EditingCancelledEvent]);
3069                                 if (eh != null)
3070                                         eh (this, e);
3071                         }
3072                         
3073                         protected void OnEditingFinished (EventArgs e)
3074                         {
3075                                 EventHandler eh = (EventHandler)(Events [EditingFinishedEvent]);
3076                                 if (eh != null)
3077                                         eh (this, e);
3078                         }
3079                         
3080                         private void ResizeTextBoxWidth (int new_width)
3081                         {
3082                                 if (new_width > max_width)
3083                                         base.Width = max_width;
3084                                 else 
3085                                 if (new_width >= min_width)
3086                                         base.Width = new_width;
3087                                 else
3088                                         base.Width = min_width;
3089                         }
3090                         
3091                         private void ResizeTextBoxHeight (int new_height)
3092                         {
3093                                 if (new_height > max_height)
3094                                         base.Height = max_height;
3095                                 else 
3096                                 if (new_height >= min_height)
3097                                         base.Height = new_height;
3098                                 else
3099                                         base.Height = min_height;
3100                         }
3101                         
3102                         public void Reset ()
3103                         {
3104                                 max_width = -1;
3105                                 min_width = -1;
3106                                 
3107                                 max_height = -1;
3108                                 
3109                                 old_number_lines = 1;
3110                                 
3111                                 Text = String.Empty;
3112                                 
3113                                 Size = DefaultSize;
3114                         }
3115
3116                         static object EditingCancelledEvent = new object ();
3117                         public event EventHandler EditingCancelled {
3118                                 add { Events.AddHandler (EditingCancelledEvent, value); }
3119                                 remove { Events.RemoveHandler (EditingCancelledEvent, value); }
3120                         }
3121
3122                         static object EditingFinishedEvent = new object ();
3123                         public event EventHandler EditingFinished {
3124                                 add { Events.AddHandler (EditingFinishedEvent, value); }
3125                                 remove { Events.RemoveHandler (EditingFinishedEvent, value); }
3126                         }
3127                 }
3128
3129                 internal override void OnPaintInternal (PaintEventArgs pe)
3130                 {
3131                         if (updating)
3132                                 return;
3133                                 
3134                         CalculateScrollBars ();
3135                 }
3136
3137                 void FocusChanged (object o, EventArgs args)
3138                 {
3139                         if (Items.Count == 0)
3140                                 return;
3141
3142                         if (FocusedItem == null)
3143                                 SetFocusedItem (0);
3144
3145                         ListViewItem focused_item = FocusedItem;
3146
3147                         if (focused_item.ListView != null) {
3148                                 item_control.Invalidate (focused_item.Bounds);
3149                                 focused_item.Layout ();
3150                                 item_control.Invalidate (focused_item.Bounds);
3151                         }
3152                 }
3153
3154                 private void ListView_MouseEnter (object sender, EventArgs args)
3155                 {
3156                         hover_pending = true; // Need a hover event for every Enter/Leave cycle
3157                 }
3158
3159                 private void ListView_MouseWheel (object sender, MouseEventArgs me)
3160                 {
3161                         if (Items.Count == 0)
3162                                 return;
3163
3164                         int lines = me.Delta / 120;
3165
3166                         if (lines == 0)
3167                                 return;
3168
3169                         switch (View) {
3170                         case View.Details:
3171                         case View.SmallIcon:
3172                                 Scroll (v_scroll, -ItemSize.Height * SystemInformation.MouseWheelScrollLines * lines);
3173                                 break;
3174                         case View.LargeIcon:
3175                                 Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing)  * lines);
3176                                 break;
3177                         case View.List:
3178                                 Scroll (h_scroll, -ItemSize.Width * lines);
3179                                 break;
3180 #if NET_2_0
3181                         case View.Tile:
3182                                 Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * 2 * lines);
3183                                 break;
3184 #endif
3185                         }
3186                 }
3187
3188                 private void ListView_SizeChanged (object sender, EventArgs e)
3189                 {
3190                         CalculateListView (alignment);
3191                 }
3192                 
3193                 private void SetFocusedItem (int index)
3194                 {
3195                         if (index != -1)
3196                                 items [index].Focused = true;
3197                         else if (focused_item_index != -1 && focused_item_index < items.Count) // Previous focused item
3198                                 items [focused_item_index].Focused = false;
3199
3200                         focused_item_index = index;
3201                 }
3202
3203                 private void HorizontalScroller (object sender, EventArgs e)
3204                 {
3205                         item_control.EndEdit (item_control.edit_item);
3206                         
3207                         // Avoid unnecessary flickering, when button is
3208                         // kept pressed at the end
3209                         if (h_marker != h_scroll.Value) {
3210                                 
3211                                 int pixels = h_marker - h_scroll.Value;
3212                                 
3213                                 h_marker = h_scroll.Value;
3214                                 if (header_control.Visible)
3215                                         XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
3216
3217                                 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
3218                         }
3219                 }
3220
3221                 private void VerticalScroller (object sender, EventArgs e)
3222                 {
3223                         item_control.EndEdit (item_control.edit_item);
3224                         
3225                         // Avoid unnecessary flickering, when button is
3226                         // kept pressed at the end
3227                         if (v_marker != v_scroll.Value) {
3228                                 int pixels = v_marker - v_scroll.Value;
3229                                 Rectangle area = item_control.ClientRectangle;
3230                                 if (header_control.Visible) {
3231                                         area.Y += header_control.Height;
3232                                         area.Height -= header_control.Height;
3233                                 }
3234
3235                                 v_marker = v_scroll.Value;
3236                                 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
3237                         }
3238                 }
3239
3240                 internal override bool IsInputCharInternal (char charCode)
3241                 {
3242                         return true;
3243                 }
3244                 #endregion      // Internal Methods Properties
3245
3246                 #region Protected Methods
3247                 protected override void CreateHandle ()
3248                 {
3249                         base.CreateHandle ();
3250                         for (int i = 0; i < SelectedItems.Count; i++)
3251                                 OnSelectedIndexChanged (EventArgs.Empty);
3252                 }
3253
3254                 protected override void Dispose (bool disposing)
3255                 {
3256                         if (disposing) {
3257                                 h_scroll.Dispose ();
3258                                 v_scroll.Dispose ();
3259                                 
3260                                 large_image_list = null;
3261                                 small_image_list = null;
3262                                 state_image_list = null;
3263
3264                                 foreach (ColumnHeader col in columns)
3265                                         col.SetListView (null);
3266
3267 #if NET_2_0
3268                                 if (!virtual_mode) // In virtual mode we don't save the items
3269 #endif
3270                                         foreach (ListViewItem item in items)
3271                                                 item.Owner = null;
3272                         }
3273                         
3274                         base.Dispose (disposing);
3275                 }
3276
3277                 protected override bool IsInputKey (Keys keyData)
3278                 {
3279                         switch (keyData) {
3280                         case Keys.Up:
3281                         case Keys.Down:
3282                         case Keys.PageUp:
3283                         case Keys.PageDown:
3284                         case Keys.Right:
3285                         case Keys.Left:
3286                         case Keys.End:
3287                         case Keys.Home:
3288                                 return true;
3289
3290                         default:
3291                                 break;
3292                         }
3293                         
3294                         return base.IsInputKey (keyData);
3295                 }
3296
3297                 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
3298                 {
3299                         LabelEditEventHandler eh = (LabelEditEventHandler)(Events [AfterLabelEditEvent]);
3300                         if (eh != null)
3301                                 eh (this, e);
3302                 }
3303
3304 #if NET_2_0
3305                 protected override void OnBackgroundImageChanged (EventArgs e)
3306                 {
3307                         item_control.BackgroundImage = BackgroundImage;
3308                         base.OnBackgroundImageChanged (e);
3309                 }
3310 #endif
3311
3312                 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
3313                 {
3314                         LabelEditEventHandler eh = (LabelEditEventHandler)(Events [BeforeLabelEditEvent]);
3315                         if (eh != null)
3316                                 eh (this, e);
3317                 }
3318
3319                 protected virtual void OnColumnClick (ColumnClickEventArgs e)
3320                 {
3321                         ColumnClickEventHandler eh = (ColumnClickEventHandler)(Events [ColumnClickEvent]);
3322                         if (eh != null)
3323                                 eh (this, e);
3324                 }
3325
3326 #if NET_2_0
3327                 protected internal virtual void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
3328                 {
3329                         DrawListViewColumnHeaderEventHandler eh = (DrawListViewColumnHeaderEventHandler)(Events[DrawColumnHeaderEvent]);
3330                         if (eh != null)
3331                                 eh(this, e);
3332                 }
3333
3334                 protected internal virtual void OnDrawItem(DrawListViewItemEventArgs e)
3335                 {
3336                         DrawListViewItemEventHandler eh = (DrawListViewItemEventHandler)(Events[DrawItemEvent]);
3337                         if (eh != null)
3338                                 eh(this, e);
3339                 }
3340
3341                 protected internal virtual void OnDrawSubItem(DrawListViewSubItemEventArgs e)
3342                 {
3343                         DrawListViewSubItemEventHandler eh = (DrawListViewSubItemEventHandler)(Events[DrawSubItemEvent]);
3344                         if (eh != null)
3345                                 eh(this, e);
3346                 }
3347
3348 #else
3349                 protected override void OnEnabledChanged (EventArgs e)
3350                 {
3351                         base.OnEnabledChanged (e);
3352                 }
3353 #endif
3354
3355                 protected override void OnFontChanged (EventArgs e)
3356                 {
3357                         base.OnFontChanged (e);
3358                         Redraw (true);
3359                 }
3360
3361                 protected override void OnHandleCreated (EventArgs e)
3362                 {
3363                         base.OnHandleCreated (e);
3364                         CalculateListView (alignment);
3365 #if NET_2_0
3366                         if (!virtual_mode) // Sorting is not allowed in virtual mode
3367 #endif
3368                                 Sort ();
3369                 }
3370
3371                 protected override void OnHandleDestroyed (EventArgs e)
3372                 {
3373                         base.OnHandleDestroyed (e);
3374                 }
3375
3376                 protected virtual void OnItemActivate (EventArgs e)
3377                 {
3378                         EventHandler eh = (EventHandler)(Events [ItemActivateEvent]);
3379                         if (eh != null)
3380                                 eh (this, e);
3381                 }
3382
3383                 protected internal virtual void OnItemCheck (ItemCheckEventArgs ice)
3384                 {
3385                         ItemCheckEventHandler eh = (ItemCheckEventHandler)(Events [ItemCheckEvent]);
3386                         if (eh != null)
3387                                 eh (this, ice);
3388                 }
3389
3390 #if NET_2_0
3391                 protected internal virtual void OnItemChecked (ItemCheckedEventArgs e)
3392                 {
3393                         ItemCheckedEventHandler eh = (ItemCheckedEventHandler)(Events [ItemCheckedEvent]);
3394                         if (eh != null)
3395                                 eh (this, e);
3396                 }
3397 #endif
3398
3399                 protected virtual void OnItemDrag (ItemDragEventArgs e)
3400                 {
3401                         ItemDragEventHandler eh = (ItemDragEventHandler)(Events [ItemDragEvent]);
3402                         if (eh != null)
3403                                 eh (this, e);
3404                 }
3405
3406 #if NET_2_0
3407                 protected virtual void OnItemMouseHover (ListViewItemMouseHoverEventArgs e)
3408                 {
3409                         ListViewItemMouseHoverEventHandler eh = (ListViewItemMouseHoverEventHandler)(Events [ItemMouseHoverEvent]);
3410                         if (eh != null)
3411                                 eh (this, e);
3412                 }
3413
3414                 protected internal virtual void OnItemSelectionChanged (ListViewItemSelectionChangedEventArgs e)
3415                 {
3416                         ListViewItemSelectionChangedEventHandler eh = 
3417                                 (ListViewItemSelectionChangedEventHandler) Events [ItemSelectionChangedEvent];
3418                         if (eh != null)
3419                                 eh (this, e);
3420                 }
3421
3422                 protected override void OnMouseHover (EventArgs e)
3423                 {
3424                         base.OnMouseHover (e);
3425                 }
3426
3427                 protected override void OnParentChanged (EventArgs e)
3428                 {
3429                         base.OnParentChanged (e);
3430                 }
3431 #endif
3432
3433                 protected virtual void OnSelectedIndexChanged (EventArgs e)
3434                 {
3435                         EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
3436                         if (eh != null)
3437                                 eh (this, e);
3438                 }
3439
3440                 protected override void OnSystemColorsChanged (EventArgs e)
3441                 {
3442                         base.OnSystemColorsChanged (e);
3443                 }
3444
3445 #if NET_2_0
3446                 protected virtual void OnCacheVirtualItems (CacheVirtualItemsEventArgs e)
3447                 {
3448                         EventHandler eh = (EventHandler)Events [CacheVirtualItemsEvent];
3449                         if (eh != null)
3450                                 eh (this, e);
3451                 }
3452
3453                 protected virtual void OnRetrieveVirtualItem (RetrieveVirtualItemEventArgs e)
3454                 {
3455                         RetrieveVirtualItemEventHandler eh = (RetrieveVirtualItemEventHandler)Events [RetrieveVirtualItemEvent];
3456                         if (eh != null)
3457                                 eh (this, e);
3458                 }
3459
3460                 [EditorBrowsable (EditorBrowsableState.Advanced)]
3461                 protected virtual void OnRightToLeftLayoutChanged (EventArgs e)
3462                 {
3463                         EventHandler eh = (EventHandler)Events[RightToLeftLayoutChangedEvent];
3464                         if (eh != null)
3465                                 eh (this, e);
3466                 }
3467
3468                 protected virtual void OnSearchForVirtualItem (SearchForVirtualItemEventArgs e)
3469                 {
3470                         SearchForVirtualItemEventHandler eh = (SearchForVirtualItemEventHandler) Events [SearchForVirtualItemEvent];
3471                         if (eh != null)
3472                                 eh (this, e);
3473                 }
3474                 
3475                 protected virtual void OnVirtualItemsSelectionRangeChanged (ListViewVirtualItemsSelectionRangeChangedEventArgs e)
3476                 {
3477                         ListViewVirtualItemsSelectionRangeChangedEventHandler eh = 
3478                                 (ListViewVirtualItemsSelectionRangeChangedEventHandler) Events [VirtualItemsSelectionRangeChangedEvent];
3479                         if (eh != null)
3480                                 eh (this, e);
3481                 }
3482 #endif
3483
3484                 protected void RealizeProperties ()
3485                 {
3486                         // FIXME: TODO
3487                 }
3488
3489                 protected void UpdateExtendedStyles ()
3490                 {
3491                         // FIXME: TODO
3492                 }
3493
3494                 bool refocusing = false;
3495
3496                 protected override void WndProc (ref Message m)
3497                 {
3498                         switch ((Msg)m.Msg) {
3499                         case Msg.WM_KILLFOCUS:
3500                                 Control receiver = Control.FromHandle (m.WParam);
3501                                 if (receiver == item_control) {
3502                                         has_focus = false;
3503                                         refocusing = true;
3504                                         return;
3505                                 }
3506                                 break;
3507                         case Msg.WM_SETFOCUS:
3508                                 if (refocusing) {
3509                                         has_focus = true;
3510                                         refocusing = false;
3511                                         return;
3512                                 }
3513                                 break;
3514                         default:
3515                                 break;
3516                         }
3517                         base.WndProc (ref m);
3518                 }
3519                 #endregion // Protected Methods
3520
3521                 #region Public Instance Methods
3522                 public void ArrangeIcons ()
3523                 {
3524                         ArrangeIcons (this.alignment);
3525                 }
3526
3527                 public void ArrangeIcons (ListViewAlignment value)
3528                 {
3529                         // Icons are arranged only if view is set to LargeIcon or SmallIcon
3530                         if (view == View.LargeIcon || view == View.SmallIcon) {
3531                                 this.CalculateListView (value);
3532                                 // we have done the calculations already
3533                                 this.Redraw (false);
3534                         }
3535                 }
3536
3537 #if NET_2_0
3538                 public void AutoResizeColumn (int columnIndex, ColumnHeaderAutoResizeStyle headerAutoResize)
3539                 {
3540                         if (columnIndex < 0 || columnIndex >= columns.Count)
3541                                 throw new ArgumentOutOfRangeException ("columnIndex");
3542
3543                         columns [columnIndex].AutoResize (headerAutoResize);
3544                 }
3545
3546                 public void AutoResizeColumns (ColumnHeaderAutoResizeStyle headerAutoResize)
3547                 {
3548                         BeginUpdate ();
3549                         foreach (ColumnHeader col in columns) 
3550                                 col.AutoResize (headerAutoResize);
3551                         EndUpdate ();
3552                 }
3553 #endif
3554
3555                 public void BeginUpdate ()
3556                 {
3557                         // flag to avoid painting
3558                         updating = true;
3559                 }
3560
3561                 public void Clear ()
3562                 {
3563                         columns.Clear ();
3564                         items.Clear (); // Redraw (true) called here
3565                 }
3566
3567                 public void EndUpdate ()
3568                 {
3569                         // flag to avoid painting
3570                         updating = false;
3571
3572                         // probably, now we need a redraw with recalculations
3573                         this.Redraw (true);
3574                 }
3575
3576                 public void EnsureVisible (int index)
3577                 {
3578                         if (index < 0 || index >= items.Count || scrollable == false)
3579                                 return;
3580
3581                         Rectangle view_rect = item_control.ClientRectangle;
3582                         Rectangle bounds = new Rectangle (GetItemLocation (index), ItemSize);
3583
3584                         if (view_rect.Contains (bounds))
3585                                 return;
3586
3587                         if (View != View.Details) {
3588                                 if (bounds.Left < 0)
3589                                         h_scroll.Value += bounds.Left;
3590                                 else if (bounds.Right > view_rect.Right)
3591                                         h_scroll.Value += (bounds.Right - view_rect.Right);
3592                         }
3593
3594                         if (bounds.Top < 0)
3595                                 v_scroll.Value += bounds.Top;
3596                         else if (bounds.Bottom > view_rect.Bottom)
3597                                 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
3598                 }
3599
3600 #if NET_2_0
3601                 public ListViewItem FindItemWithText (string text)
3602                 {
3603                         if (items.Count == 0)
3604                                 return null;
3605
3606                         return FindItemWithText (text, true, 0, true);
3607                 }
3608
3609                 public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex)
3610                 {
3611                         return FindItemWithText (text, includeSubItemsInSearch, startIndex, true);
3612                 }
3613
3614                 public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch)
3615                 {
3616                         if (startIndex < 0 || startIndex >= items.Count)
3617                                 throw new ArgumentOutOfRangeException ("startIndex");
3618
3619                         if (text == null)
3620                                 throw new ArgumentNullException ("text");
3621
3622                         if (virtual_mode) {
3623                                 SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (true,
3624                                                 isPrefixSearch, includeSubItemsInSearch, text, Point.Empty, 
3625                                                 SearchDirectionHint.Down, startIndex);
3626
3627                                 OnSearchForVirtualItem (args);
3628                                 int idx = args.Index;
3629                                 if (idx >= 0 && idx < virtual_list_size)
3630                                         return items [idx];
3631
3632                                 return null;
3633                         }
3634
3635                         for (int i = startIndex; i < items.Count; i++) {
3636                                 ListViewItem lvi = items [i];
3637
3638                                 if ((isPrefixSearch && lvi.Text.StartsWith (text, true, CultureInfo.CurrentCulture)) // prefix search
3639                                                 || String.Compare (lvi.Text, text, true) == 0) // match
3640                                         return lvi;
3641                         }
3642
3643                         if (includeSubItemsInSearch) {
3644                                 for (int i = startIndex; i < items.Count; i++) {
3645                                         ListViewItem lvi = items [i];
3646                                         foreach (ListViewItem.ListViewSubItem sub_item in lvi.SubItems)
3647                                                 if ((isPrefixSearch && sub_item.Text.StartsWith (text, true, CultureInfo.CurrentCulture))
3648                                                                 || String.Compare (sub_item.Text, text, true) == 0)
3649                                                         return lvi;
3650                                 }
3651                         }
3652
3653                         return null;
3654                 }
3655
3656                 public ListViewItem FindNearestItem (SearchDirectionHint searchDirection, int x, int y)
3657                 {
3658                         return FindNearestItem (searchDirection, new Point (x, y));
3659                 }
3660
3661                 public ListViewItem FindNearestItem (SearchDirectionHint dir, Point point)
3662                 {
3663                         if (dir < SearchDirectionHint.Left || dir > SearchDirectionHint.Down)
3664                                 throw new ArgumentOutOfRangeException ("searchDirection");
3665
3666                         if (view != View.LargeIcon && view != View.SmallIcon)
3667                                 throw new InvalidOperationException ();
3668
3669                         if (virtual_mode) {
3670                                 SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (false,
3671                                                 false, false, String.Empty, point, 
3672                                                 dir, 0);
3673
3674                                 OnSearchForVirtualItem (args);
3675                                 int idx = args.Index;
3676                                 if (idx >= 0 && idx < virtual_list_size)
3677                                         return items [idx];
3678
3679                                 return null;
3680                         }
3681
3682                         ListViewItem item = null;
3683                         int min_dist = Int32.MaxValue;
3684
3685                         //
3686                         // It looks like .Net does a previous adjustment
3687                         //
3688                         switch (dir) {
3689                                 case SearchDirectionHint.Up:
3690                                         point.Y -= item_size.Height;
3691                                         break;
3692                                 case SearchDirectionHint.Down:
3693                                         point.Y += item_size.Height;
3694                                         break;
3695                                 case SearchDirectionHint.Left:
3696                                         point.X -= item_size.Width;
3697                                         break;
3698                                 case SearchDirectionHint.Right:
3699                                         point.X += item_size.Width;
3700                                         break;
3701                         }
3702
3703                         for (int i = 0; i < items.Count; i++) {
3704                                 Point item_loc = GetItemLocation (i);
3705
3706                                 if (dir == SearchDirectionHint.Up) {
3707                                         if (point.Y < item_loc.Y)
3708                                                 continue;
3709                                 } else if (dir == SearchDirectionHint.Down) {
3710                                         if (point.Y > item_loc.Y)
3711                                                 continue;
3712                                 } else if (dir == SearchDirectionHint.Left) {
3713                                         if (point.X < item_loc.X)
3714                                                 continue;
3715                                 } else if (dir == SearchDirectionHint.Right) {
3716                                         if (point.X > item_loc.X)
3717                                                 continue;
3718                                 }
3719
3720                                 int x_dist = point.X - item_loc.X;
3721                                 int y_dist = point.Y - item_loc.Y;
3722
3723                                 int dist = x_dist * x_dist  + y_dist * y_dist;
3724                                 if (dist < min_dist) {
3725                                         item = items [i];
3726                                         min_dist = dist;
3727                                 }
3728                         }
3729
3730                         return item;
3731                 }
3732 #endif
3733                 
3734                 public ListViewItem GetItemAt (int x, int y)
3735                 {
3736                         Size item_size = ItemSize;
3737                         for (int i = 0; i < items.Count; i++) {
3738                                 Point item_location = GetItemLocation (i);
3739                                 Rectangle item_rect = new Rectangle (item_location, item_size);
3740                                 if (item_rect.Contains (x, y))
3741                                         return items [i];
3742                         }
3743
3744                         return null;
3745                 }
3746
3747                 public Rectangle GetItemRect (int index)
3748                 {
3749                         return GetItemRect (index, ItemBoundsPortion.Entire);
3750                 }
3751
3752                 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
3753                 {
3754                         if (index < 0 || index >= items.Count)
3755                                 throw new IndexOutOfRangeException ("index");
3756
3757                         return items [index].GetBounds (portion);
3758                 }
3759
3760 #if NET_2_0
3761                 public ListViewHitTestInfo HitTest (Point point)
3762                 {
3763                         return HitTest (point.X, point.Y);
3764                 }
3765
3766                 public ListViewHitTestInfo HitTest (int x, int y)
3767                 {
3768                         if (x < 0)
3769                                 throw new ArgumentOutOfRangeException ("x");
3770                         if (y < 0)
3771                                 throw new ArgumentOutOfRangeException ("y");
3772
3773                         ListViewItem item = GetItemAt (x, y);
3774                         if (item == null)
3775                                 return new ListViewHitTestInfo (null, null, ListViewHitTestLocations.None);
3776
3777                         ListViewHitTestLocations locations = 0;
3778                         if (item.GetBounds (ItemBoundsPortion.Label).Contains (x, y))
3779                                 locations |= ListViewHitTestLocations.Label;
3780                         else if (item.GetBounds (ItemBoundsPortion.Icon).Contains (x, y))
3781                                 locations |= ListViewHitTestLocations.Image;
3782                         else if (item.CheckRectReal.Contains (x, y))
3783                                 locations |= ListViewHitTestLocations.StateImage;
3784
3785                         ListViewItem.ListViewSubItem subitem = null;
3786                         if (view == View.Details)
3787                                 foreach (ListViewItem.ListViewSubItem si in item.SubItems)
3788                                         if (si.Bounds.Contains (x, y)) {
3789                                                 subitem = si;
3790                                                 break;
3791                                         }
3792
3793                         return new ListViewHitTestInfo (item, subitem, locations);
3794                 }
3795
3796                 [EditorBrowsable (EditorBrowsableState.Advanced)]
3797                 public void RedrawItems (int startIndex, int endIndex, bool invalidateOnly)
3798                 {
3799                         if (startIndex < 0 || startIndex >= items.Count)
3800                                 throw new ArgumentOutOfRangeException ("startIndex");
3801                         if (endIndex < 0 || endIndex >= items.Count)
3802                                 throw new ArgumentOutOfRangeException ("endIndex");
3803                         if (startIndex > endIndex)
3804                                 throw new ArgumentException ("startIndex");
3805
3806                         if (updating)
3807                                 return;
3808
3809                         for (int i = startIndex; i <= endIndex; i++)
3810                                 item_control.Invalidate (items [i].Bounds);
3811
3812                         if (!invalidateOnly)
3813                                 Update ();
3814                 }
3815 #endif
3816
3817                 public void Sort ()
3818                 {
3819 #if NET_2_0
3820                         if (virtual_mode)
3821                                 throw new InvalidOperationException ();
3822 #endif
3823
3824                         Sort (true);
3825                 }
3826
3827                 // we need this overload to reuse the logic for sorting, while allowing
3828                 // redrawing to be done by caller or have it done by this method when
3829                 // sorting is really performed
3830                 //
3831                 // ListViewItemCollection's Add and AddRange methods call this overload
3832                 // with redraw set to false, as they take care of redrawing themselves
3833                 // (they even want to redraw the listview if no sort is performed, as 
3834                 // an item was added), while ListView.Sort () only wants to redraw if 
3835                 // sorting was actually performed
3836                 private void Sort (bool redraw)
3837                 {
3838                         if (!IsHandleCreated || item_sorter == null) {
3839                                 return;
3840                         }
3841                         
3842                         items.Sort (item_sorter);
3843                         if (redraw)
3844                                 this.Redraw (true);
3845                 }
3846
3847                 public override string ToString ()
3848                 {
3849                         int count = this.Items.Count;
3850
3851                         if (count == 0)
3852                                 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
3853                         else
3854                                 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
3855                 }
3856                 #endregion      // Public Instance Methods
3857
3858
3859                 #region Subclasses
3860
3861                 class HeaderControl : Control {
3862
3863                         ListView owner;
3864                         bool column_resize_active = false;
3865                         ColumnHeader resize_column;
3866                         ColumnHeader clicked_column;
3867                         ColumnHeader drag_column;
3868                         int drag_x;
3869                         int drag_to_index = -1;
3870
3871                         public HeaderControl (ListView owner)
3872                         {
3873                                 this.owner = owner;
3874                                 MouseDown += new MouseEventHandler (HeaderMouseDown);
3875                                 MouseMove += new MouseEventHandler (HeaderMouseMove);
3876                                 MouseUp += new MouseEventHandler (HeaderMouseUp);
3877                         }
3878
3879                         private ColumnHeader ColumnAtX (int x)
3880                         {
3881                                 Point pt = new Point (x, 0);
3882                                 ColumnHeader result = null;
3883                                 foreach (ColumnHeader col in owner.Columns) {
3884                                         if (col.Rect.Contains (pt)) {
3885                                                 result = col;
3886                                                 break;
3887                                         }
3888                                 }
3889                                 return result;
3890                         }
3891
3892                         private int GetReorderedIndex (ColumnHeader col)
3893                         {
3894                                 if (owner.reordered_column_indices == null)
3895                                         return col.Index;
3896                                 else
3897                                         for (int i = 0; i < owner.Columns.Count; i++)
3898                                                 if (owner.reordered_column_indices [i] == col.Index)
3899                                                         return i;
3900                                 throw new Exception ("Column index missing from reordered array");
3901                         }
3902
3903                         private void HeaderMouseDown (object sender, MouseEventArgs me)
3904                         {
3905                                 if (resize_column != null) {
3906                                         column_resize_active = true;
3907                                         Capture = true;
3908                                         return;
3909                                 }
3910
3911                                 clicked_column = ColumnAtX (me.X + owner.h_marker);
3912
3913                                 if (clicked_column != null) {
3914                                         Capture = true;
3915                                         if (owner.AllowColumnReorder) {
3916                                                 drag_x = me.X;
3917                                                 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
3918                                                 drag_column.Rect = clicked_column.Rect;
3919                                                 drag_to_index = GetReorderedIndex (clicked_column);
3920                                         }
3921                                         clicked_column.Pressed = true;
3922                                         Rectangle bounds = clicked_column.Rect;
3923                                         bounds.X -= owner.h_marker;
3924                                         Invalidate (bounds);
3925                                         return;
3926                                 }
3927                         }
3928
3929                         void StopResize ()
3930                         {
3931                                 column_resize_active = false;
3932                                 resize_column = null;
3933                                 Capture = false;
3934                                 Cursor = Cursors.Default;
3935                         }
3936                         
3937                         private void HeaderMouseMove (object sender, MouseEventArgs me)
3938                         {
3939                                 Point pt = new Point (me.X + owner.h_marker, me.Y);
3940
3941                                 if (column_resize_active) {
3942                                         int width = pt.X - resize_column.X;
3943                                         if (width < 0)
3944                                                 width = 0;
3945
3946                                         if (!owner.CanProceedWithResize (resize_column, width)){
3947                                                 StopResize ();
3948                                                 return;
3949                                         }
3950                                         resize_column.Width = width;
3951                                         return;
3952                                 }
3953
3954                                 resize_column = null;
3955
3956                                 if (clicked_column != null) {
3957                                         if (owner.AllowColumnReorder) {
3958                                                 Rectangle r;
3959
3960                                                 r = drag_column.Rect;
3961                                                 r.X = clicked_column.Rect.X + me.X - drag_x;
3962                                                 drag_column.Rect = r;
3963
3964                                                 int x = me.X + owner.h_marker;
3965                                                 ColumnHeader over = ColumnAtX (x);
3966                                                 if (over == null)
3967                                                         drag_to_index = owner.Columns.Count;
3968                                                 else if (x < over.X + over.Width / 2)
3969                                                         drag_to_index = GetReorderedIndex (over);
3970                                                 else
3971                                                         drag_to_index = GetReorderedIndex (over) + 1;
3972                                                 Invalidate ();
3973                                         } else {
3974                                                 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
3975                                                 bool pressed = clicked_column.Pressed;
3976                                                 clicked_column.Pressed = over == clicked_column;
3977                                                 if (clicked_column.Pressed ^ pressed) {
3978                                                         Rectangle bounds = clicked_column.Rect;
3979                                                         bounds.X -= owner.h_marker;
3980                                                         Invalidate (bounds);
3981                                                 }
3982                                         }
3983                                         return;
3984                                 }
3985
3986                                 for (int i = 0; i < owner.Columns.Count; i++) {
3987                                         Rectangle zone = owner.Columns [i].Rect;
3988                                         zone.X = zone.Right - 5;
3989                                         zone.Width = 10;
3990                                         if (zone.Contains (pt)) {
3991                                                 if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
3992                                                         i++;
3993                                                 resize_column = owner.Columns [i];
3994                                                 break;
3995                                         }
3996                                 }
3997
3998                                 if (resize_column == null)
3999                                         Cursor = Cursors.Default;
4000                                 else
4001                                         Cursor = Cursors.VSplit;
4002                         }
4003
4004                         void HeaderMouseUp (object sender, MouseEventArgs me)
4005                         {
4006                                 Capture = false;
4007
4008                                 if (column_resize_active) {
4009                                         int column_idx = resize_column.Index;
4010                                         StopResize ();
4011                                         owner.RaiseColumnWidthChanged (column_idx);
4012                                         return;
4013                                 }
4014
4015                                 if (clicked_column != null && clicked_column.Pressed) {
4016                                         clicked_column.Pressed = false;
4017                                         Rectangle bounds = clicked_column.Rect;
4018                                         bounds.X -= owner.h_marker;
4019                                         Invalidate (bounds);
4020                                         owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
4021                                 }
4022
4023                                 if (drag_column != null && owner.AllowColumnReorder) {
4024                                         drag_column = null;
4025                                         if (drag_to_index > GetReorderedIndex (clicked_column))
4026                                                 drag_to_index--;
4027                                         if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
4028                                                 owner.ReorderColumn (clicked_column, drag_to_index, true);
4029                                         drag_to_index = -1;
4030                                         Invalidate ();
4031                                 }
4032
4033                                 clicked_column = null;
4034                         }
4035
4036                         internal override void OnPaintInternal (PaintEventArgs pe)
4037                         {
4038                                 if (owner.updating)
4039                                         return;
4040                                 
4041                                 Theme theme = ThemeEngine.Current;
4042                                 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
4043
4044                                 if (drag_column == null)
4045                                         return;
4046
4047                                 int target_x;
4048                                 if (drag_to_index == owner.Columns.Count)
4049                                         target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
4050                                 else
4051                                         target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
4052                                 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
4053                         }
4054
4055                         protected override void WndProc (ref Message m)
4056                         {
4057                                 switch ((Msg)m.Msg) {
4058                                 case Msg.WM_SETFOCUS:
4059                                         owner.Focus ();
4060                                         break;
4061                                 default:
4062                                         base.WndProc (ref m);
4063                                         break;
4064                                 }
4065                         }
4066                 }
4067
4068                 private class ItemComparer : IComparer {
4069                         readonly SortOrder sort_order;
4070
4071                         public ItemComparer (SortOrder sortOrder)
4072                         {
4073                                 sort_order = sortOrder;
4074                         }
4075
4076                         public int Compare (object x, object y)
4077                         {
4078                                 ListViewItem item_x = x as ListViewItem;
4079                                 ListViewItem item_y = y as ListViewItem;
4080                                 if (sort_order == SortOrder.Ascending)
4081                                         return String.Compare (item_x.Text, item_y.Text);
4082                                 else
4083                                         return String.Compare (item_y.Text, item_x.Text);
4084                         }
4085                 }
4086
4087 #if NET_2_0
4088                 [ListBindable (false)]
4089 #endif
4090                 public class CheckedIndexCollection : IList, ICollection, IEnumerable
4091                 {
4092                         private readonly ListView owner;
4093
4094                         #region Public Constructor
4095                         public CheckedIndexCollection (ListView owner)
4096                         {
4097                                 this.owner = owner;
4098                         }
4099                         #endregion      // Public Constructor
4100
4101                         #region Public Properties
4102                         [Browsable (false)]
4103                         public int Count {
4104                                 get { return owner.CheckedItems.Count; }
4105                         }
4106
4107                         public bool IsReadOnly {
4108                                 get { return true; }
4109                         }
4110
4111                         public int this [int index] {
4112                                 get {
4113                                         int [] indices = GetIndices ();
4114                                         if (index < 0 || index >= indices.Length)
4115                                                 throw new ArgumentOutOfRangeException ("index");
4116                                         return indices [index];
4117                                 }
4118                         }
4119
4120                         bool ICollection.IsSynchronized {
4121                                 get { return false; }
4122                         }
4123
4124                         object ICollection.SyncRoot {
4125                                 get { return this; }
4126                         }
4127
4128                         bool IList.IsFixedSize {
4129                                 get { return true; }
4130                         }
4131
4132                         object IList.this [int index] {
4133                                 get { return this [index]; }
4134                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4135                         }
4136                         #endregion      // Public Properties
4137
4138                         #region Public Methods
4139                         public bool Contains (int checkedIndex)
4140                         {
4141                                 int [] indices = GetIndices ();
4142                                 for (int i = 0; i < indices.Length; i++) {
4143                                         if (indices [i] == checkedIndex)
4144                                                 return true;
4145                                 }
4146                                 return false;
4147                         }
4148
4149                         public IEnumerator GetEnumerator ()
4150                         {
4151                                 int [] indices = GetIndices ();
4152                                 return indices.GetEnumerator ();
4153                         }
4154
4155                         void ICollection.CopyTo (Array dest, int index)
4156                         {
4157                                 int [] indices = GetIndices ();
4158                                 Array.Copy (indices, 0, dest, index, indices.Length);
4159                         }
4160
4161                         int IList.Add (object value)
4162                         {
4163                                 throw new NotSupportedException ("Add operation is not supported.");
4164                         }
4165
4166                         void IList.Clear ()
4167                         {
4168                                 throw new NotSupportedException ("Clear operation is not supported.");
4169                         }
4170
4171                         bool IList.Contains (object checkedIndex)
4172                         {
4173                                 if (!(checkedIndex is int))
4174                                         return false;
4175                                 return Contains ((int) checkedIndex);
4176                         }
4177
4178                         int IList.IndexOf (object checkedIndex)
4179                         {
4180                                 if (!(checkedIndex is int))
4181                                         return -1;
4182                                 return IndexOf ((int) checkedIndex);
4183                         }
4184
4185                         void IList.Insert (int index, object value)
4186                         {
4187                                 throw new NotSupportedException ("Insert operation is not supported.");
4188                         }
4189
4190                         void IList.Remove (object value)
4191                         {
4192                                 throw new NotSupportedException ("Remove operation is not supported.");
4193                         }
4194
4195                         void IList.RemoveAt (int index)
4196                         {
4197                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
4198                         }
4199
4200                         public int IndexOf (int checkedIndex)
4201                         {
4202                                 int [] indices = GetIndices ();
4203                                 for (int i = 0; i < indices.Length; i++) {
4204                                         if (indices [i] == checkedIndex)
4205                                                 return i;
4206                                 }
4207                                 return -1;
4208                         }
4209                         #endregion      // Public Methods
4210
4211                         private int [] GetIndices ()
4212                         {
4213                                 ArrayList checked_items = owner.CheckedItems.List;
4214                                 int [] indices = new int [checked_items.Count];
4215                                 for (int i = 0; i < checked_items.Count; i++) {
4216                                         ListViewItem item = (ListViewItem) checked_items [i];
4217                                         indices [i] = item.Index;
4218                                 }
4219                                 return indices;
4220                         }
4221                 }       // CheckedIndexCollection
4222
4223 #if NET_2_0
4224                 [ListBindable (false)]
4225 #endif
4226                 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
4227                 {
4228                         private readonly ListView owner;
4229                         private ArrayList list;
4230
4231                         #region Public Constructor
4232                         public CheckedListViewItemCollection (ListView owner)
4233                         {
4234                                 this.owner = owner;
4235                                 this.owner.Items.Changed += new CollectionChangedHandler (
4236                                         ItemsCollection_Changed);
4237                         }
4238                         #endregion      // Public Constructor
4239
4240                         #region Public Properties
4241                         [Browsable (false)]
4242                         public int Count {
4243                                 get {
4244                                         if (!owner.CheckBoxes)
4245                                                 return 0;
4246                                         return List.Count;
4247                                 }
4248                         }
4249
4250                         public bool IsReadOnly {
4251                                 get { return true; }
4252                         }
4253
4254                         public ListViewItem this [int index] {
4255                                 get {
4256 #if NET_2_0
4257                                         if (owner.VirtualMode)
4258                                                 throw new InvalidOperationException ();
4259 #endif
4260                                         ArrayList checked_items = List;
4261                                         if (index < 0 || index >= checked_items.Count)
4262                                                 throw new ArgumentOutOfRangeException ("index");
4263                                         return (ListViewItem) checked_items [index];
4264                                 }
4265                         }
4266
4267 #if NET_2_0
4268                         public virtual ListViewItem this [string key] {
4269                                 get {
4270                                         int idx = IndexOfKey (key);
4271                                         return idx == -1 ? null : (ListViewItem) List [idx];
4272                                 }
4273                         }
4274 #endif
4275
4276                         bool ICollection.IsSynchronized {
4277                                 get { return false; }
4278                         }
4279
4280                         object ICollection.SyncRoot {
4281                                 get { return this; }
4282                         }
4283
4284                         bool IList.IsFixedSize {
4285                                 get { return true; }
4286                         }
4287
4288                         object IList.this [int index] {
4289                                 get { return this [index]; }
4290                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4291                         }
4292                         #endregion      // Public Properties
4293
4294                         #region Public Methods
4295                         public bool Contains (ListViewItem item)
4296                         {
4297                                 if (!owner.CheckBoxes)
4298                                         return false;
4299                                 return List.Contains (item);
4300                         }
4301
4302 #if NET_2_0
4303                         public virtual bool ContainsKey (string key)
4304                         {
4305                                 return IndexOfKey (key) != -1;
4306                         }
4307 #endif
4308
4309                         public void CopyTo (Array dest, int index)
4310                         {
4311 #if NET_2_0
4312                                 if (owner.VirtualMode)
4313                                         throw new InvalidOperationException ();
4314 #endif
4315                                 if (!owner.CheckBoxes)
4316                                         return;
4317                                 List.CopyTo (dest, index);
4318                         }
4319
4320                         public IEnumerator GetEnumerator ()
4321                         {
4322 #if NET_2_0
4323                                 if (owner.VirtualMode)
4324                                         throw new InvalidOperationException ();
4325 #endif
4326                                 if (!owner.CheckBoxes)
4327                                         return (new ListViewItem [0]).GetEnumerator ();
4328                                 return List.GetEnumerator ();
4329                         }
4330
4331                         int IList.Add (object value)
4332                         {
4333                                 throw new NotSupportedException ("Add operation is not supported.");
4334                         }
4335
4336                         void IList.Clear ()
4337                         {
4338                                 throw new NotSupportedException ("Clear operation is not supported.");
4339                         }
4340
4341                         bool IList.Contains (object item)
4342                         {
4343                                 if (!(item is ListViewItem))
4344                                         return false;
4345                                 return Contains ((ListViewItem) item);
4346                         }
4347
4348                         int IList.IndexOf (object item)
4349                         {
4350                                 if (!(item is ListViewItem))
4351                                         return -1;
4352                                 return IndexOf ((ListViewItem) item);
4353                         }
4354
4355                         void IList.Insert (int index, object value)
4356                         {
4357                                 throw new NotSupportedException ("Insert operation is not supported.");
4358                         }
4359
4360                         void IList.Remove (object value)
4361                         {
4362                                 throw new NotSupportedException ("Remove operation is not supported.");
4363                         }
4364
4365                         void IList.RemoveAt (int index)
4366                         {
4367                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
4368                         }
4369
4370                         public int IndexOf (ListViewItem item)
4371                         {
4372 #if NET_2_0
4373                                 if (owner.VirtualMode)
4374                                         throw new InvalidOperationException ();
4375 #endif
4376                                 if (!owner.CheckBoxes)
4377                                         return -1;
4378                                 return List.IndexOf (item);
4379                         }
4380
4381 #if NET_2_0
4382                         public virtual int IndexOfKey (string key)
4383                         {
4384 #if NET_2_0
4385                                 if (owner.VirtualMode)
4386                                         throw new InvalidOperationException ();
4387 #endif
4388                                 if (key == null || key.Length == 0)
4389                                         return -1;
4390
4391                                 ArrayList checked_items = List;
4392                                 for (int i = 0; i < checked_items.Count; i++) {
4393                                         ListViewItem item = (ListViewItem) checked_items [i];
4394                                         if (String.Compare (key, item.Name, true) == 0)
4395                                                 return i;
4396                                 }
4397
4398                                 return -1;
4399                         }
4400 #endif
4401                         #endregion      // Public Methods
4402
4403                         internal ArrayList List {
4404                                 get {
4405                                         if (list == null) {
4406                                                 list = new ArrayList ();
4407                                                 foreach (ListViewItem item in owner.Items) {
4408                                                         if (item.Checked)
4409                                                                 list.Add (item);
4410                                                 }
4411                                         }
4412                                         return list;
4413                                 }
4414                         }
4415
4416                         internal void Reset ()
4417                         {
4418                                 // force re-population of list
4419                                 list = null;
4420                         }
4421
4422                         private void ItemsCollection_Changed ()
4423                         {
4424                                 Reset ();
4425                         }
4426                 }       // CheckedListViewItemCollection
4427
4428 #if NET_2_0
4429                 [ListBindable (false)]
4430 #endif
4431                 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
4432                 {
4433                         internal ArrayList list;
4434                         private ListView owner;
4435
4436                         #region Public Constructor
4437                         public ColumnHeaderCollection (ListView owner)
4438                         {
4439                                 list = new ArrayList ();
4440                                 this.owner = owner;
4441                         }
4442                         #endregion      // Public Constructor
4443
4444                         #region Public Properties
4445                         [Browsable (false)]
4446                         public int Count {
4447                                 get { return list.Count; }
4448                         }
4449
4450                         public bool IsReadOnly {
4451                                 get { return false; }
4452                         }
4453
4454                         public virtual ColumnHeader this [int index] {
4455                                 get {
4456                                         if (index < 0 || index >= list.Count)
4457                                                 throw new ArgumentOutOfRangeException ("index");
4458                                         return (ColumnHeader) list [index];
4459                                 }
4460                         }
4461
4462 #if NET_2_0
4463                         public virtual ColumnHeader this [string key] {
4464                                 get {
4465                                         int idx = IndexOfKey (key);
4466                                         if (idx == -1)
4467                                                 return null;
4468
4469                                         return (ColumnHeader) list [idx];
4470                                 }
4471                         }
4472 #endif
4473
4474                         bool ICollection.IsSynchronized {
4475                                 get { return true; }
4476                         }
4477
4478                         object ICollection.SyncRoot {
4479                                 get { return this; }
4480                         }
4481
4482                         bool IList.IsFixedSize {
4483                                 get { return list.IsFixedSize; }
4484                         }
4485
4486                         object IList.this [int index] {
4487                                 get { return this [index]; }
4488                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4489                         }
4490                         #endregion      // Public Properties
4491
4492                         #region Public Methods
4493                         public virtual int Add (ColumnHeader value)
4494                         {
4495                                 int idx = list.Add (value);
4496                                 owner.AddColumn (value, idx, true);
4497                                 return idx;
4498                         }
4499
4500 #if NET_2_0
4501                         public virtual ColumnHeader Add (string text, int width, HorizontalAlignment textAlign)
4502                         {
4503                                 string str = text;
4504 #else
4505                         public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
4506                         {
4507 #endif
4508                                 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
4509                                 this.Add (colHeader);
4510                                 return colHeader;
4511                         }
4512
4513 #if NET_2_0
4514                         public virtual ColumnHeader Add (string text)
4515                         {
4516                                 return Add (String.Empty, text);
4517                         }
4518
4519                         public virtual ColumnHeader Add (string text, int width)
4520                         {
4521                                 return Add (String.Empty, text, width);
4522                         }
4523
4524                         public virtual ColumnHeader Add (string key, string text)
4525                         {
4526                                 ColumnHeader colHeader = new ColumnHeader ();
4527                                 colHeader.Name = key;
4528                                 colHeader.Text = text;
4529                                 Add (colHeader);
4530                                 return colHeader;
4531                         }
4532
4533                         public virtual ColumnHeader Add (string key, string text, int width)
4534                         {
4535                                 return Add (key, text, width, HorizontalAlignment.Left, -1);
4536                         }
4537
4538                         public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
4539                         {
4540                                 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4541                                 colHeader.ImageIndex = imageIndex;
4542                                 Add (colHeader);
4543                                 return colHeader;
4544                         }
4545
4546                         public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
4547                         {
4548                                 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4549                                 colHeader.ImageKey = imageKey;
4550                                 Add (colHeader);
4551                                 return colHeader;
4552                         }
4553 #endif
4554
4555                         public virtual void AddRange (ColumnHeader [] values)
4556                         {
4557                                 foreach (ColumnHeader colHeader in values) {
4558                                         int idx = list.Add (colHeader);
4559                                         owner.AddColumn (colHeader, idx, false);
4560                                 }
4561                                 
4562                                 owner.Redraw (true);
4563                         }
4564
4565                         public virtual void Clear ()
4566                         {
4567                                 foreach (ColumnHeader col in list)
4568                                         col.SetListView (null);
4569                                 list.Clear ();
4570                                 owner.ReorderColumns (new int [0], true);
4571                         }
4572
4573                         public bool Contains (ColumnHeader value)
4574                         {
4575                                 return list.Contains (value);
4576                         }
4577
4578 #if NET_2_0
4579                         public virtual bool ContainsKey (string key)
4580                         {
4581                                 return IndexOfKey (key) != -1;
4582                         }
4583 #endif
4584
4585                         public IEnumerator GetEnumerator ()
4586                         {
4587                                 return list.GetEnumerator ();
4588                         }
4589
4590                         void ICollection.CopyTo (Array dest, int index)
4591                         {
4592                                 list.CopyTo (dest, index);
4593                         }
4594
4595                         int IList.Add (object value)
4596                         {
4597                                 if (! (value is ColumnHeader)) {
4598                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
4599                                 }
4600
4601                                 return this.Add ((ColumnHeader) value);
4602                         }
4603
4604                         bool IList.Contains (object value)
4605                         {
4606                                 if (! (value is ColumnHeader)) {
4607                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
4608                                 }
4609
4610                                 return this.Contains ((ColumnHeader) value);
4611                         }
4612
4613                         int IList.IndexOf (object value)
4614                         {
4615                                 if (! (value is ColumnHeader)) {
4616                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
4617                                 }
4618
4619                                 return this.IndexOf ((ColumnHeader) value);
4620                         }
4621
4622                         void IList.Insert (int index, object value)
4623                         {
4624                                 if (! (value is ColumnHeader)) {
4625                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
4626                                 }
4627
4628                                 this.Insert (index, (ColumnHeader) value);
4629                         }
4630
4631                         void IList.Remove (object value)
4632                         {
4633                                 if (! (value is ColumnHeader)) {
4634                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
4635                                 }
4636
4637                                 this.Remove ((ColumnHeader) value);
4638                         }
4639
4640                         public int IndexOf (ColumnHeader value)
4641                         {
4642                                 return list.IndexOf (value);
4643                         }
4644
4645 #if NET_2_0
4646                         public virtual int IndexOfKey (string key)
4647                         {
4648                                 if (key == null || key.Length == 0)
4649                                         return -1;
4650
4651                                 for (int i = 0; i < list.Count; i++) {
4652                                         ColumnHeader col = (ColumnHeader) list [i];
4653                                         if (String.Compare (key, col.Name, true) == 0)
4654                                                 return i;
4655                                 }
4656
4657                                 return -1;
4658                         }
4659 #endif
4660
4661                         public void Insert (int index, ColumnHeader value)
4662                         {
4663                                 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
4664                                 // but it's really only greater.
4665                                 if (index < 0 || index > list.Count)
4666                                         throw new ArgumentOutOfRangeException ("index");
4667
4668                                 list.Insert (index, value);
4669                                 owner.AddColumn (value, index, true);
4670                         }
4671
4672 #if NET_2_0
4673                         public void Insert (int index, string text)
4674                         {
4675                                 Insert (index, String.Empty, text);
4676                         }
4677
4678                         public void Insert (int index, string text, int width)
4679                         {
4680                                 Insert (index, String.Empty, text, width);
4681                         }
4682
4683                         public void Insert (int index, string key, string text)
4684                         {
4685                                 ColumnHeader colHeader = new ColumnHeader ();
4686                                 colHeader.Name = key;
4687                                 colHeader.Text = text;
4688                                 Insert (index, colHeader);
4689                         }
4690
4691                         public void Insert (int index, string key, string text, int width)
4692                         {
4693                                 ColumnHeader colHeader = new ColumnHeader (key, text, width, HorizontalAlignment.Left);
4694                                 Insert (index, colHeader);
4695                         }
4696
4697                         public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
4698                         {
4699                                 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4700                                 colHeader.ImageIndex = imageIndex;
4701                                 Insert (index, colHeader);
4702                         }
4703
4704                         public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
4705                         {
4706                                 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4707                                 colHeader.ImageKey = imageKey;
4708                                 Insert (index, colHeader);
4709                         }
4710 #endif
4711
4712 #if NET_2_0
4713                         public void Insert (int index, string text, int width, HorizontalAlignment textAlign)
4714                         {
4715                                 string str = text;
4716 #else
4717                         public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
4718                         {
4719 #endif
4720                                 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
4721                                 this.Insert (index, colHeader);
4722                         }
4723
4724                         public virtual void Remove (ColumnHeader column)
4725                         {
4726                                 if (!Contains (column))
4727                                         return;
4728
4729                                 list.Remove (column);
4730                                 column.SetListView (null);
4731
4732                                 int rem_display_index = column.InternalDisplayIndex;
4733                                 int [] display_indices = new int [list.Count];
4734                                 for (int i = 0; i < display_indices.Length; i++) {
4735                                         ColumnHeader col = (ColumnHeader) list [i];
4736                                         int display_index = col.InternalDisplayIndex;
4737                                         if (display_index < rem_display_index) {
4738                                                 display_indices [i] = display_index;
4739                                         } else {
4740                                                 display_indices [i] = (display_index - 1);
4741                                         }
4742                                 }
4743
4744                                 column.InternalDisplayIndex = -1;
4745                                 owner.ReorderColumns (display_indices, true);
4746                         }
4747
4748 #if NET_2_0
4749                         public virtual void RemoveByKey (string key)
4750                         {
4751                                 int idx = IndexOfKey (key);
4752                                 if (idx != -1)
4753                                         RemoveAt (idx);
4754                         }
4755 #endif
4756
4757                         public virtual void RemoveAt (int index)
4758                         {
4759                                 if (index < 0 || index >= list.Count)
4760                                         throw new ArgumentOutOfRangeException ("index");
4761
4762                                 ColumnHeader col = (ColumnHeader) list [index];
4763                                 Remove (col);
4764                         }
4765                         #endregion      // Public Methods
4766                         
4767
4768                 }       // ColumnHeaderCollection
4769
4770 #if NET_2_0
4771                 [ListBindable (false)]
4772 #endif
4773                 public class ListViewItemCollection : IList, ICollection, IEnumerable
4774                 {
4775                         private readonly ArrayList list;
4776                         private ListView owner;
4777 #if NET_2_0
4778                         private ListViewGroup group;
4779 #endif
4780
4781                         // The collection can belong to a ListView (main) or to a ListViewGroup (sub-collection)
4782                         // In the later case ListViewItem.ListView never gets modified
4783                         private bool is_main_collection = true;
4784
4785                         #region Public Constructor
4786                         public ListViewItemCollection (ListView owner)
4787                         {
4788                                 list = new ArrayList (0);
4789                                 this.owner = owner;
4790                         }
4791                         #endregion      // Public Constructor
4792
4793 #if NET_2_0
4794                         internal ListViewItemCollection (ListView owner, ListViewGroup group) : this (owner)
4795                         {
4796                                 this.group = group;
4797                                 is_main_collection = false;
4798                         }
4799 #endif
4800
4801                         #region Public Properties
4802                         [Browsable (false)]
4803                         public int Count {
4804                                 get {
4805 #if NET_2_0
4806                                         if (owner != null && owner.VirtualMode)
4807                                                 return owner.VirtualListSize;
4808 #endif
4809
4810                                         return list.Count; 
4811                                 }
4812                         }
4813
4814                         public bool IsReadOnly {
4815                                 get { return false; }
4816                         }
4817
4818 #if NET_2_0
4819                         public virtual ListViewItem this [int index] {
4820 #else
4821                         public virtual ListViewItem this [int displayIndex] {
4822 #endif
4823                                 get {
4824 #if !NET_2_0
4825                                         int index = displayIndex;
4826 #endif
4827
4828                                         if (index < 0 || index >= Count)
4829                                                 throw new ArgumentOutOfRangeException ("index");
4830
4831 #if NET_2_0
4832                                         if (owner != null && owner.VirtualMode)
4833                                                 return RetrieveVirtualItemFromOwner (index);
4834 #endif
4835                                         return (ListViewItem) list [index];
4836                                 }
4837
4838                                 set {
4839 #if !NET_2_0
4840                                         int index = displayIndex;
4841 #endif
4842
4843                                         if (index < 0 || index >= Count)
4844                                                 throw new ArgumentOutOfRangeException ("index");
4845
4846 #if NET_2_0
4847                                         if (owner != null && owner.VirtualMode)
4848                                                 throw new InvalidOperationException ();
4849 #endif
4850
4851                                         if (list.Contains (value))
4852                                                 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
4853
4854                                         if (value.ListView != null && value.ListView != owner)
4855                                                 throw new ArgumentException ("Cannot add or insert the item '" + value.Text + "' in more than one place. You must first remove it from its current location or clone it.", "value");
4856
4857                                         if (is_main_collection)
4858                                                 value.Owner = owner;
4859 #if NET_2_0
4860                                         else {
4861                                                 if (value.Group != null)
4862                                                         value.Group.Items.Remove (value);
4863
4864                                                 value.SetGroup (group);
4865                                         }
4866 #endif
4867
4868                                         list [index] = value;
4869                                         CollectionChanged (true);
4870                                 }
4871                         }
4872
4873 #if NET_2_0
4874                         public virtual ListViewItem this [string key] {
4875                                 get {
4876                                         int idx = IndexOfKey (key);
4877                                         if (idx == -1)
4878                                                 return null;
4879
4880                                         return this [idx];
4881                                 }
4882                         }
4883 #endif
4884
4885                         bool ICollection.IsSynchronized {
4886                                 get { return true; }
4887                         }
4888
4889                         object ICollection.SyncRoot {
4890                                 get { return this; }
4891                         }
4892
4893                         bool IList.IsFixedSize {
4894                                 get { return list.IsFixedSize; }
4895                         }
4896
4897                         object IList.this [int index] {
4898                                 get { return this [index]; }
4899                                 set {
4900                                         if (value is ListViewItem)
4901                                                 this [index] = (ListViewItem) value;
4902                                         else
4903                                                 this [index] = new ListViewItem (value.ToString ());
4904                                         OnChange ();
4905                                 }
4906                         }
4907                         #endregion      // Public Properties
4908
4909                         #region Public Methods
4910                         public virtual ListViewItem Add (ListViewItem value)
4911                         {
4912 #if NET_2_0
4913                                 if (owner != null && owner.VirtualMode)
4914                                         throw new InvalidOperationException ();
4915 #endif
4916
4917                                 AddItem (value);
4918                                 CollectionChanged (true);
4919
4920                                 return value;
4921                         }
4922
4923                         public virtual ListViewItem Add (string text)
4924                         {
4925                                 ListViewItem item = new ListViewItem (text);
4926                                 return this.Add (item);
4927                         }
4928
4929                         public virtual ListViewItem Add (string text, int imageIndex)
4930                         {
4931                                 ListViewItem item = new ListViewItem (text, imageIndex);
4932                                 return this.Add (item);
4933                         }
4934
4935 #if NET_2_0
4936                         public virtual ListViewItem Add (string text, string imageKey)
4937                         {
4938                                 ListViewItem item = new ListViewItem (text, imageKey);
4939                                 return this.Add (item);
4940                         }
4941
4942                         public virtual ListViewItem Add (string key, string text, int imageIndex)
4943                         {
4944                                 ListViewItem item = new ListViewItem (text, imageIndex);
4945                                 item.Name = key;
4946                                 return this.Add (item);
4947                         }
4948
4949                         public virtual ListViewItem Add (string key, string text, string imageKey)
4950                         {
4951                                 ListViewItem item = new ListViewItem (text, imageKey);
4952                                 item.Name = key;
4953                                 return this.Add (item);
4954                         }
4955 #endif
4956
4957 #if NET_2_0
4958                         public void AddRange (ListViewItem [] items)
4959                         {
4960 #else
4961                         public void AddRange (ListViewItem [] values)
4962                         {
4963                                 ListViewItem [] items = values;
4964 #endif
4965                                 if (items == null)
4966                                         throw new ArgumentNullException ("Argument cannot be null!", "items");
4967 #if NET_2_0
4968                                 if (owner != null && owner.VirtualMode)
4969                                         throw new InvalidOperationException ();
4970 #endif
4971
4972                                 foreach (ListViewItem item in items)
4973                                         AddItem (item);
4974
4975                                 CollectionChanged (true);
4976                         }
4977
4978 #if NET_2_0
4979                         public void AddRange (ListViewItemCollection items)
4980                         {
4981                                 if (items == null)
4982                                         throw new ArgumentNullException ("Argument cannot be null!", "items");
4983
4984                                 ListViewItem[] itemArray = new ListViewItem[items.Count];
4985                                 items.CopyTo (itemArray,0);
4986                                 this.AddRange (itemArray);
4987                         }
4988 #endif
4989
4990                         public virtual void Clear ()
4991                         {
4992 #if NET_2_0
4993                                 if (owner != null && owner.VirtualMode)
4994                                         throw new InvalidOperationException ();
4995 #endif
4996                                 if (is_main_collection && owner != null) {
4997                                         owner.SetFocusedItem (-1);
4998                                         owner.h_scroll.Value = owner.v_scroll.Value = 0;
4999                                                 
5000                                         foreach (ListViewItem item in list) {
5001                                                 owner.item_control.CancelEdit (item);
5002                                                 item.Owner = null;
5003                                         }
5004                                         
5005                                 }
5006 #if NET_2_0
5007                                 else
5008                                         foreach (ListViewItem item in list)
5009                                                 item.SetGroup (null);
5010 #endif
5011
5012                                 list.Clear ();
5013                                 CollectionChanged (false);
5014                         }
5015
5016                         public bool Contains (ListViewItem item)
5017                         {
5018                                 return IndexOf (item) != -1;
5019                         }
5020
5021 #if NET_2_0
5022                         public virtual bool ContainsKey (string key)
5023                         {
5024                                 return IndexOfKey (key) != -1;
5025                         }
5026 #endif
5027
5028                         public void CopyTo (Array dest, int index)
5029                         {
5030                                 list.CopyTo (dest, index);
5031                         }
5032
5033 #if NET_2_0
5034                         public ListViewItem [] Find (string key, bool searchAllSubItems)
5035                         {
5036                                 if (key == null)
5037                                         return new ListViewItem [0];
5038
5039                                 List<ListViewItem> temp_list = new List<ListViewItem> ();
5040                                 
5041                                 for (int i = 0; i < list.Count; i++) {
5042                                         ListViewItem lvi = (ListViewItem) list [i];
5043                                         if (String.Compare (key, lvi.Name, true) == 0)
5044                                                 temp_list.Add (lvi);
5045                                 }
5046
5047                                 ListViewItem [] retval = new ListViewItem [temp_list.Count];
5048                                 temp_list.CopyTo (retval);
5049
5050                                 return retval;
5051                         }
5052 #endif
5053
5054                         public IEnumerator GetEnumerator ()
5055                         {
5056 #if NET_2_0
5057                                 if (owner != null && owner.VirtualMode)
5058                                         throw new InvalidOperationException ();
5059 #endif
5060                                 
5061                                 return list.GetEnumerator ();
5062                         }
5063
5064                         int IList.Add (object item)
5065                         {
5066                                 int result;
5067                                 ListViewItem li;
5068
5069 #if NET_2_0
5070                                 if (owner != null && owner.VirtualMode)
5071                                         throw new InvalidOperationException ();
5072 #endif
5073
5074                                 if (item is ListViewItem) {
5075                                         li = (ListViewItem) item;
5076                                         if (list.Contains (li))
5077                                                 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
5078
5079                                         if (li.ListView != null && li.ListView != owner)
5080                                                 throw new ArgumentException ("Cannot add or insert the item '" + li.Text + "' in more than one place. You must first remove it from its current location or clone it.", "item");
5081                                 }
5082                                 else
5083                                         li = new ListViewItem (item.ToString ());
5084
5085                                 li.Owner = owner;
5086                                 result = list.Add (li);
5087                                 CollectionChanged (true);
5088
5089                                 return result;
5090                         }
5091
5092                         bool IList.Contains (object item)
5093                         {
5094                                 return Contains ((ListViewItem) item);
5095                         }
5096
5097                         int IList.IndexOf (object item)
5098                         {
5099                                 return IndexOf ((ListViewItem) item);
5100                         }
5101
5102                         void IList.Insert (int index, object item)
5103                         {
5104                                 if (item is ListViewItem)
5105                                         this.Insert (index, (ListViewItem) item);
5106                                 else
5107                                         this.Insert (index, item.ToString ());
5108                         }
5109
5110                         void IList.Remove (object item)
5111                         {
5112                                 Remove ((ListViewItem) item);
5113                         }
5114
5115                         public int IndexOf (ListViewItem item)
5116                         {
5117 #if NET_2_0
5118                                 if (owner != null && owner.VirtualMode) {
5119                                         for (int i = 0; i < Count; i++)
5120                                                 if (RetrieveVirtualItemFromOwner (i) == item)
5121                                                         return i;
5122
5123                                         return -1;
5124                                 }
5125 #endif
5126                                 
5127                                 return list.IndexOf (item);
5128                         }
5129
5130 #if NET_2_0
5131                         public virtual int IndexOfKey (string key)
5132                         {
5133                                 if (key == null || key.Length == 0)
5134                                         return -1;
5135
5136                                 for (int i = 0; i < Count; i++) {
5137                                         ListViewItem lvi = this [i];
5138                                         if (String.Compare (key, lvi.Name, true) == 0)
5139                                                 return i;
5140                                 }
5141
5142                                 return -1;
5143                         }
5144 #endif
5145
5146                         public ListViewItem Insert (int index, ListViewItem item)
5147                         {
5148                                 if (index < 0 || index > list.Count)
5149                                         throw new ArgumentOutOfRangeException ("index");
5150
5151 #if NET_2_0
5152                                 if (owner != null && owner.VirtualMode)
5153                                         throw new InvalidOperationException ();
5154 #endif
5155
5156                                 if (list.Contains (item))
5157                                         throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
5158
5159                                 if (item.ListView != null && item.ListView != owner)
5160                                         throw new ArgumentException ("Cannot add or insert the item '" + item.Text + "' in more than one place. You must first remove it from its current location or clone it.", "item");
5161
5162                                 if (is_main_collection)
5163                                         item.Owner = owner;
5164 #if NET_2_0
5165                                 else {
5166                                         if (item.Group != null)
5167                                                 item.Group.Items.Remove (item);
5168
5169                                         item.SetGroup (group);
5170                                 }
5171 #endif
5172
5173                                 list.Insert (index, item);
5174                                 CollectionChanged (true);
5175                                 return item;
5176                         }
5177
5178                         public ListViewItem Insert (int index, string text)
5179                         {
5180                                 return this.Insert (index, new ListViewItem (text));
5181                         }
5182
5183                         public ListViewItem Insert (int index, string text, int imageIndex)
5184                         {
5185                                 return this.Insert (index, new ListViewItem (text, imageIndex));
5186                         }
5187
5188 #if NET_2_0
5189                         public ListViewItem Insert (int index, string text, string imageKey)
5190                         {
5191                                 ListViewItem lvi = new ListViewItem (text, imageKey);
5192                                 return Insert (index, lvi);
5193                         }
5194
5195                         public virtual ListViewItem Insert (int index, string key, string text, int imageIndex)
5196                         {
5197                                 ListViewItem lvi = new ListViewItem (text, imageIndex);
5198                                 lvi.Name = key;
5199                                 return Insert (index, lvi);
5200                         }
5201
5202                         public virtual ListViewItem Insert (int index, string key, string text, string imageKey)
5203                         {
5204                                 ListViewItem lvi = new ListViewItem (text, imageKey);
5205                                 lvi.Name = key;
5206                                 return Insert (index, lvi);
5207                         }
5208 #endif
5209
5210                         public virtual void Remove (ListViewItem item)
5211                         {
5212 #if NET_2_0
5213                                 if (owner != null && owner.VirtualMode)
5214                                         throw new InvalidOperationException ();
5215 #endif
5216
5217                                 int idx = list.IndexOf (item);
5218                                 if (idx != -1)
5219                                         RemoveAt (idx);
5220                         }
5221
5222                         public virtual void RemoveAt (int index)
5223                         {
5224                                 if (index < 0 || index >= Count)
5225                                         throw new ArgumentOutOfRangeException ("index");
5226
5227 #if NET_2_0
5228                                 if (owner != null && owner.VirtualMode)
5229                                         throw new InvalidOperationException ();
5230 #endif
5231
5232                                 ListViewItem item = (ListViewItem) list [index];
5233
5234                                 bool selection_changed = false;
5235                                 if (is_main_collection && owner != null) {
5236
5237                                         if (item.Focused && index + 1 == Count) // Last item
5238                                                 owner.SetFocusedItem (index == 0 ? -1 : index - 1);
5239
5240                                         selection_changed = owner.SelectedIndices.Contains (index);
5241                                         owner.item_control.CancelEdit (item);
5242                                 }
5243
5244                                 list.RemoveAt (index);
5245
5246                                 if (is_main_collection)
5247                                         item.Owner = null;
5248 #if NET_2_0
5249                                 else
5250                                         item.SetGroup (null);
5251 #endif
5252
5253                                 CollectionChanged (false);
5254                                 if (selection_changed && owner != null)
5255                                         owner.OnSelectedIndexChanged (EventArgs.Empty);
5256                         }
5257
5258 #if NET_2_0
5259                         public virtual void RemoveByKey (string key)
5260                         {
5261                                 int idx = IndexOfKey (key);
5262                                 if (idx != -1)
5263                                         RemoveAt (idx);
5264                         }
5265 #endif
5266
5267                         #endregion      // Public Methods
5268
5269                         internal ListView Owner {
5270                                 get {
5271                                         return owner;
5272                                 }
5273                                 set {
5274                                         owner = value;
5275                                 }
5276                         }
5277
5278 #if NET_2_0
5279                         internal ListViewGroup Group {
5280                                 get {
5281                                         return group;
5282                                 }
5283                                 set {
5284                                         group = value;
5285                                 }
5286                         }
5287 #endif
5288
5289                         void AddItem (ListViewItem value)
5290                         {
5291                                 if (list.Contains (value))
5292                                         throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
5293
5294                                 if (value.ListView != null && value.ListView != owner)
5295                                         throw new ArgumentException ("Cannot add or insert the item '" + value.Text + "' in more than one place. You must first remove it from its current location or clone it.", "value");
5296                                 if (is_main_collection)
5297                                         value.Owner = owner;
5298 #if NET_2_0
5299                                 else {
5300                                         if (value.Group != null)
5301                                                 value.Group.Items.Remove (value);
5302
5303                                         value.SetGroup (group);
5304                                 }
5305 #endif
5306
5307                                 list.Add (value);
5308                         }
5309
5310                         void CollectionChanged (bool sort)
5311                         {
5312                                 if (owner != null) {
5313                                         if (sort)
5314                                                 owner.Sort (false);
5315
5316                                         OnChange ();
5317                                         owner.Redraw (true);
5318                                 }
5319                         }
5320
5321 #if NET_2_0
5322                         ListViewItem RetrieveVirtualItemFromOwner (int displayIndex)
5323                         {
5324                                 RetrieveVirtualItemEventArgs args = new RetrieveVirtualItemEventArgs (displayIndex);
5325
5326                                 owner.OnRetrieveVirtualItem (args);
5327                                 ListViewItem retval = args.Item;
5328                                 retval.Owner = owner;
5329                                 retval.DisplayIndex = displayIndex;
5330
5331                                 return retval;
5332                         }
5333 #endif
5334
5335                         internal event CollectionChangedHandler Changed;
5336
5337                         internal void Sort (IComparer comparer)
5338                         {
5339                                 list.Sort (comparer);
5340                                 OnChange ();
5341                         }
5342
5343                         internal void OnChange ()
5344                         {
5345                                 if (Changed != null)
5346                                         Changed ();
5347                         }
5348                 }       // ListViewItemCollection
5349
5350                         
5351                 // In normal mode, the selection information resides in the Items,
5352                 // making SelectedIndexCollection.List read-only
5353                 //
5354                 // In virtual mode, SelectedIndexCollection directly saves the selection
5355                 // information, instead of getting it from Items, making List read-and-write
5356 #if NET_2_0
5357                 [ListBindable (false)]
5358 #endif
5359                 public class SelectedIndexCollection : IList, ICollection, IEnumerable
5360                 {
5361                         private readonly ListView owner;
5362                         private ArrayList list;
5363
5364                         #region Public Constructor
5365                         public SelectedIndexCollection (ListView owner)
5366                         {
5367                                 this.owner = owner;
5368                                 owner.Items.Changed += new CollectionChangedHandler (ItemsCollection_Changed);
5369                         }
5370                         #endregion      // Public Constructor
5371
5372                         #region Public Properties
5373                         [Browsable (false)]
5374                         public int Count {
5375                                 get {
5376                                         if (!owner.IsHandleCreated)
5377                                                 return 0;
5378
5379                                         return List.Count;
5380                                 }
5381                         }
5382
5383                         public bool IsReadOnly {
5384                                 get { 
5385 #if NET_2_0
5386                                         return false;
5387 #else
5388                                         return true; 
5389 #endif
5390                                 }
5391                         }
5392
5393                         public int this [int index] {
5394                                 get {
5395                                         if (!owner.IsHandleCreated || index < 0 || index >= List.Count)
5396                                                 throw new ArgumentOutOfRangeException ("index");
5397
5398                                         return (int) List [index];
5399                                 }
5400                         }
5401
5402                         bool ICollection.IsSynchronized {
5403                                 get { return false; }
5404                         }
5405
5406                         object ICollection.SyncRoot {
5407                                 get { return this; }
5408                         }
5409
5410                         bool IList.IsFixedSize {
5411                                 get { 
5412 #if NET_2_0
5413                                         return false;
5414 #else
5415                                         return true;
5416 #endif
5417                                 }
5418                         }
5419
5420                         object IList.this [int index] {
5421                                 get { return this [index]; }
5422                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
5423                         }
5424                         #endregion      // Public Properties
5425
5426                         #region Public Methods
5427 #if NET_2_0
5428                         public int Add (int itemIndex)
5429                         {
5430                                 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
5431                                         throw new ArgumentOutOfRangeException ("index");
5432
5433                                 if (owner.virtual_mode && !owner.IsHandleCreated)
5434                                         return -1;
5435
5436                                 owner.Items [itemIndex].Selected = true;
5437
5438                                 if (!owner.IsHandleCreated)
5439                                         return 0;
5440
5441                                 return List.Count;
5442                         }
5443 #endif
5444
5445 #if NET_2_0
5446                         public 
5447 #else
5448                         internal
5449 #endif  
5450                         void Clear ()
5451                         {
5452                                 if (!owner.IsHandleCreated)
5453                                         return;
5454
5455                                 int [] indexes = (int []) List.ToArray (typeof (int));
5456                                 foreach (int index in indexes)
5457                                         owner.Items [index].Selected = false;
5458                         }
5459
5460                         public bool Contains (int selectedIndex)
5461                         {
5462                                 return IndexOf (selectedIndex) != -1;
5463                         }
5464
5465                         public void CopyTo (Array dest, int index)
5466                         {
5467                                 List.CopyTo (dest, index);
5468                         }
5469
5470                         public IEnumerator GetEnumerator ()
5471                         {
5472                                 return List.GetEnumerator ();
5473                         }
5474
5475                         int IList.Add (object value)
5476                         {
5477                                 throw new NotSupportedException ("Add operation is not supported.");
5478                         }
5479
5480                         void IList.Clear ()
5481                         {
5482                                 Clear ();
5483                         }
5484
5485                         bool IList.Contains (object selectedIndex)
5486                         {
5487                                 if (!(selectedIndex is int))
5488                                         return false;
5489                                 return Contains ((int) selectedIndex);
5490                         }
5491
5492                         int IList.IndexOf (object selectedIndex)
5493                         {
5494                                 if (!(selectedIndex is int))
5495                                         return -1;
5496                                 return IndexOf ((int) selectedIndex);
5497                         }
5498
5499                         void IList.Insert (int index, object value)
5500                         {
5501                                 throw new NotSupportedException ("Insert operation is not supported.");
5502                         }
5503
5504                         void IList.Remove (object value)
5505                         {
5506                                 throw new NotSupportedException ("Remove operation is not supported.");
5507                         }
5508
5509                         void IList.RemoveAt (int index)
5510                         {
5511                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
5512                         }
5513
5514                         public int IndexOf (int selectedIndex)
5515                         {
5516                                 if (!owner.IsHandleCreated)
5517                                         return -1;
5518
5519                                 return List.IndexOf (selectedIndex);
5520                         }
5521
5522 #if NET_2_0
5523                         public void Remove (int itemIndex)
5524                         {
5525                                 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
5526                                         throw new ArgumentOutOfRangeException ("itemIndex");
5527
5528                                 owner.Items [itemIndex].Selected = false;
5529                         }
5530 #endif
5531                         #endregion      // Public Methods
5532
5533                         internal ArrayList List {
5534                                 get {
5535                                         if (list == null) {
5536                                                 list = new ArrayList ();
5537 #if NET_2_0
5538                                                 if (!owner.VirtualMode)
5539 #endif
5540                                                 for (int i = 0; i < owner.Items.Count; i++) {
5541                                                         if (owner.Items [i].Selected)
5542                                                                 list.Add (i);
5543                                                 }
5544                                         }
5545                                         return list;
5546                                 }
5547                         }
5548
5549                         internal void Reset ()
5550                         {
5551                                 // force re-population of list
5552                                 list = null;
5553                         }
5554
5555                         private void ItemsCollection_Changed ()
5556                         {
5557                                 Reset ();
5558                         }
5559
5560 #if NET_2_0
5561                         internal void RemoveIndex (int index)
5562                         {
5563                                 int idx = List.BinarySearch (index);
5564                                 if (idx != -1)
5565                                         List.RemoveAt (idx);
5566                         }
5567
5568                         // actually store index in the collection
5569                         // also, keep the collection sorted, as .Net does
5570                         internal void InsertIndex (int index)
5571                         {
5572                                 int iMin = 0;
5573                                 int iMax = List.Count - 1;
5574                                 while (iMin <= iMax) {
5575                                         int iMid = (iMin + iMax) / 2;
5576                                         int current_index = (int) List [iMid];
5577
5578                                         if (current_index == index)
5579                                                 return; // Already added
5580                                         if (current_index > index)
5581                                                 iMax = iMid - 1;
5582                                         else
5583                                                 iMin = iMid + 1;
5584                                 }
5585
5586                                 List.Insert (iMin, index);
5587                         }
5588 #endif
5589
5590                 }       // SelectedIndexCollection
5591
5592 #if NET_2_0
5593                 [ListBindable (false)]
5594 #endif
5595                 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
5596                 {
5597                         private readonly ListView owner;
5598
5599                         #region Public Constructor
5600                         public SelectedListViewItemCollection (ListView owner)
5601                         {
5602                                 this.owner = owner;
5603                         }
5604                         #endregion      // Public Constructor
5605
5606                         #region Public Properties
5607                         [Browsable (false)]
5608                         public int Count {
5609                                 get {
5610                                         return owner.SelectedIndices.Count;
5611                                 }
5612                         }
5613
5614                         public bool IsReadOnly {
5615                                 get { return true; }
5616                         }
5617
5618                         public ListViewItem this [int index] {
5619                                 get {
5620                                         if (!owner.IsHandleCreated || index < 0 || index >= Count)
5621                                                 throw new ArgumentOutOfRangeException ("index");
5622
5623                                         int item_index = owner.SelectedIndices [index];
5624                                         return owner.Items [item_index];
5625                                 }
5626                         }
5627
5628 #if NET_2_0
5629                         public virtual ListViewItem this [string key] {
5630                                 get {
5631                                         int idx = IndexOfKey (key);
5632                                         if (idx == -1)
5633                                                 return null;
5634
5635                                         return this [idx];
5636                                 }
5637                         }
5638 #endif
5639
5640                         bool ICollection.IsSynchronized {
5641                                 get { return false; }
5642                         }
5643
5644                         object ICollection.SyncRoot {
5645                                 get { return this; }
5646                         }
5647
5648                         bool IList.IsFixedSize {
5649                                 get { return true; }
5650                         }
5651
5652                         object IList.this [int index] {
5653                                 get { return this [index]; }
5654                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
5655                         }
5656                         #endregion      // Public Properties
5657
5658                         #region Public Methods
5659                         public void Clear ()
5660                         {
5661                                 owner.SelectedIndices.Clear ();
5662                         }
5663
5664                         public bool Contains (ListViewItem item)
5665                         {
5666                                 return IndexOf (item) != -1;
5667                         }
5668
5669 #if NET_2_0
5670                         public virtual bool ContainsKey (string key)
5671                         {
5672                                 return IndexOfKey (key) != -1;
5673                         }
5674 #endif
5675
5676                         public void CopyTo (Array dest, int index)
5677                         {
5678                                 if (!owner.IsHandleCreated)
5679                                         return;
5680                                 if (index > Count) // Throws ArgumentException instead of IOOR exception
5681                                         throw new ArgumentException ("index");
5682
5683                                 for (int i = 0; i < Count; i++)
5684                                         dest.SetValue (this [i], index++);
5685                         }
5686
5687                         public IEnumerator GetEnumerator ()
5688                         {
5689                                 if (!owner.IsHandleCreated)
5690                                         return (new ListViewItem [0]).GetEnumerator ();
5691
5692                                 ListViewItem [] items = new ListViewItem [Count];
5693                                 for (int i = 0; i < Count; i++)
5694                                         items [i] = this [i];
5695
5696                                 return items.GetEnumerator ();
5697                         }
5698
5699                         int IList.Add (object value)
5700                         {
5701                                 throw new NotSupportedException ("Add operation is not supported.");
5702                         }
5703
5704                         bool IList.Contains (object item)
5705                         {
5706                                 if (!(item is ListViewItem))
5707                                         return false;
5708                                 return Contains ((ListViewItem) item);
5709                         }
5710
5711                         int IList.IndexOf (object item)
5712                         {
5713                                 if (!(item is ListViewItem))
5714                                         return -1;
5715                                 return IndexOf ((ListViewItem) item);
5716                         }
5717
5718                         void IList.Insert (int index, object value)
5719                         {
5720                                 throw new NotSupportedException ("Insert operation is not supported.");
5721                         }
5722
5723                         void IList.Remove (object value)
5724                         {
5725                                 throw new NotSupportedException ("Remove operation is not supported.");
5726                         }
5727
5728                         void IList.RemoveAt (int index)
5729                         {
5730                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
5731                         }
5732
5733                         public int IndexOf (ListViewItem item)
5734                         {
5735                                 if (!owner.IsHandleCreated)
5736                                         return -1;
5737
5738                                 for (int i = 0; i < Count; i++)
5739                                         if (this [i] == item)
5740                                                 return i;
5741
5742                                 return -1;
5743                         }
5744
5745 #if NET_2_0
5746                         public virtual int IndexOfKey (string key)
5747                         {
5748                                 if (!owner.IsHandleCreated || key == null || key.Length == 0)
5749                                         return -1;
5750
5751                                 for (int i = 0; i < Count; i++) {
5752                                         ListViewItem item = this [i];
5753                                         if (String.Compare (item.Name, key, true) == 0)
5754                                                 return i;
5755                                 }
5756
5757                                 return -1;
5758                         }
5759 #endif
5760                         #endregion      // Public Methods
5761
5762                 }       // SelectedListViewItemCollection
5763
5764                 internal delegate void CollectionChangedHandler ();
5765
5766                 struct ItemMatrixLocation
5767                 {
5768                         int row;
5769                         int col;
5770
5771                         public ItemMatrixLocation (int row, int col)
5772                         {
5773                                 this.row = row;
5774                                 this.col = col;
5775                 
5776                         }
5777                 
5778                         public int Col {
5779                                 get {
5780                                         return col;
5781                                 }
5782                                 set {
5783                                         col = value;
5784                                 }
5785                         }
5786
5787                         public int Row {
5788                                 get {
5789                                         return row;
5790                                 }
5791                                 set {
5792                                         row = value;
5793                                 }
5794                         }
5795         
5796                 }
5797
5798                 #endregion // Subclasses
5799 #if NET_2_0
5800                 protected override void OnResize (EventArgs e)
5801                 {
5802                         base.OnResize (e);
5803                 }
5804
5805                 protected override void OnMouseLeave (EventArgs e)
5806                 {
5807                         base.OnMouseLeave (e);
5808                 }
5809
5810                 //
5811                 // ColumnReorder event
5812                 //
5813                 static object ColumnReorderedEvent = new object ();
5814                 public event ColumnReorderedEventHandler ColumnReordered {
5815                         add { Events.AddHandler (ColumnReorderedEvent, value); }
5816                         remove { Events.RemoveHandler (ColumnReorderedEvent, value); }
5817                 }
5818
5819                 protected virtual void OnColumnReordered (ColumnReorderedEventArgs e)
5820                 {
5821                         ColumnReorderedEventHandler creh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
5822
5823                         if (creh != null)
5824                                 creh (this, e);
5825                 }
5826
5827                 //
5828                 // ColumnWidthChanged
5829                 //
5830                 static object ColumnWidthChangedEvent = new object ();
5831                 public event ColumnWidthChangedEventHandler ColumnWidthChanged {
5832                         add { Events.AddHandler (ColumnWidthChangedEvent, value); }
5833                         remove { Events.RemoveHandler (ColumnWidthChangedEvent, value); }
5834                 }
5835
5836                 protected virtual void OnColumnWidthChanged (ColumnWidthChangedEventArgs e)
5837                 {
5838                         ColumnWidthChangedEventHandler eh = (ColumnWidthChangedEventHandler) (Events[ColumnWidthChangedEvent]);
5839                         if (eh != null)
5840                                 eh (this, e);
5841                 }
5842                 
5843                 void RaiseColumnWidthChanged (int resize_column)
5844                 {
5845                         ColumnWidthChangedEventArgs n = new ColumnWidthChangedEventArgs (resize_column);
5846
5847                         OnColumnWidthChanged (n);
5848                 }
5849                 
5850                 //
5851                 // ColumnWidthChanging
5852                 //
5853                 static object ColumnWidthChangingEvent = new object ();
5854                 public event ColumnWidthChangingEventHandler ColumnWidthChanging {
5855                         add { Events.AddHandler (ColumnWidthChangingEvent, value); }
5856                         remove { Events.RemoveHandler (ColumnWidthChangingEvent, value); }
5857                 }
5858
5859                 protected virtual void OnColumnWidthChanging (ColumnWidthChangingEventArgs e)
5860                 {
5861                         ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
5862                         if (cwceh != null)
5863                                 cwceh (this, e);
5864                 }
5865                 
5866                 //
5867                 // 2.0 profile based implementation
5868                 //
5869                 bool CanProceedWithResize (ColumnHeader col, int width)
5870                 {
5871                         ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
5872                         if (cwceh == null)
5873                                 return true;
5874                         
5875                         ColumnWidthChangingEventArgs changing = new ColumnWidthChangingEventArgs (col.Index, width);
5876                         cwceh (this, changing);
5877                         return !changing.Cancel;
5878                 }
5879 #else
5880                 //
5881                 // 1.0 profile based implementation
5882                 //
5883                 bool CanProceedWithResize (ColumnHeader col, int width)
5884                 {
5885                         return true;
5886                 }
5887
5888                 void RaiseColumnWidthChanged (int resize_column)
5889                 {
5890                 }
5891 #endif
5892         }
5893 }