8d2cce4ec602405c4f908336bc94a86a2a521c19
[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                         if (display_index == -1)
3321                                 OnUIAFocusedItemChanged ();
3322                                 // otherwise the event will have been fired
3323                                 // when the ListViewItem's Focused was set
3324 #endif
3325                 }
3326
3327                 private void HorizontalScroller (object sender, EventArgs e)
3328                 {
3329                         item_control.EndEdit (item_control.edit_item);
3330                         
3331                         // Avoid unnecessary flickering, when button is
3332                         // kept pressed at the end
3333                         if (h_marker != h_scroll.Value) {
3334                                 
3335                                 int pixels = h_marker - h_scroll.Value;
3336                                 
3337                                 h_marker = h_scroll.Value;
3338                                 if (header_control.Visible)
3339                                         XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
3340
3341                                 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
3342                         }
3343                 }
3344
3345                 private void VerticalScroller (object sender, EventArgs e)
3346                 {
3347                         item_control.EndEdit (item_control.edit_item);
3348                         
3349                         // Avoid unnecessary flickering, when button is
3350                         // kept pressed at the end
3351                         if (v_marker != v_scroll.Value) {
3352                                 int pixels = v_marker - v_scroll.Value;
3353                                 Rectangle area = item_control.ClientRectangle;
3354                                 if (header_control.Visible) {
3355                                         area.Y += header_control.Height;
3356                                         area.Height -= header_control.Height;
3357                                 }
3358
3359                                 v_marker = v_scroll.Value;
3360                                 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
3361                         }
3362                 }
3363
3364                 internal override bool IsInputCharInternal (char charCode)
3365                 {
3366                         return true;
3367                 }
3368                 #endregion      // Internal Methods Properties
3369
3370                 #region Protected Methods
3371                 protected override void CreateHandle ()
3372                 {
3373                         base.CreateHandle ();
3374                         for (int i = 0; i < SelectedItems.Count; i++)
3375                                 OnSelectedIndexChanged (EventArgs.Empty);
3376                 }
3377
3378                 protected override void Dispose (bool disposing)
3379                 {
3380                         if (disposing) {
3381                                 h_scroll.Dispose ();
3382                                 v_scroll.Dispose ();
3383                                 
3384                                 large_image_list = null;
3385                                 small_image_list = null;
3386                                 state_image_list = null;
3387
3388                                 foreach (ColumnHeader col in columns)
3389                                         col.SetListView (null);
3390
3391 #if NET_2_0
3392                                 if (!virtual_mode) // In virtual mode we don't save the items
3393 #endif
3394                                         foreach (ListViewItem item in items)
3395                                                 item.Owner = null;
3396                         }
3397                         
3398                         base.Dispose (disposing);
3399                 }
3400
3401                 protected override bool IsInputKey (Keys keyData)
3402                 {
3403                         switch (keyData) {
3404                         case Keys.Up:
3405                         case Keys.Down:
3406                         case Keys.PageUp:
3407                         case Keys.PageDown:
3408                         case Keys.Right:
3409                         case Keys.Left:
3410                         case Keys.End:
3411                         case Keys.Home:
3412                                 return true;
3413
3414                         default:
3415                                 break;
3416                         }
3417                         
3418                         return base.IsInputKey (keyData);
3419                 }
3420
3421                 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
3422                 {
3423                         LabelEditEventHandler eh = (LabelEditEventHandler)(Events [AfterLabelEditEvent]);
3424                         if (eh != null)
3425                                 eh (this, e);
3426                 }
3427
3428 #if NET_2_0
3429                 protected override void OnBackgroundImageChanged (EventArgs e)
3430                 {
3431                         item_control.BackgroundImage = BackgroundImage;
3432                         base.OnBackgroundImageChanged (e);
3433                 }
3434 #endif
3435
3436                 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
3437                 {
3438                         LabelEditEventHandler eh = (LabelEditEventHandler)(Events [BeforeLabelEditEvent]);
3439                         if (eh != null)
3440                                 eh (this, e);
3441                 }
3442
3443                 protected virtual void OnColumnClick (ColumnClickEventArgs e)
3444                 {
3445                         ColumnClickEventHandler eh = (ColumnClickEventHandler)(Events [ColumnClickEvent]);
3446                         if (eh != null)
3447                                 eh (this, e);
3448                 }
3449
3450 #if NET_2_0
3451                 protected internal virtual void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
3452                 {
3453                         DrawListViewColumnHeaderEventHandler eh = (DrawListViewColumnHeaderEventHandler)(Events[DrawColumnHeaderEvent]);
3454                         if (eh != null)
3455                                 eh(this, e);
3456                 }
3457
3458                 protected internal virtual void OnDrawItem(DrawListViewItemEventArgs e)
3459                 {
3460                         DrawListViewItemEventHandler eh = (DrawListViewItemEventHandler)(Events[DrawItemEvent]);
3461                         if (eh != null)
3462                                 eh(this, e);
3463                 }
3464
3465                 protected internal virtual void OnDrawSubItem(DrawListViewSubItemEventArgs e)
3466                 {
3467                         DrawListViewSubItemEventHandler eh = (DrawListViewSubItemEventHandler)(Events[DrawSubItemEvent]);
3468                         if (eh != null)
3469                                 eh(this, e);
3470                 }
3471
3472 #else
3473                 protected override void OnEnabledChanged (EventArgs e)
3474                 {
3475                         base.OnEnabledChanged (e);
3476                 }
3477 #endif
3478
3479                 protected override void OnFontChanged (EventArgs e)
3480                 {
3481                         base.OnFontChanged (e);
3482                         Redraw (true);
3483                 }
3484
3485                 protected override void OnHandleCreated (EventArgs e)
3486                 {
3487                         base.OnHandleCreated (e);
3488                         CalculateListView (alignment);
3489 #if NET_2_0
3490                         if (!virtual_mode) // Sorting is not allowed in virtual mode
3491 #endif
3492                                 Sort ();
3493                 }
3494
3495                 protected override void OnHandleDestroyed (EventArgs e)
3496                 {
3497                         base.OnHandleDestroyed (e);
3498                 }
3499
3500                 protected virtual void OnItemActivate (EventArgs e)
3501                 {
3502                         EventHandler eh = (EventHandler)(Events [ItemActivateEvent]);
3503                         if (eh != null)
3504                                 eh (this, e);
3505                 }
3506
3507                 protected internal virtual void OnItemCheck (ItemCheckEventArgs ice)
3508                 {
3509                         ItemCheckEventHandler eh = (ItemCheckEventHandler)(Events [ItemCheckEvent]);
3510                         if (eh != null)
3511                                 eh (this, ice);
3512                 }
3513
3514 #if NET_2_0
3515                 protected internal virtual void OnItemChecked (ItemCheckedEventArgs e)
3516                 {
3517                         ItemCheckedEventHandler eh = (ItemCheckedEventHandler)(Events [ItemCheckedEvent]);
3518                         if (eh != null)
3519                                 eh (this, e);
3520                 }
3521 #endif
3522
3523                 protected virtual void OnItemDrag (ItemDragEventArgs e)
3524                 {
3525                         ItemDragEventHandler eh = (ItemDragEventHandler)(Events [ItemDragEvent]);
3526                         if (eh != null)
3527                                 eh (this, e);
3528                 }
3529
3530 #if NET_2_0
3531                 protected virtual void OnItemMouseHover (ListViewItemMouseHoverEventArgs e)
3532                 {
3533                         ListViewItemMouseHoverEventHandler eh = (ListViewItemMouseHoverEventHandler)(Events [ItemMouseHoverEvent]);
3534                         if (eh != null)
3535                                 eh (this, e);
3536                 }
3537
3538                 protected internal virtual void OnItemSelectionChanged (ListViewItemSelectionChangedEventArgs e)
3539                 {
3540                         ListViewItemSelectionChangedEventHandler eh = 
3541                                 (ListViewItemSelectionChangedEventHandler) Events [ItemSelectionChangedEvent];
3542                         if (eh != null)
3543                                 eh (this, e);
3544                 }
3545
3546                 protected override void OnMouseHover (EventArgs e)
3547                 {
3548                         base.OnMouseHover (e);
3549                 }
3550
3551                 protected override void OnParentChanged (EventArgs e)
3552                 {
3553                         base.OnParentChanged (e);
3554                 }
3555 #endif
3556
3557                 protected virtual void OnSelectedIndexChanged (EventArgs e)
3558                 {
3559                         EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
3560                         if (eh != null)
3561                                 eh (this, e);
3562                 }
3563
3564                 protected override void OnSystemColorsChanged (EventArgs e)
3565                 {
3566                         base.OnSystemColorsChanged (e);
3567                 }
3568
3569 #if NET_2_0
3570                 protected internal virtual void OnCacheVirtualItems (CacheVirtualItemsEventArgs e)
3571                 {
3572                         CacheVirtualItemsEventHandler eh = (CacheVirtualItemsEventHandler)Events [CacheVirtualItemsEvent];
3573                         if (eh != null)
3574                                 eh (this, e);
3575                 }
3576
3577                 protected virtual void OnRetrieveVirtualItem (RetrieveVirtualItemEventArgs e)
3578                 {
3579                         RetrieveVirtualItemEventHandler eh = (RetrieveVirtualItemEventHandler)Events [RetrieveVirtualItemEvent];
3580                         if (eh != null)
3581                                 eh (this, e);
3582                 }
3583
3584                 [EditorBrowsable (EditorBrowsableState.Advanced)]
3585                 protected virtual void OnRightToLeftLayoutChanged (EventArgs e)
3586                 {
3587                         EventHandler eh = (EventHandler)Events[RightToLeftLayoutChangedEvent];
3588                         if (eh != null)
3589                                 eh (this, e);
3590                 }
3591
3592                 protected virtual void OnSearchForVirtualItem (SearchForVirtualItemEventArgs e)
3593                 {
3594                         SearchForVirtualItemEventHandler eh = (SearchForVirtualItemEventHandler) Events [SearchForVirtualItemEvent];
3595                         if (eh != null)
3596                                 eh (this, e);
3597                 }
3598                 
3599                 protected virtual void OnVirtualItemsSelectionRangeChanged (ListViewVirtualItemsSelectionRangeChangedEventArgs e)
3600                 {
3601                         ListViewVirtualItemsSelectionRangeChangedEventHandler eh = 
3602                                 (ListViewVirtualItemsSelectionRangeChangedEventHandler) Events [VirtualItemsSelectionRangeChangedEvent];
3603                         if (eh != null)
3604                                 eh (this, e);
3605                 }
3606 #endif
3607
3608                 protected void RealizeProperties ()
3609                 {
3610                         // FIXME: TODO
3611                 }
3612
3613                 protected void UpdateExtendedStyles ()
3614                 {
3615                         // FIXME: TODO
3616                 }
3617
3618                 bool refocusing = false;
3619
3620                 protected override void WndProc (ref Message m)
3621                 {
3622                         switch ((Msg)m.Msg) {
3623                         case Msg.WM_KILLFOCUS:
3624                                 Control receiver = Control.FromHandle (m.WParam);
3625                                 if (receiver == item_control) {
3626                                         has_focus = false;
3627                                         refocusing = true;
3628                                         return;
3629                                 }
3630                                 break;
3631                         case Msg.WM_SETFOCUS:
3632                                 if (refocusing) {
3633                                         has_focus = true;
3634                                         refocusing = false;
3635                                         return;
3636                                 }
3637                                 break;
3638                         default:
3639                                 break;
3640                         }
3641                         base.WndProc (ref m);
3642                 }
3643                 #endregion // Protected Methods
3644
3645                 #region Public Instance Methods
3646                 public void ArrangeIcons ()
3647                 {
3648                         ArrangeIcons (this.alignment);
3649                 }
3650
3651                 public void ArrangeIcons (ListViewAlignment value)
3652                 {
3653                         // Icons are arranged only if view is set to LargeIcon or SmallIcon
3654                         if (view == View.LargeIcon || view == View.SmallIcon)
3655                                 Redraw (true);
3656                 }
3657
3658 #if NET_2_0
3659                 public void AutoResizeColumn (int columnIndex, ColumnHeaderAutoResizeStyle headerAutoResize)
3660                 {
3661                         if (columnIndex < 0 || columnIndex >= columns.Count)
3662                                 throw new ArgumentOutOfRangeException ("columnIndex");
3663
3664                         columns [columnIndex].AutoResize (headerAutoResize);
3665                 }
3666
3667                 public void AutoResizeColumns (ColumnHeaderAutoResizeStyle headerAutoResize)
3668                 {
3669                         BeginUpdate ();
3670                         foreach (ColumnHeader col in columns) 
3671                                 col.AutoResize (headerAutoResize);
3672                         EndUpdate ();
3673                 }
3674 #endif
3675
3676                 public void BeginUpdate ()
3677                 {
3678                         // flag to avoid painting
3679                         updating = true;
3680                 }
3681
3682                 public void Clear ()
3683                 {
3684                         columns.Clear ();
3685                         items.Clear (); // Redraw (true) called here
3686                 }
3687
3688                 public void EndUpdate ()
3689                 {
3690                         // flag to avoid painting
3691                         updating = false;
3692
3693                         // probably, now we need a redraw with recalculations
3694                         this.Redraw (true);
3695                 }
3696
3697                 public void EnsureVisible (int index)
3698                 {
3699                         if (index < 0 || index >= items.Count || scrollable == false || updating)
3700                                 return;
3701
3702                         Rectangle view_rect = item_control.ClientRectangle;
3703                         Rectangle bounds = new Rectangle (GetItemLocation (index), ItemSize);
3704
3705                         if (view_rect.Contains (bounds))
3706                                 return;
3707
3708                         if (View != View.Details) {
3709                                 if (bounds.Left < 0)
3710                                         h_scroll.Value += bounds.Left;
3711                                 else if (bounds.Right > view_rect.Right)
3712                                         h_scroll.Value += (bounds.Right - view_rect.Right);
3713                         }
3714
3715                         if (bounds.Top < 0)
3716                                 v_scroll.Value += bounds.Top;
3717                         else if (bounds.Bottom > view_rect.Bottom)
3718                                 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
3719                 }
3720
3721 #if NET_2_0
3722                 public ListViewItem FindItemWithText (string text)
3723                 {
3724                         if (items.Count == 0)
3725                                 return null;
3726
3727                         return FindItemWithText (text, true, 0, true);
3728                 }
3729
3730                 public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex)
3731                 {
3732                         return FindItemWithText (text, includeSubItemsInSearch, startIndex, true, false);
3733                 }
3734
3735                 public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch)
3736                 {
3737                         return FindItemWithText (text, includeSubItemsInSearch, startIndex, isPrefixSearch, false);
3738                 }
3739 #endif
3740                 
3741                 internal ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch, bool roundtrip)
3742                 {
3743                         if (startIndex < 0 || startIndex >= items.Count)
3744                                 throw new ArgumentOutOfRangeException ("startIndex");
3745
3746                         if (text == null)
3747                                 throw new ArgumentNullException ("text");
3748
3749 #if NET_2_0
3750                         if (virtual_mode) {
3751                                 SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (true,
3752                                                 isPrefixSearch, includeSubItemsInSearch, text, Point.Empty, 
3753                                                 SearchDirectionHint.Down, startIndex);
3754
3755                                 OnSearchForVirtualItem (args);
3756                                 int idx = args.Index;
3757                                 if (idx >= 0 && idx < virtual_list_size)
3758                                         return items [idx];
3759
3760                                 return null;
3761                         }
3762 #endif
3763
3764                         int i = startIndex;
3765                         while (true) {
3766                                 ListViewItem lvi = items [i];
3767
3768                                 if (isPrefixSearch) { // prefix search
3769                                         if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (lvi.Text, text, CompareOptions.IgnoreCase))
3770                                                 return lvi;
3771                                 } else if (String.Compare (lvi.Text, text, true) == 0) // match
3772                                         return lvi;
3773
3774                                 if (i + 1 >= items.Count) {
3775                                         if (!roundtrip)
3776                                                 break;
3777
3778                                         i = 0;
3779                                 } else 
3780                                         i++;
3781
3782                                 if (i == startIndex)
3783                                         break;
3784                         }
3785
3786                         // Subitems have a minor priority, so we have to do a second linear search
3787                         // Also, we don't need to to a roundtrip search for them by now
3788                         if (includeSubItemsInSearch) {
3789                                 for (i = startIndex; i < items.Count; i++) {
3790                                         ListViewItem lvi = items [i];
3791                                         foreach (ListViewItem.ListViewSubItem sub_item in lvi.SubItems)
3792                                                 if (isPrefixSearch) {
3793                                                         if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (sub_item.Text, 
3794                                                                 text, CompareOptions.IgnoreCase))
3795                                                                 return lvi;
3796                                                 } else if (String.Compare (sub_item.Text, text, true) == 0)
3797                                                         return lvi;
3798                                 }
3799                         }
3800
3801                         return null;
3802                 }
3803
3804 #if NET_2_0
3805                 public ListViewItem FindNearestItem (SearchDirectionHint searchDirection, int x, int y)
3806                 {
3807                         return FindNearestItem (searchDirection, new Point (x, y));
3808                 }
3809
3810                 public ListViewItem FindNearestItem (SearchDirectionHint dir, Point point)
3811                 {
3812                         if (dir < SearchDirectionHint.Left || dir > SearchDirectionHint.Down)
3813                                 throw new ArgumentOutOfRangeException ("searchDirection");
3814
3815                         if (view != View.LargeIcon && view != View.SmallIcon)
3816                                 throw new InvalidOperationException ();
3817
3818                         if (virtual_mode) {
3819                                 SearchForVirtualItemEventArgs args = new SearchForVirtualItemEventArgs (false,
3820                                                 false, false, String.Empty, point, 
3821                                                 dir, 0);
3822
3823                                 OnSearchForVirtualItem (args);
3824                                 int idx = args.Index;
3825                                 if (idx >= 0 && idx < virtual_list_size)
3826                                         return items [idx];
3827
3828                                 return null;
3829                         }
3830
3831                         ListViewItem item = null;
3832                         int min_dist = Int32.MaxValue;
3833
3834                         //
3835                         // It looks like .Net does a previous adjustment
3836                         //
3837                         switch (dir) {
3838                                 case SearchDirectionHint.Up:
3839                                         point.Y -= item_size.Height;
3840                                         break;
3841                                 case SearchDirectionHint.Down:
3842                                         point.Y += item_size.Height;
3843                                         break;
3844                                 case SearchDirectionHint.Left:
3845                                         point.X -= item_size.Width;
3846                                         break;
3847                                 case SearchDirectionHint.Right:
3848                                         point.X += item_size.Width;
3849                                         break;
3850                         }
3851
3852                         for (int i = 0; i < items.Count; i++) {
3853                                 Point item_loc = GetItemLocation (i);
3854
3855                                 if (dir == SearchDirectionHint.Up) {
3856                                         if (point.Y < item_loc.Y)
3857                                                 continue;
3858                                 } else if (dir == SearchDirectionHint.Down) {
3859                                         if (point.Y > item_loc.Y)
3860                                                 continue;
3861                                 } else if (dir == SearchDirectionHint.Left) {
3862                                         if (point.X < item_loc.X)
3863                                                 continue;
3864                                 } else if (dir == SearchDirectionHint.Right) {
3865                                         if (point.X > item_loc.X)
3866                                                 continue;
3867                                 }
3868
3869                                 int x_dist = point.X - item_loc.X;
3870                                 int y_dist = point.Y - item_loc.Y;
3871
3872                                 int dist = x_dist * x_dist  + y_dist * y_dist;
3873                                 if (dist < min_dist) {
3874                                         item = items [i];
3875                                         min_dist = dist;
3876                                 }
3877                         }
3878
3879                         return item;
3880                 }
3881 #endif
3882                 
3883                 public ListViewItem GetItemAt (int x, int y)
3884                 {
3885                         Size item_size = ItemSize;
3886                         for (int i = 0; i < items.Count; i++) {
3887                                 Point item_location = GetItemLocation (i);
3888                                 Rectangle item_rect = new Rectangle (item_location, item_size);
3889                                 if (item_rect.Contains (x, y))
3890                                         return items [i];
3891                         }
3892
3893                         return null;
3894                 }
3895
3896                 public Rectangle GetItemRect (int index)
3897                 {
3898                         return GetItemRect (index, ItemBoundsPortion.Entire);
3899                 }
3900
3901                 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
3902                 {
3903                         if (index < 0 || index >= items.Count)
3904                                 throw new IndexOutOfRangeException ("index");
3905
3906                         return items [index].GetBounds (portion);
3907                 }
3908
3909 #if NET_2_0
3910                 public ListViewHitTestInfo HitTest (Point point)
3911                 {
3912                         return HitTest (point.X, point.Y);
3913                 }
3914
3915                 public ListViewHitTestInfo HitTest (int x, int y)
3916                 {
3917                         if (x < 0)
3918                                 throw new ArgumentOutOfRangeException ("x");
3919                         if (y < 0)
3920                                 throw new ArgumentOutOfRangeException ("y");
3921
3922                         ListViewItem item = GetItemAt (x, y);
3923                         if (item == null)
3924                                 return new ListViewHitTestInfo (null, null, ListViewHitTestLocations.None);
3925
3926                         ListViewHitTestLocations locations = 0;
3927                         if (item.GetBounds (ItemBoundsPortion.Label).Contains (x, y))
3928                                 locations |= ListViewHitTestLocations.Label;
3929                         else if (item.GetBounds (ItemBoundsPortion.Icon).Contains (x, y))
3930                                 locations |= ListViewHitTestLocations.Image;
3931                         else if (item.CheckRectReal.Contains (x, y))
3932                                 locations |= ListViewHitTestLocations.StateImage;
3933
3934                         ListViewItem.ListViewSubItem subitem = null;
3935                         if (view == View.Details)
3936                                 foreach (ListViewItem.ListViewSubItem si in item.SubItems)
3937                                         if (si.Bounds.Contains (x, y)) {
3938                                                 subitem = si;
3939                                                 break;
3940                                         }
3941
3942                         return new ListViewHitTestInfo (item, subitem, locations);
3943                 }
3944
3945                 [EditorBrowsable (EditorBrowsableState.Advanced)]
3946                 public void RedrawItems (int startIndex, int endIndex, bool invalidateOnly)
3947                 {
3948                         if (startIndex < 0 || startIndex >= items.Count)
3949                                 throw new ArgumentOutOfRangeException ("startIndex");
3950                         if (endIndex < 0 || endIndex >= items.Count)
3951                                 throw new ArgumentOutOfRangeException ("endIndex");
3952                         if (startIndex > endIndex)
3953                                 throw new ArgumentException ("startIndex");
3954
3955                         if (updating)
3956                                 return;
3957
3958                         for (int i = startIndex; i <= endIndex; i++)
3959                                 items [i].Invalidate ();
3960
3961                         if (!invalidateOnly)
3962                                 Update ();
3963                 }
3964 #endif
3965
3966                 public void Sort ()
3967                 {
3968 #if NET_2_0
3969                         if (virtual_mode)
3970                                 throw new InvalidOperationException ();
3971 #endif
3972
3973                         Sort (true);
3974                 }
3975
3976                 // we need this overload to reuse the logic for sorting, while allowing
3977                 // redrawing to be done by caller or have it done by this method when
3978                 // sorting is really performed
3979                 //
3980                 // ListViewItemCollection's Add and AddRange methods call this overload
3981                 // with redraw set to false, as they take care of redrawing themselves
3982                 // (they even want to redraw the listview if no sort is performed, as 
3983                 // an item was added), while ListView.Sort () only wants to redraw if 
3984                 // sorting was actually performed
3985                 private void Sort (bool redraw)
3986                 {
3987                         if (!IsHandleCreated || item_sorter == null) {
3988                                 return;
3989                         }
3990                         
3991                         items.Sort (item_sorter);
3992                         if (redraw)
3993                                 this.Redraw (true);
3994                 }
3995
3996                 public override string ToString ()
3997                 {
3998                         int count = this.Items.Count;
3999
4000                         if (count == 0)
4001                                 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
4002                         else
4003                                 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
4004                 }
4005                 #endregion      // Public Instance Methods
4006
4007
4008                 #region Subclasses
4009
4010                 internal class HeaderControl : Control {
4011
4012                         ListView owner;
4013                         bool column_resize_active = false;
4014                         ColumnHeader resize_column;
4015                         ColumnHeader clicked_column;
4016                         ColumnHeader drag_column;
4017                         int drag_x;
4018                         int drag_to_index = -1;
4019                         ColumnHeader entered_column_header;
4020
4021                         public HeaderControl (ListView owner)
4022                         {
4023                                 this.owner = owner;
4024                                 this.SetStyle (ControlStyles.DoubleBuffer, true);
4025                                 MouseDown += new MouseEventHandler (HeaderMouseDown);
4026                                 MouseMove += new MouseEventHandler (HeaderMouseMove);
4027                                 MouseUp += new MouseEventHandler (HeaderMouseUp);
4028                                 MouseLeave += new EventHandler (OnMouseLeave);
4029                         }
4030
4031                         internal ColumnHeader EnteredColumnHeader {
4032                                 get { return entered_column_header; }
4033                                 private set {
4034                                         if (entered_column_header == value)
4035                                                 return;
4036                                         if (ThemeEngine.Current.ListViewHasHotHeaderStyle) {
4037                                                 Region region_to_invalidate = new Region ();
4038                                                 region_to_invalidate.MakeEmpty ();
4039                                                 if (entered_column_header != null)
4040                                                         region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header));
4041                                                 entered_column_header = value;
4042                                                 if (entered_column_header != null)
4043                                                         region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header));
4044                                                 Invalidate (region_to_invalidate);
4045                                                 region_to_invalidate.Dispose ();
4046                                         } else
4047                                                 entered_column_header = value;
4048                                 }
4049                         }
4050
4051                         void OnMouseLeave (object sender, EventArgs e)
4052                         {
4053                                 EnteredColumnHeader = null;
4054                         }
4055
4056                         private ColumnHeader ColumnAtX (int x)
4057                         {
4058                                 Point pt = new Point (x, 0);
4059                                 ColumnHeader result = null;
4060                                 foreach (ColumnHeader col in owner.Columns) {
4061                                         if (col.Rect.Contains (pt)) {
4062                                                 result = col;
4063                                                 break;
4064                                         }
4065                                 }
4066                                 return result;
4067                         }
4068
4069                         private int GetReorderedIndex (ColumnHeader col)
4070                         {
4071                                 if (owner.reordered_column_indices == null)
4072                                         return col.Index;
4073                                 else
4074                                         for (int i = 0; i < owner.Columns.Count; i++)
4075                                                 if (owner.reordered_column_indices [i] == col.Index)
4076                                                         return i;
4077                                 throw new Exception ("Column index missing from reordered array");
4078                         }
4079
4080                         private void HeaderMouseDown (object sender, MouseEventArgs me)
4081                         {
4082                                 if (resize_column != null) {
4083                                         column_resize_active = true;
4084                                         Capture = true;
4085                                         return;
4086                                 }
4087
4088                                 clicked_column = ColumnAtX (me.X + owner.h_marker);
4089
4090                                 if (clicked_column != null) {
4091                                         Capture = true;
4092                                         if (owner.AllowColumnReorder) {
4093                                                 drag_x = me.X;
4094                                                 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
4095                                                 drag_column.Rect = clicked_column.Rect;
4096                                                 drag_to_index = GetReorderedIndex (clicked_column);
4097                                         }
4098                                         clicked_column.Pressed = true;
4099                                         Invalidate (clicked_column);
4100                                         return;
4101                                 }
4102                         }
4103
4104                         void Invalidate (ColumnHeader columnHeader)
4105                         {
4106                                 Invalidate (GetColumnHeaderInvalidateArea (columnHeader));
4107                         }
4108
4109                         Rectangle GetColumnHeaderInvalidateArea (ColumnHeader columnHeader)
4110                         {
4111                                 Rectangle bounds = columnHeader.Rect;
4112                                 bounds.X -= owner.h_marker;
4113                                 return bounds;
4114                         }
4115
4116                         void StopResize ()
4117                         {
4118                                 column_resize_active = false;
4119                                 resize_column = null;
4120                                 Capture = false;
4121                                 Cursor = Cursors.Default;
4122                         }
4123                         
4124                         private void HeaderMouseMove (object sender, MouseEventArgs me)
4125                         {
4126                                 Point pt = new Point (me.X + owner.h_marker, me.Y);
4127
4128                                 if (column_resize_active) {
4129                                         int width = pt.X - resize_column.X;
4130                                         if (width < 0)
4131                                                 width = 0;
4132
4133                                         if (!owner.CanProceedWithResize (resize_column, width)){
4134                                                 StopResize ();
4135                                                 return;
4136                                         }
4137                                         resize_column.Width = width;
4138                                         return;
4139                                 }
4140
4141                                 resize_column = null;
4142
4143                                 if (clicked_column != null) {
4144                                         if (owner.AllowColumnReorder) {
4145                                                 Rectangle r;
4146
4147                                                 r = drag_column.Rect;
4148                                                 r.X = clicked_column.Rect.X + me.X - drag_x;
4149                                                 drag_column.Rect = r;
4150
4151                                                 int x = me.X + owner.h_marker;
4152                                                 ColumnHeader over = ColumnAtX (x);
4153                                                 if (over == null)
4154                                                         drag_to_index = owner.Columns.Count;
4155                                                 else if (x < over.X + over.Width / 2)
4156                                                         drag_to_index = GetReorderedIndex (over);
4157                                                 else
4158                                                         drag_to_index = GetReorderedIndex (over) + 1;
4159                                                 Invalidate ();
4160                                         } else {
4161                                                 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
4162                                                 bool pressed = clicked_column.Pressed;
4163                                                 clicked_column.Pressed = over == clicked_column;
4164                                                 if (clicked_column.Pressed ^ pressed)
4165                                                         Invalidate (clicked_column);
4166                                         }
4167                                         return;
4168                                 }
4169
4170                                 for (int i = 0; i < owner.Columns.Count; i++) {
4171                                         Rectangle zone = owner.Columns [i].Rect;
4172                                         if (zone.Contains (pt))
4173                                                 EnteredColumnHeader = owner.Columns [i];
4174                                         zone.X = zone.Right - 5;
4175                                         zone.Width = 10;
4176                                         if (zone.Contains (pt)) {
4177                                                 if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
4178                                                         i++;
4179                                                 resize_column = owner.Columns [i];
4180                                                 break;
4181                                         }
4182                                 }
4183
4184                                 if (resize_column == null)
4185                                         Cursor = Cursors.Default;
4186                                 else
4187                                         Cursor = Cursors.VSplit;
4188                         }
4189
4190                         void HeaderMouseUp (object sender, MouseEventArgs me)
4191                         {
4192                                 Capture = false;
4193
4194                                 if (column_resize_active) {
4195                                         int column_idx = resize_column.Index;
4196                                         StopResize ();
4197                                         owner.RaiseColumnWidthChanged (column_idx);
4198                                         return;
4199                                 }
4200
4201                                 if (clicked_column != null && clicked_column.Pressed) {
4202                                         clicked_column.Pressed = false;
4203                                         Invalidate (clicked_column);
4204                                         owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
4205                                 }
4206
4207                                 if (drag_column != null && owner.AllowColumnReorder) {
4208                                         drag_column = null;
4209                                         if (drag_to_index > GetReorderedIndex (clicked_column))
4210                                                 drag_to_index--;
4211                                         if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
4212                                                 owner.ReorderColumn (clicked_column, drag_to_index, true);
4213                                         drag_to_index = -1;
4214                                         Invalidate ();
4215                                 }
4216
4217                                 clicked_column = null;
4218                         }
4219
4220                         internal override void OnPaintInternal (PaintEventArgs pe)
4221                         {
4222                                 if (owner.updating)
4223                                         return;
4224                                 
4225                                 Theme theme = ThemeEngine.Current;
4226                                 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
4227
4228                                 if (drag_column == null)
4229                                         return;
4230
4231                                 int target_x;
4232                                 if (drag_to_index == owner.Columns.Count)
4233                                         target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
4234                                 else
4235                                         target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
4236                                 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
4237                         }
4238
4239                         protected override void WndProc (ref Message m)
4240                         {
4241                                 switch ((Msg)m.Msg) {
4242                                 case Msg.WM_SETFOCUS:
4243                                         owner.Focus ();
4244                                         break;
4245                                 default:
4246                                         base.WndProc (ref m);
4247                                         break;
4248                                 }
4249                         }
4250                 }
4251
4252                 private class ItemComparer : IComparer {
4253                         readonly SortOrder sort_order;
4254
4255                         public ItemComparer (SortOrder sortOrder)
4256                         {
4257                                 sort_order = sortOrder;
4258                         }
4259
4260                         public int Compare (object x, object y)
4261                         {
4262                                 ListViewItem item_x = x as ListViewItem;
4263                                 ListViewItem item_y = y as ListViewItem;
4264                                 if (sort_order == SortOrder.Ascending)
4265                                         return String.Compare (item_x.Text, item_y.Text);
4266                                 else
4267                                         return String.Compare (item_y.Text, item_x.Text);
4268                         }
4269                 }
4270
4271 #if NET_2_0
4272                 [ListBindable (false)]
4273 #endif
4274                 public class CheckedIndexCollection : IList, ICollection, IEnumerable
4275                 {
4276                         private readonly ListView owner;
4277
4278                         #region Public Constructor
4279                         public CheckedIndexCollection (ListView owner)
4280                         {
4281                                 this.owner = owner;
4282                         }
4283                         #endregion      // Public Constructor
4284
4285                         #region Public Properties
4286                         [Browsable (false)]
4287                         public int Count {
4288                                 get { return owner.CheckedItems.Count; }
4289                         }
4290
4291                         public bool IsReadOnly {
4292                                 get { return true; }
4293                         }
4294
4295                         public int this [int index] {
4296                                 get {
4297                                         int [] indices = GetIndices ();
4298                                         if (index < 0 || index >= indices.Length)
4299                                                 throw new ArgumentOutOfRangeException ("index");
4300                                         return indices [index];
4301                                 }
4302                         }
4303
4304                         bool ICollection.IsSynchronized {
4305                                 get { return false; }
4306                         }
4307
4308                         object ICollection.SyncRoot {
4309                                 get { return this; }
4310                         }
4311
4312                         bool IList.IsFixedSize {
4313                                 get { return true; }
4314                         }
4315
4316                         object IList.this [int index] {
4317                                 get { return this [index]; }
4318                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4319                         }
4320                         #endregion      // Public Properties
4321
4322                         #region Public Methods
4323                         public bool Contains (int checkedIndex)
4324                         {
4325                                 int [] indices = GetIndices ();
4326                                 for (int i = 0; i < indices.Length; i++) {
4327                                         if (indices [i] == checkedIndex)
4328                                                 return true;
4329                                 }
4330                                 return false;
4331                         }
4332
4333                         public IEnumerator GetEnumerator ()
4334                         {
4335                                 int [] indices = GetIndices ();
4336                                 return indices.GetEnumerator ();
4337                         }
4338
4339                         void ICollection.CopyTo (Array dest, int index)
4340                         {
4341                                 int [] indices = GetIndices ();
4342                                 Array.Copy (indices, 0, dest, index, indices.Length);
4343                         }
4344
4345                         int IList.Add (object value)
4346                         {
4347                                 throw new NotSupportedException ("Add operation is not supported.");
4348                         }
4349
4350                         void IList.Clear ()
4351                         {
4352                                 throw new NotSupportedException ("Clear operation is not supported.");
4353                         }
4354
4355                         bool IList.Contains (object checkedIndex)
4356                         {
4357                                 if (!(checkedIndex is int))
4358                                         return false;
4359                                 return Contains ((int) checkedIndex);
4360                         }
4361
4362                         int IList.IndexOf (object checkedIndex)
4363                         {
4364                                 if (!(checkedIndex is int))
4365                                         return -1;
4366                                 return IndexOf ((int) checkedIndex);
4367                         }
4368
4369                         void IList.Insert (int index, object value)
4370                         {
4371                                 throw new NotSupportedException ("Insert operation is not supported.");
4372                         }
4373
4374                         void IList.Remove (object value)
4375                         {
4376                                 throw new NotSupportedException ("Remove operation is not supported.");
4377                         }
4378
4379                         void IList.RemoveAt (int index)
4380                         {
4381                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
4382                         }
4383
4384                         public int IndexOf (int checkedIndex)
4385                         {
4386                                 int [] indices = GetIndices ();
4387                                 for (int i = 0; i < indices.Length; i++) {
4388                                         if (indices [i] == checkedIndex)
4389                                                 return i;
4390                                 }
4391                                 return -1;
4392                         }
4393                         #endregion      // Public Methods
4394
4395                         private int [] GetIndices ()
4396                         {
4397                                 ArrayList checked_items = owner.CheckedItems.List;
4398                                 int [] indices = new int [checked_items.Count];
4399                                 for (int i = 0; i < checked_items.Count; i++) {
4400                                         ListViewItem item = (ListViewItem) checked_items [i];
4401                                         indices [i] = item.Index;
4402                                 }
4403                                 return indices;
4404                         }
4405                 }       // CheckedIndexCollection
4406
4407 #if NET_2_0
4408                 [ListBindable (false)]
4409 #endif
4410                 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
4411                 {
4412                         private readonly ListView owner;
4413                         private ArrayList list;
4414
4415                         #region Public Constructor
4416                         public CheckedListViewItemCollection (ListView owner)
4417                         {
4418                                 this.owner = owner;
4419                                 this.owner.Items.Changed += new CollectionChangedHandler (
4420                                         ItemsCollection_Changed);
4421                         }
4422                         #endregion      // Public Constructor
4423
4424                         #region Public Properties
4425                         [Browsable (false)]
4426                         public int Count {
4427                                 get {
4428                                         if (!owner.CheckBoxes)
4429                                                 return 0;
4430                                         return List.Count;
4431                                 }
4432                         }
4433
4434                         public bool IsReadOnly {
4435                                 get { return true; }
4436                         }
4437
4438                         public ListViewItem this [int index] {
4439                                 get {
4440 #if NET_2_0
4441                                         if (owner.VirtualMode)
4442                                                 throw new InvalidOperationException ();
4443 #endif
4444                                         ArrayList checked_items = List;
4445                                         if (index < 0 || index >= checked_items.Count)
4446                                                 throw new ArgumentOutOfRangeException ("index");
4447                                         return (ListViewItem) checked_items [index];
4448                                 }
4449                         }
4450
4451 #if NET_2_0
4452                         public virtual ListViewItem this [string key] {
4453                                 get {
4454                                         int idx = IndexOfKey (key);
4455                                         return idx == -1 ? null : (ListViewItem) List [idx];
4456                                 }
4457                         }
4458 #endif
4459
4460                         bool ICollection.IsSynchronized {
4461                                 get { return false; }
4462                         }
4463
4464                         object ICollection.SyncRoot {
4465                                 get { return this; }
4466                         }
4467
4468                         bool IList.IsFixedSize {
4469                                 get { return true; }
4470                         }
4471
4472                         object IList.this [int index] {
4473                                 get { return this [index]; }
4474                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4475                         }
4476                         #endregion      // Public Properties
4477
4478                         #region Public Methods
4479                         public bool Contains (ListViewItem item)
4480                         {
4481                                 if (!owner.CheckBoxes)
4482                                         return false;
4483                                 return List.Contains (item);
4484                         }
4485
4486 #if NET_2_0
4487                         public virtual bool ContainsKey (string key)
4488                         {
4489                                 return IndexOfKey (key) != -1;
4490                         }
4491 #endif
4492
4493                         public void CopyTo (Array dest, int index)
4494                         {
4495 #if NET_2_0
4496                                 if (owner.VirtualMode)
4497                                         throw new InvalidOperationException ();
4498 #endif
4499                                 if (!owner.CheckBoxes)
4500                                         return;
4501                                 List.CopyTo (dest, index);
4502                         }
4503
4504                         public IEnumerator GetEnumerator ()
4505                         {
4506 #if NET_2_0
4507                                 if (owner.VirtualMode)
4508                                         throw new InvalidOperationException ();
4509 #endif
4510                                 if (!owner.CheckBoxes)
4511                                         return (new ListViewItem [0]).GetEnumerator ();
4512                                 return List.GetEnumerator ();
4513                         }
4514
4515                         int IList.Add (object value)
4516                         {
4517                                 throw new NotSupportedException ("Add operation is not supported.");
4518                         }
4519
4520                         void IList.Clear ()
4521                         {
4522                                 throw new NotSupportedException ("Clear operation is not supported.");
4523                         }
4524
4525                         bool IList.Contains (object item)
4526                         {
4527                                 if (!(item is ListViewItem))
4528                                         return false;
4529                                 return Contains ((ListViewItem) item);
4530                         }
4531
4532                         int IList.IndexOf (object item)
4533                         {
4534                                 if (!(item is ListViewItem))
4535                                         return -1;
4536                                 return IndexOf ((ListViewItem) item);
4537                         }
4538
4539                         void IList.Insert (int index, object value)
4540                         {
4541                                 throw new NotSupportedException ("Insert operation is not supported.");
4542                         }
4543
4544                         void IList.Remove (object value)
4545                         {
4546                                 throw new NotSupportedException ("Remove operation is not supported.");
4547                         }
4548
4549                         void IList.RemoveAt (int index)
4550                         {
4551                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
4552                         }
4553
4554                         public int IndexOf (ListViewItem item)
4555                         {
4556 #if NET_2_0
4557                                 if (owner.VirtualMode)
4558                                         throw new InvalidOperationException ();
4559 #endif
4560                                 if (!owner.CheckBoxes)
4561                                         return -1;
4562                                 return List.IndexOf (item);
4563                         }
4564
4565 #if NET_2_0
4566                         public virtual int IndexOfKey (string key)
4567                         {
4568 #if NET_2_0
4569                                 if (owner.VirtualMode)
4570                                         throw new InvalidOperationException ();
4571 #endif
4572                                 if (key == null || key.Length == 0)
4573                                         return -1;
4574
4575                                 ArrayList checked_items = List;
4576                                 for (int i = 0; i < checked_items.Count; i++) {
4577                                         ListViewItem item = (ListViewItem) checked_items [i];
4578                                         if (String.Compare (key, item.Name, true) == 0)
4579                                                 return i;
4580                                 }
4581
4582                                 return -1;
4583                         }
4584 #endif
4585                         #endregion      // Public Methods
4586
4587                         internal ArrayList List {
4588                                 get {
4589                                         if (list == null) {
4590                                                 list = new ArrayList ();
4591                                                 foreach (ListViewItem item in owner.Items) {
4592                                                         if (item.Checked)
4593                                                                 list.Add (item);
4594                                                 }
4595                                         }
4596                                         return list;
4597                                 }
4598                         }
4599
4600                         internal void Reset ()
4601                         {
4602                                 // force re-population of list
4603                                 list = null;
4604                         }
4605
4606                         private void ItemsCollection_Changed ()
4607                         {
4608                                 Reset ();
4609                         }
4610                 }       // CheckedListViewItemCollection
4611
4612 #if NET_2_0
4613                 [ListBindable (false)]
4614 #endif
4615                 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
4616                 {
4617                         internal ArrayList list;
4618                         private ListView owner;
4619
4620                         #region UIA Framework Events 
4621 #if NET_2_0
4622                         //NOTE:
4623                         //      We are using Reflection to add/remove internal events.
4624                         //      Class ListViewProvider uses the events when View is Details.
4625                         //
4626                         //Event used to generate UIA StructureChangedEvent
4627                         static object UIACollectionChangedEvent = new object ();
4628
4629                         internal event CollectionChangeEventHandler UIACollectionChanged {
4630                                 add { 
4631                                         if (owner != null)
4632                                                 owner.Events.AddHandler (UIACollectionChangedEvent, value); 
4633                                 }
4634                                 remove { 
4635                                         if (owner != null)
4636                                                 owner.Events.RemoveHandler (UIACollectionChangedEvent, value); 
4637                                 }
4638                         }
4639
4640                         internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
4641                         {
4642                                 if (owner == null)
4643                                         return;
4644
4645                                 CollectionChangeEventHandler eh
4646                                         = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
4647                                 if (eh != null)
4648                                         eh (owner, args);
4649                         }
4650
4651 #endif
4652                         #endregion UIA Framework Events 
4653
4654                         #region Public Constructor
4655                         public ColumnHeaderCollection (ListView owner)
4656                         {
4657                                 list = new ArrayList ();
4658                                 this.owner = owner;
4659                         }
4660                         #endregion      // Public Constructor
4661
4662                         #region Public Properties
4663                         [Browsable (false)]
4664                         public int Count {
4665                                 get { return list.Count; }
4666                         }
4667
4668                         public bool IsReadOnly {
4669                                 get { return false; }
4670                         }
4671
4672                         public virtual ColumnHeader this [int index] {
4673                                 get {
4674                                         if (index < 0 || index >= list.Count)
4675                                                 throw new ArgumentOutOfRangeException ("index");
4676                                         return (ColumnHeader) list [index];
4677                                 }
4678                         }
4679
4680 #if NET_2_0
4681                         public virtual ColumnHeader this [string key] {
4682                                 get {
4683                                         int idx = IndexOfKey (key);
4684                                         if (idx == -1)
4685                                                 return null;
4686
4687                                         return (ColumnHeader) list [idx];
4688                                 }
4689                         }
4690 #endif
4691
4692                         bool ICollection.IsSynchronized {
4693                                 get { return true; }
4694                         }
4695
4696                         object ICollection.SyncRoot {
4697                                 get { return this; }
4698                         }
4699
4700                         bool IList.IsFixedSize {
4701                                 get { return list.IsFixedSize; }
4702                         }
4703
4704                         object IList.this [int index] {
4705                                 get { return this [index]; }
4706                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
4707                         }
4708                         #endregion      // Public Properties
4709
4710                         #region Public Methods
4711                         public virtual int Add (ColumnHeader value)
4712                         {
4713                                 int idx = list.Add (value);
4714                                 owner.AddColumn (value, idx, true);
4715
4716 #if NET_2_0
4717                                 //UIA Framework event: Item Added
4718                                 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
4719 #endif
4720
4721                                 return idx;
4722                         }
4723
4724 #if NET_2_0
4725                         public virtual ColumnHeader Add (string text, int width, HorizontalAlignment textAlign)
4726                         {
4727                                 string str = text;
4728 #else
4729                         public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
4730                         {
4731 #endif
4732                                 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
4733                                 this.Add (colHeader);
4734                                 return colHeader;
4735                         }
4736
4737 #if NET_2_0
4738                         public virtual ColumnHeader Add (string text)
4739                         {
4740                                 return Add (String.Empty, text);
4741                         }
4742
4743                         public virtual ColumnHeader Add (string text, int width)
4744                         {
4745                                 return Add (String.Empty, text, width);
4746                         }
4747
4748                         public virtual ColumnHeader Add (string key, string text)
4749                         {
4750                                 ColumnHeader colHeader = new ColumnHeader ();
4751                                 colHeader.Name = key;
4752                                 colHeader.Text = text;
4753                                 Add (colHeader);
4754                                 return colHeader;
4755                         }
4756
4757                         public virtual ColumnHeader Add (string key, string text, int width)
4758                         {
4759                                 return Add (key, text, width, HorizontalAlignment.Left, -1);
4760                         }
4761
4762                         public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
4763                         {
4764                                 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4765                                 colHeader.ImageIndex = imageIndex;
4766                                 Add (colHeader);
4767                                 return colHeader;
4768                         }
4769
4770                         public virtual ColumnHeader Add (string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
4771                         {
4772                                 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4773                                 colHeader.ImageKey = imageKey;
4774                                 Add (colHeader);
4775                                 return colHeader;
4776                         }
4777 #endif
4778
4779                         public virtual void AddRange (ColumnHeader [] values)
4780                         {
4781                                 foreach (ColumnHeader colHeader in values) {
4782                                         int idx = list.Add (colHeader);
4783                                         owner.AddColumn (colHeader, idx, false);
4784                                 }
4785                                 
4786                                 owner.Redraw (true);
4787                         }
4788
4789                         public virtual void Clear ()
4790                         {
4791                                 foreach (ColumnHeader col in list)
4792                                         col.SetListView (null);
4793                                 list.Clear ();
4794                                 owner.ReorderColumns (new int [0], true);
4795
4796 #if NET_2_0
4797                                 //UIA Framework event: Items cleared
4798                                 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
4799 #endif
4800
4801                         }
4802
4803                         public bool Contains (ColumnHeader value)
4804                         {
4805                                 return list.Contains (value);
4806                         }
4807
4808 #if NET_2_0
4809                         public virtual bool ContainsKey (string key)
4810                         {
4811                                 return IndexOfKey (key) != -1;
4812                         }
4813 #endif
4814
4815                         public IEnumerator GetEnumerator ()
4816                         {
4817                                 return list.GetEnumerator ();
4818                         }
4819
4820                         void ICollection.CopyTo (Array dest, int index)
4821                         {
4822                                 list.CopyTo (dest, index);
4823                         }
4824
4825                         int IList.Add (object value)
4826                         {
4827                                 if (! (value is ColumnHeader)) {
4828                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
4829                                 }
4830
4831                                 return this.Add ((ColumnHeader) value);
4832                         }
4833
4834                         bool IList.Contains (object value)
4835                         {
4836                                 if (! (value is ColumnHeader)) {
4837                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
4838                                 }
4839
4840                                 return this.Contains ((ColumnHeader) value);
4841                         }
4842
4843                         int IList.IndexOf (object value)
4844                         {
4845                                 if (! (value is ColumnHeader)) {
4846                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
4847                                 }
4848
4849                                 return this.IndexOf ((ColumnHeader) value);
4850                         }
4851
4852                         void IList.Insert (int index, object value)
4853                         {
4854                                 if (! (value is ColumnHeader)) {
4855                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
4856                                 }
4857
4858                                 this.Insert (index, (ColumnHeader) value);
4859                         }
4860
4861                         void IList.Remove (object value)
4862                         {
4863                                 if (! (value is ColumnHeader)) {
4864                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
4865                                 }
4866
4867                                 this.Remove ((ColumnHeader) value);
4868                         }
4869
4870                         public int IndexOf (ColumnHeader value)
4871                         {
4872                                 return list.IndexOf (value);
4873                         }
4874
4875 #if NET_2_0
4876                         public virtual int IndexOfKey (string key)
4877                         {
4878                                 if (key == null || key.Length == 0)
4879                                         return -1;
4880
4881                                 for (int i = 0; i < list.Count; i++) {
4882                                         ColumnHeader col = (ColumnHeader) list [i];
4883                                         if (String.Compare (key, col.Name, true) == 0)
4884                                                 return i;
4885                                 }
4886
4887                                 return -1;
4888                         }
4889 #endif
4890
4891                         public void Insert (int index, ColumnHeader value)
4892                         {
4893                                 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
4894                                 // but it's really only greater.
4895                                 if (index < 0 || index > list.Count)
4896                                         throw new ArgumentOutOfRangeException ("index");
4897
4898                                 list.Insert (index, value);
4899                                 owner.AddColumn (value, index, true);
4900
4901 #if NET_2_0
4902                                 //UIA Framework event: Item added
4903                                 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
4904 #endif
4905                         }
4906
4907 #if NET_2_0
4908                         public void Insert (int index, string text)
4909                         {
4910                                 Insert (index, String.Empty, text);
4911                         }
4912
4913                         public void Insert (int index, string text, int width)
4914                         {
4915                                 Insert (index, String.Empty, text, width);
4916                         }
4917
4918                         public void Insert (int index, string key, string text)
4919                         {
4920                                 ColumnHeader colHeader = new ColumnHeader ();
4921                                 colHeader.Name = key;
4922                                 colHeader.Text = text;
4923                                 Insert (index, colHeader);
4924                         }
4925
4926                         public void Insert (int index, string key, string text, int width)
4927                         {
4928                                 ColumnHeader colHeader = new ColumnHeader (key, text, width, HorizontalAlignment.Left);
4929                                 Insert (index, colHeader);
4930                         }
4931
4932                         public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
4933                         {
4934                                 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4935                                 colHeader.ImageIndex = imageIndex;
4936                                 Insert (index, colHeader);
4937                         }
4938
4939                         public void Insert (int index, string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
4940                         {
4941                                 ColumnHeader colHeader = new ColumnHeader (key, text, width, textAlign);
4942                                 colHeader.ImageKey = imageKey;
4943                                 Insert (index, colHeader);
4944                         }
4945 #endif
4946
4947 #if NET_2_0
4948                         public void Insert (int index, string text, int width, HorizontalAlignment textAlign)
4949                         {
4950                                 string str = text;
4951 #else
4952                         public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
4953                         {
4954 #endif
4955                                 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
4956                                 this.Insert (index, colHeader);
4957                         }
4958
4959                         public virtual void Remove (ColumnHeader column)
4960                         {
4961                                 if (!Contains (column))
4962                                         return;
4963
4964                                 list.Remove (column);
4965                                 column.SetListView (null);
4966
4967                                 int rem_display_index = column.InternalDisplayIndex;
4968                                 int [] display_indices = new int [list.Count];
4969                                 for (int i = 0; i < display_indices.Length; i++) {
4970                                         ColumnHeader col = (ColumnHeader) list [i];
4971                                         int display_index = col.InternalDisplayIndex;
4972                                         if (display_index < rem_display_index) {
4973                                                 display_indices [i] = display_index;
4974                                         } else {
4975                                                 display_indices [i] = (display_index - 1);
4976                                         }
4977                                 }
4978
4979                                 column.InternalDisplayIndex = -1;
4980                                 owner.ReorderColumns (display_indices, true);
4981
4982 #if NET_2_0
4983                                 //UIA Framework event: Item Removed
4984                                 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, column));
4985 #endif
4986                         }
4987
4988 #if NET_2_0
4989                         public virtual void RemoveByKey (string key)
4990                         {
4991                                 int idx = IndexOfKey (key);
4992                                 if (idx != -1)
4993                                         RemoveAt (idx);
4994                         }
4995 #endif
4996
4997                         public virtual void RemoveAt (int index)
4998                         {
4999                                 if (index < 0 || index >= list.Count)
5000                                         throw new ArgumentOutOfRangeException ("index");
5001
5002                                 ColumnHeader col = (ColumnHeader) list [index];
5003                                 Remove (col);
5004                         }
5005                         #endregion      // Public Methods
5006                         
5007
5008                 }       // ColumnHeaderCollection
5009
5010 #if NET_2_0
5011                 [ListBindable (false)]
5012 #endif
5013                 public class ListViewItemCollection : IList, ICollection, IEnumerable
5014                 {
5015                         private readonly ArrayList list;
5016                         private ListView owner;
5017 #if NET_2_0
5018                         private ListViewGroup group;
5019 #endif
5020
5021                         #region UIA Framework Events 
5022 #if NET_2_0
5023                         //NOTE:
5024                         //      We are using Reflection to add/remove internal events.
5025                         //      Class ListViewProvider uses the events.
5026                         //
5027                         //Event used to generate UIA StructureChangedEvent
5028                         static object UIACollectionChangedEvent = new object ();
5029
5030                         internal event CollectionChangeEventHandler UIACollectionChanged {
5031                                 add { 
5032                                         if (owner != null)
5033                                                 owner.Events.AddHandler (UIACollectionChangedEvent, value); 
5034                                 }
5035                                 remove { 
5036                                         if (owner != null)
5037                                                 owner.Events.RemoveHandler (UIACollectionChangedEvent, value); 
5038                                 }
5039                         }
5040
5041                         internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
5042                         {
5043                                 if (owner == null)
5044                                         return;
5045
5046                                 CollectionChangeEventHandler eh
5047                                         = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
5048                                 if (eh != null)
5049                                         eh (owner, args);
5050                         }
5051
5052 #endif
5053                         #endregion UIA Framework Events 
5054
5055                         // The collection can belong to a ListView (main) or to a ListViewGroup (sub-collection)
5056                         // In the later case ListViewItem.ListView never gets modified
5057                         private bool is_main_collection = true;
5058
5059                         #region Public Constructor
5060                         public ListViewItemCollection (ListView owner)
5061                         {
5062                                 list = new ArrayList (0);
5063                                 this.owner = owner;
5064                         }
5065                         #endregion      // Public Constructor
5066
5067 #if NET_2_0
5068                         internal ListViewItemCollection (ListView owner, ListViewGroup group) : this (owner)
5069                         {
5070                                 this.group = group;
5071                                 is_main_collection = false;
5072                         }
5073 #endif
5074
5075                         #region Public Properties
5076                         [Browsable (false)]
5077                         public int Count {
5078                                 get {
5079 #if NET_2_0
5080                                         if (owner != null && owner.VirtualMode)
5081                                                 return owner.VirtualListSize;
5082 #endif
5083
5084                                         return list.Count; 
5085                                 }
5086                         }
5087
5088                         public bool IsReadOnly {
5089                                 get { return false; }
5090                         }
5091
5092 #if NET_2_0
5093                         public virtual ListViewItem this [int index] {
5094 #else
5095                         public virtual ListViewItem this [int displayIndex] {
5096 #endif
5097                                 get {
5098 #if !NET_2_0
5099                                         int index = displayIndex;
5100 #endif
5101
5102                                         if (index < 0 || index >= Count)
5103                                                 throw new ArgumentOutOfRangeException ("index");
5104
5105 #if NET_2_0
5106                                         if (owner != null && owner.VirtualMode)
5107                                                 return RetrieveVirtualItemFromOwner (index);
5108 #endif
5109                                         return (ListViewItem) list [index];
5110                                 }
5111
5112                                 set {
5113 #if !NET_2_0
5114                                         int index = displayIndex;
5115 #endif
5116
5117                                         if (index < 0 || index >= Count)
5118                                                 throw new ArgumentOutOfRangeException ("index");
5119
5120 #if NET_2_0
5121                                         if (owner != null && owner.VirtualMode)
5122                                                 throw new InvalidOperationException ();
5123 #endif
5124
5125                                         if (list.Contains (value))
5126                                                 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
5127
5128                                         if (value.ListView != null && value.ListView != owner)
5129                                                 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");
5130
5131                                         if (is_main_collection)
5132                                                 value.Owner = owner;
5133 #if NET_2_0
5134                                         else {
5135                                                 if (value.Group != null)
5136                                                         value.Group.Items.Remove (value);
5137
5138                                                 value.SetGroup (group);
5139                                         }
5140 #endif
5141
5142 #if NET_2_0
5143                                         //UIA Framework event: Item Replaced
5144                                         OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, list [index]));
5145 #endif
5146
5147                                         list [index] = value;
5148
5149                                         CollectionChanged (true);
5150
5151 #if NET_2_0
5152                                         //UIA Framework event: Item Replaced
5153                                         OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5154 #endif
5155
5156                                 }
5157                         }
5158
5159 #if NET_2_0
5160                         public virtual ListViewItem this [string key] {
5161                                 get {
5162                                         int idx = IndexOfKey (key);
5163                                         if (idx == -1)
5164                                                 return null;
5165
5166                                         return this [idx];
5167                                 }
5168                         }
5169 #endif
5170
5171                         bool ICollection.IsSynchronized {
5172                                 get { return true; }
5173                         }
5174
5175                         object ICollection.SyncRoot {
5176                                 get { return this; }
5177                         }
5178
5179                         bool IList.IsFixedSize {
5180                                 get { return list.IsFixedSize; }
5181                         }
5182
5183                         object IList.this [int index] {
5184                                 get { return this [index]; }
5185                                 set {
5186 #if NET_2_0
5187                                         //UIA Framework event: Item Replaced
5188                                         OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, this [index]));
5189 #endif
5190
5191                                         if (value is ListViewItem)
5192                                                 this [index] = (ListViewItem) value;
5193                                         else
5194                                                 this [index] = new ListViewItem (value.ToString ());
5195
5196                                         OnChange ();
5197 #if NET_2_0
5198                                         //UIA Framework event: Item Replaced
5199                                         OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5200 #endif
5201                                 }
5202                         }
5203                         #endregion      // Public Properties
5204
5205                         #region Public Methods
5206                         public virtual ListViewItem Add (ListViewItem value)
5207                         {
5208 #if NET_2_0
5209                                 if (owner != null && owner.VirtualMode)
5210                                         throw new InvalidOperationException ();
5211 #endif
5212
5213                                 AddItem (value);
5214
5215                                 // Item is ignored until it has been added to the ListView
5216                                 if (is_main_collection || value.ListView != null)
5217                                         CollectionChanged (true);
5218
5219 #if NET_2_0
5220                                 //UIA Framework event: Item Added
5221                                 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
5222 #endif
5223
5224                                 return value;
5225                         }
5226
5227                         public virtual ListViewItem Add (string text)
5228                         {
5229                                 ListViewItem item = new ListViewItem (text);
5230                                 return this.Add (item);
5231                         }
5232
5233                         public virtual ListViewItem Add (string text, int imageIndex)
5234                         {
5235                                 ListViewItem item = new ListViewItem (text, imageIndex);
5236                                 return this.Add (item);
5237                         }
5238
5239 #if NET_2_0
5240                         public virtual ListViewItem Add (string text, string imageKey)
5241                         {
5242                                 ListViewItem item = new ListViewItem (text, imageKey);
5243                                 return this.Add (item);
5244                         }
5245
5246                         public virtual ListViewItem Add (string key, string text, int imageIndex)
5247                         {
5248                                 ListViewItem item = new ListViewItem (text, imageIndex);
5249                                 item.Name = key;
5250                                 return this.Add (item);
5251                         }
5252
5253                         public virtual ListViewItem Add (string key, string text, string imageKey)
5254                         {
5255                                 ListViewItem item = new ListViewItem (text, imageKey);
5256                                 item.Name = key;
5257                                 return this.Add (item);
5258                         }
5259 #endif
5260
5261 #if NET_2_0
5262                         public void AddRange (ListViewItem [] items)
5263                         {
5264 #else
5265                         public void AddRange (ListViewItem [] values)
5266                         {
5267                                 ListViewItem [] items = values;
5268 #endif
5269                                 if (items == null)
5270                                         throw new ArgumentNullException ("Argument cannot be null!", "items");
5271 #if NET_2_0
5272                                 if (owner != null && owner.VirtualMode)
5273                                         throw new InvalidOperationException ();
5274 #endif
5275
5276                                 owner.BeginUpdate ();
5277                                 
5278                                 foreach (ListViewItem item in items) {
5279                                         AddItem (item);
5280
5281 #if NET_2_0
5282                                         //UIA Framework event: Item Added
5283                                         OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
5284 #endif
5285                                 }
5286
5287                                 owner.EndUpdate ();
5288                                 
5289                                 CollectionChanged (true);
5290                         }
5291
5292 #if NET_2_0
5293                         public void AddRange (ListViewItemCollection items)
5294                         {
5295                                 if (items == null)
5296                                         throw new ArgumentNullException ("Argument cannot be null!", "items");
5297
5298                                 ListViewItem[] itemArray = new ListViewItem[items.Count];
5299                                 items.CopyTo (itemArray,0);
5300                                 this.AddRange (itemArray);
5301                         }
5302 #endif
5303
5304                         public virtual void Clear ()
5305                         {
5306 #if NET_2_0
5307                                 if (owner != null && owner.VirtualMode)
5308                                         throw new InvalidOperationException ();
5309 #endif
5310                                 if (is_main_collection && owner != null) {
5311                                         owner.SetFocusedItem (-1);
5312                                         owner.h_scroll.Value = owner.v_scroll.Value = 0;
5313                                                 
5314                                         foreach (ListViewItem item in list) {
5315                                                 owner.item_control.CancelEdit (item);
5316                                                 item.Owner = null;
5317                                         }
5318                                         
5319                                 }
5320 #if NET_2_0
5321                                 else
5322                                         foreach (ListViewItem item in list)
5323                                                 item.SetGroup (null);
5324 #endif
5325
5326                                 list.Clear ();
5327                                 CollectionChanged (false);
5328
5329 #if NET_2_0
5330                                 //UIA Framework event: Items Removed
5331                                 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
5332 #endif
5333
5334                         }
5335
5336                         public bool Contains (ListViewItem item)
5337                         {
5338                                 return IndexOf (item) != -1;
5339                         }
5340
5341 #if NET_2_0
5342                         public virtual bool ContainsKey (string key)
5343                         {
5344                                 return IndexOfKey (key) != -1;
5345                         }
5346 #endif
5347
5348                         public void CopyTo (Array dest, int index)
5349                         {
5350                                 list.CopyTo (dest, index);
5351                         }
5352
5353 #if NET_2_0
5354                         public ListViewItem [] Find (string key, bool searchAllSubItems)
5355                         {
5356                                 if (key == null)
5357                                         return new ListViewItem [0];
5358
5359                                 List<ListViewItem> temp_list = new List<ListViewItem> ();
5360                                 
5361                                 for (int i = 0; i < list.Count; i++) {
5362                                         ListViewItem lvi = (ListViewItem) list [i];
5363                                         if (String.Compare (key, lvi.Name, true) == 0)
5364                                                 temp_list.Add (lvi);
5365                                 }
5366
5367                                 ListViewItem [] retval = new ListViewItem [temp_list.Count];
5368                                 temp_list.CopyTo (retval);
5369
5370                                 return retval;
5371                         }
5372 #endif
5373
5374                         public IEnumerator GetEnumerator ()
5375                         {
5376 #if NET_2_0
5377                                 if (owner != null && owner.VirtualMode)
5378                                         throw new InvalidOperationException ();
5379 #endif
5380
5381                                 // This enumerator makes a copy of the collection so
5382                                 // it can be deleted from in a foreach
5383                                 return new Control.ControlCollection.ControlCollectionEnumerator (list);
5384                         }
5385
5386                         int IList.Add (object item)
5387                         {
5388                                 int result;
5389                                 ListViewItem li;
5390
5391 #if NET_2_0
5392                                 if (owner != null && owner.VirtualMode)
5393                                         throw new InvalidOperationException ();
5394 #endif
5395
5396                                 if (item is ListViewItem) {
5397                                         li = (ListViewItem) item;
5398                                         if (list.Contains (li))
5399                                                 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
5400
5401                                         if (li.ListView != null && li.ListView != owner)
5402                                                 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");
5403                                 }
5404                                 else
5405                                         li = new ListViewItem (item.ToString ());
5406
5407                                 li.Owner = owner;
5408                                 
5409                                 
5410                                 result = list.Add (li);
5411                                 CollectionChanged (true);
5412
5413 #if NET_2_0
5414                                 //UIA Framework event: Item Added
5415                                 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, li));
5416 #endif
5417
5418                                 return result;
5419                         }
5420
5421                         bool IList.Contains (object item)
5422                         {
5423                                 return Contains ((ListViewItem) item);
5424                         }
5425
5426                         int IList.IndexOf (object item)
5427                         {
5428                                 return IndexOf ((ListViewItem) item);
5429                         }
5430
5431                         void IList.Insert (int index, object item)
5432                         {
5433                                 if (item is ListViewItem)
5434                                         this.Insert (index, (ListViewItem) item);
5435                                 else
5436                                         this.Insert (index, item.ToString ());
5437
5438 #if NET_2_0
5439                                 //UIA Framework event: Item Added
5440                                 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, this [index]));
5441 #endif
5442                         }
5443
5444                         void IList.Remove (object item)
5445                         {
5446                                 Remove ((ListViewItem) item);
5447                         }
5448
5449                         public int IndexOf (ListViewItem item)
5450                         {
5451 #if NET_2_0
5452                                 if (owner != null && owner.VirtualMode) {
5453                                         for (int i = 0; i < Count; i++)
5454                                                 if (RetrieveVirtualItemFromOwner (i) == item)
5455                                                         return i;
5456
5457                                         return -1;
5458                                 }
5459 #endif
5460                                 
5461                                 return list.IndexOf (item);
5462                         }
5463
5464 #if NET_2_0
5465                         public virtual int IndexOfKey (string key)
5466                         {
5467                                 if (key == null || key.Length == 0)
5468                                         return -1;
5469
5470                                 for (int i = 0; i < Count; i++) {
5471                                         ListViewItem lvi = this [i];
5472                                         if (String.Compare (key, lvi.Name, true) == 0)
5473                                                 return i;
5474                                 }
5475
5476                                 return -1;
5477                         }
5478 #endif
5479
5480                         public ListViewItem Insert (int index, ListViewItem item)
5481                         {
5482                                 if (index < 0 || index > list.Count)
5483                                         throw new ArgumentOutOfRangeException ("index");
5484
5485 #if NET_2_0
5486                                 if (owner != null && owner.VirtualMode)
5487                                         throw new InvalidOperationException ();
5488 #endif
5489
5490                                 if (list.Contains (item))
5491                                         throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
5492
5493                                 if (item.ListView != null && item.ListView != owner)
5494                                         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");
5495
5496                                 if (is_main_collection)
5497                                         item.Owner = owner;
5498 #if NET_2_0
5499                                 else {
5500                                         if (item.Group != null)
5501                                                 item.Group.Items.Remove (item);
5502
5503                                         item.SetGroup (group);
5504                                 }
5505 #endif
5506
5507                                 list.Insert (index, item);
5508
5509                                 if (is_main_collection || item.ListView != null)
5510                                         CollectionChanged (true);
5511
5512 #if NET_2_0
5513                                 //UIA Framework event: Item Added
5514                                 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
5515 #endif
5516
5517                                 return item;
5518                         }
5519
5520                         public ListViewItem Insert (int index, string text)
5521                         {
5522                                 return this.Insert (index, new ListViewItem (text));
5523                         }
5524
5525                         public ListViewItem Insert (int index, string text, int imageIndex)
5526                         {
5527                                 return this.Insert (index, new ListViewItem (text, imageIndex));
5528                         }
5529
5530 #if NET_2_0
5531                         public ListViewItem Insert (int index, string text, string imageKey)
5532                         {
5533                                 ListViewItem lvi = new ListViewItem (text, imageKey);
5534                                 return Insert (index, lvi);
5535                         }
5536
5537                         public virtual ListViewItem Insert (int index, string key, string text, int imageIndex)
5538                         {
5539                                 ListViewItem lvi = new ListViewItem (text, imageIndex);
5540                                 lvi.Name = key;
5541                                 return Insert (index, lvi);
5542                         }
5543
5544                         public virtual ListViewItem Insert (int index, string key, string text, string imageKey)
5545                         {
5546                                 ListViewItem lvi = new ListViewItem (text, imageKey);
5547                                 lvi.Name = key;
5548                                 return Insert (index, lvi);
5549                         }
5550 #endif
5551
5552                         public virtual void Remove (ListViewItem item)
5553                         {
5554 #if NET_2_0
5555                                 if (owner != null && owner.VirtualMode)
5556                                         throw new InvalidOperationException ();
5557 #endif
5558
5559                                 int idx = list.IndexOf (item);
5560                                 if (idx != -1)
5561                                         RemoveAt (idx);
5562                         }
5563
5564                         public virtual void RemoveAt (int index)
5565                         {
5566                                 if (index < 0 || index >= Count)
5567                                         throw new ArgumentOutOfRangeException ("index");
5568
5569 #if NET_2_0
5570                                 if (owner != null && owner.VirtualMode)
5571                                         throw new InvalidOperationException ();
5572 #endif
5573
5574                                 ListViewItem item = (ListViewItem) list [index];
5575
5576                                 bool selection_changed = false;
5577                                 if (is_main_collection && owner != null) {
5578
5579                                         int display_index = item.DisplayIndex;
5580                                         if (item.Focused && display_index + 1 == Count) // Last item
5581                                                 owner.SetFocusedItem (display_index == 0 ? -1 : display_index - 1);
5582
5583                                         selection_changed = owner.SelectedIndices.Contains (index);
5584                                         owner.item_control.CancelEdit (item);
5585                                 }
5586
5587                                 list.RemoveAt (index);
5588
5589 #if NET_2_0
5590                                 if (is_main_collection) {
5591                                         item.Owner = null;
5592                                         if (item.Group != null)
5593                                                 item.Group.Items.Remove (item);
5594                                 } else
5595                                         item.SetGroup (null);
5596 #else
5597                                 item.Owner = null;
5598 #endif
5599
5600                                 CollectionChanged (false);
5601                                 if (selection_changed && owner != null)
5602                                         owner.OnSelectedIndexChanged (EventArgs.Empty);
5603
5604
5605 #if NET_2_0
5606                                 //UIA Framework event: Item Removed 
5607                                 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, item));
5608 #endif
5609                         }
5610
5611 #if NET_2_0
5612                         public virtual void RemoveByKey (string key)
5613                         {
5614                                 int idx = IndexOfKey (key);
5615                                 if (idx != -1)
5616                                         RemoveAt (idx);
5617                         }
5618 #endif
5619
5620                         #endregion      // Public Methods
5621
5622                         internal ListView Owner {
5623                                 get {
5624                                         return owner;
5625                                 }
5626                                 set {
5627                                         owner = value;
5628                                 }
5629                         }
5630
5631 #if NET_2_0
5632                         internal ListViewGroup Group {
5633                                 get {
5634                                         return group;
5635                                 }
5636                                 set {
5637                                         group = value;
5638                                 }
5639                         }
5640 #endif
5641
5642                         void AddItem (ListViewItem value)
5643                         {
5644                                 if (list.Contains (value))
5645                                         throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
5646
5647                                 if (value.ListView != null && value.ListView != owner)
5648                                         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");
5649                                 if (is_main_collection)
5650                                         value.Owner = owner;
5651 #if NET_2_0
5652                                 else {
5653                                         if (value.Group != null)
5654                                                 value.Group.Items.Remove (value);
5655
5656                                         value.SetGroup (group);
5657                                 }
5658 #endif
5659
5660                                 list.Add (value);
5661
5662                         }
5663
5664                         void CollectionChanged (bool sort)
5665                         {
5666                                 if (owner != null) {
5667                                         if (sort)
5668                                                 owner.Sort (false);
5669
5670                                         OnChange ();
5671                                         owner.Redraw (true);
5672                                 }
5673                         }
5674
5675 #if NET_2_0
5676                         ListViewItem RetrieveVirtualItemFromOwner (int displayIndex)
5677                         {
5678                                 RetrieveVirtualItemEventArgs args = new RetrieveVirtualItemEventArgs (displayIndex);
5679
5680                                 owner.OnRetrieveVirtualItem (args);
5681                                 ListViewItem retval = args.Item;
5682                                 retval.Owner = owner;
5683                                 retval.DisplayIndex = displayIndex;
5684
5685                                 return retval;
5686                         }
5687 #endif
5688
5689                         internal event CollectionChangedHandler Changed;
5690
5691                         internal void Sort (IComparer comparer)
5692                         {
5693                                 list.Sort (comparer);
5694                                 OnChange ();
5695                         }
5696
5697                         internal void OnChange ()
5698                         {
5699                                 if (Changed != null)
5700                                         Changed ();
5701                         }
5702                 }       // ListViewItemCollection
5703
5704                         
5705                 // In normal mode, the selection information resides in the Items,
5706                 // making SelectedIndexCollection.List read-only
5707                 //
5708                 // In virtual mode, SelectedIndexCollection directly saves the selection
5709                 // information, instead of getting it from Items, making List read-and-write
5710 #if NET_2_0
5711                 [ListBindable (false)]
5712 #endif
5713                 public class SelectedIndexCollection : IList, ICollection, IEnumerable
5714                 {
5715                         private readonly ListView owner;
5716                         private ArrayList list;
5717
5718                         #region Public Constructor
5719                         public SelectedIndexCollection (ListView owner)
5720                         {
5721                                 this.owner = owner;
5722                                 owner.Items.Changed += new CollectionChangedHandler (ItemsCollection_Changed);
5723                         }
5724                         #endregion      // Public Constructor
5725
5726                         #region Public Properties
5727                         [Browsable (false)]
5728                         public int Count {
5729                                 get {
5730                                         if (!owner.IsHandleCreated)
5731                                                 return 0;
5732
5733                                         return List.Count;
5734                                 }
5735                         }
5736
5737                         public bool IsReadOnly {
5738                                 get { 
5739 #if NET_2_0
5740                                         return false;
5741 #else
5742                                         return true; 
5743 #endif
5744                                 }
5745                         }
5746
5747                         public int this [int index] {
5748                                 get {
5749                                         if (!owner.IsHandleCreated || index < 0 || index >= List.Count)
5750                                                 throw new ArgumentOutOfRangeException ("index");
5751
5752                                         return (int) List [index];
5753                                 }
5754                         }
5755
5756                         bool ICollection.IsSynchronized {
5757                                 get { return false; }
5758                         }
5759
5760                         object ICollection.SyncRoot {
5761                                 get { return this; }
5762                         }
5763
5764                         bool IList.IsFixedSize {
5765                                 get { 
5766 #if NET_2_0
5767                                         return false;
5768 #else
5769                                         return true;
5770 #endif
5771                                 }
5772                         }
5773
5774                         object IList.this [int index] {
5775                                 get { return this [index]; }
5776                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
5777                         }
5778                         #endregion      // Public Properties
5779
5780                         #region Public Methods
5781 #if NET_2_0
5782                         public int Add (int itemIndex)
5783                         {
5784                                 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
5785                                         throw new ArgumentOutOfRangeException ("index");
5786
5787                                 if (owner.virtual_mode && !owner.IsHandleCreated)
5788                                         return -1;
5789
5790                                 owner.Items [itemIndex].Selected = true;
5791
5792                                 if (!owner.IsHandleCreated)
5793                                         return 0;
5794
5795                                 return List.Count;
5796                         }
5797 #endif
5798
5799 #if NET_2_0
5800                         public 
5801 #else
5802                         internal
5803 #endif  
5804                         void Clear ()
5805                         {
5806                                 if (!owner.IsHandleCreated)
5807                                         return;
5808
5809                                 int [] indexes = (int []) List.ToArray (typeof (int));
5810                                 foreach (int index in indexes)
5811                                         owner.Items [index].Selected = false;
5812                         }
5813
5814                         public bool Contains (int selectedIndex)
5815                         {
5816                                 return IndexOf (selectedIndex) != -1;
5817                         }
5818
5819                         public void CopyTo (Array dest, int index)
5820                         {
5821                                 List.CopyTo (dest, index);
5822                         }
5823
5824                         public IEnumerator GetEnumerator ()
5825                         {
5826                                 return List.GetEnumerator ();
5827                         }
5828
5829                         int IList.Add (object value)
5830                         {
5831                                 throw new NotSupportedException ("Add operation is not supported.");
5832                         }
5833
5834                         void IList.Clear ()
5835                         {
5836                                 Clear ();
5837                         }
5838
5839                         bool IList.Contains (object selectedIndex)
5840                         {
5841                                 if (!(selectedIndex is int))
5842                                         return false;
5843                                 return Contains ((int) selectedIndex);
5844                         }
5845
5846                         int IList.IndexOf (object selectedIndex)
5847                         {
5848                                 if (!(selectedIndex is int))
5849                                         return -1;
5850                                 return IndexOf ((int) selectedIndex);
5851                         }
5852
5853                         void IList.Insert (int index, object value)
5854                         {
5855                                 throw new NotSupportedException ("Insert operation is not supported.");
5856                         }
5857
5858                         void IList.Remove (object value)
5859                         {
5860                                 throw new NotSupportedException ("Remove operation is not supported.");
5861                         }
5862
5863                         void IList.RemoveAt (int index)
5864                         {
5865                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
5866                         }
5867
5868                         public int IndexOf (int selectedIndex)
5869                         {
5870                                 if (!owner.IsHandleCreated)
5871                                         return -1;
5872
5873                                 return List.IndexOf (selectedIndex);
5874                         }
5875
5876 #if NET_2_0
5877                         public void Remove (int itemIndex)
5878                         {
5879                                 if (itemIndex < 0 || itemIndex >= owner.Items.Count)
5880                                         throw new ArgumentOutOfRangeException ("itemIndex");
5881
5882                                 owner.Items [itemIndex].Selected = false;
5883                         }
5884 #endif
5885                         #endregion      // Public Methods
5886
5887                         internal ArrayList List {
5888                                 get {
5889                                         if (list == null) {
5890                                                 list = new ArrayList ();
5891 #if NET_2_0
5892                                                 if (!owner.VirtualMode)
5893 #endif
5894                                                 for (int i = 0; i < owner.Items.Count; i++) {
5895                                                         if (owner.Items [i].Selected)
5896                                                                 list.Add (i);
5897                                                 }
5898                                         }
5899                                         return list;
5900                                 }
5901                         }
5902
5903                         internal void Reset ()
5904                         {
5905                                 // force re-population of list
5906                                 list = null;
5907                         }
5908
5909                         private void ItemsCollection_Changed ()
5910                         {
5911                                 Reset ();
5912                         }
5913
5914 #if NET_2_0
5915                         internal void RemoveIndex (int index)
5916                         {
5917                                 int idx = List.BinarySearch (index);
5918                                 if (idx != -1)
5919                                         List.RemoveAt (idx);
5920                         }
5921
5922                         // actually store index in the collection
5923                         // also, keep the collection sorted, as .Net does
5924                         internal void InsertIndex (int index)
5925                         {
5926                                 int iMin = 0;
5927                                 int iMax = List.Count - 1;
5928                                 while (iMin <= iMax) {
5929                                         int iMid = (iMin + iMax) / 2;
5930                                         int current_index = (int) List [iMid];
5931
5932                                         if (current_index == index)
5933                                                 return; // Already added
5934                                         if (current_index > index)
5935                                                 iMax = iMid - 1;
5936                                         else
5937                                                 iMin = iMid + 1;
5938                                 }
5939
5940                                 List.Insert (iMin, index);
5941                         }
5942 #endif
5943
5944                 }       // SelectedIndexCollection
5945
5946 #if NET_2_0
5947                 [ListBindable (false)]
5948 #endif
5949                 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
5950                 {
5951                         private readonly ListView owner;
5952
5953                         #region Public Constructor
5954                         public SelectedListViewItemCollection (ListView owner)
5955                         {
5956                                 this.owner = owner;
5957                         }
5958                         #endregion      // Public Constructor
5959
5960                         #region Public Properties
5961                         [Browsable (false)]
5962                         public int Count {
5963                                 get {
5964                                         return owner.SelectedIndices.Count;
5965                                 }
5966                         }
5967
5968                         public bool IsReadOnly {
5969                                 get { return true; }
5970                         }
5971
5972                         public ListViewItem this [int index] {
5973                                 get {
5974                                         if (!owner.IsHandleCreated || index < 0 || index >= Count)
5975                                                 throw new ArgumentOutOfRangeException ("index");
5976
5977                                         int item_index = owner.SelectedIndices [index];
5978                                         return owner.Items [item_index];
5979                                 }
5980                         }
5981
5982 #if NET_2_0
5983                         public virtual ListViewItem this [string key] {
5984                                 get {
5985                                         int idx = IndexOfKey (key);
5986                                         if (idx == -1)
5987                                                 return null;
5988
5989                                         return this [idx];
5990                                 }
5991                         }
5992 #endif
5993
5994                         bool ICollection.IsSynchronized {
5995                                 get { return false; }
5996                         }
5997
5998                         object ICollection.SyncRoot {
5999                                 get { return this; }
6000                         }
6001
6002                         bool IList.IsFixedSize {
6003                                 get { return true; }
6004                         }
6005
6006                         object IList.this [int index] {
6007                                 get { return this [index]; }
6008                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
6009                         }
6010                         #endregion      // Public Properties
6011
6012                         #region Public Methods
6013                         public void Clear ()
6014                         {
6015                                 owner.SelectedIndices.Clear ();
6016                         }
6017
6018                         public bool Contains (ListViewItem item)
6019                         {
6020                                 return IndexOf (item) != -1;
6021                         }
6022
6023 #if NET_2_0
6024                         public virtual bool ContainsKey (string key)
6025                         {
6026                                 return IndexOfKey (key) != -1;
6027                         }
6028 #endif
6029
6030                         public void CopyTo (Array dest, int index)
6031                         {
6032                                 if (!owner.IsHandleCreated)
6033                                         return;
6034                                 if (index > Count) // Throws ArgumentException instead of IOOR exception
6035                                         throw new ArgumentException ("index");
6036
6037                                 for (int i = 0; i < Count; i++)
6038                                         dest.SetValue (this [i], index++);
6039                         }
6040
6041                         public IEnumerator GetEnumerator ()
6042                         {
6043                                 if (!owner.IsHandleCreated)
6044                                         return (new ListViewItem [0]).GetEnumerator ();
6045
6046                                 ListViewItem [] items = new ListViewItem [Count];
6047                                 for (int i = 0; i < Count; i++)
6048                                         items [i] = this [i];
6049
6050                                 return items.GetEnumerator ();
6051                         }
6052
6053                         int IList.Add (object value)
6054                         {
6055                                 throw new NotSupportedException ("Add operation is not supported.");
6056                         }
6057
6058                         bool IList.Contains (object item)
6059                         {
6060                                 if (!(item is ListViewItem))
6061                                         return false;
6062                                 return Contains ((ListViewItem) item);
6063                         }
6064
6065                         int IList.IndexOf (object item)
6066                         {
6067                                 if (!(item is ListViewItem))
6068                                         return -1;
6069                                 return IndexOf ((ListViewItem) item);
6070                         }
6071
6072                         void IList.Insert (int index, object value)
6073                         {
6074                                 throw new NotSupportedException ("Insert operation is not supported.");
6075                         }
6076
6077                         void IList.Remove (object value)
6078                         {
6079                                 throw new NotSupportedException ("Remove operation is not supported.");
6080                         }
6081
6082                         void IList.RemoveAt (int index)
6083                         {
6084                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
6085                         }
6086
6087                         public int IndexOf (ListViewItem item)
6088                         {
6089                                 if (!owner.IsHandleCreated)
6090                                         return -1;
6091
6092                                 for (int i = 0; i < Count; i++)
6093                                         if (this [i] == item)
6094                                                 return i;
6095
6096                                 return -1;
6097                         }
6098
6099 #if NET_2_0
6100                         public virtual int IndexOfKey (string key)
6101                         {
6102                                 if (!owner.IsHandleCreated || key == null || key.Length == 0)
6103                                         return -1;
6104
6105                                 for (int i = 0; i < Count; i++) {
6106                                         ListViewItem item = this [i];
6107                                         if (String.Compare (item.Name, key, true) == 0)
6108                                                 return i;
6109                                 }
6110
6111                                 return -1;
6112                         }
6113 #endif
6114                         #endregion      // Public Methods
6115
6116                 }       // SelectedListViewItemCollection
6117
6118                 internal delegate void CollectionChangedHandler ();
6119
6120                 struct ItemMatrixLocation
6121                 {
6122                         int row;
6123                         int col;
6124
6125                         public ItemMatrixLocation (int row, int col)
6126                         {
6127                                 this.row = row;
6128                                 this.col = col;
6129                 
6130                         }
6131                 
6132                         public int Col {
6133                                 get {
6134                                         return col;
6135                                 }
6136                                 set {
6137                                         col = value;
6138                                 }
6139                         }
6140
6141                         public int Row {
6142                                 get {
6143                                         return row;
6144                                 }
6145                                 set {
6146                                         row = value;
6147                                 }
6148                         }
6149         
6150                 }
6151
6152                 #endregion // Subclasses
6153 #if NET_2_0
6154                 protected override void OnResize (EventArgs e)
6155                 {
6156                         base.OnResize (e);
6157                 }
6158
6159                 protected override void OnMouseLeave (EventArgs e)
6160                 {
6161                         base.OnMouseLeave (e);
6162                 }
6163
6164                 //
6165                 // ColumnReorder event
6166                 //
6167                 static object ColumnReorderedEvent = new object ();
6168                 public event ColumnReorderedEventHandler ColumnReordered {
6169                         add { Events.AddHandler (ColumnReorderedEvent, value); }
6170                         remove { Events.RemoveHandler (ColumnReorderedEvent, value); }
6171                 }
6172
6173                 protected virtual void OnColumnReordered (ColumnReorderedEventArgs e)
6174                 {
6175                         ColumnReorderedEventHandler creh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]);
6176
6177                         if (creh != null)
6178                                 creh (this, e);
6179                 }
6180
6181                 //
6182                 // ColumnWidthChanged
6183                 //
6184                 static object ColumnWidthChangedEvent = new object ();
6185                 public event ColumnWidthChangedEventHandler ColumnWidthChanged {
6186                         add { Events.AddHandler (ColumnWidthChangedEvent, value); }
6187                         remove { Events.RemoveHandler (ColumnWidthChangedEvent, value); }
6188                 }
6189
6190                 protected virtual void OnColumnWidthChanged (ColumnWidthChangedEventArgs e)
6191                 {
6192                         ColumnWidthChangedEventHandler eh = (ColumnWidthChangedEventHandler) (Events[ColumnWidthChangedEvent]);
6193                         if (eh != null)
6194                                 eh (this, e);
6195                 }
6196                 
6197                 void RaiseColumnWidthChanged (int resize_column)
6198                 {
6199                         ColumnWidthChangedEventArgs n = new ColumnWidthChangedEventArgs (resize_column);
6200
6201                         OnColumnWidthChanged (n);
6202                 }
6203                 
6204                 //
6205                 // ColumnWidthChanging
6206                 //
6207                 static object ColumnWidthChangingEvent = new object ();
6208                 public event ColumnWidthChangingEventHandler ColumnWidthChanging {
6209                         add { Events.AddHandler (ColumnWidthChangingEvent, value); }
6210                         remove { Events.RemoveHandler (ColumnWidthChangingEvent, value); }
6211                 }
6212
6213                 protected virtual void OnColumnWidthChanging (ColumnWidthChangingEventArgs e)
6214                 {
6215                         ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
6216                         if (cwceh != null)
6217                                 cwceh (this, e);
6218                 }
6219                 
6220                 //
6221                 // 2.0 profile based implementation
6222                 //
6223                 bool CanProceedWithResize (ColumnHeader col, int width)
6224                 {
6225                         ColumnWidthChangingEventHandler cwceh = (ColumnWidthChangingEventHandler) (Events[ColumnWidthChangingEvent]);
6226                         if (cwceh == null)
6227                                 return true;
6228                         
6229                         ColumnWidthChangingEventArgs changing = new ColumnWidthChangingEventArgs (col.Index, width);
6230                         cwceh (this, changing);
6231                         return !changing.Cancel;
6232                 }
6233 #else
6234                 //
6235                 // 1.0 profile based implementation
6236                 //
6237                 bool CanProceedWithResize (ColumnHeader col, int width)
6238                 {
6239                         return true;
6240                 }
6241
6242                 void RaiseColumnWidthChanged (int resize_column)
6243                 {
6244                 }
6245 #endif
6246
6247 #if NET_2_0
6248                 
6249                 #region UIA Framework: Methods, Properties and Events
6250                 
6251                 static object UIALabelEditChangedEvent = new object ();
6252                 static object UIAShowGroupsChangedEvent = new object ();
6253                 static object UIAMultiSelectChangedEvent = new object ();
6254                 static object UIAViewChangedEvent = new object ();
6255                 static object UIACheckBoxesChangedEvent = new object ();
6256                 static object UIAFocusedItemChangedEvent = new object ();
6257
6258                 internal Rectangle UIAHeaderControl {
6259                         get { return header_control.Bounds; }
6260                 }
6261
6262                 internal int UIAColumns {
6263                         get { return cols; }
6264                 }
6265
6266                 internal int UIARows {
6267                         get { return rows; }
6268                 }
6269
6270                 internal ListViewGroup UIADefaultListViewGroup 
6271                 {
6272                         get { return groups.DefaultGroup; }
6273                 }
6274
6275                 internal ScrollBar UIAHScrollBar {
6276                         get { return h_scroll; }
6277                 }
6278
6279                 internal ScrollBar UIAVScrollBar {
6280                         get { return v_scroll; }
6281                 }
6282
6283                 internal event EventHandler UIAShowGroupsChanged {
6284                         add { Events.AddHandler (UIAShowGroupsChangedEvent, value); }
6285                         remove { Events.RemoveHandler (UIAShowGroupsChangedEvent, value); }
6286                 }
6287
6288                 internal event EventHandler UIACheckBoxesChanged {
6289                         add { Events.AddHandler (UIACheckBoxesChangedEvent, value); }
6290                         remove { Events.RemoveHandler (UIACheckBoxesChangedEvent, value); }
6291                 }
6292
6293                 internal event EventHandler UIAMultiSelectChanged {
6294                         add { Events.AddHandler (UIAMultiSelectChangedEvent, value); }
6295                         remove { Events.RemoveHandler (UIAMultiSelectChangedEvent, value); }
6296                 }
6297
6298                 internal event EventHandler UIALabelEditChanged {
6299                         add { Events.AddHandler (UIALabelEditChangedEvent, value); }
6300                         remove { Events.RemoveHandler (UIALabelEditChangedEvent, value); }
6301                 }
6302
6303                 internal event EventHandler UIAViewChanged {
6304                         add { Events.AddHandler (UIAViewChangedEvent, value); }
6305                         remove { Events.RemoveHandler (UIAViewChangedEvent, value); }
6306                 }
6307
6308                 internal event EventHandler UIAFocusedItemChanged {
6309                         add { Events.AddHandler (UIAFocusedItemChangedEvent, value); }
6310                         remove { Events.RemoveHandler (UIAFocusedItemChangedEvent, value); }
6311                 }
6312
6313                 internal Rectangle UIAGetHeaderBounds (ListViewGroup group)
6314                 {
6315                         return group.HeaderBounds;
6316                 }
6317
6318                 private void OnUIACheckBoxesChanged ()
6319                 {
6320                         EventHandler eh = (EventHandler) Events [UIACheckBoxesChangedEvent];
6321                         if (eh != null)
6322                                 eh (this, EventArgs.Empty);
6323                 }
6324
6325                 private void OnUIAShowGroupsChanged ()
6326                 {
6327                         EventHandler eh = (EventHandler) Events [UIAShowGroupsChangedEvent];
6328                         if (eh != null)
6329                                 eh (this, EventArgs.Empty);
6330                 }
6331
6332                 private void OnUIAMultiSelectChanged ()
6333                 {
6334                         EventHandler eh = (EventHandler) Events [UIAMultiSelectChangedEvent];
6335                         if (eh != null)
6336                                 eh (this, EventArgs.Empty);
6337                 }
6338
6339                 private void OnUIALabelEditChanged ()
6340                 {
6341                         EventHandler eh = (EventHandler) Events [UIALabelEditChangedEvent];
6342                         if (eh != null)
6343                                 eh (this, EventArgs.Empty);
6344                 }
6345                 
6346                 private void OnUIAViewChanged ()
6347                 {
6348                         EventHandler eh = (EventHandler) Events [UIAViewChangedEvent];
6349                         if (eh != null)
6350                                 eh (this, EventArgs.Empty);
6351                 }
6352
6353                 internal void OnUIAFocusedItemChanged ()
6354                 {
6355                         EventHandler eh = (EventHandler) Events [UIAFocusedItemChangedEvent];
6356                         if (eh != null)
6357                                 eh (this, EventArgs.Empty);
6358                 }
6359
6360                 #endregion // UIA Framework: Methods, Properties and Events
6361
6362 #endif
6363         }
6364 }