* support-test-*.cs: Rename from test-*-p2.cs.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ListView.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2004-2005 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //      Ravindra Kumar (rkumar@novell.com)
24 //      Jordi Mas i Hernandez, jordi@ximian.com
25 //
26 // TODO:
27 //   - Item text editing
28 //   - Column resizing/reodering
29 //   - Feedback for item activation, change in cursor types as mouse moves.
30 //   - HideSelection
31 //   - LabelEdit
32 //   - Manual column resizing
33 //   - Drag and drop
34
35
36 // NOT COMPLETE
37
38
39 using System.Collections;
40 using System.ComponentModel;
41 using System.ComponentModel.Design;
42 using System.Drawing;
43 using System.Runtime.InteropServices;
44 using System.Globalization;
45
46 namespace System.Windows.Forms
47 {
48         [DefaultEvent ("SelectedIndexChanged")]
49         [DefaultProperty ("Items")]
50         [Designer ("System.Windows.Forms.Design.ListViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
51         public class ListView : Control
52         {
53                 private ItemActivation activation = ItemActivation.Standard;
54                 private ListViewAlignment alignment = ListViewAlignment.Top;
55                 private bool allow_column_reorder = false;
56                 private bool auto_arrange = true;
57                 private bool check_boxes = false;
58                 private CheckedIndexCollection checked_indices;
59                 private CheckedListViewItemCollection checked_items;
60                 private ColumnHeader clicked_column;
61                 private ListViewItem clicked_item;
62                 private ListViewItem last_clicked_item;
63                 private ColumnHeaderCollection columns;
64                 private bool ctrl_pressed;
65                 private bool shift_pressed;
66                 internal ListViewItem focused_item;
67                 private bool full_row_select = false;
68                 private bool grid_lines = false;
69                 private ColumnHeaderStyle header_style = ColumnHeaderStyle.Clickable;
70                 private bool hide_selection = true;
71                 private bool hover_selection = false;
72                 private IComparer item_sorter;
73                 private ListViewItemCollection items;
74                 private bool label_edit = false;
75                 private bool label_wrap = true;
76                 private bool multiselect = true;
77                 private bool scrollable = true;
78                 private SelectedIndexCollection selected_indices;
79                 private SelectedListViewItemCollection selected_items;
80                 private SortOrder sort_order = SortOrder.None;
81                 private ImageList state_image_list;
82                 private bool updating = false;
83                 private View view = View.LargeIcon;
84                 private int layout_wd;    // We might draw more than our client area
85                 private int layout_ht;    // therefore we need to have these two.
86                 //private TextBox editor;   // Used for editing an item text
87                 internal ScrollBar h_scroll; // used for scrolling horizontally
88                 internal ScrollBar v_scroll; // used for scrolling vertically
89                 internal int h_marker;          // Position markers for scrolling
90                 internal int v_marker;
91                 internal Rectangle client_area; // ClientRectangle - scrollbars
92                 private int keysearch_tickcnt;
93                 private string keysearch_text;
94                 static private readonly int keysearch_keydelay = 1000;
95
96                 // internal variables
97                 internal ImageList large_image_list;
98                 internal ImageList small_image_list;
99                 internal Size text_size = Size.Empty;
100
101                 #region Events
102                 public event LabelEditEventHandler AfterLabelEdit;
103
104                 [Browsable (false)]
105                 [EditorBrowsable (EditorBrowsableState.Never)]
106                 public new event EventHandler BackgroundImageChanged;
107
108                 public event LabelEditEventHandler BeforeLabelEdit;
109                 public event ColumnClickEventHandler ColumnClick;
110                 public event EventHandler ItemActivate;
111                 public event ItemCheckEventHandler ItemCheck;
112                 public event ItemDragEventHandler ItemDrag;
113
114                 [Browsable (false)]
115                 [EditorBrowsable (EditorBrowsableState.Never)]
116                 public new event PaintEventHandler Paint;
117
118                 public event EventHandler SelectedIndexChanged;
119
120                 [Browsable (false)]
121                 [EditorBrowsable (EditorBrowsableState.Never)]
122                 public new event EventHandler TextChanged;
123                 #endregion // Events
124
125                 #region Public Constructors
126                 public ListView ()
127                 {
128                         background_color = ThemeEngine.Current.ColorWindow;
129                         checked_indices = new CheckedIndexCollection (this);
130                         checked_items = new CheckedListViewItemCollection (this);
131                         columns = new ColumnHeaderCollection (this);
132                         foreground_color = SystemColors.WindowText;
133                         items = new ListViewItemCollection (this);
134                         selected_indices = new SelectedIndexCollection (this);
135                         selected_items = new SelectedListViewItemCollection (this);
136
137                         border_style = BorderStyle.Fixed3D;
138
139                         // we are mostly scrollable
140                         h_scroll = new HScrollBar ();
141                         v_scroll = new VScrollBar ();
142                         h_marker = v_marker = 0;
143                         keysearch_tickcnt = 0;
144
145                         // scroll bars are disabled initially
146                         h_scroll.Visible = false;
147                         h_scroll.ValueChanged += new EventHandler(HorizontalScroller);
148                         v_scroll.Visible = false;
149                         v_scroll.ValueChanged += new EventHandler(VerticalScroller);
150
151                         // event handlers
152                         base.DoubleClick += new EventHandler(ListView_DoubleClick);
153                         base.KeyDown += new KeyEventHandler(ListView_KeyDown);
154                         base.KeyUp += new KeyEventHandler(ListView_KeyUp);
155                         base.MouseDown += new MouseEventHandler(ListView_MouseDown);
156                         base.MouseHover += new EventHandler(ListView_MouseHover);
157                         base.MouseUp += new MouseEventHandler(ListView_MouseUp);
158                         base.MouseMove += new MouseEventHandler(ListView_MouseMove);
159                         base.Paint += new PaintEventHandler (ListView_Paint);
160                         SizeChanged += new EventHandler (ListView_SizeChanged);
161
162                         this.SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick, false);
163                 }
164                 #endregion      // Public Constructors
165
166                 #region Private Internal Properties
167                 internal Size CheckBoxSize {
168                         get {
169                                 if (this.check_boxes) {
170                                         if (this.state_image_list != null)
171                                                 return this.state_image_list.ImageSize;
172                                         else
173                                                 return ThemeEngine.Current.ListViewCheckBoxSize;
174                                 }
175                                 return Size.Empty;
176                         }
177                 }
178
179                 internal bool CanMultiselect {
180                         get {
181                                 if (this.multiselect &&
182                                         (this.ctrl_pressed || this.shift_pressed))
183                                         return true;
184                                 else
185                                         return false;
186                         }
187                 }
188                 #endregion      // Private Internal Properties
189
190                 #region  Protected Properties
191                 protected override CreateParams CreateParams {
192                         get { return base.CreateParams; }
193                 }
194
195                 protected override Size DefaultSize {
196                         get { return ThemeEngine.Current.ListViewDefaultSize; }
197                 }
198                 #endregion      // Protected Properties
199
200                 #region Public Instance Properties
201                 [DefaultValue (ItemActivation.Standard)]
202                 public ItemActivation Activation {
203                         get { return activation; }
204                         set { 
205                                 if (value != ItemActivation.Standard && value != ItemActivation.OneClick && 
206                                         value != ItemActivation.TwoClick) {
207                                         throw new InvalidEnumArgumentException (string.Format
208                                                 ("Enum argument value '{0}' is not valid for Activation", value));
209                                 }
210                                   
211                                 activation = value;
212                         }
213                 }
214
215                 [DefaultValue (ListViewAlignment.Top)]
216                 [Localizable (true)]
217                 public ListViewAlignment Alignment {
218                         get { return alignment; }
219                         set {
220                                 if (value != ListViewAlignment.Default && value != ListViewAlignment.Left && 
221                                         value != ListViewAlignment.SnapToGrid && value != ListViewAlignment.Top) {
222                                         throw new InvalidEnumArgumentException (string.Format 
223                                                 ("Enum argument value '{0}' is not valid for Alignment", value));
224                                 }
225                                 
226                                 if (this.alignment != value) {
227                                         alignment = value;
228                                         // alignment does not matter in Details/List views
229                                         if (this.view == View.LargeIcon ||
230                                             this.View == View.SmallIcon)
231                                                 this.Redraw (true);
232                                 }
233                         }
234                 }
235
236                 [DefaultValue (false)]
237                 public bool AllowColumnReorder {
238                         get { return allow_column_reorder; }
239                         set {
240                                 if (this.allow_column_reorder != value) {
241                                         allow_column_reorder = value;
242                                         // column reorder does not matter in Details view
243                                         if (this.view != View.Details)
244                                                 this.Redraw (true);
245                                 }
246                         }
247                 }
248
249                 [DefaultValue (true)]
250                 public bool AutoArrange {
251                         get { return auto_arrange; }
252                         set {
253                                 if (auto_arrange != value) {
254                                         auto_arrange = value;
255                                         // autoarrange does not matter in Details/List views
256                                         if (this.view == View.LargeIcon || this.View == View.SmallIcon)
257                                                 this.Redraw (true);
258                                 }
259                         }
260                 }
261
262                 public override Color BackColor {
263                         get {
264                                 if (background_color.IsEmpty)
265                                         return ThemeEngine.Current.ColorWindow;
266                                 else
267                                         return background_color;
268                         }
269                         set { background_color = value; }
270                 }
271
272                 [Browsable (false)]
273                 [EditorBrowsable (EditorBrowsableState.Never)]
274                 public override Image BackgroundImage {
275                         get { return background_image; }
276                         set {
277                                 if (value == background_image)
278                                         return;
279
280                                 background_image = value;
281                                 if (BackgroundImageChanged != null)
282                                         BackgroundImageChanged (this, new EventArgs ());
283                         }
284                 }
285
286                 [DefaultValue (BorderStyle.Fixed3D)]
287                 [DispId (-504)]
288                 public BorderStyle BorderStyle {
289                         get { return InternalBorderStyle; }
290                         set { InternalBorderStyle = value; }
291                 }
292
293                 [DefaultValue (false)]
294                 public bool CheckBoxes {
295                         get { return check_boxes; }
296                         set {
297                                 if (check_boxes != value) {
298                                         check_boxes = value;
299                                         this.Redraw (true);
300                                 }
301                         }
302                 }
303
304                 [Browsable (false)]
305                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
306                 public CheckedIndexCollection CheckedIndices {
307                         get { return checked_indices; }
308                 }
309
310                 [Browsable (false)]
311                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
312                 public CheckedListViewItemCollection CheckedItems {
313                         get { return checked_items; }
314                 }
315
316                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
317                 [Localizable (true)]
318                 [MergableProperty (false)]
319                 public ColumnHeaderCollection Columns {
320                         get { return columns; }
321                 }
322
323                 [Browsable (false)]
324                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
325                 public ListViewItem FocusedItem {
326                         get { return focused_item; }
327                 }
328
329                 public override Color ForeColor {
330                         get {
331                                 if (foreground_color.IsEmpty)
332                                         return ThemeEngine.Current.ColorWindowText;
333                                 else
334                                         return foreground_color;
335                         }
336                         set { foreground_color = value; }
337                 }
338
339                 [DefaultValue (false)]
340                 public bool FullRowSelect {
341                         get { return full_row_select; }
342                         set { full_row_select = value; }
343                 }
344
345                 [DefaultValue (false)]
346                 public bool GridLines {
347                         get { return grid_lines; }
348                         set {
349                                 if (grid_lines != value) {
350                                         grid_lines = value;
351                                         this.Redraw (false);
352                                 }
353                         }
354                 }
355
356                 [DefaultValue (ColumnHeaderStyle.Clickable)]
357                 public ColumnHeaderStyle HeaderStyle {
358                         get { return header_style; }
359                         set {
360                                 if (value != ColumnHeaderStyle.Clickable && value != ColumnHeaderStyle.Nonclickable  && 
361                                         value != ColumnHeaderStyle.None) {
362                                         throw new InvalidEnumArgumentException (string.Format 
363                                                 ("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
364                                 }
365                                 
366                                 if (header_style != value) {
367                                         header_style = value;
368                                         // header style matters only in Details view
369                                         if (this.view == View.Details)
370                                                 this.Redraw (false);
371                                 }
372                         }
373                 }
374
375                 [DefaultValue (true)]
376                 public bool HideSelection {
377                         get { return hide_selection; }
378                         set {
379                                 if (hide_selection != value) {
380                                         hide_selection = value;
381                                         this.Redraw (false);
382                                 }
383                         }
384                 }
385
386                 [DefaultValue (false)]
387                 public bool HoverSelection {
388                         get { return hover_selection; }
389                         set { hover_selection = value; }
390                 }
391
392                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
393                 [Localizable (true)]
394                 [MergableProperty (false)]              
395                 public ListViewItemCollection Items {
396                         get { return items; }
397                 }
398
399                 [DefaultValue (false)]
400                 public bool LabelEdit {
401                         get { return label_edit; }
402                         set { label_edit = value; }
403                 }
404
405                 [DefaultValue (true)]
406                 [Localizable (true)]
407                 public bool LabelWrap {
408                         get { return label_wrap; }
409                         set {
410                                 if (label_wrap != value) {
411                                         label_wrap = value;
412                                         this.Redraw (true);
413                                 }
414                         }
415                 }
416
417                 [DefaultValue (null)]
418                 public ImageList LargeImageList {
419                         get { return large_image_list; }
420                         set {
421                                 large_image_list = value;
422                                 this.Redraw (true);
423                         }
424                 }
425
426                 [Browsable (false)]
427                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
428                 public IComparer ListViewItemSorter {
429                         get { return item_sorter; }
430                         set { item_sorter = value; }
431                 }
432
433                 [DefaultValue (true)]
434                 public bool MultiSelect {
435                         get { return multiselect; }
436                         set { multiselect = value; }
437                 }
438
439                 [DefaultValue (true)]
440                 public bool Scrollable {
441                         get { return scrollable; }
442                         set {
443                                 if (scrollable != value) {
444                                         scrollable = value;
445                                         this.Redraw (true);
446                                 }
447                         }
448                 }
449
450                 [Browsable (false)]
451                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
452                 public SelectedIndexCollection SelectedIndices {
453                         get { return selected_indices; }
454                 }
455
456                 [Browsable (false)]
457                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
458                 public SelectedListViewItemCollection SelectedItems {
459                         get { return selected_items; }
460                 }
461
462                 [DefaultValue (null)]
463                 public ImageList SmallImageList {
464                         get { return small_image_list; }
465                         set {
466                                 small_image_list = value;
467                                 this.Redraw (true);
468                         }
469                 }
470
471                 [DefaultValue (SortOrder.None)]
472                 public SortOrder Sorting {
473                         get { return sort_order; }
474                         set { 
475                                 if (value != SortOrder.Ascending && value != SortOrder.Descending  && 
476                                         value != SortOrder.None) {
477                                         throw new InvalidEnumArgumentException (string.Format
478                                                 ("Enum argument value '{0}' is not valid for Sorting", value));
479                                 }
480                                 
481                                 if (sort_order != value)  {                     
482                                         sort_order = value; 
483                                         this.Redraw (false);
484                                 }
485                         }
486                 }
487
488                 [DefaultValue (null)]
489                 public ImageList StateImageList {
490                         get { return state_image_list; }
491                         set {
492                                 state_image_list = value;
493                                 this.Redraw (true);
494                         }
495                 }
496
497                 [Bindable (false)]
498                 [Browsable (false)]
499                 [EditorBrowsable (EditorBrowsableState.Never)]
500                 public override string Text {
501                         get { return text; } 
502                         set {
503                                 if (value == text)
504                                         return;
505
506                                 text = value;
507                                 this.Redraw (true);
508
509                                 if (TextChanged != null)
510                                         TextChanged (this, new EventArgs ());
511                         }
512                 }
513
514                 [Browsable (false)]
515                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
516                 public ListViewItem TopItem {
517                         get {
518                                 // there is no item
519                                 if (this.items.Count == 0)
520                                         return null;
521                                 // if contents are not scrolled
522                                 // it is the first item
523                                 else if (h_marker == 0 && v_marker == 0)
524                                         return this.items [0];
525                                 // do a hit test for the scrolled position
526                                 else {
527                                         foreach (ListViewItem item in this.items) {
528                                                 if (item.EntireRect.X >= h_marker && item.EntireRect.Y >= v_marker)
529                                                         return item;
530                                         }
531                                         return null;
532                                 }
533                         }
534                 }
535
536                 [DefaultValue (View.LargeIcon)]
537                 public View View {
538                         get { return view; }
539                         set { 
540                                 if (value != View.Details && value != View.LargeIcon  && 
541                                         value != View.List  && value != View.SmallIcon  ) {
542                                         throw new InvalidEnumArgumentException (string.Format
543                                                 ("Enum argument value '{0}' is not valid for View", value));
544                                 }
545                                 
546                                 if (view != value) {
547                                         h_scroll.Value = v_scroll.Value = 0;
548                                         view = value; 
549                                         Redraw (true);
550                                 }
551                         }
552                 }
553                 #endregion      // Public Instance Properties
554
555                 #region Internal Methods Properties
556                 
557                 internal int FirstVisibleIndex {
558                         get {
559                                 // there is no item
560                                 if (this.items.Count == 0)
561                                         return 0;
562                                                                         
563                                 if (h_marker == 0 && v_marker == 0)
564                                         return 0;                                       
565                                 
566                                 foreach (ListViewItem item in this.items) {
567                                         if (item.EntireRect.X + item.EntireRect.Width >= h_marker 
568                                                 && item.EntireRect.Y + item.EntireRect.Height >= v_marker)
569                                                 return item.Index;
570                                 }
571                                 return 0;
572
573                         }
574                 }
575
576                 
577                 internal int LastItemIndex {                    
578                         get {                                                   
579                                 for (int i = FirstVisibleIndex; i < Items.Count; i++) {                                         
580                                         if (Items[i].EntireRect.Y > v_marker + ClientRectangle.Bottom)                                          
581                                                         return i -1;                                    
582                                 }
583                                 
584                                 return Items.Count - 1;
585                         }
586                 }
587                 
588                 internal int TotalWidth {
589                         get { return Math.Max (this.Width, this.layout_wd); }
590                 }
591
592                 internal int TotalHeight {
593                         get { return Math.Max (this.Height, this.layout_ht); }
594                 }
595
596                 internal void Redraw (bool recalculate)
597                 {
598                         // Avoid calculations when control is being updated
599                         if (this.updating)
600                                 return;
601
602                         if (recalculate)
603                                 CalculateListView (this.alignment);
604
605                         Refresh ();
606                 }
607
608                 internal Size GetChildColumnSize (int index)
609                 {
610                         Size ret_size = Size.Empty;
611                         ColumnHeader col = this.columns [index];
612
613                         if (col.Width == -2) { // autosize = max(items, columnheader)
614                                 Size size = Size.Ceiling (this.DeviceContext.MeasureString
615                                                           (col.Text, this.Font));
616                                 ret_size = BiggestItem (index);
617                                 if (size.Width > ret_size.Width)
618                                         ret_size = size;
619                         }
620                         else { // -1 and all the values < -2 are put under one category
621                                 ret_size = BiggestItem (index);
622                                 // fall back to empty columns' width if no subitem is available for a column
623                                 if (ret_size.IsEmpty) {
624                                         ret_size.Width = ThemeEngine.Current.ListViewEmptyColumnWidth;
625                                         if (col.Text.Length > 0)
626                                                 ret_size.Height = Size.Ceiling (this.DeviceContext.MeasureString
627                                                                                 (col.Text, this.Font)).Height;
628                                         else
629                                                 ret_size.Height = this.Font.Height;
630                                 }
631                         }
632
633                         // adjust the size for icon and checkbox for 0th column
634                         if (index == 0) {
635                                 ret_size.Width += (this.CheckBoxSize.Width + 4);
636                                 if (this.small_image_list != null)
637                                         ret_size.Width += this.small_image_list.ImageSize.Width;
638                         }
639                         return ret_size;
640                 }
641
642                 // Returns the size of biggest item text in a column.
643                 private Size BiggestItem (int col)
644                 {
645                         Size temp = Size.Empty;
646                         Size ret_size = Size.Empty;
647
648                         // 0th column holds the item text, we check the size of
649                         // the various subitems falling in that column and get
650                         // the biggest one's size.
651                         foreach (ListViewItem item in items) {
652                                 if (col >= item.SubItems.Count)
653                                         continue;
654
655                                 temp = Size.Ceiling (this.DeviceContext.MeasureString
656                                                      (item.SubItems [col].Text, this.Font));
657                                 if (temp.Width > ret_size.Width)
658                                         ret_size = temp;
659                         }
660
661                         // adjustment for space
662                         if (!ret_size.IsEmpty)
663                                 ret_size.Width += 4;
664
665                         return ret_size;
666                 }
667
668                 // Sets the size of the biggest item text as per the view
669                 private void CalcTextSize ()
670                 {                       
671                         // clear the old value
672                         text_size = Size.Empty;
673
674                         if (items.Count == 0)
675                                 return;
676
677                         text_size = BiggestItem (0);
678
679                         if (view == View.LargeIcon && this.label_wrap) {
680                                 Size temp = Size.Empty;
681                                 if (this.check_boxes)
682                                         temp.Width += 2 * this.CheckBoxSize.Width;
683                                 if (large_image_list != null)
684                                         temp.Width += large_image_list.ImageSize.Width;
685                                 if (temp.Width == 0)
686                                         temp.Width = 43;
687                                 // wrapping is done for two lines only
688                                 if (text_size.Width > temp.Width) {
689                                         text_size.Width = temp.Width;
690                                         text_size.Height *= 2;
691                                 }
692                         }
693                         else if (view == View.List) {
694                                 // in list view max text shown in determined by the
695                                 // control width, even if scolling is enabled.
696                                 int max_wd = this.Width - (this.CheckBoxSize.Width - 2);
697                                 if (this.small_image_list != null)
698                                         max_wd -= this.small_image_list.ImageSize.Width;
699
700                                 if (text_size.Width > max_wd)
701                                         text_size.Width = max_wd;
702                         }
703
704                         // we do the default settings, if we have got 0's
705                         if (text_size.Height <= 0)
706                                 text_size.Height = this.Font.Height;
707                         if (text_size.Width <= 0)
708                                 text_size.Width = this.Width;
709
710                         // little adjustment
711                         text_size.Width += 4;
712                         text_size.Height += 2;
713                 }
714
715                 private void CalculateScrollBars ()
716                 {
717                         client_area = ClientRectangle;
718                         
719                         if (!this.scrollable || this.items.Count <= 0) {
720                                 h_scroll.Visible = false;
721                                 v_scroll.Visible = false;
722                                 return;
723                         }
724
725                         // making a scroll bar visible might make
726                         // other scroll bar visible                     
727                         if (layout_wd > client_area.Right) {
728                                 h_scroll.Visible = true;
729                                 if ((layout_ht + h_scroll.Height) > client_area.Bottom) {
730                                         v_scroll.Visible = true;                                        
731                                 }
732                                 else {
733                                         v_scroll.Visible = false;
734                                 }
735                         } else if (layout_ht > client_area.Bottom) {                            
736                                 v_scroll.Visible = true;
737                                 if ((layout_wd + v_scroll.Width) > client_area.Right) {
738                                         h_scroll.Visible = true;
739                                 }
740                                 else {
741                                         h_scroll.Visible = false;
742                                 }
743                         } else {
744                                 h_scroll.Visible = false;
745                                 v_scroll.Visible = false;
746                         }                       
747
748                         if (h_scroll.Visible) {
749                                 h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
750                                 h_scroll.Minimum = 0;
751
752                                 // if v_scroll is visible, adjust the maximum of the
753                                 // h_scroll to account for the width of v_scroll
754                                 if (v_scroll.Visible) {
755                                         h_scroll.Maximum = layout_wd + v_scroll.Width;
756                                         h_scroll.Width = client_area.Width - v_scroll.Width;
757                                 }
758                                 else {
759                                         h_scroll.Maximum = layout_wd;
760                                         h_scroll.Width = client_area.Width;
761                                 }
762    
763                                 h_scroll.LargeChange = client_area.Width;
764                                 h_scroll.SmallChange = Font.Height;
765                                 client_area.Height -= h_scroll.Height;
766                         }
767
768                         // vertical scrollbar
769                         if (v_scroll.Visible) {
770                                 v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
771                                 v_scroll.Minimum = 0;
772
773                                 // if h_scroll is visible, adjust the maximum of the
774                                 // v_scroll to account for the height of h_scroll
775                                 if (h_scroll.Visible) {
776                                         v_scroll.Maximum = layout_ht + h_scroll.Height;
777                                         v_scroll.Height = client_area.Height; // - h_scroll.Height already done 
778                                 } else {
779                                         v_scroll.Maximum = layout_ht;
780                                         v_scroll.Height = client_area.Height;
781                                 }
782
783                                 v_scroll.LargeChange = client_area.Height;
784                                 v_scroll.SmallChange = Font.Height;
785                                 client_area.Width -= v_scroll.Width;
786                         }
787                 }
788                 
789                 
790                 // Sets the location of every item on
791                 // the ListView as per the view
792                 private void CalculateListView (ListViewAlignment align)
793                 {
794                         int current_pos_x = 0; // our x-position marker
795                         int current_pos_y = 0; // our y-position marker
796                         int item_ht;
797                         int item_wd;
798                         int max;         // max x_pos or y_pos depending on the alignment
799                         int current = 0; // current row or column
800                         int vertical_spacing = ThemeEngine.Current.ListViewVerticalSpacing;
801                         int horizontal_spacing = ThemeEngine.Current.ListViewHorizontalSpacing;
802
803                         CalcTextSize ();
804
805                         switch (view) {
806
807                         case View.Details:
808                                 // ColumnHeaders are not drawn if headerstyle is none
809                                 int ht = (this.header_style == ColumnHeaderStyle.None) ? 
810                                         0 : this.Font.Height + 3;
811                                 
812                                 if (columns.Count > 0) {
813                                         foreach (ColumnHeader col in columns) {
814                                                 col.X = current_pos_x;
815                                                 col.Y = current_pos_y;
816                                                 col.CalcColumnHeader ();
817                                                 current_pos_x += col.Wd;
818                                         }
819                                         this.layout_wd = current_pos_x;
820                                 }
821                                 // set the position marker for placing items
822                                 // vertically down
823                                 current_pos_y = ht;
824
825                                 if (items.Count > 0) {
826                                         foreach (ListViewItem item in items) {
827                                                 item.location.X = 0;
828                                                 item.location.Y = current_pos_y;
829                                                 item.CalcListViewItem ();
830                                                 current_pos_y += item.EntireRect.Height;
831                                         }
832                                         this.layout_ht = current_pos_y;
833
834                                         // some space for bottom gridline
835                                         if (this.grid_lines)
836                                                 this.layout_ht += 2;
837                                 }
838                                 break;
839
840                         case View.SmallIcon:
841                                 vertical_spacing = 0;
842                                 horizontal_spacing = 0;
843                                 goto case View.LargeIcon;
844
845                         case View.LargeIcon:
846                                 if (items.Count > 0) {
847                                         items [0].CalcListViewItem ();
848                                         item_ht = items [0].EntireRect.Height;
849                                         item_wd = items [0].EntireRect.Width;
850
851                                         // top (default) and snaptogrid alignments are handled same way
852                                         if (align == ListViewAlignment.Left) {
853                                                 max = client_area.Height;
854                                                 foreach (ListViewItem item in items) {
855                                                         item.location.X = current_pos_x +
856                                                                 horizontal_spacing;
857                                                         item.location.Y = 0;
858                                                         item.CalcListViewItem ();
859                                                         current_pos_y += item_ht;
860
861                                                         current ++; // just to know about the last element
862                                                         // we just did the last item
863                                                         if (current == items.Count) {
864                                                                 if (max < current_pos_y)
865                                                                         max = current_pos_y;
866                                                                 current_pos_x = item.EntireRect.Right;
867                                                                 break;
868                                                         }
869                                                         else {
870                                                                 // is there enough space for another row ?
871                                                                 if ((current_pos_y + vertical_spacing
872                                                                      + item_ht) <= client_area.Height)
873                                                                         current_pos_y += vertical_spacing;
874                                                                 else {
875                                                                         // start another column
876                                                                         // make current_pos_y as the
877                                                                         // max value and reset
878                                                                         // current_pos_y value.
879                                                                         max = current_pos_y;
880                                                                         current_pos_x += item_wd;
881                                                                         current_pos_y = 0;
882                                                                 }
883                                                         }
884                                                 }
885                                                 // adjust the layout dimensions
886                                                 this.layout_ht = max;
887                                                 this.layout_wd = current_pos_x;
888                                         }
889                                         else { // other default/top alignment
890                                                 max = client_area.Width;
891                                                 foreach (ListViewItem item in items) {
892                                                         item.location.X = current_pos_x +
893                                                                 horizontal_spacing;
894
895                                                         item.location.Y = current_pos_y;
896                                                         item.CalcListViewItem ();
897                                                         current_pos_x += item_wd;
898
899                                                         current ++; // just to know about the last element
900                                                         // we just did the last item
901                                                         if (current == items.Count) {
902                                                                 if (max < current_pos_x)
903                                                                         max = current_pos_x;
904                                                                 current_pos_y = item.EntireRect.Bottom;
905                                                                 break;
906                                                         }
907                                                         else {
908                                                                 // is there enough space for another column?
909                                                                 if ((current_pos_x + horizontal_spacing
910                                                                      + item_wd) <= client_area.Width)
911                                                                         continue;
912                                                                 else {
913                                                                         // start another row
914                                                                         // make current_pos_x as the
915                                                                         // max value and reset
916                                                                         // current_pos_x value.
917                                                                         max = current_pos_x;
918                                                                         current_pos_y += (item_ht +
919                                                                                           vertical_spacing);
920                                                                         current_pos_x = 0;
921                                                                 }
922                                                         }
923                                                 }
924                                                 // adjust the layout dimensions
925                                                 this.layout_wd = max;
926                                                 this.layout_ht = current_pos_y;
927                                         }
928                                 }
929                                 break;
930
931                         case View.List:
932                                 if (items.Count > 0) {
933                                         items [0].CalcListViewItem ();
934                                         item_ht = items [0].EntireRect.Height;
935                                         item_wd = items [0].EntireRect.Width;
936
937                                         max = client_area.Height / item_ht;
938                                         if (max == 0)
939                                                 max = 1; // we draw at least one row
940
941                                         foreach (ListViewItem item in items) {
942                                                 item.location.X = current_pos_x;
943                                                 item.location.Y = current_pos_y;
944                                                 item.CalcListViewItem ();
945                                                 current ++;
946                                                 if (current == max) {
947                                                         current_pos_x += item_wd;
948                                                         current_pos_y = 0;
949                                                         current = 0;
950                                                 }
951                                                 else
952                                                         current_pos_y += item_ht;
953                                         }
954
955                                         // adjust the layout dimensions
956                                         this.layout_ht = max * item_ht;
957                                         if (current == 0) // we have fully filled layout
958                                                 this.layout_wd = current_pos_x;
959                                         else
960                                                 this.layout_wd = current_pos_x + item_wd;
961                                 }
962                                 break;
963                         }
964
965                         CalculateScrollBars ();
966                         
967                 }
968
969                 private bool KeySearchString (KeyEventArgs ke)
970                 {
971                         int current_tickcnt = Environment.TickCount;
972                         if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
973                                 keysearch_text = string.Empty;
974                         }
975                         
976                         keysearch_text += (char) ke.KeyData;
977                         keysearch_tickcnt = current_tickcnt;
978
979                         int i = FocusedItem.Index;
980                         while (true) {
981                                 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (Items[i].Text, keysearch_text,
982                                         CompareOptions.IgnoreCase)) {
983                                         SetFocusedItem (Items [i]);
984                                         items [i].Selected = true;
985                                         EnsureVisible (i);
986                                         break;
987                                 }
988                                 i = (i + 1  < Items.Count) ? i+1 : 0;
989
990                                 if (i == FocusedItem.Index)
991                                         break;
992                         }
993                         return true;
994                 }
995
996                                 
997                 // Event Handlers
998                 private void ListView_DoubleClick (object sender, EventArgs e)
999                 {
1000                         if (this.activation == ItemActivation.Standard
1001                             && this.ItemActivate != null)
1002                                 this.ItemActivate (this, e);
1003                 }
1004
1005                 private void ListView_KeyDown (object sender, KeyEventArgs ke)
1006                 {                       
1007                         int index = -1;
1008                         if (ke.Handled || Items.Count == 0)
1009                                 return;
1010
1011                         ke.Handled = true;
1012
1013                         switch (ke.KeyCode) {
1014
1015                         case Keys.ControlKey:
1016                                 ctrl_pressed = true;
1017                                 break;
1018
1019                         case Keys.Down:
1020                                 if (focused_item != null && focused_item.Index + 1 < Items.Count) {
1021                                         index = focused_item.Index + 1;
1022                                 }
1023                                 break;
1024
1025                         case Keys.End:
1026                                 index = Items.Count - 1;
1027                                 break;
1028
1029                         case Keys.Home:                 
1030                                 index = 0;
1031                                 break;
1032
1033                         case Keys.Left:
1034                                 index = -1;
1035                                 if (focused_item != null)
1036                                         index = focused_item.Index;
1037                                 else
1038                                         break;
1039
1040                                 if (index > 0)
1041                                         index -= 1;
1042                                                                         
1043                                 break;
1044
1045                         case Keys.Right:
1046                                 if (focused_item != null)
1047                                         index = focused_item.Index + 1;
1048                                 else
1049                                         index = 1;
1050
1051                                 if (index == items.Count)
1052                                         index = -1;
1053
1054                                 break;
1055
1056                         case Keys.ShiftKey:
1057                                 shift_pressed = true;
1058                                 break;
1059
1060                         case Keys.Up:                           
1061                                 if (focused_item != null)
1062                                         index = focused_item.Index;
1063                                 else
1064                                         break;
1065
1066                                 if (index > 0)
1067                                         index--;
1068
1069                                 if (index < 0) {
1070                                         index = -1;
1071                                 }
1072                                 break;
1073
1074                         default:
1075                                 if (KeySearchString (ke)) {
1076                                         ke.Handled = true;
1077                                 } else {
1078                                         ke.Handled = false;
1079                                 }
1080                                 return;
1081                         }
1082                         
1083                         if (index != -1) {
1084                                 items [index].Selected = true;
1085                                 SetFocusedItem (items [index]);                         
1086                                 EnsureVisible (index);
1087                         }
1088                 }
1089
1090                 private void ListView_KeyUp (object sender, KeyEventArgs ke)
1091                 {
1092                         if (!ke.Handled) {
1093                                 if (ke.KeyCode == Keys.ControlKey)
1094                                         this.ctrl_pressed = false;
1095
1096                                 if (ke.KeyCode == Keys.ShiftKey)
1097                                         this.shift_pressed = false;
1098                                 ke.Handled = true;
1099                         }
1100                 }
1101
1102                 private void ListView_MouseDown (object sender, MouseEventArgs me)
1103                 {
1104                         if (items.Count == 0)
1105                                 return;
1106
1107                         Point hit = Point.Empty;
1108                         if (this.HeaderStyle != ColumnHeaderStyle.None) {
1109                                 // take horizontal scrolling into account
1110                                 hit = new Point (me.X + h_marker, me.Y);
1111
1112                                 // hit test on columns
1113                                 if (this.view == View.Details && this.columns.Count > 0) {
1114                                         foreach (ColumnHeader col in this.columns) {
1115                                                 if (col.Rect.Contains (hit)) {
1116                                                         this.clicked_column = col;
1117                                                         this.Capture = true;
1118                                                         break;
1119                                                 }
1120                                         }
1121
1122                                         if (this.clicked_column != null) {
1123                                                 this.clicked_column.pressed = true;
1124                                                 this.Redraw (false);
1125                                                 return;
1126                                         }
1127                                 }
1128                         }
1129
1130                         // hit test on items
1131                         // we need to take scrolling into account
1132                         hit = new Point (me.X + h_marker, me.Y + v_marker);
1133                         foreach (ListViewItem item in this.items) {
1134                                 if (item.CheckRect.Contains (hit)) {
1135                                         CheckState curr_state = item.Checked ?
1136                                                 CheckState.Checked : CheckState.Unchecked;
1137                                         if (item.Checked)
1138                                                 item.Checked = false;
1139                                         else
1140                                                 item.Checked = true;
1141
1142                                         CheckState new_state = item.Checked ?
1143                                                 CheckState.Checked : CheckState.Unchecked;
1144                                         this.Redraw (false);
1145
1146                                         // Raise the ItemCheck event
1147                                         ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index,
1148                                                                                          curr_state,
1149                                                                                          new_state);
1150                                         this.OnItemCheck (ice);
1151                                         break;
1152                                 }
1153
1154                                 if (this.view == View.Details &&
1155                                     this.FullRowSelect == false) {
1156                                         if (item.LabelRect.Contains (hit)) {
1157                                                 this.clicked_item = item;
1158                                                 break;
1159                                         }
1160                                 }
1161                                 else {
1162                                         if (item.EntireRect.Contains (hit)) {
1163                                                 this.clicked_item = item;
1164                                                 break;
1165                                         }
1166                                 }
1167                         }
1168
1169                         // set the FocusedItem to be the current clicked_item
1170                         SetFocusedItem (clicked_item);
1171
1172                         if (clicked_item != null) {
1173                                 bool changed = !clicked_item.Selected;
1174                                 clicked_item.Selected = true;
1175                                 
1176                                 // Only Raise the event if the selected item has changed
1177                                 if (changed)
1178                                         OnSelectedIndexChanged (EventArgs.Empty);
1179
1180                                 // Raise double click if the item was clicked. On MS the
1181                                 // double click is only raised if you double click an item
1182                                 if (me.Clicks > 1 && this.clicked_item != null)
1183                                         OnDoubleClick (EventArgs.Empty);
1184                                 else if (me.Clicks == 1 && clicked_item != null)
1185                                         OnClick (EventArgs.Empty);
1186
1187                                 this.Redraw (false);
1188                         } else if (selected_indices.Count > 0) {
1189                                 // NOTE: selected_indices isn't computed properly so
1190                                 // this doesn't actually work
1191                                 
1192                                 // Raise the event if there was at least one item
1193                                 // selected and the user click on a dead area (unselecting all)
1194                                 OnSelectedIndexChanged (EventArgs.Empty);
1195                                 Redraw (false);
1196                         }
1197                 }
1198
1199                 private void ListView_MouseHover (object sender, EventArgs e)
1200                 {
1201                         // handle the hover events only when the mouse
1202                         // is not captured.
1203                         if (this.hover_selection == false || this.Capture)
1204                                 return;
1205
1206                         // hit test for the items
1207                         Point hit = this.PointToClient (Control.MousePosition);
1208                         ListViewItem item = this.GetItemAt (hit.X, hit.Y);
1209
1210                         if (item != null) {
1211                                 item.Selected = true;
1212                                 // Raise the event
1213                                 this.OnSelectedIndexChanged (new EventArgs ());
1214
1215                                 this.Redraw (false);
1216                         }
1217                 }
1218
1219                 private void ListView_MouseMove (object sender, MouseEventArgs me)
1220                 {
1221                         // Column header is always at the top. It can
1222                         // scroll only horizontally. So, we have to take
1223                         // only horizontal scrolling into account
1224                         Point hit = new Point (me.X + h_marker, me.Y);
1225
1226                         // non-null clicked_col means mouse down has happened
1227                         // on a column
1228                         if (this.clicked_column != null) {
1229                                 if (this.clicked_column.pressed == false &&
1230                                     this.clicked_column.Rect.Contains (hit)) {
1231                                         this.clicked_column.pressed = true;
1232                                         this.Redraw (false);
1233                                 }
1234                                 else if (this.clicked_column.pressed && 
1235                                          ! this.clicked_column.Rect.Contains (hit)) {
1236                                         this.clicked_column.pressed = false;
1237                                         this.Redraw (false);
1238                                 }
1239                         }
1240                 }
1241
1242                 private void ListView_MouseUp (object sender, MouseEventArgs me)
1243                 {
1244                         this.Capture = false;
1245                         if (items.Count == 0)
1246                                 return;
1247
1248                         Point hit = new Point (me.X, me.Y);
1249
1250                         if (this.clicked_column != null) {
1251                                 if (this.clicked_column.pressed) {
1252                                         this.clicked_column.pressed = false;
1253                                         this.Redraw (false);
1254
1255                                         // Raise the ColumnClick event
1256                                         this.OnColumnClick (new ColumnClickEventArgs
1257                                                             (this.clicked_column.Index));
1258                                 }
1259                         }
1260
1261                         // Raise the ItemActivate event
1262                         Rectangle rect = Rectangle.Empty;
1263                         if (this.clicked_item != null) {
1264                                 if (this.view == View.Details && !this.full_row_select)
1265                                         rect = this.clicked_item.LabelRect;
1266                                 else
1267                                         rect = this.clicked_item.EntireRect;
1268
1269                                 // We handle double click in a separate handler
1270                                 if (this.activation != ItemActivation.Standard &&
1271                                     rect.Contains (hit)) {
1272                                         if (this.activation == ItemActivation.OneClick)
1273                                                 this.ItemActivate (this, EventArgs.Empty);
1274
1275                                         // ItemActivate is raised on the second click on the same item
1276                                         else if (this.activation == ItemActivation.TwoClick) {
1277                                                 if (this.last_clicked_item == this.clicked_item) {
1278                                                         this.ItemActivate (this, EventArgs.Empty);
1279                                                         this.last_clicked_item = null;
1280                                                 }
1281                                                 else
1282                                                         this.last_clicked_item = this.clicked_item;
1283                                         }
1284                                 }
1285                         }
1286
1287                         this.clicked_column = null;
1288                         this.clicked_item = null;
1289                 }
1290
1291                 private void ListView_Paint (object sender, PaintEventArgs pe)
1292                 {
1293                         if (this.Width <= 0 || this.Height <=  0 ||
1294                             this.Visible == false || this.updating == true)
1295                                 return; 
1296                                 
1297                         CalculateScrollBars ();
1298
1299                         ThemeEngine.Current.DrawListView (pe.Graphics,
1300                                         pe.ClipRectangle, this);
1301                                         
1302                         // Raise the Paint event
1303                         if (Paint != null)
1304                                 Paint (this, pe);
1305                 }
1306
1307                 private void ListView_SizeChanged (object sender, EventArgs e)
1308                 {
1309                         CalculateListView (alignment);
1310                 }
1311                 
1312                 private void SetFocusedItem (ListViewItem item)
1313                 {
1314                         if (focused_item != null)
1315                                 focused_item.Focused = false;
1316                         
1317                         if (item != null)
1318                                 item.Focused = true;
1319                                 
1320                         focused_item = item;
1321                 }
1322
1323                 private void HorizontalScroller (object sender, EventArgs e)
1324                 {
1325                         // Avoid unnecessary flickering, when button is
1326                         // kept pressed at the end
1327                         if (h_marker != h_scroll.Value) {
1328                                 
1329                                 int pixels =  h_marker - h_scroll.Value;
1330                                 Rectangle area = client_area;
1331                                 
1332                                 if (View == View.Details && Columns.Count > 0) {
1333                                         area.Y += Columns[0].Ht;
1334                                         area.Height -= Columns[0].Ht;
1335                                 }
1336                                 
1337                                 h_marker = h_scroll.Value;
1338                                 XplatUI.ScrollWindow (Handle, area, pixels, 0, false);
1339                         }
1340                 }
1341
1342                 private void VerticalScroller (object sender, EventArgs e)
1343                 {
1344                         // Avoid unnecessary flickering, when button is
1345                         // kept pressed at the end
1346                         if (v_marker != v_scroll.Value) {
1347                                 int pixels =  v_marker - v_scroll.Value;
1348                                 Rectangle area = client_area;
1349                                 
1350                                 if (View == View.Details && header_style != ColumnHeaderStyle.None && Columns.Count > 0) {
1351                                         area.Y += Columns[0].Ht;
1352                                         area.Height -= Columns[0].Ht;
1353                                 }
1354                                 
1355                                 v_marker = v_scroll.Value;
1356                                 XplatUI.ScrollWindow (Handle, area, 0, pixels, false);
1357                         }
1358                 }
1359                 #endregion      // Internal Methods Properties
1360
1361                 #region Protected Methods
1362                 protected override void CreateHandle ()
1363                 {
1364                         base.CreateHandle ();
1365                 }
1366
1367                 protected override void Dispose (bool disposing)
1368                 {                       
1369                         if (disposing) {                        
1370                                 h_scroll.Dispose ();
1371                                 v_scroll.Dispose ();
1372                                 
1373                                 large_image_list = null;
1374                                 small_image_list = null;
1375                                 state_image_list = null;
1376                         }
1377                         
1378                         base.Dispose (disposing);
1379                 }
1380
1381                 protected override bool IsInputKey (Keys keyData)
1382                 {
1383                         switch (keyData) {
1384                         case Keys.Up:
1385                         case Keys.Down:
1386                         case Keys.PageUp:
1387                         case Keys.PageDown:
1388                         case Keys.Right:
1389                         case Keys.Left:
1390                         case Keys.End:
1391                         case Keys.Home:                         
1392                                 return true;
1393
1394                         default:
1395                                 break;
1396                         }
1397                         
1398                         return base.IsInputKey (keyData);
1399                 }
1400
1401                 protected virtual void OnAfterLabelEdit (LabelEditEventArgs e)
1402                 {
1403                         if (AfterLabelEdit != null)
1404                                 AfterLabelEdit (this, e);
1405                 }
1406
1407                 protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e)
1408                 {
1409                         if (BeforeLabelEdit != null)
1410                                 BeforeLabelEdit (this, e);
1411                 }
1412
1413                 protected virtual void OnColumnClick (ColumnClickEventArgs e)
1414                 {
1415                         if (ColumnClick != null)
1416                                 ColumnClick (this, e);
1417                 }
1418
1419                 protected override void OnEnabledChanged (EventArgs e)
1420                 {
1421                         base.OnEnabledChanged (e);
1422                 }
1423
1424                 protected override void OnFontChanged (EventArgs e)
1425                 {
1426                         base.OnFontChanged (e);
1427                         Redraw (true);
1428                 }
1429
1430                 protected override void OnHandleCreated (EventArgs e)
1431                 {
1432                         base.OnHandleCreated (e);
1433                         SuspendLayout ();
1434                         Controls.AddImplicit (this.v_scroll);
1435                         Controls.AddImplicit (this.h_scroll);
1436                         ResumeLayout ();
1437                 }
1438
1439                 protected override void OnHandleDestroyed (EventArgs e)
1440                 {
1441                         base.OnHandleDestroyed (e);
1442                 }
1443
1444                 protected virtual void OnItemActivate (EventArgs e)
1445                 {
1446                         if (ItemActivate != null)
1447                                 ItemActivate (this, e);
1448                 }
1449
1450                 protected virtual void OnItemCheck (ItemCheckEventArgs ice)
1451                 {
1452                         if (ItemCheck != null)
1453                                 ItemCheck (this, ice);
1454                 }
1455
1456                 protected virtual void OnItemDrag (ItemDragEventArgs e)
1457                 {
1458                         if (ItemDrag != null)
1459                                 ItemDrag (this, e);
1460                 }
1461
1462                 protected virtual void OnSelectedIndexChanged (EventArgs e)
1463                 {
1464                         if (SelectedIndexChanged != null)
1465                                 SelectedIndexChanged (this, e);
1466                 }
1467
1468                 protected override void OnSystemColorsChanged (EventArgs e)
1469                 {
1470                         base.OnSystemColorsChanged (e);
1471                 }
1472
1473                 protected void RealizeProperties ()
1474                 {
1475                         // FIXME: TODO
1476                 }
1477
1478                 protected void UpdateExtendedStyles ()
1479                 {
1480                         // FIXME: TODO
1481                 }
1482
1483                 protected override void WndProc (ref Message m)
1484                 {
1485                         base.WndProc (ref m);
1486                 }
1487                 #endregion // Protected Methods
1488
1489                 #region Public Instance Methods
1490                 public void ArrangeIcons ()
1491                 {
1492                         ArrangeIcons (this.alignment);
1493                 }
1494
1495                 public void ArrangeIcons (ListViewAlignment alignment)
1496                 {
1497                         // Icons are arranged only if view is set to LargeIcon or SmallIcon
1498                         if (view == View.LargeIcon || view == View.SmallIcon) {
1499                                 this.CalculateListView (alignment);
1500                                 // we have done the calculations already
1501                                 this.Redraw (false);
1502                         }
1503                 }
1504
1505                 public void BeginUpdate ()
1506                 {
1507                         // flag to avoid painting
1508                         updating = true;
1509                 }
1510
1511                 public void Clear ()
1512                 {
1513                         columns.Clear ();
1514                         items.Clear (); // Redraw (true) called here                    
1515                 }
1516
1517                 public void EndUpdate ()
1518                 {
1519                         // flag to avoid painting
1520                         updating = false;
1521
1522                         // probably, now we need a redraw with recalculations
1523                         this.Redraw (true);
1524                 }
1525
1526                 public void EnsureVisible (int index)
1527                 {
1528                         if (index < 0 || index >= this.items.Count || this.scrollable == false)
1529                                 return;
1530
1531                         // dimensions of visible area
1532                         int view_wd = client_area.Width;
1533                         int view_ht = client_area.Height;
1534                         // visible area is decided by the h_marker and v_marker
1535                         Rectangle view_rect = new Rectangle (h_marker, v_marker, view_wd, view_ht);
1536                         
1537                         // an item's bounding rect
1538                         Rectangle rect = this.items [index].EntireRect;
1539
1540                         // we don't need to do anything if item is visible.
1541                         // visible area is represented by (0,0,view_wd,view_ht)
1542                         if (view_rect.Contains (rect))
1543                                 return;
1544
1545                         // Scroll Left or Up
1546                         if ((rect.Left < view_rect.Left) || (rect.Top < view_rect.Top)) {
1547                                 if (rect.Left < view_rect.Left)
1548                                         this.h_scroll.Value -= (view_rect.Left - rect.Left);
1549                                 if (rect.Top < view_rect.Top)
1550                                         this.v_scroll.Value -= (view_rect.Top - rect.Top);
1551                         }
1552                         // Scroll Right or Down
1553                         else {
1554                                 if (rect.Right > view_rect.Right)
1555                                         this.h_scroll.Value += (rect.Right - view_rect.Right);
1556                                 if (rect.Bottom > view_rect.Bottom)
1557                                         this.v_scroll.Value += (rect.Bottom - view_rect.Bottom);
1558                         }
1559                 }
1560                 
1561                 public ListViewItem GetItemAt (int x, int y)
1562                 {
1563                         foreach (ListViewItem item in items) {
1564                                 if (item.Bounds.Contains (x, y))
1565                                         return item;
1566                         }
1567                         return null;
1568                 }
1569
1570                 public Rectangle GetItemRect (int index)
1571                 {
1572                         return GetItemRect (index, ItemBoundsPortion.Entire);
1573                 }
1574
1575                 public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
1576                 {
1577                         if (index < 0 || index >= items.Count)
1578                                 throw new IndexOutOfRangeException ("Invalid Index");
1579
1580                         return items [index].GetBounds (portion);
1581                 }
1582
1583                 public void Sort ()
1584                 {
1585                         if (sort_order != SortOrder.None)
1586                                 items.list.Sort (item_sorter);
1587
1588                         if (sort_order == SortOrder.Descending)
1589                                 items.list.Reverse ();
1590
1591                         this.Redraw (true);
1592                 }
1593
1594                 public override string ToString ()
1595                 {
1596                         int count = this.Items.Count;
1597
1598                         if (count == 0)
1599                                 return string.Format ("System.Windows.Forms.ListView, Items.Count: 0");
1600                         else
1601                                 return string.Format ("System.Windows.Forms.ListView, Items.Count: {0}, Items[0]: {1}", count, this.Items [0].ToString ());
1602                 }
1603                 #endregion      // Public Instance Methods
1604
1605
1606                 #region Subclasses
1607                 public class CheckedIndexCollection : IList, ICollection, IEnumerable
1608                 {
1609                         internal ArrayList list;
1610                         private ListView owner;
1611
1612                         #region Public Constructor
1613                         public CheckedIndexCollection (ListView owner)
1614                         {
1615                                 list = new ArrayList ();
1616                                 this.owner = owner;
1617                         }
1618                         #endregion      // Public Constructor
1619
1620                         #region Public Properties
1621                         [Browsable (false)]
1622                         public virtual int Count {
1623                                 get { return list.Count; }
1624                         }
1625
1626                         public virtual bool IsReadOnly {
1627                                 get { return true; }
1628                         }
1629
1630                         public int this [int index] {
1631                                 get {
1632                                         if (index < 0 || index >= list.Count)
1633                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
1634                                         return (int) list [index];
1635                                 }
1636                         }
1637
1638                         bool ICollection.IsSynchronized {
1639                                 get { return false; }
1640                         }
1641
1642                         object ICollection.SyncRoot {
1643                                 get { return this; }
1644                         }
1645
1646                         bool IList.IsFixedSize {
1647                                 get { return true; }
1648                         }
1649
1650                         object IList.this [int index] {
1651                                 get { return this [index]; }
1652                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
1653                         }
1654                         #endregion      // Public Properties
1655
1656                         #region Public Methods
1657                         public bool Contains (int checkedIndex)
1658                         {
1659                                 return list.Contains (checkedIndex);
1660                         }
1661
1662                         public virtual IEnumerator GetEnumerator ()
1663                         {
1664                                 return list.GetEnumerator ();
1665                         }
1666
1667                         void ICollection.CopyTo (Array dest, int index)
1668                         {
1669                                 list.CopyTo (dest, index);
1670                         }
1671
1672                         int IList.Add (object value)
1673                         {
1674                                 throw new NotSupportedException ("Add operation is not supported.");
1675                         }
1676
1677                         void IList.Clear ()
1678                         {
1679                                 throw new NotSupportedException ("Clear operation is not supported.");
1680                         }
1681
1682                         bool IList.Contains (object checkedIndex)
1683                         {
1684                                 return list.Contains (checkedIndex);
1685                         }
1686
1687                         int IList.IndexOf (object checkedIndex)
1688                         {
1689                                 return list.IndexOf (checkedIndex);
1690                         }
1691
1692                         void IList.Insert (int index, object value)
1693                         {
1694                                 throw new NotSupportedException ("Insert operation is not supported.");
1695                         }
1696
1697                         void IList.Remove (object value)
1698                         {
1699                                 throw new NotSupportedException ("Remove operation is not supported.");
1700                         }
1701
1702                         void IList.RemoveAt (int index)
1703                         {
1704                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
1705                         }
1706
1707                         public int IndexOf (int checkedIndex)
1708                         {
1709                                 return list.IndexOf (checkedIndex);
1710                         }
1711                         #endregion      // Public Methods
1712
1713                 }       // CheckedIndexCollection
1714
1715                 public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
1716                 {
1717                         internal ArrayList list;
1718                         private ListView owner;
1719
1720                         #region Public Constructor
1721                         public CheckedListViewItemCollection (ListView owner)
1722                         {
1723                                 list = new ArrayList ();
1724                                 this.owner = owner;
1725                         }
1726                         #endregion      // Public Constructor
1727
1728                         #region Public Properties
1729                         [Browsable (false)]
1730                         public virtual int Count {
1731                                 get { return list.Count; }
1732                         }
1733
1734                         public virtual bool IsReadOnly {
1735                                 get { return true; }
1736                         }
1737
1738                         public ListViewItem this [int index] {
1739                                 get {
1740                                         if (index < 0 || index >= list.Count)
1741                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
1742                                         return (ListViewItem) list [index];
1743                                 }
1744                         }
1745
1746                         bool ICollection.IsSynchronized {
1747                                 get { return list.IsSynchronized; }
1748                         }
1749
1750                         object ICollection.SyncRoot {
1751                                 get { return this; }
1752                         }
1753
1754                         bool IList.IsFixedSize {
1755                                 get { return true; }
1756                         }
1757
1758                         object IList.this [int index] {
1759                                 get { return this [index]; }
1760                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
1761                         }
1762                         #endregion      // Public Properties
1763
1764                         #region Public Methods
1765                         public bool Contains (ListViewItem item)
1766                         {
1767                                 return list.Contains (item);
1768                         }
1769
1770                         public virtual void CopyTo (Array dest, int index)
1771                         {
1772                                 list.CopyTo (dest, index);
1773                         }
1774
1775                         public virtual IEnumerator GetEnumerator ()
1776                         {
1777                                 return list.GetEnumerator ();
1778                         }
1779
1780                         int IList.Add (object value)
1781                         {
1782                                 throw new NotSupportedException ("Add operation is not supported.");
1783                         }
1784
1785                         void IList.Clear ()
1786                         {
1787                                 throw new NotSupportedException ("Clear operation is not supported.");
1788                         }
1789
1790                         bool IList.Contains (object item)
1791                         {
1792                                 return list.Contains (item);
1793                         }
1794
1795                         int IList.IndexOf (object item)
1796                         {
1797                                 return list.IndexOf (item);
1798                         }
1799
1800                         void IList.Insert (int index, object value)
1801                         {
1802                                 throw new NotSupportedException ("Insert operation is not supported.");
1803                         }
1804
1805                         void IList.Remove (object value)
1806                         {
1807                                 throw new NotSupportedException ("Remove operation is not supported.");
1808                         }
1809
1810                         void IList.RemoveAt (int index)
1811                         {
1812                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
1813                         }
1814
1815                         public int IndexOf (ListViewItem item)
1816                         {
1817                                 return list.IndexOf (item);
1818                         }
1819                         #endregion      // Public Methods
1820
1821                 }       // CheckedListViewItemCollection
1822
1823                 public class ColumnHeaderCollection : IList, ICollection, IEnumerable
1824                 {
1825                         internal ArrayList list;
1826                         private ListView owner;
1827
1828                         #region Public Constructor
1829                         public ColumnHeaderCollection (ListView owner)
1830                         {
1831                                 list = new ArrayList ();
1832                                 this.owner = owner;
1833                         }
1834                         #endregion      // Public Constructor
1835
1836                         #region Public Properties
1837                         [Browsable (false)]
1838                         public virtual int Count {
1839                                 get { return list.Count; }
1840                         }
1841
1842                         public virtual bool IsReadOnly {
1843                                 get { return false; }
1844                         }
1845
1846                         public virtual ColumnHeader this [int index] {
1847                                 get {
1848                                         if (index < 0 || index >= list.Count)
1849                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
1850                                         return (ColumnHeader) list [index];
1851                                 }
1852                         }
1853
1854                         bool ICollection.IsSynchronized {
1855                                 get { return true; }
1856                         }
1857
1858                         object ICollection.SyncRoot {
1859                                 get { return this; }
1860                         }
1861
1862                         bool IList.IsFixedSize {
1863                                 get { return list.IsFixedSize; }
1864                         }
1865
1866                         object IList.this [int index] {
1867                                 get { return this [index]; }
1868                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
1869                         }
1870                         #endregion      // Public Properties
1871
1872                         #region Public Methods
1873                         public virtual int Add (ColumnHeader value)
1874                         {
1875                                 int idx;
1876                                 value.owner = this.owner;
1877                                 idx = list.Add (value);
1878                                 owner.Redraw (true); 
1879                                 return idx;
1880                         }
1881
1882                         public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign)
1883                         {
1884                                 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
1885                                 this.Add (colHeader);                                                                   
1886                                 return colHeader;
1887                         }
1888
1889                         public virtual void AddRange (ColumnHeader [] values)
1890                         {
1891                                 foreach (ColumnHeader colHeader in values) {
1892                                         colHeader.owner = this.owner;
1893                                         Add (colHeader);
1894                                 }
1895                                 
1896                                 owner.Redraw (true); 
1897                         }
1898
1899                         public virtual void Clear ()
1900                         {
1901                                 list.Clear ();
1902                                 owner.Redraw (true);
1903                         }
1904
1905                         public bool Contains (ColumnHeader value)
1906                         {
1907                                 return list.Contains (value);
1908                         }
1909
1910                         public virtual IEnumerator GetEnumerator ()
1911                         {
1912                                 return list.GetEnumerator ();
1913                         }
1914
1915                         void ICollection.CopyTo (Array dest, int index)
1916                         {
1917                                 list.CopyTo (dest, index);
1918                         }
1919
1920                         int IList.Add (object value)
1921                         {
1922                                 if (! (value is ColumnHeader)) {
1923                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
1924                                 }
1925
1926                                 return this.Add ((ColumnHeader) value);
1927                         }
1928
1929                         bool IList.Contains (object value)
1930                         {
1931                                 if (! (value is ColumnHeader)) {
1932                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
1933                                 }
1934
1935                                 return this.Contains ((ColumnHeader) value);
1936                         }
1937
1938                         int IList.IndexOf (object value)
1939                         {
1940                                 if (! (value is ColumnHeader)) {
1941                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
1942                                 }
1943
1944                                 return this.IndexOf ((ColumnHeader) value);
1945                         }
1946
1947                         void IList.Insert (int index, object value)
1948                         {
1949                                 if (! (value is ColumnHeader)) {
1950                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
1951                                 }
1952
1953                                 this.Insert (index, (ColumnHeader) value);
1954                         }
1955
1956                         void IList.Remove (object value)
1957                         {
1958                                 if (! (value is ColumnHeader)) {
1959                                         throw new ArgumentException ("Not of type ColumnHeader", "value");
1960                                 }
1961
1962                                 this.Remove ((ColumnHeader) value);
1963                         }
1964
1965                         public int IndexOf (ColumnHeader value)
1966                         {
1967                                 return list.IndexOf (value);
1968                         }
1969
1970                         public void Insert (int index, ColumnHeader value)
1971                         {
1972                                 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
1973                                 // but it's really only greater.
1974                                 if (index < 0 || index > list.Count)
1975                                         throw new ArgumentOutOfRangeException ("Index out of range.");
1976
1977                                 value.owner = this.owner;
1978                                 list.Insert (index, value);
1979                                 owner.Redraw (true);
1980                         }
1981
1982                         public void Insert (int index, string str, int width, HorizontalAlignment textAlign)
1983                         {
1984                                 ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width);
1985                                 this.Insert (index, colHeader);
1986                         }
1987
1988                         public virtual void Remove (ColumnHeader column)
1989                         {
1990                                 // TODO: Update Column internal index ?
1991                                 list.Remove (column);
1992                                 owner.Redraw (true);
1993                         }
1994
1995                         public virtual void RemoveAt (int index)
1996                         {
1997                                 if (index < 0 || index >= list.Count)
1998                                         throw new ArgumentOutOfRangeException ("Index out of range.");
1999
2000                                 // TODO: Update Column internal index ?
2001                                 list.RemoveAt (index);
2002                                 owner.Redraw (true);
2003                         }
2004                         #endregion      // Public Methods
2005                         
2006
2007                 }       // ColumnHeaderCollection
2008
2009                 public class ListViewItemCollection : IList, ICollection, IEnumerable
2010                 {
2011                         internal ArrayList list;
2012                         private ListView owner;
2013
2014                         #region Public Constructor
2015                         public ListViewItemCollection (ListView owner)
2016                         {
2017                                 list = new ArrayList ();
2018                                 this.owner = owner;
2019                         }
2020                         #endregion      // Public Constructor
2021
2022                         #region Public Properties
2023                         [Browsable (false)]
2024                         public virtual int Count {
2025                                 get { return list.Count; }
2026                         }
2027
2028                         public virtual bool IsReadOnly {
2029                                 get { return false; }
2030                         }
2031
2032                         public virtual ListViewItem this [int displayIndex] {
2033                                 get {
2034                                         if (displayIndex < 0 || displayIndex >= list.Count)
2035                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
2036                                         return (ListViewItem) list [displayIndex];
2037                                 }
2038
2039                                 set {
2040                                         if (displayIndex < 0 || displayIndex >= list.Count)
2041                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
2042
2043                                         if (list.Contains (value))
2044                                                 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2045
2046                                         value.owner = this.owner;
2047                                         list [displayIndex] = value;
2048
2049                                         owner.Redraw (true);
2050                                 }
2051                         }
2052
2053                         bool ICollection.IsSynchronized {
2054                                 get { return true; }
2055                         }
2056
2057                         object ICollection.SyncRoot {
2058                                 get { return this; }
2059                         }
2060
2061                         bool IList.IsFixedSize {
2062                                 get { return list.IsFixedSize; }
2063                         }
2064
2065                         object IList.this [int index] {
2066                                 get { return this [index]; }
2067                                 set {
2068                                         if (value is ListViewItem)
2069                                                 this [index] = (ListViewItem) value;
2070                                         else
2071                                                 this [index] = new ListViewItem (value.ToString ());
2072                                 }
2073                         }
2074                         #endregion      // Public Properties
2075
2076                         #region Public Methods
2077                         public virtual ListViewItem Add (ListViewItem value)
2078                         {
2079                                 if (list.Contains (value))
2080                                         throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value");
2081
2082                                 value.owner = this.owner;
2083                                 list.Add (value);
2084
2085                                 if (owner.Sorting != SortOrder.None)
2086                                         owner.Sort ();
2087
2088                                 owner.Redraw (true);
2089
2090                                 return value;
2091                         }
2092
2093                         public virtual ListViewItem Add (string text)
2094                         {
2095                                 ListViewItem item = new ListViewItem (text);
2096                                 return this.Add (item);
2097                         }
2098
2099                         public virtual ListViewItem Add (string text, int imageIndex)
2100                         {
2101                                 ListViewItem item = new ListViewItem (text, imageIndex);
2102                                 return this.Add (item);
2103                         }
2104
2105                         public void AddRange (ListViewItem [] values)
2106                         {
2107                                 list.Clear ();
2108                                 owner.SelectedItems.list.Clear ();
2109                                 owner.SelectedIndices.list.Clear ();
2110                                 owner.CheckedItems.list.Clear ();
2111                                 owner.CheckedIndices.list.Clear ();
2112
2113                                 foreach (ListViewItem item in values) {
2114                                         item.owner = this.owner;
2115                                         list.Add (item);
2116                                 }
2117
2118                                 if (owner.Sorting != SortOrder.None)
2119                                         owner.Sort ();
2120
2121                                 owner.Redraw (true);
2122                         }
2123
2124                         public virtual void Clear ()
2125                         {
2126                                 owner.SetFocusedItem (null);
2127                                 owner.h_scroll.Value = owner.v_scroll.Value = 0;
2128                                 list.Clear ();
2129                                 owner.SelectedItems.list.Clear ();
2130                                 owner.SelectedIndices.list.Clear ();
2131                                 owner.CheckedItems.list.Clear ();
2132                                 owner.CheckedIndices.list.Clear ();
2133                                 owner.Redraw (true);
2134                         }
2135
2136                         public bool Contains (ListViewItem item)
2137                         {
2138                                 return list.Contains (item);
2139                         }
2140
2141                         public virtual void CopyTo (Array dest, int index)
2142                         {
2143                                 list.CopyTo (dest, index);
2144                         }
2145
2146                         public virtual IEnumerator GetEnumerator ()
2147                         {
2148                                 return list.GetEnumerator ();
2149                         }
2150
2151                         int IList.Add (object item)
2152                         {
2153                                 int result;
2154                                 ListViewItem li;
2155
2156                                 if (item is ListViewItem) {
2157                                         li = (ListViewItem) item;
2158                                         if (list.Contains (li))
2159                                                 throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2160                                 }
2161                                 else
2162                                         li = new ListViewItem (item.ToString ());
2163
2164                                 li.owner = this.owner;
2165                                 result = list.Add (li);
2166                                 owner.Redraw (true);
2167
2168                                 return result;
2169                         }
2170
2171                         bool IList.Contains (object item)
2172                         {
2173                                 return list.Contains (item);
2174                         }
2175
2176                         int IList.IndexOf (object item)
2177                         {
2178                                 return list.IndexOf (item);
2179                         }
2180
2181                         void IList.Insert (int index, object item)
2182                         {
2183                                 if (item is ListViewItem)
2184                                         this.Insert (index, (ListViewItem) item);
2185                                 else
2186                                         this.Insert (index, item.ToString ());
2187                         }
2188
2189                         void IList.Remove (object item)
2190                         {
2191                                 Remove ((ListViewItem) item);
2192                         }
2193
2194                         public int IndexOf (ListViewItem item)
2195                         {
2196                                 return list.IndexOf (item);
2197                         }
2198
2199                         public ListViewItem Insert (int index, ListViewItem item)
2200                         {
2201                                 // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
2202                                 // but it's really only greater.
2203                                 if (index < 0 || index > list.Count)
2204                                         throw new ArgumentOutOfRangeException ("Index out of range.");
2205
2206                                 if (list.Contains (item))
2207                                         throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item");
2208
2209                                 item.owner = this.owner;
2210                                 list.Insert (index, item);
2211                                 owner.Redraw (true);
2212                                 return item;
2213                         }
2214
2215                         public ListViewItem Insert (int index, string text)
2216                         {
2217                                 return this.Insert (index, new ListViewItem (text));
2218                         }
2219
2220                         public ListViewItem Insert (int index, string text, int imageIndex)
2221                         {
2222                                 return this.Insert (index, new ListViewItem (text, imageIndex));
2223                         }
2224
2225                         public virtual void Remove (ListViewItem item)
2226                         {
2227                                 if (!list.Contains (item))
2228                                         return;
2229                                         
2230                                 owner.SelectedItems.list.Remove (item);
2231                                 owner.SelectedIndices.list.Remove (item.Index);
2232                                 owner.CheckedItems.list.Remove (item);
2233                                 owner.CheckedIndices.list.Remove (item.Index);
2234                                 list.Remove (item);
2235                                 owner.Redraw (true);                            
2236                         }
2237
2238                         public virtual void RemoveAt (int index)
2239                         {
2240                                 if (index < 0 || index >= list.Count)
2241                                         throw new ArgumentOutOfRangeException ("Index out of range.");
2242
2243                                 list.RemoveAt (index);
2244                                 owner.SelectedItems.list.RemoveAt (index);
2245                                 owner.SelectedIndices.list.RemoveAt (index);
2246                                 owner.CheckedItems.list.RemoveAt (index);
2247                                 owner.CheckedIndices.list.RemoveAt (index);
2248                                 owner.Redraw (false);
2249                         }
2250                         #endregion      // Public Methods
2251
2252                 }       // ListViewItemCollection
2253
2254                 public class SelectedIndexCollection : IList, ICollection, IEnumerable
2255                 {
2256                         internal ArrayList list;
2257                         private ListView owner;
2258
2259                         #region Public Constructor
2260                         public SelectedIndexCollection (ListView owner)
2261                         {
2262                                 list = new ArrayList ();
2263                                 this.owner = owner;
2264                         }
2265                         #endregion      // Public Constructor
2266
2267                         #region Public Properties
2268                         [Browsable (false)]
2269                         public virtual int Count {
2270                                 get { return list.Count; }
2271                         }
2272
2273                         public virtual bool IsReadOnly {
2274                                 get { return true; }
2275                         }
2276
2277                         public int this [int index] {
2278                                 get {
2279                                         if (index < 0 || index >= list.Count)
2280                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
2281                                         return (int) list [index];
2282                                 }
2283                         }
2284
2285                         bool ICollection.IsSynchronized {
2286                                 get { return list.IsSynchronized; }
2287                         }
2288
2289                         object ICollection.SyncRoot {
2290                                 get { return this; }
2291                         }
2292
2293                         bool IList.IsFixedSize {
2294                                 get { return true; }
2295                         }
2296
2297                         object IList.this [int index] {
2298                                 get { return this [index]; }
2299                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2300                         }
2301                         #endregion      // Public Properties
2302
2303                         #region Public Methods
2304                         public bool Contains (int selectedIndex)
2305                         {
2306                                 return list.Contains (selectedIndex);
2307                         }
2308
2309                         public virtual void CopyTo (Array dest, int index)
2310                         {
2311                                 list.CopyTo (dest, index);
2312                         }
2313
2314                         public virtual IEnumerator GetEnumerator ()
2315                         {
2316                                 return list.GetEnumerator ();
2317                         }
2318
2319                         int IList.Add (object value)
2320                         {
2321                                 throw new NotSupportedException ("Add operation is not supported.");
2322                         }
2323
2324                         void IList.Clear ()
2325                         {
2326                                 throw new NotSupportedException ("Clear operation is not supported.");
2327                         }
2328
2329                         bool IList.Contains (object selectedIndex)
2330                         {
2331                                 return list.Contains (selectedIndex);
2332                         }
2333
2334                         int IList.IndexOf (object selectedIndex)
2335                         {
2336                                 return list.IndexOf (selectedIndex);
2337                         }
2338
2339                         void IList.Insert (int index, object value)
2340                         {
2341                                 throw new NotSupportedException ("Insert operation is not supported.");
2342                         }
2343
2344                         void IList.Remove (object value)
2345                         {
2346                                 throw new NotSupportedException ("Remove operation is not supported.");
2347                         }
2348
2349                         void IList.RemoveAt (int index)
2350                         {
2351                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
2352                         }
2353
2354                         public int IndexOf (int selectedIndex)
2355                         {
2356                                 return list.IndexOf (selectedIndex);
2357                         }
2358                         #endregion      // Public Methods
2359
2360                 }       // SelectedIndexCollection
2361
2362                 public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
2363                 {
2364                         internal ArrayList list;
2365                         private ListView owner;
2366
2367                         #region Public Constructor
2368                         public SelectedListViewItemCollection (ListView owner)
2369                         {
2370                                 list = new ArrayList ();
2371                                 this.owner = owner;
2372                         }
2373                         #endregion      // Public Constructor
2374
2375                         #region Public Properties
2376                         [Browsable (false)]
2377                         public virtual int Count {
2378                                 get { return list.Count; }
2379                         }
2380
2381                         public virtual bool IsReadOnly {
2382                                 get { return true; }
2383                         }
2384
2385                         public ListViewItem this [int index] {
2386                                 get {
2387                                         if (index < 0 || index >= list.Count)
2388                                                 throw new ArgumentOutOfRangeException ("Index out of range.");
2389                                         return (ListViewItem) list [index];
2390                                 }
2391                         }
2392
2393                         bool ICollection.IsSynchronized {
2394                                 get { return list.IsSynchronized; }
2395                         }
2396
2397                         object ICollection.SyncRoot {
2398                                 get { return this; }
2399                         }
2400
2401                         bool IList.IsFixedSize {
2402                                 get { return true; }
2403                         }
2404
2405                         object IList.this [int index] {
2406                                 get { return this [index]; }
2407                                 set { throw new NotSupportedException ("SetItem operation is not supported."); }
2408                         }
2409                         #endregion      // Public Properties
2410
2411                         #region Public Methods
2412                         public virtual void Clear ()
2413                         {
2414                                 // mark the items as unselected before clearing the list
2415                                 for (int i = 0; i < list.Count; i++)
2416                                         ((ListViewItem) list [i]).selected = false;
2417
2418                                 list.Clear ();
2419                                 
2420                                 if (owner != null)
2421                                         owner.Invalidate ();
2422                         }
2423
2424                         public bool Contains (ListViewItem item)
2425                         {
2426                                 return list.Contains (item);
2427                         }
2428
2429                         public virtual void CopyTo (Array dest, int index)
2430                         {
2431                                 list.CopyTo (dest, index);
2432                         }
2433
2434                         public virtual IEnumerator GetEnumerator ()
2435                         {
2436                                 return list.GetEnumerator ();
2437                         }
2438
2439                         int IList.Add (object value)
2440                         {
2441                                 throw new NotSupportedException ("Add operation is not supported.");
2442                         }
2443
2444                         bool IList.Contains (object item)
2445                         {
2446                                 return list.Contains (item);
2447                         }
2448
2449                         int IList.IndexOf (object item)
2450                         {
2451                                 return list.IndexOf (item);
2452                         }
2453
2454                         void IList.Insert (int index, object value)
2455                         {
2456                                 throw new NotSupportedException ("Insert operation is not supported.");
2457                         }
2458
2459                         void IList.Remove (object value)
2460                         {
2461                                 throw new NotSupportedException ("Remove operation is not supported.");
2462                         }
2463
2464                         void IList.RemoveAt (int index)
2465                         {
2466                                 throw new NotSupportedException ("RemoveAt operation is not supported.");
2467                         }
2468
2469                         public int IndexOf (ListViewItem item)
2470                         {
2471                                 return list.IndexOf (item);
2472                         }
2473                         #endregion      // Public Methods
2474
2475                 }       // SelectedListViewItemCollection
2476
2477                 #endregion // Subclasses
2478         }
2479 }