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:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
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.
20 // Copyright (c) 2004-2005 Novell, Inc. (http://www.novell.com)
23 // Ravindra Kumar (rkumar@novell.com)
24 // Jordi Mas i Hernandez, jordi@ximian.com
25 // Mike Kestner (mkestner@novell.com)
28 // - Feedback for item activation, change in cursor types as mouse moves.
37 using System.Collections;
38 using System.ComponentModel;
39 using System.ComponentModel.Design;
41 using System.Runtime.InteropServices;
42 using System.Globalization;
44 namespace System.Windows.Forms
46 [DefaultEvent ("SelectedIndexChanged")]
47 [DefaultProperty ("Items")]
48 [Designer ("System.Windows.Forms.Design.ListViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
49 public class ListView : Control
51 private ItemActivation activation = ItemActivation.Standard;
52 private ListViewAlignment alignment = ListViewAlignment.Top;
53 private bool allow_column_reorder = false;
54 private bool auto_arrange = true;
55 private bool check_boxes = false;
56 private CheckedIndexCollection checked_indices;
57 private CheckedListViewItemCollection checked_items;
58 private ColumnHeaderCollection columns;
59 internal ListViewItem focused_item;
60 private bool full_row_select = false;
61 private bool grid_lines = false;
62 private ColumnHeaderStyle header_style = ColumnHeaderStyle.Clickable;
63 private bool hide_selection = true;
64 private bool hover_selection = false;
65 private IComparer item_sorter;
66 private ListViewItemCollection items;
67 private bool label_edit = false;
68 private bool label_wrap = true;
69 private bool multiselect = true;
70 private bool scrollable = true;
71 private SelectedIndexCollection selected_indices;
72 private SelectedListViewItemCollection selected_items;
73 private SortOrder sort_order = SortOrder.None;
74 private ImageList state_image_list;
75 private bool updating = false;
76 private View view = View.LargeIcon;
77 private int layout_wd; // We might draw more than our client area
78 private int layout_ht; // therefore we need to have these two.
79 //private TextBox editor; // Used for editing an item text
80 HeaderControl header_control;
81 internal ItemControl item_control;
82 internal ScrollBar h_scroll; // used for scrolling horizontally
83 internal ScrollBar v_scroll; // used for scrolling vertically
84 internal int h_marker; // Position markers for scrolling
85 internal int v_marker;
86 private int keysearch_tickcnt;
87 private string keysearch_text;
88 static private readonly int keysearch_keydelay = 1000;
89 private int[] reordered_column_indices;
92 internal ImageList large_image_list;
93 internal ImageList small_image_list;
94 internal Size text_size = Size.Empty;
97 public event LabelEditEventHandler AfterLabelEdit;
100 [EditorBrowsable (EditorBrowsableState.Never)]
101 public new event EventHandler BackgroundImageChanged {
102 add { base.BackgroundImageChanged += value; }
103 remove { base.BackgroundImageChanged -= value; }
106 public event LabelEditEventHandler BeforeLabelEdit;
107 public event ColumnClickEventHandler ColumnClick;
108 public event EventHandler ItemActivate;
109 public event ItemCheckEventHandler ItemCheck;
110 public event ItemDragEventHandler ItemDrag;
113 [EditorBrowsable (EditorBrowsableState.Never)]
114 public new event PaintEventHandler Paint {
115 add { base.Paint += value; }
116 remove { base.Paint -= value; }
119 public event EventHandler SelectedIndexChanged;
122 [EditorBrowsable (EditorBrowsableState.Never)]
123 public new event EventHandler TextChanged {
124 add { base.TextChanged += value; }
125 remove { base.TextChanged -= value; }
130 #region Public Constructors
133 background_color = ThemeEngine.Current.ColorWindow;
134 checked_indices = new CheckedIndexCollection (this);
135 checked_items = new CheckedListViewItemCollection (this);
136 columns = new ColumnHeaderCollection (this);
137 foreground_color = SystemColors.WindowText;
138 items = new ListViewItemCollection (this);
139 selected_indices = new SelectedIndexCollection (this);
140 selected_items = new SelectedListViewItemCollection (this);
142 border_style = BorderStyle.Fixed3D;
144 header_control = new HeaderControl (this);
145 header_control.Visible = false;
146 Controls.AddImplicit (header_control);
148 item_control = new ItemControl (this);
149 Controls.AddImplicit (item_control);
151 h_scroll = new HScrollBar ();
152 Controls.AddImplicit (this.h_scroll);
154 v_scroll = new VScrollBar ();
155 Controls.AddImplicit (this.v_scroll);
157 h_marker = v_marker = 0;
158 keysearch_tickcnt = 0;
160 // scroll bars are disabled initially
161 h_scroll.Visible = false;
162 h_scroll.ValueChanged += new EventHandler(HorizontalScroller);
163 v_scroll.Visible = false;
164 v_scroll.ValueChanged += new EventHandler(VerticalScroller);
167 base.KeyDown += new KeyEventHandler(ListView_KeyDown);
168 SizeChanged += new EventHandler (ListView_SizeChanged);
170 this.SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick, false);
172 #endregion // Public Constructors
174 #region Private Internal Properties
175 internal Size CheckBoxSize {
177 if (this.check_boxes) {
178 if (this.state_image_list != null)
179 return this.state_image_list.ImageSize;
181 return ThemeEngine.Current.ListViewCheckBoxSize;
189 bool CanMultiselect {
193 else if (multiselect && (XplatUI.State.ModifierKeys & (Keys.Control | Keys.Shift)) != 0)
200 #endregion // Private Internal Properties
202 #region Protected Properties
203 protected override CreateParams CreateParams {
204 get { return base.CreateParams; }
207 protected override Size DefaultSize {
208 get { return ThemeEngine.Current.ListViewDefaultSize; }
210 #endregion // Protected Properties
212 #region Public Instance Properties
213 [DefaultValue (ItemActivation.Standard)]
214 public ItemActivation Activation {
215 get { return activation; }
217 if (value != ItemActivation.Standard && value != ItemActivation.OneClick &&
218 value != ItemActivation.TwoClick) {
219 throw new InvalidEnumArgumentException (string.Format
220 ("Enum argument value '{0}' is not valid for Activation", value));
227 [DefaultValue (ListViewAlignment.Top)]
229 public ListViewAlignment Alignment {
230 get { return alignment; }
232 if (value != ListViewAlignment.Default && value != ListViewAlignment.Left &&
233 value != ListViewAlignment.SnapToGrid && value != ListViewAlignment.Top) {
234 throw new InvalidEnumArgumentException (string.Format
235 ("Enum argument value '{0}' is not valid for Alignment", value));
238 if (this.alignment != value) {
240 // alignment does not matter in Details/List views
241 if (this.view == View.LargeIcon ||
242 this.View == View.SmallIcon)
248 [DefaultValue (false)]
249 public bool AllowColumnReorder {
250 get { return allow_column_reorder; }
251 set { allow_column_reorder = value; }
254 [DefaultValue (true)]
255 public bool AutoArrange {
256 get { return auto_arrange; }
258 if (auto_arrange != value) {
259 auto_arrange = value;
260 // autoarrange does not matter in Details/List views
261 if (this.view == View.LargeIcon || this.View == View.SmallIcon)
267 public override Color BackColor {
269 if (background_color.IsEmpty)
270 return ThemeEngine.Current.ColorWindow;
272 return background_color;
274 set { background_color = value; }
278 [EditorBrowsable (EditorBrowsableState.Never)]
279 public override Image BackgroundImage {
280 get { return background_image; }
282 if (value == background_image)
285 background_image = value;
286 OnBackgroundImageChanged (EventArgs.Empty);
290 [DefaultValue (BorderStyle.Fixed3D)]
292 public BorderStyle BorderStyle {
293 get { return InternalBorderStyle; }
294 set { InternalBorderStyle = value; }
297 [DefaultValue (false)]
298 public bool CheckBoxes {
299 get { return check_boxes; }
301 if (check_boxes != value) {
309 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
310 public CheckedIndexCollection CheckedIndices {
311 get { return checked_indices; }
315 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
316 public CheckedListViewItemCollection CheckedItems {
317 get { return checked_items; }
320 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
322 [MergableProperty (false)]
323 public ColumnHeaderCollection Columns {
324 get { return columns; }
328 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
329 public ListViewItem FocusedItem {
331 if (focused_item == null && Focused && items.Count > 0)
332 focused_item = items [0];
337 public override Color ForeColor {
339 if (foreground_color.IsEmpty)
340 return ThemeEngine.Current.ColorWindowText;
342 return foreground_color;
344 set { foreground_color = value; }
347 [DefaultValue (false)]
348 public bool FullRowSelect {
349 get { return full_row_select; }
350 set { full_row_select = value; }
353 [DefaultValue (false)]
354 public bool GridLines {
355 get { return grid_lines; }
357 if (grid_lines != value) {
364 [DefaultValue (ColumnHeaderStyle.Clickable)]
365 public ColumnHeaderStyle HeaderStyle {
366 get { return header_style; }
368 if (header_style == value)
372 case ColumnHeaderStyle.Clickable:
373 case ColumnHeaderStyle.Nonclickable:
374 case ColumnHeaderStyle.None:
377 throw new InvalidEnumArgumentException (string.Format
378 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
381 header_style = value;
382 if (view == View.Details)
387 [DefaultValue (true)]
388 public bool HideSelection {
389 get { return hide_selection; }
391 if (hide_selection != value) {
392 hide_selection = value;
398 [DefaultValue (false)]
399 public bool HoverSelection {
400 get { return hover_selection; }
401 set { hover_selection = value; }
404 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
406 [MergableProperty (false)]
407 public ListViewItemCollection Items {
408 get { return items; }
411 [DefaultValue (false)]
412 public bool LabelEdit {
413 get { return label_edit; }
414 set { label_edit = value; }
417 [DefaultValue (true)]
419 public bool LabelWrap {
420 get { return label_wrap; }
422 if (label_wrap != value) {
429 [DefaultValue (null)]
430 public ImageList LargeImageList {
431 get { return large_image_list; }
433 large_image_list = value;
439 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
440 public IComparer ListViewItemSorter {
441 get { return item_sorter; }
442 set { item_sorter = value; }
445 [DefaultValue (true)]
446 public bool MultiSelect {
447 get { return multiselect; }
448 set { multiselect = value; }
451 [DefaultValue (true)]
452 public bool Scrollable {
453 get { return scrollable; }
455 if (scrollable != value) {
463 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
464 public SelectedIndexCollection SelectedIndices {
465 get { return selected_indices; }
469 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
470 public SelectedListViewItemCollection SelectedItems {
471 get { return selected_items; }
475 [MonoTODO("Implement")]
476 public bool ShowGroups {
486 [DefaultValue (null)]
487 public ImageList SmallImageList {
488 get { return small_image_list; }
490 small_image_list = value;
495 [DefaultValue (SortOrder.None)]
496 public SortOrder Sorting {
497 get { return sort_order; }
499 if (value != SortOrder.Ascending && value != SortOrder.Descending &&
500 value != SortOrder.None) {
501 throw new InvalidEnumArgumentException (string.Format
502 ("Enum argument value '{0}' is not valid for Sorting", value));
505 if (sort_order != value) {
512 [DefaultValue (null)]
513 public ImageList StateImageList {
514 get { return state_image_list; }
516 state_image_list = value;
523 [EditorBrowsable (EditorBrowsableState.Never)]
524 public override string Text {
533 OnTextChanged (EventArgs.Empty);
538 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
539 public ListViewItem TopItem {
542 if (this.items.Count == 0)
544 // if contents are not scrolled
545 // it is the first item
546 else if (h_marker == 0 && v_marker == 0)
547 return this.items [0];
548 // do a hit test for the scrolled position
550 foreach (ListViewItem item in this.items) {
551 if (item.Bounds.X >= 0 && item.Bounds.Y >= 0)
560 [MonoTODO("Implement")]
561 public bool UseCompatibleStateImageBehavior {
571 [DefaultValue (View.LargeIcon)]
575 if (value != View.Details && value != View.LargeIcon &&
576 value != View.List && value != View.SmallIcon ) {
577 throw new InvalidEnumArgumentException (string.Format
578 ("Enum argument value '{0}' is not valid for View", value));
582 h_scroll.Value = v_scroll.Value = 0;
588 #endregion // Public Instance Properties
590 #region Internal Methods Properties
592 internal int FirstVisibleIndex {
595 if (this.items.Count == 0)
598 if (h_marker == 0 && v_marker == 0)
601 foreach (ListViewItem item in this.items) {
602 if (item.Bounds.Right >= 0 && item.Bounds.Bottom >= 0)
611 internal int LastVisibleIndex {
613 for (int i = FirstVisibleIndex; i < Items.Count; i++) {
614 if (View == View.List || Alignment == ListViewAlignment.Left) {
615 if (Items[i].Bounds.X > ClientRectangle.Right)
618 if (Items[i].Bounds.Y > ClientRectangle.Bottom)
623 return Items.Count - 1;
627 internal int TotalWidth {
628 get { return Math.Max (this.Width, this.layout_wd); }
631 internal int TotalHeight {
632 get { return Math.Max (this.Height, this.layout_ht); }
635 internal void Redraw (bool recalculate)
637 // Avoid calculations when control is being updated
642 CalculateListView (this.alignment);
647 internal Size GetChildColumnSize (int index)
649 Size ret_size = Size.Empty;
650 ColumnHeader col = this.columns [index];
652 if (col.Width == -2) { // autosize = max(items, columnheader)
653 Size size = Size.Ceiling (this.DeviceContext.MeasureString
654 (col.Text, this.Font));
655 ret_size = BiggestItem (index);
656 if (size.Width > ret_size.Width)
659 else { // -1 and all the values < -2 are put under one category
660 ret_size = BiggestItem (index);
661 // fall back to empty columns' width if no subitem is available for a column
662 if (ret_size.IsEmpty) {
663 ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth;
664 if (col.Text.Length > 0)
665 ret_size.Height = Size.Ceiling (this.DeviceContext.MeasureString
666 (col.Text, this.Font)).Height;
668 ret_size.Height = this.Font.Height;
672 // adjust the size for icon and checkbox for 0th column
674 ret_size.Width += (this.CheckBoxSize.Width + 4);
675 if (this.small_image_list != null)
676 ret_size.Width += this.small_image_list.ImageSize.Width;
681 // Returns the size of biggest item text in a column.
682 private Size BiggestItem (int col)
684 Size temp = Size.Empty;
685 Size ret_size = Size.Empty;
687 // 0th column holds the item text, we check the size of
688 // the various subitems falling in that column and get
689 // the biggest one's size.
690 foreach (ListViewItem item in items) {
691 if (col >= item.SubItems.Count)
694 temp = Size.Ceiling (this.DeviceContext.MeasureString
695 (item.SubItems [col].Text, this.Font));
696 if (temp.Width > ret_size.Width)
700 // adjustment for space
701 if (!ret_size.IsEmpty)
707 // Sets the size of the biggest item text as per the view
708 private void CalcTextSize ()
710 // clear the old value
711 text_size = Size.Empty;
713 if (items.Count == 0)
716 text_size = BiggestItem (0);
718 if (view == View.LargeIcon && this.label_wrap) {
719 Size temp = Size.Empty;
720 if (this.check_boxes)
721 temp.Width += 2 * this.CheckBoxSize.Width;
722 if (large_image_list != null)
723 temp.Width += large_image_list.ImageSize.Width;
726 // wrapping is done for two lines only
727 if (text_size.Width > temp.Width) {
728 text_size.Width = temp.Width;
729 text_size.Height *= 2;
732 else if (view == View.List) {
733 // in list view max text shown in determined by the
734 // control width, even if scolling is enabled.
735 int max_wd = this.Width - (this.CheckBoxSize.Width - 2);
736 if (this.small_image_list != null)
737 max_wd -= this.small_image_list.ImageSize.Width;
739 if (text_size.Width > max_wd)
740 text_size.Width = max_wd;
743 // we do the default settings, if we have got 0's
744 if (text_size.Height <= 0)
745 text_size.Height = this.Font.Height;
746 if (text_size.Width <= 0)
747 text_size.Width = this.Width;
750 text_size.Width += 4;
751 text_size.Height += 2;
754 private void Scroll (ScrollBar scrollbar, int delta)
756 if (delta == 0 || !scrollbar.Visible)
760 if (scrollbar == h_scroll)
761 max = h_scroll.Maximum - item_control.Width;
763 max = v_scroll.Maximum - item_control.Height;
765 int val = scrollbar.Value + delta;
768 else if (val < scrollbar.Minimum)
769 val = scrollbar.Minimum;
770 scrollbar.Value = val;
773 private void CalculateScrollBars ()
775 Rectangle client_area = ClientRectangle;
777 if (!this.scrollable || this.items.Count <= 0) {
778 h_scroll.Visible = false;
779 v_scroll.Visible = false;
783 // making a scroll bar visible might make
784 // other scroll bar visible
785 if (layout_wd > client_area.Right) {
786 h_scroll.Visible = true;
787 if ((layout_ht + h_scroll.Height) > client_area.Bottom)
788 v_scroll.Visible = true;
790 v_scroll.Visible = false;
791 } else if (layout_ht > client_area.Bottom) {
792 v_scroll.Visible = true;
793 if ((layout_wd + v_scroll.Width) > client_area.Right)
794 h_scroll.Visible = true;
796 h_scroll.Visible = false;
798 h_scroll.Visible = false;
799 v_scroll.Visible = false;
802 item_control.Height = ClientRectangle.Height - header_control.Height;
804 if (h_scroll.Visible) {
805 h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
806 h_scroll.Minimum = 0;
808 // if v_scroll is visible, adjust the maximum of the
809 // h_scroll to account for the width of v_scroll
810 if (v_scroll.Visible) {
811 h_scroll.Maximum = layout_wd + v_scroll.Width;
812 h_scroll.Width = client_area.Width - v_scroll.Width;
815 h_scroll.Maximum = layout_wd;
816 h_scroll.Width = client_area.Width;
819 h_scroll.LargeChange = client_area.Width;
820 h_scroll.SmallChange = Font.Height;
821 item_control.Height -= h_scroll.Height;
824 if (header_control.Visible)
825 header_control.Width = ClientRectangle.Width;
826 item_control.Width = ClientRectangle.Width;
828 if (v_scroll.Visible) {
829 v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
830 v_scroll.Minimum = 0;
832 // if h_scroll is visible, adjust the maximum of the
833 // v_scroll to account for the height of h_scroll
834 if (h_scroll.Visible) {
835 v_scroll.Maximum = layout_ht + h_scroll.Height;
836 v_scroll.Height = client_area.Height; // - h_scroll.Height already done
838 v_scroll.Maximum = layout_ht;
839 v_scroll.Height = client_area.Height;
842 v_scroll.LargeChange = client_area.Height;
843 v_scroll.SmallChange = Font.Height;
844 if (header_control.Visible)
845 header_control.Width -= v_scroll.Width;
846 item_control.Width -= v_scroll.Width;
850 ColumnHeader GetReorderedColumn (int index)
852 if (reordered_column_indices == null)
853 return Columns [index];
855 return Columns [reordered_column_indices [index]];
858 void ReorderColumn (ColumnHeader col, int index)
860 if (reordered_column_indices == null) {
861 reordered_column_indices = new int [Columns.Count];
862 for (int i = 0; i < Columns.Count; i++)
863 reordered_column_indices [i] = i;
866 if (reordered_column_indices [index] == col.Index)
869 int[] curr = reordered_column_indices;
870 int[] result = new int [Columns.Count];
872 for (int i = 0; i < Columns.Count; i++) {
873 if (curr_idx < Columns.Count && curr [curr_idx] == col.Index)
877 result [i] = col.Index;
879 result [i] = curr [curr_idx++];
882 reordered_column_indices = result;
884 header_control.Invalidate ();
885 item_control.Invalidate ();
888 Size LargeIconItemSize {
890 int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
891 int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
892 int w = CheckBoxSize.Width + 2 + Math.Max (text_size.Width, image_w);
893 int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
894 return new Size (w, h);
898 Size SmallIconItemSize {
900 int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
901 int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
902 int w = text_size.Width + 2 + CheckBoxSize.Width + image_w;
903 int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
904 return new Size (w, h);
910 ListViewItem[,] item_matrix;
912 void LayoutIcons (bool large_icons, bool left_aligned, int x_spacing, int y_spacing)
914 header_control.Visible = false;
915 header_control.Size = Size.Empty;
916 item_control.Location = Point.Empty;
918 if (items.Count == 0)
921 Size sz = large_icons ? LargeIconItemSize : SmallIconItemSize;
923 Rectangle area = ClientRectangle;
926 rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(sz.Height + y_spacing));
929 cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
931 cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(sz.Width + x_spacing));
934 rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
937 layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
938 layout_wd = cols * (sz.Width + x_spacing) - x_spacing;
939 item_matrix = new ListViewItem [rows, cols];
942 foreach (ListViewItem item in items) {
943 int x = col * (sz.Width + x_spacing);
944 int y = row * (sz.Height + y_spacing);
945 item.Location = new Point (x, y);
949 item_matrix [row, col] = item;
963 item_control.Size = new Size (layout_wd, layout_ht);
968 if (columns.Count == 0 || header_style == ColumnHeaderStyle.None) {
969 header_control.Visible = false;
970 header_control.Size = Size.Empty;
975 for (int i = 0; i < Columns.Count; i++) {
976 ColumnHeader col = GetReorderedColumn (i);
979 col.CalcColumnHeader ();
983 if (x < ClientRectangle.Width)
984 x = ClientRectangle.Width;
986 header_control.Width = x;
987 header_control.Height = columns [0].Ht;
988 header_control.is_visible = true;
991 void LayoutDetails ()
995 item_control.Location = new Point (0, header_control.Height);
998 if (items.Count > 0) {
999 foreach (ListViewItem item in items) {
1001 item.Location = new Point (0, y);
1002 y += item.Bounds.Height + 2;
1005 // some space for bottom gridline
1010 layout_wd = Math.Max (header_control.Width, item_control.Width);
1011 layout_ht = y + header_control.Height;
1014 private void CalculateListView (ListViewAlignment align)
1023 case View.SmallIcon:
1024 LayoutIcons (false, alignment == ListViewAlignment.Left, 4, 2);
1027 case View.LargeIcon:
1028 LayoutIcons (true, alignment == ListViewAlignment.Left,
1029 ThemeEngine.Current.ListViewHorizontalSpacing,
1030 ThemeEngine.Current.ListViewVerticalSpacing);
1034 LayoutIcons (false, true, 4, 2);
1038 CalculateScrollBars ();
1041 internal void UpdateSelection (ListViewItem item)
1043 if (item.Selected) {
1045 if (!CanMultiselect && SelectedItems.Count > 0) {
1046 SelectedItems.Clear ();
1047 SelectedIndices.list.Clear ();
1050 if (!SelectedItems.Contains (item)) {
1051 SelectedItems.list.Add (item);
1052 SelectedIndices.list.Add (item.Index);
1055 SelectedItems.list.Remove (item);
1056 SelectedIndices.list.Remove (item.Index);
1060 private bool KeySearchString (KeyEventArgs ke)
1062 int current_tickcnt = Environment.TickCount;
1063 if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
1064 keysearch_text = string.Empty;
1067 keysearch_text += (char) ke.KeyData;
1068 keysearch_tickcnt = current_tickcnt;
1070 int start = FocusedItem == null ? 0 : FocusedItem.Index;
1073 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (Items[i].Text, keysearch_text,
1074 CompareOptions.IgnoreCase)) {
1075 SetFocusedItem (Items [i]);
1076 items [i].Selected = true;
1080 i = (i + 1 < Items.Count) ? i+1 : 0;
1088 int GetAdjustedIndex (Keys key)
1092 if (View == View.Details) {
1094 result = FocusedItem.Index - 1;
1095 else if (key == Keys.Down) {
1096 result = FocusedItem.Index + 1;
1097 if (result == items.Count)
1103 int row = FocusedItem.row;
1104 int col = FocusedItem.col;
1110 return item_matrix [row, col - 1].Index;
1113 if (col == (cols - 1))
1115 while (item_matrix [row, col + 1] == null)
1117 return item_matrix [row, col + 1].Index;
1122 return item_matrix [row - 1, col].Index;
1125 if (row == (rows - 1))
1127 while (item_matrix [row + 1, col] == null)
1129 return item_matrix [row + 1, col].Index;
1136 ListViewItem selection_start;
1138 private void SelectItems (ArrayList sel_items)
1140 multiselecting = true;
1141 ArrayList curr_items = (ArrayList) SelectedItems.list.Clone ();
1142 foreach (ListViewItem item in curr_items)
1143 if (!sel_items.Contains (item))
1144 item.Selected = false;
1145 foreach (ListViewItem item in sel_items)
1146 item.Selected = true;
1147 multiselecting = false;
1150 private void UpdateMultiSelection (int index)
1152 bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
1153 bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
1154 ListViewItem item = items [index];
1156 if (shift_pressed && selection_start != null) {
1157 ArrayList list = new ArrayList ();
1158 int start = Math.Min (selection_start.Index, index);
1159 int end = Math.Max (selection_start.Index, index);
1160 if (View == View.Details) {
1161 for (int i = start; i <= end; i++)
1162 list.Add (items [i]);
1164 int left = Math.Min (items [start].col, items [end].col);
1165 int right = Math.Max (items [start].col, items [end].col);
1166 int top = Math.Min (items [start].row, items [end].row);
1167 int bottom = Math.Max (items [start].row, items [end].row);
1168 foreach (ListViewItem curr in items)
1169 if (curr.row >= top && curr.row <= bottom &&
1170 curr.col >= left && curr.col <= right)
1174 } else if (!ctrl_pressed) {
1175 SelectedItems.Clear ();
1176 SelectedIndices.list.Clear ();
1177 item.Selected = true;
1178 selection_start = item;
1182 private void ListView_KeyDown (object sender, KeyEventArgs ke)
1184 if (ke.Handled || Items.Count == 0)
1190 switch (ke.KeyCode) {
1193 index = Items.Count - 1;
1204 index = GetAdjustedIndex (ke.KeyCode);
1208 ke.Handled = KeySearchString (ke);
1216 UpdateMultiSelection (index);
1218 items [index].Selected = true;
1220 SetFocusedItem (items [index]);
1221 EnsureVisible (index);
1225 internal class ItemControl : Control {
1228 ListViewItem clicked_item;
1229 ListViewItem last_clicked_item;
1230 bool hover_processed = false;
1232 public ItemControl (ListView owner)
1235 DoubleClick += new EventHandler(ItemsDoubleClick);
1236 KeyDown += new KeyEventHandler (ItemsKeyDown);
1237 KeyUp += new KeyEventHandler (ItemsKeyUp);
1238 MouseDown += new MouseEventHandler(ItemsMouseDown);
1239 MouseMove += new MouseEventHandler(ItemsMouseMove);
1240 MouseHover += new EventHandler(ItemsMouseHover);
1241 MouseUp += new MouseEventHandler(ItemsMouseUp);
1242 MouseWheel += new MouseEventHandler(ItemsMouseWheel);
1245 void ItemsDoubleClick (object sender, EventArgs e)
1247 if (owner.activation == ItemActivation.Standard && owner.ItemActivate != null)
1248 owner.ItemActivate (this, e);
1251 void ItemsKeyDown (object sender, KeyEventArgs args)
1253 owner.OnKeyDown (args);
1256 void ItemsKeyUp (object sender, KeyEventArgs args)
1258 owner.OnKeyUp (args);
1268 BoxSelect box_select_mode = BoxSelect.None;
1269 ArrayList prev_selection;
1270 Point box_select_start;
1272 Rectangle box_select_rect;
1273 internal Rectangle BoxSelectRectangle {
1274 get { return box_select_rect; }
1276 if (box_select_rect == value)
1279 InvalidateBoxSelectRect ();
1280 box_select_rect = value;
1281 InvalidateBoxSelectRect ();
1285 void InvalidateBoxSelectRect ()
1287 if (BoxSelectRectangle.Size.IsEmpty)
1290 Rectangle edge = BoxSelectRectangle;
1296 edge.Y = BoxSelectRectangle.Bottom - 1;
1298 edge.Y = BoxSelectRectangle.Y - 1;
1300 edge.Height = BoxSelectRectangle.Height + 2;
1302 edge.X = BoxSelectRectangle.Right - 1;
1306 private Rectangle CalculateBoxSelectRectangle (Point pt)
1308 int left = Math.Min (box_select_start.X, pt.X);
1309 int right = Math.Max (box_select_start.X, pt.X);
1310 int top = Math.Min (box_select_start.Y, pt.Y);
1311 int bottom = Math.Max (box_select_start.Y, pt.Y);
1312 return Rectangle.FromLTRB (left, top, right, bottom);
1315 ArrayList BoxSelectedItems {
1317 ArrayList result = new ArrayList ();
1318 foreach (ListViewItem item in owner.Items) {
1319 Rectangle r = item.Bounds;
1321 r.Y += r.Height / 4;
1324 if (BoxSelectRectangle.IntersectsWith (r))
1331 private bool PerformBoxSelection (Point pt)
1333 if (box_select_mode == BoxSelect.None)
1336 BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
1338 ArrayList box_items = BoxSelectedItems;
1342 switch (box_select_mode) {
1344 case BoxSelect.Normal:
1348 case BoxSelect.Control:
1349 items = new ArrayList ();
1350 foreach (ListViewItem item in prev_selection)
1351 if (!box_items.Contains (item))
1353 foreach (ListViewItem item in box_items)
1354 if (!prev_selection.Contains (item))
1358 case BoxSelect.Shift:
1360 foreach (ListViewItem item in box_items)
1361 prev_selection.Remove (item);
1362 foreach (ListViewItem item in prev_selection)
1367 throw new Exception ("Unexpected Selection mode: " + box_select_mode);
1371 owner.SelectItems (items);
1377 private void ItemsMouseDown (object sender, MouseEventArgs me)
1379 if (owner.items.Count == 0)
1382 Point pt = new Point (me.X, me.Y);
1383 foreach (ListViewItem item in owner.items) {
1384 if (item.CheckRectReal.Contains (pt)) {
1385 CheckState curr_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1386 item.Checked = !item.Checked;
1388 CheckState new_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
1390 // Raise the ItemCheck event
1391 ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index, curr_state, new_state);
1392 owner.OnItemCheck (ice);
1396 if (owner.View == View.Details && !owner.FullRowSelect) {
1397 if (item.GetBounds (ItemBoundsPortion.Label).Contains (pt)) {
1398 clicked_item = item;
1402 if (item.Bounds.Contains (pt)) {
1403 clicked_item = item;
1410 if (clicked_item != null) {
1411 owner.SetFocusedItem (clicked_item);
1412 bool changed = !clicked_item.Selected;
1413 if (owner.MultiSelect && (XplatUI.State.ModifierKeys & Keys.Control) == 0)
1414 owner.UpdateMultiSelection (clicked_item.Index);
1416 clicked_item.Selected = true;
1419 owner.OnSelectedIndexChanged (EventArgs.Empty);
1421 // Raise double click if the item was clicked. On MS the
1422 // double click is only raised if you double click an item
1423 if (me.Clicks > 1 && clicked_item != null)
1424 owner.OnDoubleClick (EventArgs.Empty);
1425 else if (me.Clicks == 1 && clicked_item != null)
1426 owner.OnClick (EventArgs.Empty);
1428 if (owner.FocusedItem == null)
1429 owner.SetFocusedItem (owner.Items [0]);
1430 if (owner.MultiSelect) {
1431 Keys mods = XplatUI.State.ModifierKeys;
1432 if ((mods & Keys.Shift) != 0)
1433 box_select_mode = BoxSelect.Shift;
1434 else if ((mods & Keys.Control) != 0)
1435 box_select_mode = BoxSelect.Control;
1437 box_select_mode = BoxSelect.Normal;
1438 box_select_start = pt;
1439 prev_selection = (ArrayList) owner.SelectedItems.list.Clone ();
1440 } else if (owner.selected_indices.Count > 0) {
1441 owner.SelectedItems.Clear ();
1442 owner.SelectedIndices.list.Clear ();
1443 owner.OnSelectedIndexChanged (EventArgs.Empty);
1448 private void ItemsMouseMove (object sender, MouseEventArgs me)
1450 if (PerformBoxSelection (new Point (me.X, me.Y)))
1453 if (owner.HoverSelection && hover_processed) {
1455 Point pt = PointToClient (Control.MousePosition);
1456 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1457 if (item == null || item.Selected)
1460 hover_processed = false;
1461 XplatUI.ResetMouseHover (Handle);
1466 private void ItemsMouseHover (object sender, EventArgs e)
1468 if (Capture || !owner.HoverSelection)
1471 hover_processed = true;
1472 Point pt = PointToClient (Control.MousePosition);
1473 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1478 item.Selected = true;
1479 owner.OnSelectedIndexChanged (new EventArgs ());
1482 private void ItemsMouseUp (object sender, MouseEventArgs me)
1485 if (owner.Items.Count == 0)
1488 Point pt = new Point (me.X, me.Y);
1490 Rectangle rect = Rectangle.Empty;
1491 if (clicked_item != null) {
1492 if (owner.view == View.Details && !owner.full_row_select)
1493 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
1495 rect = clicked_item.Bounds;
1497 if (rect.Contains (pt)) {
1498 switch (owner.activation) {
1499 case ItemActivation.OneClick:
1500 owner.OnItemActivate (EventArgs.Empty);
1503 case ItemActivation.TwoClick:
1504 if (last_clicked_item == clicked_item) {
1505 owner.OnItemActivate (EventArgs.Empty);
1506 last_clicked_item = null;
1508 last_clicked_item = clicked_item;
1511 // DoubleClick activation is handled in another handler
1515 } else if (owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
1516 // Need this to clean up background clicks
1517 owner.SelectedItems.Clear ();
1518 owner.SelectedIndices.list.Clear ();
1519 owner.OnSelectedIndexChanged (EventArgs.Empty);
1522 clicked_item = null;
1523 box_select_start = Point.Empty;
1524 BoxSelectRectangle = Rectangle.Empty;
1525 prev_selection = null;
1526 box_select_mode = BoxSelect.None;
1529 private void ItemsMouseWheel (object sender, MouseEventArgs me)
1531 if (owner.Items.Count == 0)
1534 int lines = me.Delta / 120;
1539 switch (owner.View) {
1541 case View.SmallIcon:
1542 owner.Scroll (owner.v_scroll, -owner.Items [0].Bounds.Height * SystemInformation.MouseWheelScrollLines * lines);
1544 case View.LargeIcon:
1545 owner.Scroll (owner.v_scroll, -(owner.Items [0].Bounds.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
1548 owner.Scroll (owner.h_scroll, -owner.Items [0].Bounds.Width * lines);
1553 internal override void OnPaintInternal (PaintEventArgs pe)
1555 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
1559 internal override void OnPaintInternal (PaintEventArgs pe)
1564 CalculateScrollBars ();
1567 private void ListView_SizeChanged (object sender, EventArgs e)
1569 CalculateListView (alignment);
1572 private void SetFocusedItem (ListViewItem item)
1574 if (focused_item != null)
1575 focused_item.Focused = false;
1578 item.Focused = true;
1580 focused_item = item;
1583 private void HorizontalScroller (object sender, EventArgs e)
1585 // Avoid unnecessary flickering, when button is
1586 // kept pressed at the end
1587 if (h_marker != h_scroll.Value) {
1589 int pixels = h_marker - h_scroll.Value;
1591 h_marker = h_scroll.Value;
1592 if (header_control.Visible)
1593 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
1595 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
1599 private void VerticalScroller (object sender, EventArgs e)
1601 // Avoid unnecessary flickering, when button is
1602 // kept pressed at the end
1603 if (v_marker != v_scroll.Value) {
1604 int pixels = v_marker - v_scroll.Value;
1605 Rectangle area = item_control.ClientRectangle;
1606 v_marker = v_scroll.Value;
1607 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
1610 #endregion // Internal Methods Properties
1612 #region Protected Methods
1613 protected override void CreateHandle ()
1615 base.CreateHandle ();
1618 protected override void Dispose (bool disposing)
1621 h_scroll.Dispose ();
1622 v_scroll.Dispose ();
1624 large_image_list = null;
1625 small_image_list = null;
1626 state_image_list = null;
1629 base.Dispose (disposing);
1632 protected override bool IsInputKey (Keys keyData)
1649 return base.IsInputKey (keyData);
1652 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
1654 if (AfterLabelEdit != null)
1655 AfterLabelEdit (this, e);
1658 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
1660 if (BeforeLabelEdit != null)
1661 BeforeLabelEdit (this, e);
1664 protected virtual void OnColumnClick (ColumnClickEventArgs e)
1666 if (ColumnClick != null)
1667 ColumnClick (this, e);
1670 protected override void OnEnabledChanged (EventArgs e)
1672 base.OnEnabledChanged (e);
1675 protected override void OnFontChanged (EventArgs e)
1677 base.OnFontChanged (e);
1681 protected override void OnHandleCreated (EventArgs e)
1683 base.OnHandleCreated (e);
1686 protected override void OnHandleDestroyed (EventArgs e)
1688 base.OnHandleDestroyed (e);
1691 protected virtual void OnItemActivate (EventArgs e)
1693 if (ItemActivate != null)
1694 ItemActivate (this, e);
1697 protected virtual void OnItemCheck (ItemCheckEventArgs ice)
1699 if (ItemCheck != null)
1700 ItemCheck (this, ice);
1703 protected virtual void OnItemDrag (ItemDragEventArgs e)
1705 if (ItemDrag != null)
1709 protected virtual void OnSelectedIndexChanged (EventArgs e)
1711 if (SelectedIndexChanged != null)
1712 SelectedIndexChanged (this, e);
1715 protected override void OnSystemColorsChanged (EventArgs e)
1717 base.OnSystemColorsChanged (e);
1720 protected void RealizeProperties ()
1725 protected void UpdateExtendedStyles ()
1730 protected override void WndProc (ref Message m)
1732 base.WndProc (ref m);
1734 #endregion // Protected Methods
1736 #region Public Instance Methods
1737 public void ArrangeIcons ()
1739 ArrangeIcons (this.alignment);
1742 public void ArrangeIcons (ListViewAlignment alignment)
1744 // Icons are arranged only if view is set to LargeIcon or SmallIcon
1745 if (view == View.LargeIcon || view == View.SmallIcon) {
1746 this.CalculateListView (alignment);
1747 // we have done the calculations already
1748 this.Redraw (false);
1752 public void BeginUpdate ()
1754 // flag to avoid painting
1758 public void Clear ()
1761 items.Clear (); // Redraw (true) called here
1764 public void EndUpdate ()
1766 // flag to avoid painting
1769 // probably, now we need a redraw with recalculations
1773 public void EnsureVisible (int index)
1775 if (index < 0 || index >= items.Count || scrollable == false)
1778 Rectangle view_rect = item_control.ClientRectangle;
1779 Rectangle bounds = items [index].Bounds;
1781 if (view_rect.Contains (bounds))
1784 if (bounds.Left < 0)
1785 h_scroll.Value += bounds.Left;
1786 else if (bounds.Right > view_rect.Right)
1787 h_scroll.Value += (bounds.Right - view_rect.Right);
1790 v_scroll.Value += bounds.Top;
1791 else if (bounds.Bottom > view_rect.Bottom)
1792 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
1795 public ListViewItem GetItemAt (int x, int y)
1797 foreach (ListViewItem item in items) {
1798 if (item.Bounds.Contains (x, y))
1804 public Rectangle GetItemRect (int index)
1806 return GetItemRect (index, ItemBoundsPortion.Entire);
1809 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
1811 if (index < 0 || index >= items.Count)
1812 throw new IndexOutOfRangeException ("Invalid Index");
1814 return items [index].GetBounds (portion);
1819 if (sort_order != SortOrder.None)
1820 items.list.Sort (item_sorter);
1822 if (sort_order == SortOrder.Descending)
1823 items.list.Reverse ();
1828 public override string ToString ()
1830 int count = this.Items.Count;
1833 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
1835 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
1837 #endregion // Public Instance Methods
1842 class HeaderControl : Control {
1845 bool column_resize_active = false;
1846 ColumnHeader resize_column;
1847 ColumnHeader clicked_column;
1848 ColumnHeader drag_column;
1850 int drag_to_index = -1;
1852 public HeaderControl (ListView owner)
1855 MouseDown += new MouseEventHandler (HeaderMouseDown);
1856 MouseMove += new MouseEventHandler (HeaderMouseMove);
1857 MouseUp += new MouseEventHandler (HeaderMouseUp);
1860 private ColumnHeader ColumnAtX (int x)
1862 Point pt = new Point (x, 0);
1863 ColumnHeader result = null;
1864 foreach (ColumnHeader col in owner.Columns) {
1865 if (col.Rect.Contains (pt)) {
1873 private int GetReorderedIndex (ColumnHeader col)
1875 if (owner.reordered_column_indices == null)
1878 for (int i = 0; i < owner.Columns.Count; i++)
1879 if (owner.reordered_column_indices [i] == col.Index)
1881 throw new Exception ("Column index missing from reordered array");
1884 private void HeaderMouseDown (object sender, MouseEventArgs me)
1886 if (resize_column != null) {
1887 column_resize_active = true;
1892 clicked_column = ColumnAtX (me.X + owner.h_marker);
1894 if (clicked_column != null) {
1896 if (owner.AllowColumnReorder) {
1898 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
1899 drag_column.column_rect = clicked_column.Rect;
1900 drag_to_index = GetReorderedIndex (clicked_column);
1902 clicked_column.pressed = true;
1903 Rectangle bounds = clicked_column.Rect;
1904 bounds.X -= owner.h_marker;
1905 Invalidate (bounds);
1910 private void HeaderMouseMove (object sender, MouseEventArgs me)
1912 Point pt = new Point (me.X + owner.h_marker, me.Y);
1914 if (column_resize_active) {
1915 resize_column.Width = pt.X - resize_column.X;
1916 if (resize_column.Width < 0)
1917 resize_column.Width = 0;
1921 resize_column = null;
1923 if (clicked_column != null) {
1924 if (owner.AllowColumnReorder) {
1927 r = drag_column.column_rect;
1928 r.X = clicked_column.Rect.X + me.X - drag_x;
1929 drag_column.column_rect = r;
1931 int x = me.X + owner.h_marker;
1932 ColumnHeader over = ColumnAtX (x);
1934 drag_to_index = owner.Columns.Count;
1935 else if (x < over.X + over.Width / 2)
1936 drag_to_index = GetReorderedIndex (over);
1938 drag_to_index = GetReorderedIndex (over) + 1;
1941 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
1942 bool pressed = clicked_column.pressed;
1943 clicked_column.pressed = over == clicked_column;
1944 if (clicked_column.pressed ^ pressed) {
1945 Rectangle bounds = clicked_column.Rect;
1946 bounds.X -= owner.h_marker;
1947 Invalidate (bounds);
1953 for (int i = 0; i < owner.Columns.Count; i++) {
1954 Rectangle zone = owner.Columns [i].Rect;
1955 zone.X = zone.Right - 5;
1957 if (zone.Contains (pt)) {
1958 resize_column = owner.Columns [i];
1963 if (resize_column == null)
1964 Cursor = Cursors.Default;
1966 Cursor = Cursors.VSplit;
1969 void HeaderMouseUp (object sender, MouseEventArgs me)
1973 if (column_resize_active) {
1974 column_resize_active = false;
1975 resize_column = null;
1976 Cursor = Cursors.Default;
1980 if (clicked_column != null && clicked_column.pressed) {
1981 clicked_column.pressed = false;
1982 Rectangle bounds = clicked_column.Rect;
1983 bounds.X -= owner.h_marker;
1984 Invalidate (bounds);
1985 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
1988 if (drag_column != null && owner.AllowColumnReorder) {
1990 if (drag_to_index > GetReorderedIndex (clicked_column))
1992 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
1993 owner.ReorderColumn (clicked_column, drag_to_index);
1998 clicked_column = null;
2001 internal override void OnPaintInternal (PaintEventArgs pe)
2006 Theme theme = ThemeEngine.Current;
2007 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
2009 if (drag_column == null)
2013 if (drag_to_index == owner.Columns.Count)
2014 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
2016 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
2017 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
2021 public class CheckedIndexCollection : IList, ICollection, IEnumerable
2023 internal ArrayList list;
2024 private ListView owner;
2026 #region Public Constructor
2027 public CheckedIndexCollection (ListView owner)
2029 list = new ArrayList ();
2032 #endregion // Public Constructor
2034 #region Public Properties
2037 get { return list.Count; }
2040 public bool IsReadOnly {
2041 get { return true; }
2044 public int this [int index] {
2046 if (index < 0 || index >= list.Count)
2047 throw new ArgumentOutOfRangeException ("Index out of range.");
2048 return (int) list [index];
2052 bool ICollection.IsSynchronized {
2053 get { return false; }
2056 object ICollection.SyncRoot {
2057 get { return this; }
2060 bool IList.IsFixedSize {
2061 get { return true; }
2064 object IList.this [int index] {
2065 get { return this [index]; }
2066 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2068 #endregion // Public Properties
2070 #region Public Methods
2071 public bool Contains (int checkedIndex)
2073 return list.Contains (checkedIndex);
2076 public IEnumerator GetEnumerator ()
2078 return list.GetEnumerator ();
2081 void ICollection.CopyTo (Array dest, int index)
2083 list.CopyTo (dest, index);
2086 int IList.Add (object value)
2088 throw new NotSupportedException ("Add operation is not supported.");
2093 throw new NotSupportedException ("Clear operation is not supported.");
2096 bool IList.Contains (object checkedIndex)
2098 return list.Contains (checkedIndex);
2101 int IList.IndexOf (object checkedIndex)
2103 return list.IndexOf (checkedIndex);
2106 void IList.Insert (int index, object value)
2108 throw new NotSupportedException ("Insert operation is not supported.");
2111 void IList.Remove (object value)
2113 throw new NotSupportedException ("Remove operation is not supported.");
2116 void IList.RemoveAt (int index)
2118 throw new NotSupportedException ("RemoveAt operation is not supported.");
2121 public int IndexOf (int checkedIndex)
2123 return list.IndexOf (checkedIndex);
2125 #endregion // Public Methods
2127 } // CheckedIndexCollection
2129 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
2131 internal ArrayList list;
2132 private ListView owner;
2134 #region Public Constructor
2135 public CheckedListViewItemCollection (ListView owner)
2137 list = new ArrayList ();
2140 #endregion // Public Constructor
2142 #region Public Properties
2145 get { return list.Count; }
2148 public bool IsReadOnly {
2149 get { return true; }
2152 public ListViewItem this [int index] {
2154 if (index < 0 || index >= list.Count)
2155 throw new ArgumentOutOfRangeException ("Index out of range.");
2156 return (ListViewItem) list [index];
2160 bool ICollection.IsSynchronized {
2161 get { return list.IsSynchronized; }
2164 object ICollection.SyncRoot {
2165 get { return this; }
2168 bool IList.IsFixedSize {
2169 get { return true; }
2172 object IList.this [int index] {
2173 get { return this [index]; }
2174 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2176 #endregion // Public Properties
2178 #region Public Methods
2179 public bool Contains (ListViewItem item)
2181 return list.Contains (item);
2184 public void CopyTo (Array dest, int index)
2186 list.CopyTo (dest, index);
2189 public IEnumerator GetEnumerator ()
2191 return list.GetEnumerator ();
2194 int IList.Add (object value)
2196 throw new NotSupportedException ("Add operation is not supported.");
2201 throw new NotSupportedException ("Clear operation is not supported.");
2204 bool IList.Contains (object item)
2206 return list.Contains (item);
2209 int IList.IndexOf (object item)
2211 return list.IndexOf (item);
2214 void IList.Insert (int index, object value)
2216 throw new NotSupportedException ("Insert operation is not supported.");
2219 void IList.Remove (object value)
2221 throw new NotSupportedException ("Remove operation is not supported.");
2224 void IList.RemoveAt (int index)
2226 throw new NotSupportedException ("RemoveAt operation is not supported.");
2229 public int IndexOf (ListViewItem item)
2231 return list.IndexOf (item);
2233 #endregion // Public Methods
2235 } // CheckedListViewItemCollection
2237 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
2239 internal ArrayList list;
2240 private ListView owner;
2242 #region Public Constructor
2243 public ColumnHeaderCollection (ListView owner)
2245 list = new ArrayList ();
2248 #endregion // Public Constructor
2250 #region Public Properties
2253 get { return list.Count; }
2256 public bool IsReadOnly {
2257 get { return false; }
2260 public virtual ColumnHeader this [int index] {
2262 if (index < 0 || index >= list.Count)
2263 throw new ArgumentOutOfRangeException ("Index out of range.");
2264 return (ColumnHeader) list [index];
2268 bool ICollection.IsSynchronized {
2269 get { return true; }
2272 object ICollection.SyncRoot {
2273 get { return this; }
2276 bool IList.IsFixedSize {
2277 get { return list.IsFixedSize; }
2280 object IList.this [int index] {
2281 get { return this [index]; }
2282 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2284 #endregion // Public Properties
2286 #region Public Methods
2287 public virtual int Add (ColumnHeader value)
2290 value.owner = this.owner;
2291 idx = list.Add (value);
2292 if (owner.IsHandleCreated) {
2293 owner.Redraw (true);
2298 public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
2300 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2301 this.Add (colHeader);
2305 public virtual void AddRange (ColumnHeader [] values)
2307 foreach (ColumnHeader colHeader in values) {
2308 colHeader.owner = this.owner;
2312 owner.Redraw (true);
2315 public virtual void Clear ()
2318 owner.Redraw (true);
2321 public bool Contains (ColumnHeader value)
2323 return list.Contains (value);
2326 public IEnumerator GetEnumerator ()
2328 return list.GetEnumerator ();
2331 void ICollection.CopyTo (Array dest, int index)
2333 list.CopyTo (dest, index);
2336 int IList.Add (object value)
2338 if (! (value is ColumnHeader)) {
2339 throw new ArgumentException ("Not of type ColumnHeader", "value");
2342 return this.Add ((ColumnHeader) value);
2345 bool IList.Contains (object value)
2347 if (! (value is ColumnHeader)) {
2348 throw new ArgumentException ("Not of type ColumnHeader", "value");
2351 return this.Contains ((ColumnHeader) value);
2354 int IList.IndexOf (object value)
2356 if (! (value is ColumnHeader)) {
2357 throw new ArgumentException ("Not of type ColumnHeader", "value");
2360 return this.IndexOf ((ColumnHeader) value);
2363 void IList.Insert (int index, object value)
2365 if (! (value is ColumnHeader)) {
2366 throw new ArgumentException ("Not of type ColumnHeader", "value");
2369 this.Insert (index, (ColumnHeader) value);
2372 void IList.Remove (object value)
2374 if (! (value is ColumnHeader)) {
2375 throw new ArgumentException ("Not of type ColumnHeader", "value");
2378 this.Remove ((ColumnHeader) value);
2381 public int IndexOf (ColumnHeader value)
2383 return list.IndexOf (value);
2386 public void Insert (int index, ColumnHeader value)
2388 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2389 // but it's really only greater.
2390 if (index < 0 || index > list.Count)
2391 throw new ArgumentOutOfRangeException ("Index out of range.");
2393 value.owner = this.owner;
2394 list.Insert (index, value);
2395 owner.Redraw (true);
2398 public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
2400 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2401 this.Insert (index, colHeader);
2404 public virtual void Remove (ColumnHeader column)
2406 // TODO: Update Column internal index ?
2407 list.Remove (column);
2408 owner.Redraw (true);
2411 public virtual void RemoveAt (int index)
2413 if (index < 0 || index >= list.Count)
2414 throw new ArgumentOutOfRangeException ("Index out of range.");
2416 // TODO: Update Column internal index ?
2417 list.RemoveAt (index);
2418 owner.Redraw (true);
2420 #endregion // Public Methods
2423 } // ColumnHeaderCollection
2425 public class ListViewItemCollection : IList, ICollection, IEnumerable
2427 internal ArrayList list;
2428 private ListView owner;
2430 #region Public Constructor
2431 public ListViewItemCollection (ListView owner)
2433 list = new ArrayList ();
2436 #endregion // Public Constructor
2438 #region Public Properties
2441 get { return list.Count; }
2444 public bool IsReadOnly {
2445 get { return false; }
2448 public virtual ListViewItem this [int displayIndex] {
2450 if (displayIndex < 0 || displayIndex >= list.Count)
2451 throw new ArgumentOutOfRangeException ("Index out of range.");
2452 return (ListViewItem) list [displayIndex];
2456 if (displayIndex < 0 || displayIndex >= list.Count)
2457 throw new ArgumentOutOfRangeException ("Index out of range.");
2459 if (list.Contains (value))
2460 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2462 value.Owner = owner;
2463 list [displayIndex] = value;
2465 owner.Redraw (true);
2469 bool ICollection.IsSynchronized {
2470 get { return true; }
2473 object ICollection.SyncRoot {
2474 get { return this; }
2477 bool IList.IsFixedSize {
2478 get { return list.IsFixedSize; }
2481 object IList.this [int index] {
2482 get { return this [index]; }
2484 if (value is ListViewItem)
2485 this [index] = (ListViewItem) value;
2487 this [index] = new ListViewItem (value.ToString ());
2490 #endregion // Public Properties
2492 #region Public Methods
2493 public virtual ListViewItem Add (ListViewItem value)
2495 if (list.Contains (value))
2496 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2498 value.Owner = owner;
2501 if (owner.Sorting != SortOrder.None)
2504 owner.Redraw (true);
2509 public virtual ListViewItem Add (string text)
2511 ListViewItem item = new ListViewItem (text);
2512 return this.Add (item);
2515 public virtual ListViewItem Add (string text, int imageIndex)
2517 ListViewItem item = new ListViewItem (text, imageIndex);
2518 return this.Add (item);
2521 public void AddRange (ListViewItem [] values)
2524 owner.SelectedItems.list.Clear ();
2525 owner.SelectedIndices.list.Clear ();
2526 owner.CheckedItems.list.Clear ();
2527 owner.CheckedIndices.list.Clear ();
2529 foreach (ListViewItem item in values) {
2534 if (owner.Sorting != SortOrder.None)
2537 owner.Redraw (true);
2540 public virtual void Clear ()
2542 owner.SetFocusedItem (null);
2543 owner.h_scroll.Value = owner.v_scroll.Value = 0;
2545 owner.SelectedItems.list.Clear ();
2546 owner.SelectedIndices.list.Clear ();
2547 owner.CheckedItems.list.Clear ();
2548 owner.CheckedIndices.list.Clear ();
2549 owner.Redraw (true);
2552 public bool Contains (ListViewItem item)
2554 return list.Contains (item);
2557 public void CopyTo (Array dest, int index)
2559 list.CopyTo (dest, index);
2562 public IEnumerator GetEnumerator ()
2564 return list.GetEnumerator ();
2567 int IList.Add (object item)
2572 if (item is ListViewItem) {
2573 li = (ListViewItem) item;
2574 if (list.Contains (li))
2575 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2578 li = new ListViewItem (item.ToString ());
2581 result = list.Add (li);
2582 owner.Redraw (true);
2587 bool IList.Contains (object item)
2589 return list.Contains (item);
2592 int IList.IndexOf (object item)
2594 return list.IndexOf (item);
2597 void IList.Insert (int index, object item)
2599 if (item is ListViewItem)
2600 this.Insert (index, (ListViewItem) item);
2602 this.Insert (index, item.ToString ());
2605 void IList.Remove (object item)
2607 Remove ((ListViewItem) item);
2610 public int IndexOf (ListViewItem item)
2612 return list.IndexOf (item);
2615 public ListViewItem Insert (int index, ListViewItem item)
2617 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2618 // but it's really only greater.
2619 if (index < 0 || index > list.Count)
2620 throw new ArgumentOutOfRangeException ("Index out of range.");
2622 if (list.Contains (item))
2623 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2626 list.Insert (index, item);
2627 owner.Redraw (true);
2631 public ListViewItem Insert (int index, string text)
2633 return this.Insert (index, new ListViewItem (text));
2636 public ListViewItem Insert (int index, string text, int imageIndex)
2638 return this.Insert (index, new ListViewItem (text, imageIndex));
2641 public virtual void Remove (ListViewItem item)
2643 if (!list.Contains (item))
2646 owner.SelectedItems.list.Remove (item);
2647 owner.SelectedIndices.list.Remove (item.Index);
2648 owner.CheckedItems.list.Remove (item);
2649 owner.CheckedIndices.list.Remove (item.Index);
2651 owner.Redraw (true);
2654 public virtual void RemoveAt (int index)
2656 if (index < 0 || index >= list.Count)
2657 throw new ArgumentOutOfRangeException ("Index out of range.");
2659 list.RemoveAt (index);
2660 owner.SelectedItems.list.RemoveAt (index);
2661 owner.SelectedIndices.list.RemoveAt (index);
2662 owner.CheckedItems.list.RemoveAt (index);
2663 owner.CheckedIndices.list.RemoveAt (index);
2664 owner.Redraw (false);
2666 #endregion // Public Methods
2668 } // ListViewItemCollection
2670 public class SelectedIndexCollection : IList, ICollection, IEnumerable
2672 internal ArrayList list;
2673 private ListView owner;
2675 #region Public Constructor
2676 public SelectedIndexCollection (ListView owner)
2678 list = new ArrayList ();
2681 #endregion // Public Constructor
2683 #region Public Properties
2686 get { return list.Count; }
2689 public bool IsReadOnly {
2690 get { return true; }
2693 public int this [int index] {
2695 if (index < 0 || index >= list.Count)
2696 throw new ArgumentOutOfRangeException ("Index out of range.");
2697 return (int) list [index];
2701 bool ICollection.IsSynchronized {
2702 get { return list.IsSynchronized; }
2705 object ICollection.SyncRoot {
2706 get { return this; }
2709 bool IList.IsFixedSize {
2710 get { return true; }
2713 object IList.this [int index] {
2714 get { return this [index]; }
2715 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2717 #endregion // Public Properties
2719 #region Public Methods
2720 public bool Contains (int selectedIndex)
2722 return list.Contains (selectedIndex);
2725 public void CopyTo (Array dest, int index)
2727 list.CopyTo (dest, index);
2730 public IEnumerator GetEnumerator ()
2732 return list.GetEnumerator ();
2735 int IList.Add (object value)
2737 throw new NotSupportedException ("Add operation is not supported.");
2742 throw new NotSupportedException ("Clear operation is not supported.");
2745 bool IList.Contains (object selectedIndex)
2747 return list.Contains (selectedIndex);
2750 int IList.IndexOf (object selectedIndex)
2752 return list.IndexOf (selectedIndex);
2755 void IList.Insert (int index, object value)
2757 throw new NotSupportedException ("Insert operation is not supported.");
2760 void IList.Remove (object value)
2762 throw new NotSupportedException ("Remove operation is not supported.");
2765 void IList.RemoveAt (int index)
2767 throw new NotSupportedException ("RemoveAt operation is not supported.");
2770 public int IndexOf (int selectedIndex)
2772 return list.IndexOf (selectedIndex);
2774 #endregion // Public Methods
2776 } // SelectedIndexCollection
2778 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
2780 internal ArrayList list;
2781 private ListView owner;
2783 #region Public Constructor
2784 public SelectedListViewItemCollection (ListView owner)
2786 list = new ArrayList ();
2789 #endregion // Public Constructor
2791 #region Public Properties
2794 get { return list.Count; }
2797 public bool IsReadOnly {
2798 get { return true; }
2801 public ListViewItem this [int index] {
2803 if (index < 0 || index >= list.Count)
2804 throw new ArgumentOutOfRangeException ("Index out of range.");
2805 return (ListViewItem) list [index];
2809 bool ICollection.IsSynchronized {
2810 get { return list.IsSynchronized; }
2813 object ICollection.SyncRoot {
2814 get { return this; }
2817 bool IList.IsFixedSize {
2818 get { return true; }
2821 object IList.this [int index] {
2822 get { return this [index]; }
2823 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2825 #endregion // Public Properties
2827 #region Public Methods
2828 public void Clear ()
2830 ArrayList copy = (ArrayList) list.Clone ();
2831 for (int i = 0; i < copy.Count; i++)
2832 ((ListViewItem) copy [i]).Selected = false;
2837 public bool Contains (ListViewItem item)
2839 return list.Contains (item);
2842 public void CopyTo (Array dest, int index)
2844 list.CopyTo (dest, index);
2847 public IEnumerator GetEnumerator ()
2849 return list.GetEnumerator ();
2852 int IList.Add (object value)
2854 throw new NotSupportedException ("Add operation is not supported.");
2857 bool IList.Contains (object item)
2859 return list.Contains (item);
2862 int IList.IndexOf (object item)
2864 return list.IndexOf (item);
2867 void IList.Insert (int index, object value)
2869 throw new NotSupportedException ("Insert operation is not supported.");
2872 void IList.Remove (object value)
2874 throw new NotSupportedException ("Remove operation is not supported.");
2877 void IList.RemoveAt (int index)
2879 throw new NotSupportedException ("RemoveAt operation is not supported.");
2882 public int IndexOf (ListViewItem item)
2884 return list.IndexOf (item);
2886 #endregion // Public Methods
2888 } // SelectedListViewItemCollection
2890 #endregion // Subclasses