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