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