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