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