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