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;
1409 owner.SetFocusedItem (clicked_item);
1411 if (clicked_item != null) {
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.MultiSelect) {
1429 Keys mods = XplatUI.State.ModifierKeys;
1430 if ((mods & Keys.Shift) != 0)
1431 box_select_mode = BoxSelect.Shift;
1432 else if ((mods & Keys.Control) != 0)
1433 box_select_mode = BoxSelect.Control;
1435 box_select_mode = BoxSelect.Normal;
1436 box_select_start = pt;
1437 prev_selection = (ArrayList) owner.SelectedItems.list.Clone ();
1438 } else if (owner.selected_indices.Count > 0) {
1439 owner.SelectedItems.Clear ();
1440 owner.SelectedIndices.list.Clear ();
1441 owner.OnSelectedIndexChanged (EventArgs.Empty);
1446 private void ItemsMouseMove (object sender, MouseEventArgs me)
1448 if (PerformBoxSelection (new Point (me.X, me.Y)))
1451 if (owner.HoverSelection && hover_processed) {
1453 Point pt = PointToClient (Control.MousePosition);
1454 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1455 if (item == null || item.Selected)
1458 hover_processed = false;
1459 XplatUI.ResetMouseHover (Handle);
1464 private void ItemsMouseHover (object sender, EventArgs e)
1466 if (Capture || !owner.HoverSelection)
1469 hover_processed = true;
1470 Point pt = PointToClient (Control.MousePosition);
1471 ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
1476 item.Selected = true;
1477 owner.OnSelectedIndexChanged (new EventArgs ());
1480 private void ItemsMouseUp (object sender, MouseEventArgs me)
1483 if (owner.Items.Count == 0)
1486 Point pt = new Point (me.X, me.Y);
1488 Rectangle rect = Rectangle.Empty;
1489 if (clicked_item != null) {
1490 if (owner.view == View.Details && !owner.full_row_select)
1491 rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
1493 rect = clicked_item.Bounds;
1495 if (rect.Contains (pt)) {
1496 switch (owner.activation) {
1497 case ItemActivation.OneClick:
1498 owner.OnItemActivate (EventArgs.Empty);
1501 case ItemActivation.TwoClick:
1502 if (last_clicked_item == clicked_item) {
1503 owner.OnItemActivate (EventArgs.Empty);
1504 last_clicked_item = null;
1506 last_clicked_item = clicked_item;
1509 // DoubleClick activation is handled in another handler
1513 } else if (owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
1514 // Need this to clean up background clicks
1515 owner.SelectedItems.Clear ();
1516 owner.SelectedIndices.list.Clear ();
1517 owner.OnSelectedIndexChanged (EventArgs.Empty);
1520 clicked_item = null;
1521 box_select_start = Point.Empty;
1522 BoxSelectRectangle = Rectangle.Empty;
1523 prev_selection = null;
1524 box_select_mode = BoxSelect.None;
1527 private void ItemsMouseWheel (object sender, MouseEventArgs me)
1529 if (owner.Items.Count == 0)
1532 int lines = me.Delta / 120;
1537 switch (owner.View) {
1539 case View.SmallIcon:
1540 owner.Scroll (owner.v_scroll, -owner.Items [0].Bounds.Height * SystemInformation.MouseWheelScrollLines * lines);
1542 case View.LargeIcon:
1543 owner.Scroll (owner.v_scroll, -(owner.Items [0].Bounds.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
1546 owner.Scroll (owner.h_scroll, -owner.Items [0].Bounds.Width * lines);
1551 internal override void OnPaintInternal (PaintEventArgs pe)
1553 ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
1557 internal override void OnPaintInternal (PaintEventArgs pe)
1562 CalculateScrollBars ();
1565 private void ListView_SizeChanged (object sender, EventArgs e)
1567 CalculateListView (alignment);
1570 private void SetFocusedItem (ListViewItem item)
1572 if (focused_item != null)
1573 focused_item.Focused = false;
1576 item.Focused = true;
1578 focused_item = item;
1581 private void HorizontalScroller (object sender, EventArgs e)
1583 // Avoid unnecessary flickering, when button is
1584 // kept pressed at the end
1585 if (h_marker != h_scroll.Value) {
1587 int pixels = h_marker - h_scroll.Value;
1589 h_marker = h_scroll.Value;
1590 if (header_control.Visible)
1591 XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
1593 XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
1597 private void VerticalScroller (object sender, EventArgs e)
1599 // Avoid unnecessary flickering, when button is
1600 // kept pressed at the end
1601 if (v_marker != v_scroll.Value) {
1602 int pixels = v_marker - v_scroll.Value;
1603 Rectangle area = item_control.ClientRectangle;
1604 v_marker = v_scroll.Value;
1605 XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
1608 #endregion // Internal Methods Properties
1610 #region Protected Methods
1611 protected override void CreateHandle ()
1613 base.CreateHandle ();
1616 protected override void Dispose (bool disposing)
1619 h_scroll.Dispose ();
1620 v_scroll.Dispose ();
1622 large_image_list = null;
1623 small_image_list = null;
1624 state_image_list = null;
1627 base.Dispose (disposing);
1630 protected override bool IsInputKey (Keys keyData)
1647 return base.IsInputKey (keyData);
1650 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
1652 if (AfterLabelEdit != null)
1653 AfterLabelEdit (this, e);
1656 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
1658 if (BeforeLabelEdit != null)
1659 BeforeLabelEdit (this, e);
1662 protected virtual void OnColumnClick (ColumnClickEventArgs e)
1664 if (ColumnClick != null)
1665 ColumnClick (this, e);
1668 protected override void OnEnabledChanged (EventArgs e)
1670 base.OnEnabledChanged (e);
1673 protected override void OnFontChanged (EventArgs e)
1675 base.OnFontChanged (e);
1679 protected override void OnHandleCreated (EventArgs e)
1681 base.OnHandleCreated (e);
1684 protected override void OnHandleDestroyed (EventArgs e)
1686 base.OnHandleDestroyed (e);
1689 protected virtual void OnItemActivate (EventArgs e)
1691 if (ItemActivate != null)
1692 ItemActivate (this, e);
1695 protected virtual void OnItemCheck (ItemCheckEventArgs ice)
1697 if (ItemCheck != null)
1698 ItemCheck (this, ice);
1701 protected virtual void OnItemDrag (ItemDragEventArgs e)
1703 if (ItemDrag != null)
1707 protected virtual void OnSelectedIndexChanged (EventArgs e)
1709 if (SelectedIndexChanged != null)
1710 SelectedIndexChanged (this, e);
1713 protected override void OnSystemColorsChanged (EventArgs e)
1715 base.OnSystemColorsChanged (e);
1718 protected void RealizeProperties ()
1723 protected void UpdateExtendedStyles ()
1728 protected override void WndProc (ref Message m)
1730 base.WndProc (ref m);
1732 #endregion // Protected Methods
1734 #region Public Instance Methods
1735 public void ArrangeIcons ()
1737 ArrangeIcons (this.alignment);
1740 public void ArrangeIcons (ListViewAlignment alignment)
1742 // Icons are arranged only if view is set to LargeIcon or SmallIcon
1743 if (view == View.LargeIcon || view == View.SmallIcon) {
1744 this.CalculateListView (alignment);
1745 // we have done the calculations already
1746 this.Redraw (false);
1750 public void BeginUpdate ()
1752 // flag to avoid painting
1756 public void Clear ()
1759 items.Clear (); // Redraw (true) called here
1762 public void EndUpdate ()
1764 // flag to avoid painting
1767 // probably, now we need a redraw with recalculations
1771 public void EnsureVisible (int index)
1773 if (index < 0 || index >= items.Count || scrollable == false)
1776 Rectangle view_rect = item_control.ClientRectangle;
1777 Rectangle bounds = items [index].Bounds;
1779 if (view_rect.Contains (bounds))
1782 if (bounds.Left < 0)
1783 h_scroll.Value += bounds.Left;
1784 else if (bounds.Right > view_rect.Right)
1785 h_scroll.Value += (bounds.Right - view_rect.Right);
1788 v_scroll.Value += bounds.Top;
1789 else if (bounds.Bottom > view_rect.Bottom)
1790 v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
1793 public ListViewItem GetItemAt (int x, int y)
1795 foreach (ListViewItem item in items) {
1796 if (item.Bounds.Contains (x, y))
1802 public Rectangle GetItemRect (int index)
1804 return GetItemRect (index, ItemBoundsPortion.Entire);
1807 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
1809 if (index < 0 || index >= items.Count)
1810 throw new IndexOutOfRangeException ("Invalid Index");
1812 return items [index].GetBounds (portion);
1817 if (sort_order != SortOrder.None)
1818 items.list.Sort (item_sorter);
1820 if (sort_order == SortOrder.Descending)
1821 items.list.Reverse ();
1826 public override string ToString ()
1828 int count = this.Items.Count;
1831 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
1833 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
1835 #endregion // Public Instance Methods
1840 class HeaderControl : Control {
1843 bool column_resize_active = false;
1844 ColumnHeader resize_column;
1845 ColumnHeader clicked_column;
1846 ColumnHeader drag_column;
1848 int drag_to_index = -1;
1850 public HeaderControl (ListView owner)
1853 MouseDown += new MouseEventHandler (HeaderMouseDown);
1854 MouseMove += new MouseEventHandler (HeaderMouseMove);
1855 MouseUp += new MouseEventHandler (HeaderMouseUp);
1858 private ColumnHeader ColumnAtX (int x)
1860 Point pt = new Point (x, 0);
1861 ColumnHeader result = null;
1862 foreach (ColumnHeader col in owner.Columns) {
1863 if (col.Rect.Contains (pt)) {
1871 private int GetReorderedIndex (ColumnHeader col)
1873 if (owner.reordered_column_indices == null)
1876 for (int i = 0; i < owner.Columns.Count; i++)
1877 if (owner.reordered_column_indices [i] == col.Index)
1879 throw new Exception ("Column index missing from reordered array");
1882 private void HeaderMouseDown (object sender, MouseEventArgs me)
1884 if (resize_column != null) {
1885 column_resize_active = true;
1890 clicked_column = ColumnAtX (me.X + owner.h_marker);
1892 if (clicked_column != null) {
1894 if (owner.AllowColumnReorder) {
1896 drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
1897 drag_column.column_rect = clicked_column.Rect;
1898 drag_to_index = GetReorderedIndex (clicked_column);
1900 clicked_column.pressed = true;
1901 Rectangle bounds = clicked_column.Rect;
1902 bounds.X -= owner.h_marker;
1903 Invalidate (bounds);
1908 private void HeaderMouseMove (object sender, MouseEventArgs me)
1910 Point pt = new Point (me.X + owner.h_marker, me.Y);
1912 if (column_resize_active) {
1913 resize_column.Width = pt.X - resize_column.X;
1914 if (resize_column.Width < 0)
1915 resize_column.Width = 0;
1919 resize_column = null;
1921 if (clicked_column != null) {
1922 if (owner.AllowColumnReorder) {
1925 r = drag_column.column_rect;
1926 r.X = clicked_column.Rect.X + me.X - drag_x;
1927 drag_column.column_rect = r;
1929 int x = me.X + owner.h_marker;
1930 ColumnHeader over = ColumnAtX (x);
1932 drag_to_index = owner.Columns.Count;
1933 else if (x < over.X + over.Width / 2)
1934 drag_to_index = GetReorderedIndex (over);
1936 drag_to_index = GetReorderedIndex (over) + 1;
1939 ColumnHeader over = ColumnAtX (me.X + owner.h_marker);
1940 bool pressed = clicked_column.pressed;
1941 clicked_column.pressed = over == clicked_column;
1942 if (clicked_column.pressed ^ pressed) {
1943 Rectangle bounds = clicked_column.Rect;
1944 bounds.X -= owner.h_marker;
1945 Invalidate (bounds);
1951 for (int i = 0; i < owner.Columns.Count; i++) {
1952 Rectangle zone = owner.Columns [i].Rect;
1953 zone.X = zone.Right - 5;
1955 if (zone.Contains (pt)) {
1956 resize_column = owner.Columns [i];
1961 if (resize_column == null)
1962 Cursor = Cursors.Default;
1964 Cursor = Cursors.VSplit;
1967 void HeaderMouseUp (object sender, MouseEventArgs me)
1971 if (column_resize_active) {
1972 column_resize_active = false;
1973 resize_column = null;
1974 Cursor = Cursors.Default;
1978 if (clicked_column != null && clicked_column.pressed) {
1979 clicked_column.pressed = false;
1980 Rectangle bounds = clicked_column.Rect;
1981 bounds.X -= owner.h_marker;
1982 Invalidate (bounds);
1983 owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
1986 if (drag_column != null && owner.AllowColumnReorder) {
1988 if (drag_to_index > GetReorderedIndex (clicked_column))
1990 if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
1991 owner.ReorderColumn (clicked_column, drag_to_index);
1996 clicked_column = null;
1999 internal override void OnPaintInternal (PaintEventArgs pe)
2004 Theme theme = ThemeEngine.Current;
2005 theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
2007 if (drag_column == null)
2011 if (drag_to_index == owner.Columns.Count)
2012 target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
2014 target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
2015 theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
2019 public class CheckedIndexCollection : IList, ICollection, IEnumerable
2021 internal ArrayList list;
2022 private ListView owner;
2024 #region Public Constructor
2025 public CheckedIndexCollection (ListView owner)
2027 list = new ArrayList ();
2030 #endregion // Public Constructor
2032 #region Public Properties
2035 get { return list.Count; }
2038 public bool IsReadOnly {
2039 get { return true; }
2042 public int this [int index] {
2044 if (index < 0 || index >= list.Count)
2045 throw new ArgumentOutOfRangeException ("Index out of range.");
2046 return (int) list [index];
2050 bool ICollection.IsSynchronized {
2051 get { return false; }
2054 object ICollection.SyncRoot {
2055 get { return this; }
2058 bool IList.IsFixedSize {
2059 get { return true; }
2062 object IList.this [int index] {
2063 get { return this [index]; }
2064 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2066 #endregion // Public Properties
2068 #region Public Methods
2069 public bool Contains (int checkedIndex)
2071 return list.Contains (checkedIndex);
2074 public IEnumerator GetEnumerator ()
2076 return list.GetEnumerator ();
2079 void ICollection.CopyTo (Array dest, int index)
2081 list.CopyTo (dest, index);
2084 int IList.Add (object value)
2086 throw new NotSupportedException ("Add operation is not supported.");
2091 throw new NotSupportedException ("Clear operation is not supported.");
2094 bool IList.Contains (object checkedIndex)
2096 return list.Contains (checkedIndex);
2099 int IList.IndexOf (object checkedIndex)
2101 return list.IndexOf (checkedIndex);
2104 void IList.Insert (int index, object value)
2106 throw new NotSupportedException ("Insert operation is not supported.");
2109 void IList.Remove (object value)
2111 throw new NotSupportedException ("Remove operation is not supported.");
2114 void IList.RemoveAt (int index)
2116 throw new NotSupportedException ("RemoveAt operation is not supported.");
2119 public int IndexOf (int checkedIndex)
2121 return list.IndexOf (checkedIndex);
2123 #endregion // Public Methods
2125 } // CheckedIndexCollection
2127 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
2129 internal ArrayList list;
2130 private ListView owner;
2132 #region Public Constructor
2133 public CheckedListViewItemCollection (ListView owner)
2135 list = new ArrayList ();
2138 #endregion // Public Constructor
2140 #region Public Properties
2143 get { return list.Count; }
2146 public bool IsReadOnly {
2147 get { return true; }
2150 public ListViewItem this [int index] {
2152 if (index < 0 || index >= list.Count)
2153 throw new ArgumentOutOfRangeException ("Index out of range.");
2154 return (ListViewItem) list [index];
2158 bool ICollection.IsSynchronized {
2159 get { return list.IsSynchronized; }
2162 object ICollection.SyncRoot {
2163 get { return this; }
2166 bool IList.IsFixedSize {
2167 get { return true; }
2170 object IList.this [int index] {
2171 get { return this [index]; }
2172 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2174 #endregion // Public Properties
2176 #region Public Methods
2177 public bool Contains (ListViewItem item)
2179 return list.Contains (item);
2182 public void CopyTo (Array dest, int index)
2184 list.CopyTo (dest, index);
2187 public IEnumerator GetEnumerator ()
2189 return list.GetEnumerator ();
2192 int IList.Add (object value)
2194 throw new NotSupportedException ("Add operation is not supported.");
2199 throw new NotSupportedException ("Clear operation is not supported.");
2202 bool IList.Contains (object item)
2204 return list.Contains (item);
2207 int IList.IndexOf (object item)
2209 return list.IndexOf (item);
2212 void IList.Insert (int index, object value)
2214 throw new NotSupportedException ("Insert operation is not supported.");
2217 void IList.Remove (object value)
2219 throw new NotSupportedException ("Remove operation is not supported.");
2222 void IList.RemoveAt (int index)
2224 throw new NotSupportedException ("RemoveAt operation is not supported.");
2227 public int IndexOf (ListViewItem item)
2229 return list.IndexOf (item);
2231 #endregion // Public Methods
2233 } // CheckedListViewItemCollection
2235 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
2237 internal ArrayList list;
2238 private ListView owner;
2240 #region Public Constructor
2241 public ColumnHeaderCollection (ListView owner)
2243 list = new ArrayList ();
2246 #endregion // Public Constructor
2248 #region Public Properties
2251 get { return list.Count; }
2254 public bool IsReadOnly {
2255 get { return false; }
2258 public virtual ColumnHeader this [int index] {
2260 if (index < 0 || index >= list.Count)
2261 throw new ArgumentOutOfRangeException ("Index out of range.");
2262 return (ColumnHeader) list [index];
2266 bool ICollection.IsSynchronized {
2267 get { return true; }
2270 object ICollection.SyncRoot {
2271 get { return this; }
2274 bool IList.IsFixedSize {
2275 get { return list.IsFixedSize; }
2278 object IList.this [int index] {
2279 get { return this [index]; }
2280 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2282 #endregion // Public Properties
2284 #region Public Methods
2285 public virtual int Add (ColumnHeader value)
2288 value.owner = this.owner;
2289 idx = list.Add (value);
2290 if (owner.IsHandleCreated) {
2291 owner.Redraw (true);
2296 public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
2298 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2299 this.Add (colHeader);
2303 public virtual void AddRange (ColumnHeader [] values)
2305 foreach (ColumnHeader colHeader in values) {
2306 colHeader.owner = this.owner;
2310 owner.Redraw (true);
2313 public virtual void Clear ()
2316 owner.Redraw (true);
2319 public bool Contains (ColumnHeader value)
2321 return list.Contains (value);
2324 public IEnumerator GetEnumerator ()
2326 return list.GetEnumerator ();
2329 void ICollection.CopyTo (Array dest, int index)
2331 list.CopyTo (dest, index);
2334 int IList.Add (object value)
2336 if (! (value is ColumnHeader)) {
2337 throw new ArgumentException ("Not of type ColumnHeader", "value");
2340 return this.Add ((ColumnHeader) value);
2343 bool IList.Contains (object value)
2345 if (! (value is ColumnHeader)) {
2346 throw new ArgumentException ("Not of type ColumnHeader", "value");
2349 return this.Contains ((ColumnHeader) value);
2352 int IList.IndexOf (object value)
2354 if (! (value is ColumnHeader)) {
2355 throw new ArgumentException ("Not of type ColumnHeader", "value");
2358 return this.IndexOf ((ColumnHeader) value);
2361 void IList.Insert (int index, object value)
2363 if (! (value is ColumnHeader)) {
2364 throw new ArgumentException ("Not of type ColumnHeader", "value");
2367 this.Insert (index, (ColumnHeader) value);
2370 void IList.Remove (object value)
2372 if (! (value is ColumnHeader)) {
2373 throw new ArgumentException ("Not of type ColumnHeader", "value");
2376 this.Remove ((ColumnHeader) value);
2379 public int IndexOf (ColumnHeader value)
2381 return list.IndexOf (value);
2384 public void Insert (int index, ColumnHeader value)
2386 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2387 // but it's really only greater.
2388 if (index < 0 || index > list.Count)
2389 throw new ArgumentOutOfRangeException ("Index out of range.");
2391 value.owner = this.owner;
2392 list.Insert (index, value);
2393 owner.Redraw (true);
2396 public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
2398 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
2399 this.Insert (index, colHeader);
2402 public virtual void Remove (ColumnHeader column)
2404 // TODO: Update Column internal index ?
2405 list.Remove (column);
2406 owner.Redraw (true);
2409 public virtual void RemoveAt (int index)
2411 if (index < 0 || index >= list.Count)
2412 throw new ArgumentOutOfRangeException ("Index out of range.");
2414 // TODO: Update Column internal index ?
2415 list.RemoveAt (index);
2416 owner.Redraw (true);
2418 #endregion // Public Methods
2421 } // ColumnHeaderCollection
2423 public class ListViewItemCollection : IList, ICollection, IEnumerable
2425 internal ArrayList list;
2426 private ListView owner;
2428 #region Public Constructor
2429 public ListViewItemCollection (ListView owner)
2431 list = new ArrayList ();
2434 #endregion // Public Constructor
2436 #region Public Properties
2439 get { return list.Count; }
2442 public bool IsReadOnly {
2443 get { return false; }
2446 public virtual ListViewItem this [int displayIndex] {
2448 if (displayIndex < 0 || displayIndex >= list.Count)
2449 throw new ArgumentOutOfRangeException ("Index out of range.");
2450 return (ListViewItem) list [displayIndex];
2454 if (displayIndex < 0 || displayIndex >= list.Count)
2455 throw new ArgumentOutOfRangeException ("Index out of range.");
2457 if (list.Contains (value))
2458 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2460 value.Owner = owner;
2461 list [displayIndex] = value;
2463 owner.Redraw (true);
2467 bool ICollection.IsSynchronized {
2468 get { return true; }
2471 object ICollection.SyncRoot {
2472 get { return this; }
2475 bool IList.IsFixedSize {
2476 get { return list.IsFixedSize; }
2479 object IList.this [int index] {
2480 get { return this [index]; }
2482 if (value is ListViewItem)
2483 this [index] = (ListViewItem) value;
2485 this [index] = new ListViewItem (value.ToString ());
2488 #endregion // Public Properties
2490 #region Public Methods
2491 public virtual ListViewItem Add (ListViewItem value)
2493 if (list.Contains (value))
2494 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2496 value.Owner = owner;
2499 if (owner.Sorting != SortOrder.None)
2502 owner.Redraw (true);
2507 public virtual ListViewItem Add (string text)
2509 ListViewItem item = new ListViewItem (text);
2510 return this.Add (item);
2513 public virtual ListViewItem Add (string text, int imageIndex)
2515 ListViewItem item = new ListViewItem (text, imageIndex);
2516 return this.Add (item);
2519 public void AddRange (ListViewItem [] values)
2522 owner.SelectedItems.list.Clear ();
2523 owner.SelectedIndices.list.Clear ();
2524 owner.CheckedItems.list.Clear ();
2525 owner.CheckedIndices.list.Clear ();
2527 foreach (ListViewItem item in values) {
2532 if (owner.Sorting != SortOrder.None)
2535 owner.Redraw (true);
2538 public virtual void Clear ()
2540 owner.SetFocusedItem (null);
2541 owner.h_scroll.Value = owner.v_scroll.Value = 0;
2543 owner.SelectedItems.list.Clear ();
2544 owner.SelectedIndices.list.Clear ();
2545 owner.CheckedItems.list.Clear ();
2546 owner.CheckedIndices.list.Clear ();
2547 owner.Redraw (true);
2550 public bool Contains (ListViewItem item)
2552 return list.Contains (item);
2555 public void CopyTo (Array dest, int index)
2557 list.CopyTo (dest, index);
2560 public IEnumerator GetEnumerator ()
2562 return list.GetEnumerator ();
2565 int IList.Add (object item)
2570 if (item is ListViewItem) {
2571 li = (ListViewItem) item;
2572 if (list.Contains (li))
2573 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2576 li = new ListViewItem (item.ToString ());
2579 result = list.Add (li);
2580 owner.Redraw (true);
2585 bool IList.Contains (object item)
2587 return list.Contains (item);
2590 int IList.IndexOf (object item)
2592 return list.IndexOf (item);
2595 void IList.Insert (int index, object item)
2597 if (item is ListViewItem)
2598 this.Insert (index, (ListViewItem) item);
2600 this.Insert (index, item.ToString ());
2603 void IList.Remove (object item)
2605 Remove ((ListViewItem) item);
2608 public int IndexOf (ListViewItem item)
2610 return list.IndexOf (item);
2613 public ListViewItem Insert (int index, ListViewItem item)
2615 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2616 // but it's really only greater.
2617 if (index < 0 || index > list.Count)
2618 throw new ArgumentOutOfRangeException ("Index out of range.");
2620 if (list.Contains (item))
2621 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2624 list.Insert (index, item);
2625 owner.Redraw (true);
2629 public ListViewItem Insert (int index, string text)
2631 return this.Insert (index, new ListViewItem (text));
2634 public ListViewItem Insert (int index, string text, int imageIndex)
2636 return this.Insert (index, new ListViewItem (text, imageIndex));
2639 public virtual void Remove (ListViewItem item)
2641 if (!list.Contains (item))
2644 owner.SelectedItems.list.Remove (item);
2645 owner.SelectedIndices.list.Remove (item.Index);
2646 owner.CheckedItems.list.Remove (item);
2647 owner.CheckedIndices.list.Remove (item.Index);
2649 owner.Redraw (true);
2652 public virtual void RemoveAt (int index)
2654 if (index < 0 || index >= list.Count)
2655 throw new ArgumentOutOfRangeException ("Index out of range.");
2657 list.RemoveAt (index);
2658 owner.SelectedItems.list.RemoveAt (index);
2659 owner.SelectedIndices.list.RemoveAt (index);
2660 owner.CheckedItems.list.RemoveAt (index);
2661 owner.CheckedIndices.list.RemoveAt (index);
2662 owner.Redraw (false);
2664 #endregion // Public Methods
2666 } // ListViewItemCollection
2668 public class SelectedIndexCollection : IList, ICollection, IEnumerable
2670 internal ArrayList list;
2671 private ListView owner;
2673 #region Public Constructor
2674 public SelectedIndexCollection (ListView owner)
2676 list = new ArrayList ();
2679 #endregion // Public Constructor
2681 #region Public Properties
2684 get { return list.Count; }
2687 public bool IsReadOnly {
2688 get { return true; }
2691 public int this [int index] {
2693 if (index < 0 || index >= list.Count)
2694 throw new ArgumentOutOfRangeException ("Index out of range.");
2695 return (int) list [index];
2699 bool ICollection.IsSynchronized {
2700 get { return list.IsSynchronized; }
2703 object ICollection.SyncRoot {
2704 get { return this; }
2707 bool IList.IsFixedSize {
2708 get { return true; }
2711 object IList.this [int index] {
2712 get { return this [index]; }
2713 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2715 #endregion // Public Properties
2717 #region Public Methods
2718 public bool Contains (int selectedIndex)
2720 return list.Contains (selectedIndex);
2723 public void CopyTo (Array dest, int index)
2725 list.CopyTo (dest, index);
2728 public IEnumerator GetEnumerator ()
2730 return list.GetEnumerator ();
2733 int IList.Add (object value)
2735 throw new NotSupportedException ("Add operation is not supported.");
2740 throw new NotSupportedException ("Clear operation is not supported.");
2743 bool IList.Contains (object selectedIndex)
2745 return list.Contains (selectedIndex);
2748 int IList.IndexOf (object selectedIndex)
2750 return list.IndexOf (selectedIndex);
2753 void IList.Insert (int index, object value)
2755 throw new NotSupportedException ("Insert operation is not supported.");
2758 void IList.Remove (object value)
2760 throw new NotSupportedException ("Remove operation is not supported.");
2763 void IList.RemoveAt (int index)
2765 throw new NotSupportedException ("RemoveAt operation is not supported.");
2768 public int IndexOf (int selectedIndex)
2770 return list.IndexOf (selectedIndex);
2772 #endregion // Public Methods
2774 } // SelectedIndexCollection
2776 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
2778 internal ArrayList list;
2779 private ListView owner;
2781 #region Public Constructor
2782 public SelectedListViewItemCollection (ListView owner)
2784 list = new ArrayList ();
2787 #endregion // Public Constructor
2789 #region Public Properties
2792 get { return list.Count; }
2795 public bool IsReadOnly {
2796 get { return true; }
2799 public ListViewItem this [int index] {
2801 if (index < 0 || index >= list.Count)
2802 throw new ArgumentOutOfRangeException ("Index out of range.");
2803 return (ListViewItem) list [index];
2807 bool ICollection.IsSynchronized {
2808 get { return list.IsSynchronized; }
2811 object ICollection.SyncRoot {
2812 get { return this; }
2815 bool IList.IsFixedSize {
2816 get { return true; }
2819 object IList.this [int index] {
2820 get { return this [index]; }
2821 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2823 #endregion // Public Properties
2825 #region Public Methods
2826 public void Clear ()
2828 ArrayList copy = (ArrayList) list.Clone ();
2829 for (int i = 0; i < copy.Count; i++)
2830 ((ListViewItem) copy [i]).Selected = false;
2835 public bool Contains (ListViewItem item)
2837 return list.Contains (item);
2840 public void CopyTo (Array dest, int index)
2842 list.CopyTo (dest, index);
2845 public IEnumerator GetEnumerator ()
2847 return list.GetEnumerator ();
2850 int IList.Add (object value)
2852 throw new NotSupportedException ("Add operation is not supported.");
2855 bool IList.Contains (object item)
2857 return list.Contains (item);
2860 int IList.IndexOf (object item)
2862 return list.IndexOf (item);
2865 void IList.Insert (int index, object value)
2867 throw new NotSupportedException ("Insert operation is not supported.");
2870 void IList.Remove (object value)
2872 throw new NotSupportedException ("Remove operation is not supported.");
2875 void IList.RemoveAt (int index)
2877 throw new NotSupportedException ("RemoveAt operation is not supported.");
2880 public int IndexOf (ListViewItem item)
2882 return list.IndexOf (item);
2884 #endregion // Public Methods
2886 } // SelectedListViewItemCollection
2888 #endregion // Subclasses