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