Merge pull request #3018 from ludovic-henry/coop-marshal-attach
[mono.git] / mcs / class / System.Windows.Forms / System.Windows.Forms / ListBox.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-2006 Novell, Inc.
21 //
22 // Authors:
23 //      Jordi Mas i Hernandez, jordi@ximian.com
24 //      Mike Kestner  <mkestner@novell.com>
25 //
26
27 // COMPLETE
28
29 using System;
30 using System.Drawing;
31 using System.Collections;
32 using System.ComponentModel;
33 using System.ComponentModel.Design;
34 using System.ComponentModel.Design.Serialization;
35 using System.Globalization;
36 using System.Reflection;
37 using System.Runtime.InteropServices;
38 using System.Collections.Generic;
39
40 namespace System.Windows.Forms
41 {
42         [DefaultProperty("Items")]
43         [DefaultEvent("SelectedIndexChanged")]
44         [Designer ("System.Windows.Forms.Design.ListBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
45         [DefaultBindingProperty ("SelectedValue")]
46         [ClassInterface (ClassInterfaceType.AutoDispatch)]
47         [ComVisible (true)]
48         public class ListBox : ListControl
49         {
50                 public const int DefaultItemHeight = 13;
51                 public const int NoMatches = -1;
52                 
53                 internal enum ItemNavigation
54                 {
55                         First,
56                         Last,
57                         Next,
58                         Previous,
59                         NextPage,
60                         PreviousPage,
61                         PreviousColumn,
62                         NextColumn
63                 }
64                 
65                 Hashtable item_heights;
66                 private int item_height = -1;
67                 private int column_width = 0;
68                 private int requested_height;
69                 private DrawMode draw_mode = DrawMode.Normal;
70                 private int horizontal_extent = 0;
71                 private bool horizontal_scrollbar = false;
72                 private bool integral_height = true;
73                 private bool multicolumn = false;
74                 private bool scroll_always_visible = false;
75                 private SelectedIndexCollection selected_indices;
76                 private SelectedObjectCollection selected_items;
77                 private SelectionMode selection_mode = SelectionMode.One;
78                 private bool sorted = false;
79                 private bool use_tabstops = true;
80                 private int column_width_internal = 120;
81                 private ImplicitVScrollBar vscrollbar;
82                 private ImplicitHScrollBar hscrollbar;
83                 private int hbar_offset;
84                 private bool suspend_layout;
85                 private bool ctrl_pressed = false;
86                 private bool shift_pressed = false;
87                 private bool explicit_item_height = false;
88                 private int top_index = 0;
89                 private int last_visible_index = 0;
90                 private Rectangle items_area;
91                 private int focused_item = -1;
92                 private ObjectCollection items;
93                 private IntegerCollection custom_tab_offsets;
94                 private Padding padding;
95                 private bool use_custom_tab_offsets;
96
97                 public ListBox ()
98                 {
99                         items = CreateItemCollection ();
100                         selected_indices = new SelectedIndexCollection (this);
101                         selected_items = new SelectedObjectCollection (this);
102
103                         requested_height = bounds.Height;
104                         InternalBorderStyle = BorderStyle.Fixed3D;
105                         BackColor = ThemeEngine.Current.ColorControl;
106
107                         /* Vertical scrollbar */
108                         vscrollbar = new ImplicitVScrollBar ();
109                         vscrollbar.Minimum = 0;
110                         vscrollbar.SmallChange = 1;
111                         vscrollbar.LargeChange = 1;
112                         vscrollbar.Maximum = 0;
113                         vscrollbar.ValueChanged += new EventHandler (VerticalScrollEvent);
114                         vscrollbar.Visible = false;
115
116                         /* Horizontal scrollbar */
117                         hscrollbar = new ImplicitHScrollBar ();
118                         hscrollbar.Minimum = 0;
119                         hscrollbar.SmallChange = 1;
120                         hscrollbar.LargeChange = 1;
121                         hscrollbar.Maximum = 0;
122                         hscrollbar.Visible = false;
123                         hscrollbar.ValueChanged += new EventHandler (HorizontalScrollEvent);
124
125                         Controls.AddImplicit (vscrollbar);
126                         Controls.AddImplicit (hscrollbar);
127
128                         /* Events */
129                         MouseDown += new MouseEventHandler (OnMouseDownLB);
130                         MouseMove += new MouseEventHandler (OnMouseMoveLB);
131                         MouseUp += new MouseEventHandler (OnMouseUpLB);
132                         MouseWheel += new MouseEventHandler (OnMouseWheelLB);
133                         KeyUp += new KeyEventHandler (OnKeyUpLB);
134                         GotFocus += new EventHandler (OnGotFocus);
135                         LostFocus += new EventHandler (OnLostFocus);
136                         
137                         SetStyle (ControlStyles.UserPaint, false);
138
139                         custom_tab_offsets = new IntegerCollection (this);
140                 }
141
142                 #region Events
143                 static object DrawItemEvent = new object ();
144                 static object MeasureItemEvent = new object ();
145                 static object SelectedIndexChangedEvent = new object ();
146
147                 [Browsable (false)]
148                 [EditorBrowsable (EditorBrowsableState.Never)]
149                 public new event EventHandler BackgroundImageChanged {
150                         add { base.BackgroundImageChanged += value; }
151                         remove { base.BackgroundImageChanged -= value; }
152                 }
153
154                 [Browsable (false)]
155                 [EditorBrowsable (EditorBrowsableState.Never)]
156                 public new event EventHandler BackgroundImageLayoutChanged {
157                         add { base.BackgroundImageLayoutChanged += value; }
158                         remove { base.BackgroundImageLayoutChanged -= value; }
159                 }
160
161                 [Browsable (true)]
162                 [EditorBrowsable (EditorBrowsableState.Always)]
163                 public new event EventHandler Click {
164                         add { base.Click += value; }
165                         remove { base.Click -= value; }
166                 }
167
168                 public event DrawItemEventHandler DrawItem {
169                         add { Events.AddHandler (DrawItemEvent, value); }
170                         remove { Events.RemoveHandler (DrawItemEvent, value); }
171                 }
172
173                 public event MeasureItemEventHandler MeasureItem {
174                         add { Events.AddHandler (MeasureItemEvent, value); }
175                         remove { Events.RemoveHandler (MeasureItemEvent, value); }
176                 }
177
178                 [Browsable (true)]
179                 [EditorBrowsable (EditorBrowsableState.Always)]
180                 public new event MouseEventHandler MouseClick {
181                         add { base.MouseClick += value; }
182                         remove { base.MouseClick -= value; }
183                 }
184
185                 [Browsable (false)]
186                 [EditorBrowsable (EditorBrowsableState.Never)]
187                 public new event EventHandler PaddingChanged {
188                         add { base.PaddingChanged += value; }
189                         remove { base.PaddingChanged -= value; }
190                 }
191
192                 [Browsable (false)]
193                 [EditorBrowsable (EditorBrowsableState.Never)]
194                 public new event PaintEventHandler Paint {
195                         add { base.Paint += value; }
196                         remove { base.Paint -= value; }
197                 }
198
199                 public event EventHandler SelectedIndexChanged {
200                         add { Events.AddHandler (SelectedIndexChangedEvent, value); }
201                         remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
202                 }
203
204                 [Browsable (false)]
205                 [EditorBrowsable (EditorBrowsableState.Advanced)]
206                 public new event EventHandler TextChanged {
207                         add { base.TextChanged += value; }
208                         remove { base.TextChanged -= value; }
209                 }
210                 #endregion // Events
211
212                 #region UIA Framework Events 
213                 //NOTE:
214                 //      We are using Reflection to add/remove internal events.
215                 //      Class ListProvider uses the events.
216                 //
217                 //Event used to generate UIA Selection Pattern 
218                 static object UIASelectionModeChangedEvent = new object ();
219
220                 internal event EventHandler UIASelectionModeChanged {
221                         add { Events.AddHandler (UIASelectionModeChangedEvent, value); }
222                         remove { Events.RemoveHandler (UIASelectionModeChangedEvent, value); }
223                 }
224
225                 internal void OnUIASelectionModeChangedEvent ()
226                 {
227                         EventHandler eh = (EventHandler) Events [UIASelectionModeChangedEvent];
228                         if (eh != null)
229                                 eh (this, EventArgs.Empty);
230                 }
231
232                 static object UIAFocusedItemChangedEvent = new object ();
233
234                 internal event EventHandler UIAFocusedItemChanged {
235                         add { Events.AddHandler (UIAFocusedItemChangedEvent, value); }
236                         remove { Events.RemoveHandler (UIAFocusedItemChangedEvent, value); }
237                 }
238
239                 internal void OnUIAFocusedItemChangedEvent ()
240                 {
241                         EventHandler eh = (EventHandler) Events [UIAFocusedItemChangedEvent];
242                         if (eh != null)
243                                 eh (this, EventArgs.Empty);
244                 }
245                 #endregion UIA Framework Events 
246
247                 #region Public Properties
248                 public override Color BackColor {
249                         get { return base.BackColor; }
250                         set {
251                                 if (base.BackColor == value)
252                                         return;
253
254                                 base.BackColor = value;
255                                 base.Refresh ();        // Careful. Calling the base method is not the same that calling 
256                         }                               // the overriden one that refresh also all the items
257                 }
258
259                 [Browsable (false)]
260                 [EditorBrowsable (EditorBrowsableState.Never)]
261                 public override Image BackgroundImage {
262                         get { return base.BackgroundImage; }
263                         set { 
264                                 base.BackgroundImage = value;
265                                 base.Refresh ();
266                         }
267                 }
268
269                 [Browsable (false)]
270                 [EditorBrowsable (EditorBrowsableState.Never)]
271                 public override ImageLayout BackgroundImageLayout {
272                         get { return base.BackgroundImageLayout; }
273                         set { base.BackgroundImageLayout = value; }
274                 }
275
276                 [DefaultValue (BorderStyle.Fixed3D)]
277                 [DispId(-504)]
278                 public BorderStyle BorderStyle {
279                         get { return InternalBorderStyle; }
280                         set { 
281                                 InternalBorderStyle = value; 
282                                 UpdateListBoxBounds ();
283                         }
284                 }
285
286                 [DefaultValue (0)]
287                 [Localizable (true)]
288                 public int ColumnWidth {
289                         get { return column_width; }
290                         set {
291                                 if (value < 0)
292                                         throw new ArgumentException ("A value less than zero is assigned to the property.");
293
294                                 column_width = value;
295
296                                 if (value == 0)
297                                         ColumnWidthInternal = 120;
298                                 else
299                                         ColumnWidthInternal = value;
300
301                                 base.Refresh ();
302                         }
303                 }
304
305                 protected override CreateParams CreateParams {
306                         get { return base.CreateParams;}
307                 }
308
309                 [Browsable (false)]
310                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
311                 public IntegerCollection CustomTabOffsets {
312                         get { return custom_tab_offsets; }
313                 }
314
315                 protected override Size DefaultSize {
316                         get { return new Size (120, 96); }
317                 }
318
319                 [RefreshProperties(RefreshProperties.Repaint)]
320                 [DefaultValue (DrawMode.Normal)]
321                 public virtual DrawMode DrawMode {
322                         get { return draw_mode; }
323                         set {
324                                 if (!Enum.IsDefined (typeof (DrawMode), value))
325                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for DrawMode", value));
326                                         
327                                 if (value == DrawMode.OwnerDrawVariable && multicolumn == true)
328                                         throw new ArgumentException ("Cannot have variable height and multicolumn");
329
330                                 if (draw_mode == value)
331                                         return;
332
333                                 draw_mode = value;
334
335                                 if (draw_mode == DrawMode.OwnerDrawVariable)
336                                         item_heights = new Hashtable ();
337                                 else
338                                         item_heights = null;
339
340                                 if (Parent != null)
341                                         Parent.PerformLayout (this, "DrawMode");
342                                 base.Refresh ();
343                         }
344                 }
345
346                 public override Font Font {
347                         get { return base.Font; }
348                         set { base.Font = value; }
349                 }
350
351                 public override Color ForeColor {
352                         get { return base.ForeColor; }
353                         set {
354                                 if (base.ForeColor == value)
355                                         return;
356
357                                 base.ForeColor = value;
358                                 base.Refresh ();
359                         }
360                 }
361
362                 [DefaultValue (0)]
363                 [Localizable (true)]
364                 public int HorizontalExtent {
365                         get { return horizontal_extent; }
366                         set {
367                                 if (horizontal_extent == value)
368                                         return;
369
370                                 horizontal_extent = value;
371                                 base.Refresh ();
372                         }
373                 }
374
375                 [DefaultValue (false)]
376                 [Localizable (true)]
377                 public bool HorizontalScrollbar {
378                         get { return horizontal_scrollbar; }
379                         set {
380                                 if (horizontal_scrollbar == value)
381                                         return;
382
383                                 horizontal_scrollbar = value;
384                                 UpdateScrollBars ();
385                                 base.Refresh ();
386                         }
387                 }
388
389                 [DefaultValue (true)]
390                 [Localizable (true)]
391                 [RefreshProperties(RefreshProperties.Repaint)]
392                 public bool IntegralHeight {
393                         get { return integral_height; }
394                         set {
395                                 if (integral_height == value)
396                                         return;
397
398                                 integral_height = value;
399                                 UpdateListBoxBounds ();
400                         }
401                 }
402
403                 [DefaultValue (13)]
404                 [Localizable (true)]
405                 [RefreshProperties(RefreshProperties.Repaint)]
406                 public virtual int ItemHeight {
407                         get {
408                                 if (item_height == -1) {
409                                         SizeF sz = TextRenderer.MeasureString ("The quick brown Fox", Font);
410                                         item_height = (int) sz.Height;
411                                 }
412                                 return item_height;
413                         }
414                         set {
415                                 if (value > 255)
416                                         throw new ArgumentOutOfRangeException ("The ItemHeight property was set beyond 255 pixels");
417
418                                 explicit_item_height = true;
419                                 if (item_height == value)
420                                         return;
421
422                                 item_height = value;
423                                 if (IntegralHeight)
424                                         UpdateListBoxBounds ();
425                                 LayoutListBox ();
426                         }
427                 }
428
429                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
430                 [Localizable (true)]
431                 [Editor ("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
432                 [MergableProperty (false)]
433                 public ObjectCollection Items {
434                         get { return items; }
435                 }
436
437                 [DefaultValue (false)]
438                 public bool MultiColumn {
439                         get { return multicolumn; }
440                         set {
441                                 if (multicolumn == value)
442                                         return;
443
444                                 if (value == true && DrawMode == DrawMode.OwnerDrawVariable)
445                                         throw new ArgumentException ("A multicolumn ListBox cannot have a variable-sized height.");
446                                         
447                                 multicolumn = value;
448                                 LayoutListBox ();
449                                 Invalidate ();
450                         }
451                 }
452
453                 [Browsable (false)]
454                 [EditorBrowsable (EditorBrowsableState.Never)]
455                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
456                 public new Padding Padding {
457                         get { return padding; }
458                         set { padding = value; }
459                 }
460
461                 [Browsable (false)]
462                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
463                 [EditorBrowsable (EditorBrowsableState.Advanced)]
464                 public int PreferredHeight {
465                         get {
466                                 int itemsHeight = 0;
467                                 if (draw_mode == DrawMode.Normal)
468                                         itemsHeight = FontHeight * items.Count;
469                                 else if (draw_mode == DrawMode.OwnerDrawFixed)
470                                         itemsHeight = ItemHeight * items.Count;
471                                 else if (draw_mode == DrawMode.OwnerDrawVariable) {
472                                         for (int i = 0; i < items.Count; i++)
473                                                 itemsHeight += (int) item_heights [Items [i]];
474                                 }
475                                 
476                                 return itemsHeight;
477                         }
478                 }
479
480                 public override RightToLeft RightToLeft {
481                         get { return base.RightToLeft; }
482                         set {
483                                 base.RightToLeft = value;
484                                 if (base.RightToLeft == RightToLeft.Yes)
485                                         StringFormat.Alignment = StringAlignment.Far;
486                                 else
487                                         StringFormat.Alignment = StringAlignment.Near;
488                                 base.Refresh ();
489                         }
490                 }
491
492                 // Only affects the Vertical ScrollBar
493                 [DefaultValue (false)]
494                 [Localizable (true)]
495                 public bool ScrollAlwaysVisible {
496                         get { return scroll_always_visible; }
497                         set {
498                                 if (scroll_always_visible == value)
499                                         return;
500
501                                 scroll_always_visible = value;
502                                 UpdateScrollBars ();
503                         }
504                 }
505
506                 [Bindable(true)]
507                 [Browsable (false)]
508                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
509                 public override int SelectedIndex {
510                         get { 
511                                 if (selected_indices == null)
512                                         return -1;
513                                         
514                                 return selected_indices.Count > 0 ? selected_indices [0] : -1;
515                         }
516                         set {
517                                 if (value < -1 || value >= Items.Count)
518                                         throw new ArgumentOutOfRangeException ("Index of out range");
519
520                                 if (SelectionMode == SelectionMode.None)
521                                         throw new ArgumentException ("cannot call this method if SelectionMode is SelectionMode.None");
522
523                                 if (value == -1)
524                                         selected_indices.Clear ();
525                                 else
526                                         selected_indices.Add (value);
527                         }
528                 }
529
530                 [Browsable (false)]
531                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
532                 public SelectedIndexCollection SelectedIndices {
533                         get { return selected_indices; }
534                 }
535
536                 [Bindable(true)]
537                 [Browsable (false)]
538                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
539                 public object SelectedItem {
540                         get {
541                                 if (SelectedItems.Count > 0)
542                                         return SelectedItems[0];
543                                 else
544                                         return null;
545                         }
546                         set {
547                                 if (value != null && !Items.Contains (value))
548                                         return; // FIXME: this is probably an exception
549                                         
550                                 SelectedIndex = value == null ? - 1 : Items.IndexOf (value);
551                         }
552                 }
553
554                 [Browsable (false)]
555                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
556                 public SelectedObjectCollection SelectedItems {
557                         get {return selected_items;}
558                 }
559
560                 [DefaultValue (SelectionMode.One)]
561                 public virtual SelectionMode SelectionMode {
562                         get { return selection_mode; }
563                         set {
564                                 if (!Enum.IsDefined (typeof (SelectionMode), value))
565                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for SelectionMode", value));
566
567                                 if (selection_mode == value)
568                                         return;
569                                         
570                                 selection_mode = value;
571                                         
572                                 switch (selection_mode) {
573                                 case SelectionMode.None: 
574                                         SelectedIndices.Clear ();
575                                         break;
576
577                                 case SelectionMode.One:
578                                         // FIXME: Probably this can be improved
579                                         ArrayList old_selection = (ArrayList) SelectedIndices.List.Clone ();
580                                         for (int i = 1; i < old_selection.Count; i++)
581                                                 SelectedIndices.Remove ((int)old_selection [i]);
582                                         break;
583
584                                 default:
585                                         break;
586                                 }
587
588                                 // UIA Framework: Generates SelectionModeChanged event.
589                                 OnUIASelectionModeChangedEvent ();
590                         }
591                 }
592
593                 [DefaultValue (false)]
594                 public bool Sorted {
595                         get { return sorted; }
596                         set {
597                                 if (sorted == value)
598                                         return;
599
600                                 sorted = value;
601                                 if (sorted)
602                                         Sort ();
603                         }
604                 }
605
606                 [Bindable (false)]
607                 [Browsable (false)]
608                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
609                 [EditorBrowsable (EditorBrowsableState.Advanced)]
610                 public override string Text {
611                         get {
612                                 if (SelectionMode != SelectionMode.None && SelectedIndex != -1)
613                                         return GetItemText (SelectedItem);
614
615                                 return base.Text;
616                         }
617                         set {
618
619                                 base.Text = value;
620
621                                 if (SelectionMode == SelectionMode.None)
622                                         return;
623
624                                 int index;
625
626                                 index = FindStringExact (value);
627
628                                 if (index == -1)
629                                         return;
630
631                                 SelectedIndex = index;
632                         }
633                 }
634
635                 [Browsable (false)]
636                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
637                 public int TopIndex {
638                         get { return top_index; }
639                         set {
640                                 if (value == top_index)
641                                         return;
642
643                                 if (value < 0 || value >= Items.Count)
644                                         return;
645
646                                 int page_size = (items_area.Height / ItemHeight);
647                                 
648                                 if (Items.Count < page_size)
649                                         value = 0;
650                                 else if (!multicolumn)
651                                         top_index = Math.Min (value, Items.Count - page_size);
652                                 else
653                                         top_index = value;
654                                         
655                                 UpdateTopItem ();
656                                 base.Refresh ();
657                         }
658                 }
659
660                 [Browsable (false)]
661                 [DefaultValue (false)]
662                 public bool UseCustomTabOffsets {
663                         get { return use_custom_tab_offsets; }
664                         set { 
665                                 if (use_custom_tab_offsets != value) {
666                                         use_custom_tab_offsets = value;
667                                         CalculateTabStops ();
668                                 }
669                          }
670                 }
671
672                 [DefaultValue (true)]
673                 public bool UseTabStops {
674                         get { return use_tabstops; }
675                         set {
676                                 if (use_tabstops == value)
677                                         return;
678
679                                 use_tabstops = value;
680                                 CalculateTabStops ();
681                         }
682                 }
683
684                 protected override bool AllowSelection {
685                         get {
686                                 return SelectionMode != SelectionMode.None;
687                         }
688                 }
689                 #endregion Public Properties
690
691                 #region Private Properties
692
693                 private int ColumnWidthInternal {
694                         get { return column_width_internal; }
695                         set { column_width_internal = value; }
696                 }
697
698                 private int row_count = 1;
699                 private int RowCount {
700                         get {
701                                 return MultiColumn ? row_count : Items.Count;
702                         }
703                 }
704
705                 #endregion Private Properties
706
707                 #region UIA Framework Properties
708
709                 internal ScrollBar UIAHScrollBar {
710                         get { return hscrollbar; }
711                 }
712
713                 internal ScrollBar UIAVScrollBar {
714                         get { return vscrollbar; }
715                 }
716
717                 #endregion UIA Framework Properties
718
719                 #region Public Methods
720                 [Obsolete ("this method has been deprecated")]
721                 protected virtual void AddItemsCore (object[] value)
722                 {
723                         Items.AddRange (value);
724                 }
725
726                 public void BeginUpdate ()
727                 {
728                         suspend_layout = true;
729                 }
730
731                 public void ClearSelected ()
732                 {
733                         selected_indices.Clear ();
734                 }
735
736                 protected virtual ObjectCollection CreateItemCollection ()
737                 {
738                         return new ObjectCollection (this);
739                 }
740
741                 public void EndUpdate ()
742                 {
743                         suspend_layout = false;
744                         LayoutListBox ();
745                         base.Refresh ();
746                 }
747
748                 public int FindString (String s)
749                 {
750                         return FindString (s, -1);
751                 }
752
753                 public int FindString (string s,  int startIndex)
754                 {
755                         if (Items.Count == 0)
756                                 return -1; // No exception throwing if empty
757
758                         if (startIndex < -1 || startIndex >= Items.Count)
759                                 throw new ArgumentOutOfRangeException ("Index of out range");
760
761                         startIndex = (startIndex == Items.Count - 1) ? 0 : startIndex + 1;
762
763                         int i = startIndex;
764                         while (true) {
765                                 string text = GetItemText (Items [i]);
766                                 if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (text, s,
767                                                 CompareOptions.IgnoreCase))
768                                         return i;
769
770                                 i = (i == Items.Count - 1) ? 0 : i + 1;
771                                 if (i == startIndex)
772                                         break;
773                         }
774
775                         return NoMatches;
776                 }
777
778                 public int FindStringExact (string s)
779                 {
780                         return FindStringExact (s, -1);
781                 }
782
783                 public int FindStringExact (string s,  int startIndex)
784                 {
785                         if (Items.Count == 0)
786                                 return -1; // No exception throwing if empty
787
788                         if (startIndex < -1 || startIndex >= Items.Count)
789                                 throw new ArgumentOutOfRangeException ("Index of out range");
790
791                         startIndex = (startIndex + 1 == Items.Count) ? 0 : startIndex + 1;
792
793                         int i = startIndex;
794                         while (true) {
795                                 if (String.Compare (GetItemText (Items[i]), s, true) == 0)
796                                         return i;
797
798                                 i = (i + 1 == Items.Count) ? 0 : i + 1;
799                                 if (i == startIndex)
800                                         break;
801                         }
802
803                         return NoMatches;
804                 }
805
806                 public int GetItemHeight (int index)
807                 {
808                         if (index < 0 || index >= Items.Count)
809                                 throw new ArgumentOutOfRangeException ("Index of out range");
810                                 
811                         if (DrawMode == DrawMode.OwnerDrawVariable && IsHandleCreated == true) {
812                                 
813                                 object o = Items [index];
814                                 if (item_heights.Contains (o))
815                                         return (int) item_heights [o];
816                                 
817                                 MeasureItemEventArgs args = new MeasureItemEventArgs (DeviceContext, index, ItemHeight);
818                                 OnMeasureItem (args);
819                                 item_heights [o] = args.ItemHeight;
820                                 return args.ItemHeight;
821                         }
822
823                         return ItemHeight;
824                 }
825
826                 public Rectangle GetItemRectangle (int index)
827                 {
828                         if (index < 0 || index >= Items.Count)
829                                 throw new  ArgumentOutOfRangeException ("GetItemRectangle index out of range.");
830
831                         Rectangle rect = new Rectangle ();
832
833                         if (MultiColumn) {
834                                 int col = index / RowCount;
835                                 int y = index;
836                                 if (y < 0) // We convert it to valid positive value 
837                                         y += RowCount * (top_index / RowCount);
838                                 rect.Y = (y % RowCount) * ItemHeight;
839                                 rect.X = (col - (top_index / RowCount)) * ColumnWidthInternal;
840                                 rect.Height = ItemHeight;
841                                 rect.Width = ColumnWidthInternal;
842                         } else {
843                                 rect.X = 0;
844                                 rect.Height = GetItemHeight (index);
845                                 rect.Width = items_area.Width;
846                                 
847                                 if (DrawMode == DrawMode.OwnerDrawVariable) {
848                                         rect.Y = 0;
849                                         if (index >= top_index) {
850                                                 for (int i = top_index; i < index; i++) {
851                                                         rect.Y += GetItemHeight (i);
852                                                 }
853                                         } else {
854                                                 for (int i = index; i < top_index; i++) {
855                                                         rect.Y -= GetItemHeight (i);
856                                                 }
857                                         }
858                                 } else {
859                                         rect.Y = ItemHeight * (index - top_index);      
860                                 }
861                         }
862
863                         if (this is CheckedListBox)
864                                 rect.Width += 15;
865                                 
866                         return rect;
867                 }
868
869                 [EditorBrowsable (EditorBrowsableState.Advanced)]
870                 protected override Rectangle GetScaledBounds (Rectangle bounds, SizeF factor, BoundsSpecified specified)
871                 {
872                         bounds.Height = requested_height;
873
874                         return base.GetScaledBounds (bounds, factor, specified);
875                 }
876
877                 public bool GetSelected (int index)
878                 {
879                         if (index < 0 || index >= Items.Count)
880                                 throw new ArgumentOutOfRangeException ("Index of out range");
881
882                         return SelectedIndices.Contains (index);
883                 }
884
885                 public int IndexFromPoint (Point p)
886                 {
887                         return IndexFromPoint (p.X, p.Y);
888                 }
889
890                 // Only returns visible points
891                 public int IndexFromPoint (int x, int y)
892                 {
893
894                         if (Items.Count == 0) {
895                                 return -1;
896                         }
897
898                         for (int i = top_index; i <= last_visible_index; i++) {
899                                 if (GetItemRectangle (i).Contains (x,y) == true)
900                                         return i;
901                         }
902
903                         return -1;
904                 }
905
906                 protected override void OnChangeUICues (UICuesEventArgs e)
907                 {
908                         base.OnChangeUICues (e);
909                 }
910
911                 protected override void OnDataSourceChanged (EventArgs e)
912                 {
913                         base.OnDataSourceChanged (e);
914                         BindDataItems ();
915                         
916                         if (DataSource == null || DataManager == null) {
917                                 SelectedIndex = -1;
918                         } else {
919                                 SelectedIndex = DataManager.Position;
920                         }
921                 }
922
923                 protected override void OnDisplayMemberChanged (EventArgs e)
924                 {
925                         base.OnDisplayMemberChanged (e);
926
927                         if (DataManager == null || !IsHandleCreated)
928                                 return;
929
930                         BindDataItems ();
931                         base.Refresh ();
932                 }
933
934                 protected virtual void OnDrawItem (DrawItemEventArgs e)
935                 {                       
936                         switch (DrawMode) {
937                         case DrawMode.OwnerDrawFixed:
938                         case DrawMode.OwnerDrawVariable:
939                                 DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]);
940                                 if (eh != null)
941                                         eh (this, e);
942
943                                 break;
944
945                         default:
946                                 ThemeEngine.Current.DrawListBoxItem (this, e);
947                                 break;
948                         }
949                 }
950
951                 protected override void OnFontChanged (EventArgs e)
952                 {
953                         base.OnFontChanged (e);
954
955                         if (use_tabstops)
956                                 StringFormat.SetTabStops (0, new float [] {(float)(Font.Height * 3.7)});
957
958                         if (explicit_item_height) {
959                                 base.Refresh ();
960                         } else {
961                                 SizeF sz = TextRenderer.MeasureString ("The quick brown Fox", Font);
962                                 item_height = (int) sz.Height;
963                                 if (IntegralHeight)
964                                         UpdateListBoxBounds ();
965                                 LayoutListBox ();
966                         }
967                 }
968
969                 protected override void OnHandleCreated (EventArgs e)
970                 {
971                         base.OnHandleCreated (e);
972
973                         if (IntegralHeight)
974                                 UpdateListBoxBounds ();
975
976                         LayoutListBox ();
977                         EnsureVisible (focused_item);
978                 }
979
980                 protected override void OnHandleDestroyed (EventArgs e)
981                 {
982                         base.OnHandleDestroyed (e);
983                 }
984
985                 protected virtual void OnMeasureItem (MeasureItemEventArgs e)
986                 {
987                         if (draw_mode != DrawMode.OwnerDrawVariable)
988                                 return;
989
990                         MeasureItemEventHandler eh = (MeasureItemEventHandler)(Events [MeasureItemEvent]);
991                         if (eh != null)
992                                 eh (this, e);
993                 }
994
995                 protected override void OnParentChanged (EventArgs e)
996                 {
997                         base.OnParentChanged (e);
998                 }
999
1000                 protected override void OnResize (EventArgs e)
1001                 {
1002                         base.OnResize (e);
1003                         if (canvas_size.IsEmpty || MultiColumn)
1004                                 LayoutListBox ();
1005                                 
1006                         Invalidate ();
1007                 }
1008
1009                 protected override void OnSelectedIndexChanged (EventArgs e)
1010                 {
1011                         base.OnSelectedIndexChanged (e);
1012
1013                         EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
1014                         if (eh != null)
1015                                 eh (this, e);
1016                 }
1017
1018                 protected override void OnSelectedValueChanged (EventArgs e)
1019                 {
1020                         base.OnSelectedValueChanged (e);
1021                 }
1022
1023                 public override void Refresh ()
1024                 {
1025                         if (draw_mode == DrawMode.OwnerDrawVariable)
1026                                 item_heights.Clear ();
1027                         
1028                         base.Refresh ();
1029                 }
1030
1031                 protected override void RefreshItem (int index)
1032                 {
1033                         if (index < 0 || index >= Items.Count)
1034                                 throw new ArgumentOutOfRangeException ("Index of out range");
1035                                 
1036                         if (draw_mode == DrawMode.OwnerDrawVariable)
1037                                 item_heights.Remove (Items [index]);
1038                 }
1039
1040                 protected override void RefreshItems ()
1041                 {
1042                         for (int i = 0; i < Items.Count; i++) {
1043                                 RefreshItem (i);
1044                         }
1045
1046                         LayoutListBox ();
1047                         Refresh ();
1048                 }
1049
1050                 public override void ResetBackColor ()
1051                 {
1052                         base.ResetBackColor ();
1053                 }
1054
1055                 public override void ResetForeColor ()
1056                 {
1057                         base.ResetForeColor ();
1058                 }
1059
1060                 protected override void ScaleControl (SizeF factor, BoundsSpecified specified)
1061                 {
1062                         base.ScaleControl (factor, specified);
1063                 }
1064
1065                 private int SnapHeightToIntegral (int height)
1066                 {
1067                         int border;
1068
1069                         switch (border_style) {
1070                         case BorderStyle.Fixed3D:
1071                                 border = ThemeEngine.Current.Border3DSize.Height;
1072                                 break;
1073                         case BorderStyle.FixedSingle:
1074                                 border = ThemeEngine.Current.BorderSize.Height;
1075                                 break;
1076                         case BorderStyle.None:
1077                         default:
1078                                 border = 0;
1079                                 break;
1080                         }
1081
1082                         height -= (2 * border);
1083                         height -= height % ItemHeight;
1084                         height += (2 * border);
1085
1086                         return height;
1087                 }
1088                 
1089                 protected override void SetBoundsCore (int x,  int y, int width, int height, BoundsSpecified specified)
1090                 {
1091                         if ((specified & BoundsSpecified.Height) == BoundsSpecified.Height)
1092                                 requested_height = height;
1093
1094                         if (IntegralHeight && IsHandleCreated)
1095                                 height = SnapHeightToIntegral (height);
1096
1097                         base.SetBoundsCore (x, y, width, height, specified);
1098                         UpdateScrollBars ();
1099                         last_visible_index = LastVisibleItem ();
1100                 }
1101
1102                 protected override void SetItemCore (int index,  object value)
1103                 {
1104                         if (index < 0 || index >= Items.Count)
1105                                 return;
1106
1107                         Items[index] = value;
1108                 }
1109
1110                 protected override void SetItemsCore (IList value)
1111                 {
1112                         BeginUpdate ();
1113                         try {
1114                                 Items.Clear ();
1115                                 Items.AddItems (value);
1116                         } finally {
1117                                 EndUpdate ();
1118                         }
1119                 }
1120
1121                 public void SetSelected (int index, bool value)
1122                 {
1123                         if (index < 0 || index >= Items.Count)
1124                                 throw new ArgumentOutOfRangeException ("Index of out range");
1125
1126                         if (SelectionMode == SelectionMode.None)
1127                                 throw new InvalidOperationException ();
1128
1129                         if (value)
1130                                 SelectedIndices.Add (index);
1131                         else
1132                                 SelectedIndices.Remove (index);
1133                 }
1134
1135                 protected virtual void Sort ()
1136                 {
1137                         Sort (true);
1138                 }
1139
1140                 //
1141                 // Sometimes we could need to Sort, and request a Refresh
1142                 // in a different place, to not have the painting done twice
1143                 //
1144                 void Sort (bool paint)
1145                 {
1146                         if (Items.Count == 0)
1147                                 return;
1148
1149                         Items.Sort ();
1150
1151                         if (paint)
1152                                 base.Refresh ();
1153                 }
1154
1155                 public override string ToString ()
1156                 {
1157                         return base.ToString ();
1158                 }
1159
1160                 protected virtual void WmReflectCommand (ref Message m)
1161                 {
1162                 }
1163
1164                 protected override void WndProc (ref Message m)
1165                 {
1166                         if ((Msg)m.Msg == Msg.WM_KEYDOWN) {
1167                                 if (ProcessKeyMessage (ref m))
1168                                         m.Result = IntPtr.Zero;
1169                                 else {
1170                                         HandleKeyDown ((Keys)m.WParam.ToInt32 ());
1171                                         DefWndProc (ref m);
1172                                 }
1173
1174                                 return;
1175                         }
1176
1177                         base.WndProc (ref m);
1178                 }
1179
1180                 #endregion Public Methods
1181
1182                 #region Private Methods
1183
1184                 private void CalculateTabStops ()
1185                 {
1186                         if (use_tabstops) {
1187                                 if (use_custom_tab_offsets) {
1188                                         float[] f = new float[custom_tab_offsets.Count];
1189                                         custom_tab_offsets.CopyTo (f, 0);
1190                                         StringFormat.SetTabStops (0, f);
1191                                 }
1192                                 else
1193                                         StringFormat.SetTabStops (0, new float[] { (float)(Font.Height * 3.7) });
1194                         } else
1195                                 StringFormat.SetTabStops (0, new float[0]);
1196
1197                         this.Invalidate ();
1198                 }
1199
1200                 private Size canvas_size;
1201
1202                 private void LayoutListBox ()
1203                 {
1204                         if (!IsHandleCreated || suspend_layout)
1205                                 return;
1206
1207                         if (MultiColumn)
1208                                 LayoutMultiColumn ();
1209                         else
1210                                 LayoutSingleColumn ();
1211
1212                         last_visible_index = LastVisibleItem ();
1213                         UpdateScrollBars ();
1214                 }
1215
1216                 private void LayoutSingleColumn ()
1217                 {
1218                         int height, width;
1219
1220                         switch (DrawMode) {
1221                         case DrawMode.OwnerDrawVariable:
1222                                 height = 0;
1223                                 width = HorizontalExtent;
1224                                 for (int i = 0; i < Items.Count; i++) {
1225                                         height += GetItemHeight (i);
1226                                 }
1227                                 break;
1228
1229                         case DrawMode.OwnerDrawFixed:
1230                                 height = Items.Count * ItemHeight;
1231                                 width = HorizontalExtent;
1232                                 break;
1233
1234                         case DrawMode.Normal:
1235                         default:
1236                                 height = Items.Count * ItemHeight;
1237                                 width = 0;
1238                                 for (int i = 0; i < Items.Count; i++) {
1239                                         SizeF sz = TextRenderer.MeasureString (GetItemText (Items[i]), Font);
1240                                         int t = (int)sz.Width;
1241                                         
1242                                         if (this is CheckedListBox)
1243                                                 t += 15;
1244                                                 
1245                                         if (t > width)
1246                                                 width = t;
1247                                 }
1248                                 break;
1249                         }
1250
1251                         canvas_size = new Size (width, height);
1252                 }
1253
1254                 private void LayoutMultiColumn ()
1255                 {
1256                         int usable_height = ClientRectangle.Height - (ScrollAlwaysVisible ? hscrollbar.Height : 0);
1257                         row_count = Math.Max (1, usable_height / ItemHeight);
1258
1259                         int cols = (int) Math.Ceiling ((float)Items.Count / (float) row_count);
1260                         Size sz = new Size (cols * ColumnWidthInternal, row_count * ItemHeight);
1261                         if (!ScrollAlwaysVisible && sz.Width > ClientRectangle.Width && row_count > 1) {
1262                                 usable_height = ClientRectangle.Height - hscrollbar.Height;
1263                                 row_count = Math.Max (1, usable_height / ItemHeight);
1264                                 cols = (int) Math.Ceiling ((float)Items.Count / (float) row_count);
1265                                 sz = new Size (cols * ColumnWidthInternal, row_count * ItemHeight);
1266                         }
1267                         canvas_size = sz;
1268                 }
1269
1270                 internal void Draw (Rectangle clip, Graphics dc)
1271                 {
1272                         Theme theme = ThemeEngine.Current;
1273
1274                         if (hscrollbar.Visible && vscrollbar.Visible) {
1275                                 // Paint the dead space in the bottom right corner
1276                                 Rectangle rect = new Rectangle (hscrollbar.Right, vscrollbar.Bottom, vscrollbar.Width, hscrollbar.Height);
1277                                 if (rect.IntersectsWith (clip))
1278                                         dc.FillRectangle (theme.ResPool.GetSolidBrush (theme.ColorControl), rect);
1279                         }
1280
1281                         dc.FillRectangle (theme.ResPool.GetSolidBrush (BackColor), items_area);
1282
1283                         if (Items.Count == 0)
1284                                 return;
1285
1286                         for (int i = top_index; i <= last_visible_index; i++) {
1287                                 Rectangle rect = GetItemDisplayRectangle (i, top_index);
1288
1289                                 if (!clip.IntersectsWith (rect))
1290                                         continue;
1291
1292                                 DrawItemState state = DrawItemState.None;
1293
1294                                 if (SelectedIndices.Contains (i))
1295                                         state |= DrawItemState.Selected;
1296                                         
1297                                 if (has_focus && FocusedItem == i)
1298                                         state |= DrawItemState.Focus;
1299                                         
1300                                 if (MultiColumn == false && hscrollbar != null && hscrollbar.Visible) {
1301                                         rect.X -= hscrollbar.Value;
1302                                         rect.Width += hscrollbar.Value;
1303                                 }
1304
1305                                 Color fore_color = !Enabled ? ThemeEngine.Current.ColorGrayText :
1306                                         (state & DrawItemState.Selected) != 0 ? ThemeEngine.Current.ColorHighlightText : ForeColor;
1307                                 OnDrawItem (new DrawItemEventArgs (dc, Font, rect, i, state, fore_color, BackColor));
1308                         }
1309                 }
1310
1311                 // Converts a GetItemRectangle to a one that we can display
1312                 internal Rectangle GetItemDisplayRectangle (int index, int first_displayble)
1313                 {
1314                         Rectangle item_rect;
1315                         Rectangle first_item_rect = GetItemRectangle (first_displayble);
1316                         item_rect = GetItemRectangle (index);
1317                         item_rect.X -= first_item_rect.X;
1318                         item_rect.Y -= first_item_rect.Y;
1319                         
1320                         // Subtract the checkboxes from the width
1321                         if (this is CheckedListBox)
1322                                 item_rect.Width -= 14;
1323
1324                         return item_rect;
1325                 }
1326
1327                 // Value Changed
1328                 private void HorizontalScrollEvent (object sender, EventArgs e)
1329                 {
1330                         if (multicolumn) {
1331                                 int top_item = top_index;
1332                                 int last_item = last_visible_index;
1333
1334                                 top_index = RowCount * hscrollbar.Value;
1335                                 last_visible_index = LastVisibleItem ();
1336
1337                                 if (top_item != top_index || last_item != last_visible_index)
1338                                         Invalidate (items_area);
1339                         }
1340                         else {
1341                                 int old_offset = hbar_offset;
1342                                 hbar_offset = hscrollbar.Value;
1343
1344                                 if (hbar_offset < 0)
1345                                         hbar_offset = 0;
1346
1347                                 if (IsHandleCreated) {
1348                                         XplatUI.ScrollWindow (Handle, items_area, old_offset - hbar_offset, 0, false);
1349
1350                                         // Invalidate the previous selection border, to keep it properly updated.
1351                                         Rectangle selection_border_area = new Rectangle (items_area.Width - (hbar_offset - old_offset) - 3, 0, 
1352                                                         3, items_area.Height);
1353                                         Invalidate (selection_border_area);
1354                                 }
1355                         }
1356                 }
1357
1358                 // Only returns visible points. The diference of with IndexFromPoint is that the rectangle
1359                 // has screen coordinates
1360                 private int IndexAtClientPoint (int x, int y)
1361                 {       
1362                         if (Items.Count == 0)
1363                                 return -1;
1364                         
1365                         if (x < 0)
1366                                 x = 0;
1367                         else if (x > ClientRectangle.Right)
1368                                 x = ClientRectangle.Right;
1369
1370                         if (y < 0)
1371                                 y = 0;
1372                         else if (y > ClientRectangle.Bottom)
1373                                 y = ClientRectangle.Bottom;
1374
1375                         for (int i = top_index; i <= last_visible_index; i++)
1376                                 if (GetItemDisplayRectangle (i, top_index).Contains (x, y))
1377                                         return i;
1378
1379                         return -1;
1380                 }
1381
1382                 internal override bool IsInputCharInternal (char charCode)
1383                 {
1384                         return true;
1385                 }
1386
1387                 private int LastVisibleItem ()
1388                 {
1389                         Rectangle item_rect;
1390                         int top_y = items_area.Y + items_area.Height;
1391                         int i = 0;
1392
1393                         if (top_index >= Items.Count)
1394                                 return top_index;
1395
1396                         for (i = top_index; i < Items.Count; i++) {
1397                                 item_rect = GetItemDisplayRectangle (i, top_index);
1398                                 if (MultiColumn) {
1399                                         if (item_rect.X > items_area.Width)
1400                                                 return i - 1;
1401                                 } else {
1402                                         if (item_rect.Y + item_rect.Height > top_y)
1403                                                 return i;
1404                                 }
1405                         }
1406                         return i - 1;
1407                 }
1408
1409                 private void UpdateTopItem ()
1410                 {
1411                         if (MultiColumn) {
1412                                 int col = top_index / RowCount;
1413                                 
1414                                 if (col > hscrollbar.Maximum)
1415                                         hscrollbar.Value = hscrollbar.Maximum;
1416                                 else
1417                                         hscrollbar.Value = col;
1418                         } else {
1419                                 if (top_index > vscrollbar.Maximum)
1420                                         vscrollbar.Value = vscrollbar.Maximum;
1421                                 else
1422                                         vscrollbar.Value = top_index;
1423                                 Scroll (vscrollbar, vscrollbar.Value - top_index);
1424                         }
1425                 }
1426                 
1427                 // Navigates to the indicated item and returns the new item
1428                 private int NavigateItemVisually (ItemNavigation navigation)
1429                 {                       
1430                         int page_size, columns, selected_index = -1;
1431
1432                         if (multicolumn) {
1433                                 columns = items_area.Width / ColumnWidthInternal; 
1434                                 page_size = columns * RowCount;
1435                                 if (page_size == 0) {
1436                                         page_size = RowCount;
1437                                 }
1438                         } else {
1439                                 page_size = items_area.Height / ItemHeight;     
1440                         }
1441
1442                         switch (navigation) {
1443
1444                         case ItemNavigation.PreviousColumn: {
1445                                 if (SelectedIndex - RowCount < 0) {
1446                                         return -1;
1447                                 }
1448
1449                                 if (SelectedIndex - RowCount < top_index) {
1450                                         top_index = SelectedIndex - RowCount;
1451                                         UpdateTopItem ();
1452                                 }
1453                                         
1454                                 selected_index = SelectedIndex - RowCount;
1455                                 break;
1456                         }
1457                         
1458                         case ItemNavigation.NextColumn: {
1459                                 if (SelectedIndex + RowCount >= Items.Count) {
1460                                         break;
1461                                 }
1462
1463                                 if (SelectedIndex + RowCount > last_visible_index) {
1464                                         top_index = SelectedIndex;
1465                                         UpdateTopItem ();
1466                                 }
1467                                         
1468                                 selected_index = SelectedIndex + RowCount;
1469                                 break;
1470                         }
1471
1472                         case ItemNavigation.First: {
1473                                 top_index = 0;
1474                                 selected_index  = 0;
1475                                 UpdateTopItem ();
1476                                 break;
1477                         }
1478
1479                         case ItemNavigation.Last: {
1480
1481                                 int rows = items_area.Height / ItemHeight;
1482                                 
1483                                 if (multicolumn) {
1484                                         selected_index = Items.Count - 1;
1485                                         break;
1486                                 }
1487                                 if (Items.Count < rows) {
1488                                         top_index = 0;
1489                                         selected_index  = Items.Count - 1;
1490                                         UpdateTopItem ();
1491                                 } else {
1492                                         top_index = Items.Count - rows;
1493                                         selected_index  = Items.Count - 1;
1494                                         UpdateTopItem ();
1495                                 }
1496                                 break;
1497                         }
1498
1499                         case ItemNavigation.Next: {
1500                                 if (FocusedItem == Items.Count - 1)
1501                                         return -1;
1502
1503                                 if (multicolumn) {
1504                                         selected_index = FocusedItem + 1;
1505                                         break;
1506                                 }
1507                                 
1508                                 int bottom = 0;
1509                                 ArrayList heights = new ArrayList ();
1510                                 if (draw_mode == DrawMode.OwnerDrawVariable) {
1511                                         for (int i = top_index; i <= FocusedItem + 1; i++) {
1512                                                 int h = GetItemHeight (i);
1513                                                 bottom += h;
1514                                                 heights.Add (h);
1515                                         }
1516                                 } else {
1517                                         bottom = ((FocusedItem + 1) - top_index + 1) * ItemHeight;
1518                                 }
1519
1520                                 if (bottom >= items_area.Height) {
1521                                         int overhang = bottom - items_area.Height;
1522
1523                                         int offset = 0;
1524                                         if (draw_mode == DrawMode.OwnerDrawVariable)
1525                                                 while (overhang > 0)
1526                                                         overhang -= (int) heights [offset];
1527                                         else
1528                                                 offset = (int) Math.Ceiling ((float)overhang / (float) ItemHeight);
1529                                         top_index += offset;
1530                                         UpdateTopItem ();
1531                                 }
1532                                 selected_index = FocusedItem + 1;
1533                                 break;
1534                         }
1535
1536                         case ItemNavigation.Previous: {
1537                                 if (FocusedItem > 0) {
1538                                         if (FocusedItem - 1 < top_index) {
1539                                                 top_index--;
1540                                                 UpdateTopItem ();
1541                                         }
1542                                         selected_index = FocusedItem - 1;
1543                                 }
1544                                 break;
1545                         }
1546
1547                         case ItemNavigation.NextPage: {
1548                                 if (Items.Count < page_size) {
1549                                         NavigateItemVisually (ItemNavigation.Last);
1550                                         break;
1551                                 }
1552
1553                                 if (FocusedItem + page_size - 1 >= Items.Count) {
1554                                         top_index = Items.Count - page_size;
1555                                         UpdateTopItem ();
1556                                         selected_index = Items.Count - 1;
1557                                 }
1558                                 else {
1559                                         if (FocusedItem + page_size - 1  > last_visible_index) {
1560                                                 top_index = FocusedItem;
1561                                                 UpdateTopItem ();
1562                                         }
1563                                         
1564                                         selected_index = FocusedItem + page_size - 1;
1565                                 }
1566                                         
1567                                 break;
1568                         }                       
1569
1570                         case ItemNavigation.PreviousPage: {
1571                                         
1572                                 int rows = items_area.Height / ItemHeight;
1573                                 if (FocusedItem - (rows - 1) <= 0) {
1574                                         top_index = 0;
1575                                         UpdateTopItem ();
1576                                         selected_index = 0;
1577                                 }
1578                                 else { 
1579                                         if (SelectedIndex - (rows - 1)  < top_index) {
1580                                                 top_index = FocusedItem - (rows - 1);
1581                                                 UpdateTopItem ();
1582                                         }
1583                                         
1584                                         selected_index = FocusedItem - (rows - 1);
1585                                 }
1586                                         
1587                                 break;
1588                         }               
1589                         default:
1590                                 break;
1591                         }
1592                         
1593                         return selected_index;
1594                 }
1595                 
1596                 
1597                 private void OnGotFocus (object sender, EventArgs e)
1598                 {
1599                         if (Items.Count == 0)
1600                                 return;
1601
1602                         if (FocusedItem == -1)
1603                                 FocusedItem = 0;
1604
1605                         InvalidateItem (FocusedItem);
1606                 }
1607                 
1608                 private void OnLostFocus (object sender, EventArgs e)
1609                 {
1610                         if (FocusedItem != -1)
1611                                 InvalidateItem (FocusedItem);
1612                 }
1613
1614                 private bool KeySearch (Keys key)
1615                 {
1616                         char c = (char) key;
1617                         if (!Char.IsLetterOrDigit (c))
1618                                 return false;
1619
1620                         int idx = FindString (c.ToString (), SelectedIndex);
1621                         if (idx != ListBox.NoMatches)
1622                                 SelectedIndex = idx;
1623
1624                         return true;
1625                 }
1626
1627                 internal void HandleKeyDown (Keys key)
1628                 {
1629                         int new_item = -1;
1630                         
1631                         if (Items.Count == 0)
1632                                 return;
1633
1634                         if (KeySearch (key))
1635                                 return;
1636
1637                         switch (key) {
1638                                 
1639                                 case Keys.ControlKey:
1640                                         ctrl_pressed = true;
1641                                         break;
1642                                         
1643                                 case Keys.ShiftKey:
1644                                         shift_pressed = true;
1645                                         break;
1646                                         
1647                                 case Keys.Home:
1648                                         new_item = NavigateItemVisually (ItemNavigation.First);
1649                                         break;
1650
1651                                 case Keys.End:
1652                                         new_item = NavigateItemVisually (ItemNavigation.Last);
1653                                         break;
1654
1655                                 case Keys.Up:
1656                                         new_item = NavigateItemVisually (ItemNavigation.Previous);
1657                                         break;
1658         
1659                                 case Keys.Down:
1660                                         new_item = NavigateItemVisually (ItemNavigation.Next);
1661                                         break;
1662                                 
1663                                 case Keys.PageUp:
1664                                         new_item = NavigateItemVisually (ItemNavigation.PreviousPage);
1665                                         break;
1666         
1667                                 case Keys.PageDown:
1668                                         new_item = NavigateItemVisually (ItemNavigation.NextPage);
1669                                         break;
1670
1671                                 case Keys.Right:
1672                                         if (multicolumn == true) {
1673                                                 new_item = NavigateItemVisually (ItemNavigation.NextColumn);
1674                                         }
1675                                         break;
1676         
1677                                 case Keys.Left:
1678                                         if (multicolumn == true) {
1679                                                 new_item = NavigateItemVisually (ItemNavigation.PreviousColumn);
1680                                         }
1681                                         break;
1682                                         
1683                                 case Keys.Space:
1684                                         if (selection_mode == SelectionMode.MultiSimple) {
1685                                                 SelectedItemFromNavigation (FocusedItem);
1686                                         }
1687                                         break;
1688                                 
1689
1690                                 default:
1691                                         break;
1692                                 }
1693                                 
1694                                 if (new_item != -1) {
1695                                         FocusedItem = new_item;
1696
1697                                         if (selection_mode != SelectionMode.MultiSimple)
1698                                                 SelectedItemFromNavigation (new_item);
1699                                 }
1700                 }
1701                 
1702                 private void OnKeyUpLB (object sender, KeyEventArgs e)
1703                 {
1704                         switch (e.KeyCode) {
1705                                 case Keys.ControlKey:
1706                                         ctrl_pressed = false;
1707                                         break;
1708                                 case Keys.ShiftKey:
1709                                         shift_pressed = false;
1710                                         break;
1711                                 default: 
1712                                         break;
1713                         }
1714                 }
1715
1716                 internal void InvalidateItem (int index)
1717                 {
1718                         if (!IsHandleCreated)
1719                                 return;
1720                         Rectangle bounds = GetItemDisplayRectangle (index, top_index);
1721                         if (ClientRectangle.IntersectsWith (bounds))
1722                                 Invalidate (bounds);
1723                 }
1724
1725                 internal virtual void OnItemClick (int index)
1726                 {
1727                         OnSelectedIndexChanged  (EventArgs.Empty);
1728                         OnSelectedValueChanged (EventArgs.Empty);
1729                 }
1730
1731                 int anchor = -1;
1732                 int[] prev_selection;
1733                 bool button_pressed = false;
1734                 Point button_pressed_loc = new Point (-1, -1);
1735
1736                 private void SelectExtended (int index)
1737                 {
1738                         SuspendLayout ();
1739
1740                         ArrayList new_selection = new ArrayList ();
1741                         int start = anchor < index ? anchor : index;
1742                         int end = anchor > index ? anchor : index;
1743                         for (int i = start; i <= end; i++)
1744                                 new_selection.Add (i);
1745
1746                         if (ctrl_pressed)
1747                                 foreach (int i in prev_selection)
1748                                         if (!new_selection.Contains (i))
1749                                                 new_selection.Add (i);
1750
1751                         // Need to make a copy since we can't enumerate and modify the collection
1752                         // at the same time
1753                         ArrayList sel_indices = (ArrayList) selected_indices.List.Clone ();
1754                         foreach (int i in sel_indices)
1755                                 if (!new_selection.Contains (i))
1756                                         selected_indices.Remove (i);
1757
1758                         foreach (int i in new_selection)
1759                                 if (!sel_indices.Contains (i))
1760                                         selected_indices.AddCore (i);
1761                         ResumeLayout ();
1762                 }
1763
1764                 private void OnMouseDownLB (object sender, MouseEventArgs e)
1765                 {
1766                         // Only do stuff with the left mouse button
1767                         if ((e.Button & MouseButtons.Left) == 0)
1768                                 return;
1769                         
1770                         int index = IndexAtClientPoint (e.X, e.Y);
1771                         if (index == -1)
1772                                 return;
1773
1774                         switch (SelectionMode) {
1775                         case SelectionMode.One:
1776                                 SelectedIndices.AddCore (index); // Unselects previous one
1777                                 break;
1778
1779                         case SelectionMode.MultiSimple:
1780                                 if (SelectedIndices.Contains (index))
1781                                         SelectedIndices.RemoveCore (index);
1782                                 else
1783                                         SelectedIndices.AddCore (index);
1784                                 break;
1785
1786                         case SelectionMode.MultiExtended:
1787                                 shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
1788                                 ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
1789
1790                                 if (shift_pressed) {
1791                                         SelectedIndices.ClearCore ();
1792                                         SelectExtended (index);
1793                                         break;
1794                                 }
1795
1796                                 anchor = index;
1797
1798                                 if (ctrl_pressed) {
1799                                         prev_selection = new int [SelectedIndices.Count];
1800                                         SelectedIndices.CopyTo (prev_selection, 0);
1801
1802                                         if (SelectedIndices.Contains (index))
1803                                                 SelectedIndices.RemoveCore (index);
1804                                         else
1805                                                 SelectedIndices.AddCore (index);
1806
1807                                         break;
1808                                 }
1809
1810                                 SelectedIndices.ClearCore ();
1811                                 SelectedIndices.AddCore (index);
1812                                 break;
1813
1814                         case SelectionMode.None:
1815                                 break;
1816                         default:
1817                                 return;
1818                         }
1819
1820                         button_pressed = true;
1821                         button_pressed_loc = new Point (e.X, e.Y);
1822                         FocusedItem = index;
1823                 }
1824
1825                 private void OnMouseMoveLB (object sender, MouseEventArgs e)
1826                 {
1827                         // Don't take into account MouseMove events generated with MouseDown
1828                         if (!button_pressed || button_pressed_loc == new Point (e.X, e.Y))
1829                                 return;
1830
1831                         int index = IndexAtClientPoint (e.X, e.Y);
1832                         if (index == -1)
1833                                 return;
1834
1835                         switch (SelectionMode) {
1836                         case SelectionMode.One:
1837                                 SelectedIndices.AddCore (index); // Unselects previous one
1838                                 break;
1839
1840                         case SelectionMode.MultiSimple:
1841                                 break;
1842
1843                         case SelectionMode.MultiExtended:
1844                                 SelectExtended (index);
1845                                 break;
1846
1847                         case SelectionMode.None:
1848                                 break;
1849                         default:
1850                                 return;
1851                         }
1852
1853                         FocusedItem = index;
1854                 }
1855
1856                 internal override void OnDragDropEnd (DragDropEffects effects)
1857                 {
1858                         // In the case of a DnD operation (started on MouseDown)
1859                         // there will be no MouseUp event, so we need to reset 
1860                         // the state here
1861                         button_pressed = false;
1862                 }
1863
1864                 private void OnMouseUpLB (object sender, MouseEventArgs e)
1865                 {
1866                         // Only do stuff with the left mouse button
1867                         if ((e.Button & MouseButtons.Left) == 0)
1868                                 return;
1869
1870                         if (e.Clicks > 1) {
1871                                 OnDoubleClick (EventArgs.Empty);
1872                                 OnMouseDoubleClick (e);
1873                         }
1874                         else if (e.Clicks == 1) {
1875                                 OnClick (EventArgs.Empty);
1876                                 OnMouseClick (e);
1877                         }
1878                         
1879                         if (!button_pressed)
1880                                 return;
1881
1882                         int index = IndexAtClientPoint (e.X, e.Y);
1883                         OnItemClick (index);
1884                         button_pressed = ctrl_pressed = shift_pressed = false;
1885                 }
1886
1887                 private void Scroll (ScrollBar scrollbar, int delta)
1888                 {
1889                         if (delta == 0 || !scrollbar.Visible || !scrollbar.Enabled)
1890                                 return;
1891
1892                         int max;
1893                         if (scrollbar == hscrollbar)
1894                                 max = hscrollbar.Maximum - (items_area.Width / ColumnWidthInternal) + 1;
1895                         else
1896                                 max = vscrollbar.Maximum - (items_area.Height / ItemHeight) + 1;
1897
1898                         int val = scrollbar.Value + delta;
1899                         if (val > max)
1900                                 val = max;
1901                         else if (val < scrollbar.Minimum)
1902                                 val = scrollbar.Minimum;
1903                         scrollbar.Value = val;
1904                 }
1905
1906                 private void OnMouseWheelLB (object sender, MouseEventArgs me)
1907                 {
1908                         if (Items.Count == 0)
1909                                 return;
1910
1911                         int lines = me.Delta / 120;
1912
1913                         if (MultiColumn)
1914                                 Scroll (hscrollbar, -SystemInformation.MouseWheelScrollLines * lines);
1915                         else
1916                                 Scroll (vscrollbar, -lines);
1917                 }
1918
1919                 internal override void OnPaintInternal (PaintEventArgs pevent)
1920                 {
1921                         if (suspend_layout)
1922                                 return;
1923
1924                         Draw (pevent.ClipRectangle, pevent.Graphics);
1925                 }
1926
1927                 internal void RepositionScrollBars ()
1928                 {
1929                         if (vscrollbar.is_visible) {
1930                                 vscrollbar.Size = new Size (vscrollbar.Width, items_area.Height);
1931                                 vscrollbar.Location = new Point (items_area.Width, 0);
1932                         }
1933
1934                         if (hscrollbar.is_visible) {
1935                                 hscrollbar.Size = new Size (items_area.Width, hscrollbar.Height);
1936                                 hscrollbar.Location = new Point (0, items_area.Height);
1937                         }
1938                 }
1939
1940                 // An item navigation operation (mouse or keyboard) has caused to select a new item
1941                 internal void SelectedItemFromNavigation (int index)
1942                 {
1943                         switch (SelectionMode) {
1944                                 case SelectionMode.None:
1945                                         // .Net doesn't select the item, only ensures that it's visible
1946                                         // and fires the selection related events
1947                                         EnsureVisible (index);
1948                                         OnSelectedIndexChanged (EventArgs.Empty);
1949                                         OnSelectedValueChanged (EventArgs.Empty);
1950                                         break;
1951                                 case SelectionMode.One: {
1952                                         SelectedIndex = index;
1953                                         break;
1954                                 }
1955                                 case SelectionMode.MultiSimple: {
1956                                         if (SelectedIndex == -1) {
1957                                                 SelectedIndex = index;
1958                                         } else {
1959
1960                                                 if (SelectedIndices.Contains (index))
1961                                                         SelectedIndices.Remove (index);
1962                                                 else {
1963                                                         SelectedIndices.AddCore (index);
1964
1965                                                         OnSelectedIndexChanged  (EventArgs.Empty);
1966                                                         OnSelectedValueChanged (EventArgs.Empty);
1967                                                 }
1968                                         }
1969                                         break;
1970                                 }
1971                                 
1972                                 case SelectionMode.MultiExtended: {
1973                                         if (SelectedIndex == -1) {
1974                                                 SelectedIndex = index;
1975                                         } else {
1976
1977                                                 if (ctrl_pressed == false && shift_pressed == false) {
1978                                                         SelectedIndices.Clear ();
1979                                                 }
1980                                                 
1981                                                 if (shift_pressed == true) {
1982                                                         ShiftSelection (index);
1983                                                 } else { // ctrl_pressed or single item
1984                                                         SelectedIndices.AddCore (index);
1985
1986                                                 }
1987
1988                                                 OnSelectedIndexChanged  (EventArgs.Empty);
1989                                                 OnSelectedValueChanged (EventArgs.Empty);
1990                                         }
1991                                         break;
1992                                 }
1993                                 
1994                                 default:
1995                                         break;
1996                         }
1997                 }
1998                 
1999                 private void ShiftSelection (int index)
2000                 {
2001                         int shorter_item = -1, dist = Items.Count + 1, cur_dist;
2002                         
2003                         foreach (int idx in selected_indices) {
2004                                 if (idx > index) {
2005                                         cur_dist = idx - index;
2006                                 } else {
2007                                         cur_dist = index - idx;
2008                                 }
2009
2010                                 if (cur_dist < dist) {
2011                                         dist = cur_dist;
2012                                         shorter_item = idx;
2013                                 }
2014                         }
2015                         
2016                         if (shorter_item != -1) {
2017                                 int start, end;
2018                                 
2019                                 if (shorter_item > index) {
2020                                         start = index;
2021                                         end = shorter_item;
2022                                 } else {
2023                                         start = shorter_item;
2024                                         end = index;
2025                                 }
2026                                 
2027                                 selected_indices.Clear ();
2028                                 for (int idx = start; idx <= end; idx++) {
2029                                         selected_indices.AddCore (idx);
2030                                 }
2031                         }
2032                 }
2033                 
2034                 internal int FocusedItem {
2035                         get { return focused_item; }
2036                         set {
2037                                 if (focused_item == value)
2038                                         return;
2039
2040                                 int prev = focused_item;
2041                         
2042                                 focused_item = value;
2043                         
2044                                 if (has_focus == false)
2045                                         return;
2046
2047                                 if (prev != -1)
2048                                         InvalidateItem (prev);
2049                         
2050                                 if (value != -1)
2051                                         InvalidateItem (value);
2052
2053                                 // UIA Framework: Generates FocusedItemChanged event.
2054                                 OnUIAFocusedItemChangedEvent ();
2055                         }
2056                 }
2057
2058                 StringFormat string_format;
2059                 internal StringFormat StringFormat {
2060                         get {
2061                                 if (string_format == null) {
2062                                         string_format = new StringFormat ();
2063                                         string_format.FormatFlags = StringFormatFlags.NoWrap;
2064
2065                                         if (RightToLeft == RightToLeft.Yes)
2066                                                 string_format.Alignment = StringAlignment.Far;
2067                                         else
2068                                                 string_format.Alignment = StringAlignment.Near;
2069                                         CalculateTabStops ();
2070                                 }
2071                                 return string_format;
2072                         }
2073                 }
2074
2075                 internal virtual void CollectionChanged ()
2076                 {
2077                         if (sorted) 
2078                                 Sort (false);
2079
2080                         if (Items.Count == 0) {
2081                                 selected_indices.List.Clear ();
2082                                 focused_item = -1;
2083                                 top_index = 0;
2084                         }
2085                         if (Items.Count <= focused_item)
2086                                 focused_item = Items.Count - 1;
2087
2088                         if (!IsHandleCreated || suspend_layout)
2089                                 return;
2090
2091                         LayoutListBox ();
2092
2093                         base.Refresh ();
2094                 }
2095
2096                 void EnsureVisible (int index)
2097                 {
2098                         if (!IsHandleCreated || index == -1)
2099                                 return;
2100
2101                         if (index < top_index) {
2102                                 top_index = index;
2103                                 UpdateTopItem ();
2104                                 Invalidate ();
2105                         } else if (!multicolumn) {
2106                                 int rows = items_area.Height / ItemHeight;
2107                                 if (index >= (top_index + rows))
2108                                         top_index = index - rows + 1;
2109
2110                                 UpdateTopItem ();
2111                         } else {
2112                                 int rows = Math.Max (1, items_area.Height / ItemHeight);
2113                                 int cols = Math.Max (1, items_area.Width / ColumnWidthInternal);
2114                                 
2115                                 if (index >= (top_index + (rows * cols))) {
2116                                         int incolumn = index / rows;
2117                                         top_index = (incolumn - (cols - 1)) * rows;
2118
2119                                         UpdateTopItem ();
2120                                         Invalidate ();
2121                                 }
2122                         }
2123                 }
2124
2125                 private void UpdateListBoxBounds ()
2126                 {
2127                         if (IsHandleCreated)
2128                                 SetBoundsInternal (bounds.X, bounds.Y, bounds.Width, IntegralHeight ? SnapHeightToIntegral (requested_height) : requested_height, BoundsSpecified.None);
2129                 }
2130
2131                 private void UpdateScrollBars ()
2132                 {
2133                         items_area = ClientRectangle;
2134                         if (UpdateHorizontalScrollBar ()) {
2135                                 items_area.Height -= hscrollbar.Height;
2136                                 if (UpdateVerticalScrollBar ()) {
2137                                         items_area.Width -= vscrollbar.Width;
2138                                         UpdateHorizontalScrollBar ();
2139                                 }
2140                         } else if (UpdateVerticalScrollBar ()) {
2141                                 items_area.Width -= vscrollbar.Width;
2142                                 if (UpdateHorizontalScrollBar ()) {
2143                                         items_area.Height -= hscrollbar.Height;
2144                                         UpdateVerticalScrollBar ();
2145                                 }
2146                         }
2147
2148                         RepositionScrollBars ();
2149                 }
2150
2151                 /* Determines if the horizontal scrollbar has to be displyed */
2152                 private bool UpdateHorizontalScrollBar ()
2153                 {
2154                         bool show = false;
2155                         bool enabled = true;
2156
2157                         if (MultiColumn) {
2158                                 if (canvas_size.Width > items_area.Width) {
2159                                         show = true;
2160                                         hscrollbar.Maximum  = canvas_size.Width / ColumnWidthInternal - 1;
2161                                 } else if (ScrollAlwaysVisible == true) {
2162                                         enabled = false;
2163                                         show = true;
2164                                         hscrollbar.Maximum  = 0;
2165                                 }
2166                         } else if (canvas_size.Width > ClientRectangle.Width && HorizontalScrollbar) {
2167                                 show = true;
2168                                 hscrollbar.Maximum = canvas_size.Width;
2169                                 hscrollbar.LargeChange = Math.Max (0, items_area.Width);
2170                         } else if (scroll_always_visible && horizontal_scrollbar) {
2171                                 show = true;
2172                                 enabled = false;
2173                                 hscrollbar.Maximum = 0;
2174                         }
2175
2176                         hbar_offset = hscrollbar.Value;
2177                         hscrollbar.Enabled = enabled;
2178                         hscrollbar.Visible = show;
2179
2180                         return show;
2181                 }
2182
2183                 /* Determines if the vertical scrollbar has to be displyed */
2184                 private bool UpdateVerticalScrollBar ()
2185                 {
2186                         if (MultiColumn || (Items.Count == 0 && !scroll_always_visible)) {
2187                                 vscrollbar.Visible = false;
2188                                 return false;
2189                         } else if (Items.Count == 0) {
2190                                 vscrollbar.Visible = true;
2191                                 vscrollbar.Enabled = false;
2192                                 vscrollbar.Maximum = 0;
2193                                 return true;
2194                         }
2195
2196                         bool show = false;
2197                         bool enabled = true;
2198                         if (canvas_size.Height > items_area.Height) {
2199                                 show = true;
2200                                 vscrollbar.Maximum = Items.Count - 1;
2201                                 vscrollbar.LargeChange = Math.Max (items_area.Height / ItemHeight, 0);
2202                         } else if (ScrollAlwaysVisible) {
2203                                 show = true;
2204                                 enabled = false;
2205                                 vscrollbar.Maximum = 0;
2206                         }
2207
2208                         vscrollbar.Enabled = enabled;
2209                         vscrollbar.Visible = show;
2210
2211                         return show;
2212                 }
2213
2214                 // Value Changed
2215                 private void VerticalScrollEvent (object sender, EventArgs e)
2216                 {
2217                         int top_item = top_index;
2218
2219                         top_index = /*row_count + */ vscrollbar.Value;
2220                         last_visible_index = LastVisibleItem ();
2221
2222                         int delta = (top_item - top_index) * ItemHeight;
2223                         if (DrawMode == DrawMode.OwnerDrawVariable) {
2224                                 delta = 0;
2225
2226                                 if (top_index < top_item)
2227                                         for (int i = top_index; i < top_item; i++)
2228                                                 delta += GetItemHeight (i);
2229                                 else 
2230                                         for (int i = top_item; i < top_index; i++)
2231                                                 delta -= GetItemHeight (i);
2232                         }
2233
2234                         if (IsHandleCreated)
2235                                 XplatUI.ScrollWindow (Handle, items_area, 0, delta, false);
2236                 }
2237
2238                 #endregion Private Methods
2239
2240                 public class IntegerCollection : IList, ICollection, IEnumerable
2241                 {
2242                         private ListBox owner;
2243                         private List<int> list;
2244                         
2245                         #region Public Constructor
2246                         public IntegerCollection (ListBox owner)
2247                         {
2248                                 this.owner = owner;
2249                                 list = new List<int> ();
2250                         }
2251                         #endregion
2252
2253                         #region Public Properties
2254                         [Browsable (false)]
2255                         public int Count {
2256                                 get { return list.Count; }
2257                         }
2258                         
2259                         public int this [int index] {
2260                                 get { return list[index]; }
2261                                 set { list[index] = value; owner.CalculateTabStops (); }
2262                         }
2263                         #endregion
2264
2265                         #region Public Methods
2266                         public int Add (int item)
2267                         {
2268                                 // This collection does not allow duplicates
2269                                 if (!list.Contains (item)) {
2270                                         list.Add (item);
2271                                         list.Sort ();
2272                                         owner.CalculateTabStops ();
2273                                 }
2274                                 
2275                                 return list.IndexOf (item);
2276                         }
2277                         
2278                         public void AddRange (int[] items)
2279                         {
2280                                 AddItems (items);
2281                         }
2282                         
2283                         public void AddRange (IntegerCollection value)
2284                         {
2285                                 AddItems (value);
2286                         }
2287
2288                         void AddItems (IList items)
2289                         {
2290                                 if (items == null)
2291                                         throw new ArgumentNullException ("items");
2292
2293                                 foreach (int i in items)
2294                                         if (!list.Contains (i))
2295                                                 list.Add (i);
2296
2297                                 list.Sort ();
2298                         }
2299
2300                         public void Clear ()
2301                         {
2302                                 list.Clear ();
2303                                 owner.CalculateTabStops ();
2304                         }
2305                         
2306                         public bool Contains (int item)
2307                         {
2308                                 return list.Contains (item);
2309                         }
2310                         
2311                         public void CopyTo (Array destination, int index)
2312                         {
2313                                 for (int i = 0; i < list.Count; i++)
2314                                         destination.SetValue (list[i], index++);
2315                         }
2316                         
2317                         public int IndexOf (int item)
2318                         {
2319                                 return list.IndexOf (item);
2320                         }
2321                         
2322                         public void Remove (int item)
2323                         {
2324                                 list.Remove (item);
2325                                 list.Sort ();
2326                                 owner.CalculateTabStops ();
2327                         }
2328                         
2329                         public void RemoveAt (int index)
2330                         {
2331                                 if (index < 0)
2332                                         throw new IndexOutOfRangeException ();
2333
2334                                 list.RemoveAt (index);
2335                                 list.Sort ();
2336                                 owner.CalculateTabStops ();
2337                         }
2338                         #endregion
2339
2340                         #region IEnumerable Members
2341                         IEnumerator IEnumerable.GetEnumerator ()
2342                         {
2343                                 return list.GetEnumerator ();
2344                         }
2345                         #endregion
2346
2347                         #region IList Members
2348                         int IList.Add (object item)
2349                         {
2350                                 int? intValue = item as int?;
2351                                 if (!intValue.HasValue)
2352                                         throw new ArgumentException ("item");
2353                                 return Add (intValue.Value);
2354                         }
2355
2356                         void IList.Clear ()
2357                         {
2358                                 Clear ();
2359                         }
2360
2361                         bool IList.Contains (object item)
2362                         {
2363                                 int? intValue = item as int?;
2364                                 if (!intValue.HasValue)
2365                                         return false;
2366                                 return Contains (intValue.Value);
2367                         }
2368
2369                         int IList.IndexOf (object item)
2370                         {
2371                                 int? intValue = item as int?;
2372                                 if (!intValue.HasValue)
2373                                         return -1;
2374                                 return IndexOf (intValue.Value);
2375                         }
2376
2377                         void IList.Insert (int index, object value)
2378                         {
2379                                 throw new NotSupportedException (string.Format (
2380                                         CultureInfo.InvariantCulture, "No items "
2381                                         + "can be inserted into {0}, since it is"
2382                                         + " a sorted collection.", this.GetType ()));
2383                         }
2384
2385                         bool IList.IsFixedSize
2386                         {
2387                                 get { return false; }
2388                         }
2389
2390                         bool IList.IsReadOnly
2391                         {
2392                                 get { return false; }
2393                         }
2394
2395                         void IList.Remove (object value)
2396                         {
2397                                 int? intValue = value as int?;
2398                                 if (!intValue.HasValue)
2399                                         throw new ArgumentException ("value");
2400
2401                                 Remove (intValue.Value);
2402                         }
2403
2404                         void IList.RemoveAt (int index)
2405                         {
2406                                 RemoveAt (index);
2407                         }
2408
2409                         object IList.this[int index] {
2410                                 get { return this[index]; }
2411                                 set { this[index] = (int)value; }
2412                         }
2413                         #endregion
2414
2415                         #region ICollection Members
2416                         bool ICollection.IsSynchronized {
2417                                 get { return true; }
2418                         }
2419
2420                         object ICollection.SyncRoot {
2421                                 get { return this; }
2422                         }
2423                         #endregion
2424                 }
2425
2426                 [ListBindable (false)]
2427                 public class ObjectCollection : IList, ICollection, IEnumerable
2428                 {
2429                         internal class ListObjectComparer : IComparer
2430                         {
2431                                 public int Compare (object a, object b)
2432                                 {
2433                                         string str1 = a.ToString ();
2434                                         string str2 = b.ToString ();
2435                                         return str1.CompareTo (str2);
2436                                 }
2437                         }
2438
2439                         private ListBox owner;
2440                         internal ArrayList object_items = new ArrayList ();
2441                         
2442                         #region UIA Framework Events 
2443                         //NOTE:
2444                         //      We are using Reflection to add/remove internal events.
2445                         //      Class ListProvider uses the events.
2446                         //
2447                         //Event used to generate UIA StructureChangedEvent
2448                         static object UIACollectionChangedEvent = new object ();
2449
2450                         internal event CollectionChangeEventHandler UIACollectionChanged {
2451                                 add { owner.Events.AddHandler (UIACollectionChangedEvent, value); }
2452                                 remove { owner.Events.RemoveHandler (UIACollectionChangedEvent, value); }
2453                         }
2454
2455                         internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
2456                         {
2457                                 CollectionChangeEventHandler eh
2458                                         = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
2459                                 if (eh != null)
2460                                         eh (owner, args);
2461                         }
2462                         #endregion UIA Framework Events 
2463
2464                         public ObjectCollection (ListBox owner)
2465                         {
2466                                 this.owner = owner;
2467                         }
2468
2469                         public ObjectCollection (ListBox owner, object[] value)
2470                         {
2471                                 this.owner = owner;
2472                                 AddRange (value);
2473                         }
2474
2475                         public ObjectCollection (ListBox owner,  ObjectCollection value)
2476                         {
2477                                 this.owner = owner;
2478                                 AddRange (value);
2479                         }
2480
2481                         #region Public Properties
2482                         public int Count {
2483                                 get { return object_items.Count; }
2484                         }
2485
2486                         public bool IsReadOnly {
2487                                 get { return false; }
2488                         }
2489
2490                         [Browsable(false)]
2491                         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
2492                         public virtual object this [int index] {
2493                                 get {
2494                                         if (index < 0 || index >= Count)
2495                                                 throw new ArgumentOutOfRangeException ("Index of out range");
2496
2497                                         return object_items[index];
2498                                 }
2499                                 set {
2500                                         if (index < 0 || index >= Count)
2501                                                 throw new ArgumentOutOfRangeException ("Index of out range");
2502                                         if (value == null)
2503                                                 throw new ArgumentNullException ("value");
2504                                                 
2505                                         //UIA Framework event: Item Removed
2506                                         OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, object_items [index]));
2507
2508                                         object_items[index] = value;
2509                                         
2510                                         //UIA Framework event: Item Added
2511                                         OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value));
2512
2513                                         owner.CollectionChanged ();
2514                                 }
2515                         }
2516
2517                         bool ICollection.IsSynchronized {
2518                                 get { return false; }
2519                         }
2520
2521                         object ICollection.SyncRoot {
2522                                 get { return this; }
2523                         }
2524
2525                         bool IList.IsFixedSize {
2526                                 get { return false; }
2527                         }
2528
2529                         #endregion Public Properties
2530                         
2531                         #region Public Methods
2532                         public int Add (object item)
2533                         {
2534                                 int idx;
2535                                 object[] selectedItems = null;
2536
2537                                 // we need to remember the original selected items so that we can update the indices
2538                                 if (owner.sorted) {
2539                                         selectedItems = new object[owner.SelectedItems.Count];
2540                                         owner.SelectedItems.CopyTo (selectedItems, 0);
2541                                 }
2542
2543                                 idx = AddItem (item);
2544                                 owner.CollectionChanged ();
2545                                 
2546                                 // If we are sorted, the item probably moved indexes, get the real one
2547                                 if (owner.sorted) {
2548                                         // update indices of selected items
2549                                         owner.SelectedIndices.Clear ();
2550                                         for (int i = 0; i < selectedItems.Length; i++) {
2551                                                 owner.SelectedIndex = this.IndexOf (selectedItems [i]);
2552                                         }
2553                                         return this.IndexOf (item);
2554                                 }
2555                                         
2556                                 return idx;
2557                         }
2558
2559                         public void AddRange (object[] items)
2560                         {
2561                                 AddItems (items);
2562                         }
2563
2564                         public void AddRange (ObjectCollection value)
2565                         {
2566                                 AddItems (value);
2567                         }
2568
2569                         internal void AddItems (IList items)
2570                         {
2571                                 if (items == null)
2572                                         throw new ArgumentNullException ("items");
2573
2574                                 foreach (object mi in items)
2575                                         AddItem (mi);
2576
2577                                 owner.CollectionChanged ();
2578                         }
2579
2580                         public virtual void Clear ()
2581                         {
2582                                 owner.selected_indices.ClearCore ();
2583                                 object_items.Clear ();
2584                                 owner.CollectionChanged ();
2585
2586                                 //UIA Framework event: Items list cleared
2587                                 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
2588                         }
2589
2590                         public bool Contains (object value)
2591                         {
2592                                 if (value == null)
2593                                         throw new ArgumentNullException ("value");
2594
2595                                 return object_items.Contains (value);
2596                         }
2597
2598                         public void CopyTo (object[] destination, int arrayIndex)
2599                         {
2600                                 object_items.CopyTo (destination, arrayIndex);
2601                         }
2602
2603                         void ICollection.CopyTo (Array destination, int index)
2604                         {
2605                                 object_items.CopyTo (destination, index);
2606                         }
2607
2608                         public IEnumerator GetEnumerator ()
2609                         {
2610                                 return object_items.GetEnumerator ();
2611                         }
2612
2613                         int IList.Add (object item)
2614                         {
2615                                 return Add (item);
2616                         }
2617
2618                         public int IndexOf (object value)
2619                         {
2620                                 if (value == null)
2621                                         throw new ArgumentNullException ("value");
2622
2623                                 return object_items.IndexOf (value);
2624                         }
2625
2626                         public void Insert (int index,  object item)
2627                         {
2628                                 if (index < 0 || index > Count)
2629                                         throw new ArgumentOutOfRangeException ("Index of out range");
2630                                 if (item == null)
2631                                         throw new ArgumentNullException ("item");
2632                                         
2633                                 owner.BeginUpdate ();
2634                                 object_items.Insert (index, item);
2635                                 owner.CollectionChanged ();
2636                                 owner.EndUpdate ();
2637                                 
2638                                 //UIA Framework event: Item Added
2639                                 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
2640                         }
2641
2642                         public void Remove (object value)
2643                         {
2644                                 if (value == null)
2645                                         return;
2646
2647                                 int index = IndexOf (value);
2648                                 if (index != -1)
2649                                         RemoveAt (index);
2650                         }
2651
2652                         public void RemoveAt (int index)
2653                         {
2654                                 if (index < 0 || index >= Count)
2655                                         throw new ArgumentOutOfRangeException ("Index of out range");
2656
2657                                 //UIA Framework element removed
2658                                 object removed = object_items [index];
2659                                 UpdateSelection (index);
2660                                 object_items.RemoveAt (index);
2661                                 owner.CollectionChanged ();
2662
2663                                 //UIA Framework event: Item Removed
2664                                 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, removed));
2665                         }
2666                         #endregion Public Methods
2667
2668                         #region Private Methods
2669                         internal int AddItem (object item)
2670                         {
2671                                 if (item == null)
2672                                         throw new ArgumentNullException ("item");
2673
2674                                 int cnt = object_items.Count;
2675                                 object_items.Add (item);
2676
2677                                 //UIA Framework event: Item Added
2678                                 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item));
2679
2680                                 return cnt;
2681                         }
2682
2683                         // we receive the index to be removed
2684                         void UpdateSelection (int removed_index)
2685                         {
2686                                 owner.selected_indices.Remove (removed_index);
2687
2688                                 if (owner.selection_mode != SelectionMode.None) {
2689                                         int last_idx = object_items.Count - 1;
2690
2691                                         // if the last item was selected, remove it from selection,
2692                                         // since it will become invalid after the removal
2693                                         if (owner.selected_indices.Contains (last_idx)) {
2694                                                 owner.selected_indices.Remove (last_idx);
2695
2696                                                 // in SelectionMode.One try to put the selection on the new last item
2697                                                 int new_idx = last_idx - 1;
2698                                                 if (owner.selection_mode == SelectionMode.One && new_idx > -1)
2699                                                         owner.selected_indices.Add (new_idx);
2700                                         }
2701                                 }
2702
2703                         }
2704
2705                         internal void Sort ()
2706                         {
2707                                 object_items.Sort (new ListObjectComparer ());
2708                         }
2709
2710                         #endregion Private Methods
2711                 }
2712
2713                 public class SelectedIndexCollection : IList, ICollection, IEnumerable
2714                 {
2715                         private ListBox owner;
2716                         ArrayList selection;
2717                         bool sorting_needed; // Selection state retrieval is done sorted - we do it lazyly
2718
2719                         #region UIA Framework Events 
2720
2721                         //NOTE:
2722                         //      We are using Reflection to add/remove internal events.
2723                         //      Class ListProvider uses the events.
2724                         //
2725                         //Event used to generate UIA StructureChangedEvent
2726                         static object UIACollectionChangedEvent = new object ();
2727
2728                         internal event CollectionChangeEventHandler UIACollectionChanged {
2729                                 add { owner.Events.AddHandler (UIACollectionChangedEvent, value); }
2730                                 remove { owner.Events.RemoveHandler (UIACollectionChangedEvent, value); }
2731                         }
2732
2733                         internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
2734                         {
2735                                 CollectionChangeEventHandler eh
2736                                         = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent];
2737                                 if (eh != null)
2738                                         eh (owner, args);
2739                         }
2740
2741                         #endregion UIA Framework Events 
2742
2743
2744                         public SelectedIndexCollection (ListBox owner)
2745                         {
2746                                 this.owner = owner;
2747                                 selection = new ArrayList ();
2748                         }
2749
2750                         #region Public Properties
2751                         [Browsable (false)]
2752                         public int Count {
2753                                 get { return selection.Count; }
2754                         }
2755
2756                         public bool IsReadOnly {
2757                                 get { return true; }
2758                         }
2759
2760                         public int this [int index] {
2761                                 get {
2762                                         if (index < 0 || index >= Count)
2763                                                 throw new ArgumentOutOfRangeException ("Index of out range");
2764
2765                                         CheckSorted ();
2766                                         return (int)selection [index];
2767                                 }
2768                         }
2769
2770                         bool ICollection.IsSynchronized {
2771                                 get { return true; }
2772                         }
2773
2774                         bool IList.IsFixedSize{
2775                                 get { return true; }
2776                         }
2777
2778                         object ICollection.SyncRoot {
2779                                 get { return selection; }
2780                         }
2781
2782                         #endregion Public Properties
2783
2784                         #region Public Methods
2785                         public void Add (int index)
2786                         {
2787                                 if (AddCore (index)) {
2788                                         owner.OnSelectedIndexChanged (EventArgs.Empty);
2789                                         owner.OnSelectedValueChanged (EventArgs.Empty);
2790                                 }
2791                         }
2792
2793                         // Need to separate selection logic from events,
2794                         // since selection changes using keys/mouse handle them their own way
2795                         internal bool AddCore (int index)
2796                         {
2797                                 if (selection.Contains (index))
2798                                         return false;
2799
2800                                 if (index == -1) // Weird MS behaviour
2801                                         return false;
2802                                 if (index < -1 || index >= owner.Items.Count)
2803                                         throw new ArgumentOutOfRangeException ("index");
2804                                 if (owner.selection_mode == SelectionMode.None)
2805                                         throw new InvalidOperationException ("Cannot call this method when selection mode is SelectionMode.None");
2806
2807                                 if (owner.selection_mode == SelectionMode.One && Count > 0) // Unselect previously selected item
2808                                         RemoveCore ((int)selection [0]);
2809
2810                                 selection.Add (index);
2811                                 sorting_needed = true;
2812                                 owner.EnsureVisible (index);
2813                                 owner.FocusedItem = index;
2814                                 owner.InvalidateItem (index);
2815
2816                                 // UIA Framework event: Selected item added
2817                                 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, index));
2818
2819                                 return true;
2820                         }
2821
2822                         public void Clear ()
2823                         {
2824                                 if (ClearCore ()) {
2825                                         owner.OnSelectedIndexChanged (EventArgs.Empty);
2826                                         owner.OnSelectedValueChanged (EventArgs.Empty);
2827                                 }
2828                         }
2829
2830                         internal bool ClearCore ()
2831                         {
2832                                 if (selection.Count == 0)
2833                                         return false;
2834
2835                                 foreach (int index in selection)
2836                                         owner.InvalidateItem (index);
2837
2838                                 selection.Clear ();
2839
2840                                 // UIA Framework event: Selected items list updated
2841                                 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, -1));
2842
2843                                 return true;
2844                         }
2845
2846                         public bool Contains (int selectedIndex)
2847                         {
2848                                 foreach (int index in selection)
2849                                         if (index == selectedIndex)
2850                                                 return true;
2851                                 return false;
2852                         }
2853
2854                         public void CopyTo (Array destination, int index)
2855                         {
2856                                 CheckSorted ();
2857                                 selection.CopyTo (destination, index);
2858                         }
2859
2860                         public IEnumerator GetEnumerator ()
2861                         {
2862                                 CheckSorted ();
2863                                 return selection.GetEnumerator ();
2864                         }
2865
2866                         // FIXME: Probably we can avoid sorting when calling
2867                         // IndexOf (imagine a scenario where multiple removal of items
2868                         // happens)
2869                         public void Remove (int index)
2870                         {
2871                                 // Separate logic from events here too
2872                                 if (RemoveCore (index)) {
2873                                         owner.OnSelectedIndexChanged (EventArgs.Empty);
2874                                         owner.OnSelectedValueChanged (EventArgs.Empty);
2875                                 }
2876                         }
2877
2878                         internal bool RemoveCore (int index)
2879                         {
2880                                 int idx = IndexOf (index);
2881                                 if (idx == -1)
2882                                         return false;
2883
2884                                 selection.RemoveAt (idx);
2885                                 owner.InvalidateItem (index);
2886
2887                                 // UIA Framework event: Selected item removed from selection
2888                                 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, index));
2889
2890                                 return true;
2891                         }
2892
2893                         int IList.Add (object value)
2894                         {
2895                                 throw new NotSupportedException ();
2896                         }
2897
2898                         void IList.Clear ()
2899                         {
2900                                 throw new NotSupportedException ();
2901                         }
2902
2903                         bool IList.Contains (object selectedIndex)
2904                         {
2905                                 return Contains ((int)selectedIndex);
2906                         }
2907
2908                         int IList.IndexOf (object selectedIndex)
2909                         {
2910                                 return IndexOf ((int) selectedIndex);
2911                         }
2912
2913                         void IList.Insert (int index, object value)
2914                         {
2915                                 throw new NotSupportedException ();
2916                         }
2917
2918                         void IList.Remove (object value)
2919                         {
2920                                 throw new NotSupportedException ();
2921                         }
2922
2923                         void IList.RemoveAt (int index)
2924                         {
2925                                 throw new NotSupportedException ();
2926                         }
2927
2928                         object IList.this[int index]{
2929                                 get { return this [index]; }
2930                                 set {throw new NotImplementedException (); }
2931                         }
2932
2933                         public int IndexOf (int selectedIndex)
2934                         {
2935                                 CheckSorted ();
2936
2937                                 for (int i = 0; i < selection.Count; i++)
2938                                         if ((int)selection [i] == selectedIndex)
2939                                                 return i;
2940
2941                                 return -1;
2942                         }
2943                         #endregion Public Methods
2944                         internal ArrayList List {
2945                                 get {
2946                                         CheckSorted ();
2947                                         return selection;
2948                                 }
2949                         }
2950
2951                         void CheckSorted ()
2952                         {
2953                                 if (sorting_needed) {
2954                                         sorting_needed = false;
2955                                         selection.Sort ();
2956                                 }
2957                         }
2958                 }
2959
2960                 public class SelectedObjectCollection : IList, ICollection, IEnumerable
2961                 {
2962                         private ListBox owner;
2963
2964                         public SelectedObjectCollection (ListBox owner)
2965                         {
2966                                 this.owner = owner;
2967                         }
2968
2969                         #region Public Properties
2970                         public int Count {
2971                                 get { return owner.selected_indices.Count; }
2972                         }
2973
2974                         public bool IsReadOnly {
2975                                 get { return true; }
2976                         }
2977
2978                         [Browsable(false)]
2979                         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
2980                         public object this [int index] {
2981                                 get {
2982                                         if (index < 0 || index >= Count)
2983                                                 throw new ArgumentOutOfRangeException ("Index of out range");
2984
2985                                         return owner.items [owner.selected_indices [index]];
2986                                 }
2987                                 set {throw new NotSupportedException ();}
2988                         }
2989
2990                         bool ICollection.IsSynchronized {
2991                                 get { return true; }
2992                         }
2993
2994                         object ICollection.SyncRoot {
2995                                 get { return this; }
2996                         }
2997
2998                         bool IList.IsFixedSize {
2999                                 get { return true; }
3000                         }
3001
3002                         #endregion Public Properties
3003
3004                         #region Public Methods
3005                         public void Add (object value)
3006                         {
3007                                 if (owner.selection_mode == SelectionMode.None)
3008                                         throw new ArgumentException ("Cannot call this method if SelectionMode is SelectionMode.None");
3009
3010                                 int idx = owner.items.IndexOf (value);
3011                                 if (idx == -1)
3012                                         return;
3013
3014                                 owner.selected_indices.Add (idx);
3015                         }
3016
3017                         public void Clear ()
3018                         {
3019                                 owner.selected_indices.Clear ();
3020                         }
3021
3022                         public bool Contains (object selectedObject)
3023                         {
3024                                 int idx = owner.items.IndexOf (selectedObject);
3025                                 return idx == -1 ? false : owner.selected_indices.Contains (idx);
3026                         }
3027
3028                         public void CopyTo (Array destination, int index)
3029                         {
3030                                 for (int i = 0; i < Count; i++)
3031                                         destination.SetValue (this [i], index++);
3032                         }
3033
3034                         public void Remove (object value)
3035                         {
3036                                 if (value == null)
3037                                         return;
3038
3039                                 int idx = owner.items.IndexOf (value);
3040                                 if (idx == -1)
3041                                         return;
3042
3043                                 owner.selected_indices.Remove (idx);
3044                         }
3045
3046                         int IList.Add (object value)
3047                         {
3048                                 throw new NotSupportedException ();
3049                         }
3050
3051                         void IList.Clear ()
3052                         {
3053                                 throw new NotSupportedException ();
3054                         }
3055
3056                         void IList.Insert (int index, object value)
3057                         {
3058                                 throw new NotSupportedException ();
3059                         }
3060
3061                         void IList.Remove (object value)
3062                         {
3063                                 throw new NotSupportedException ();
3064                         }
3065
3066                         void IList.RemoveAt (int index)
3067                         {
3068                                 throw new NotSupportedException ();
3069                         }
3070         
3071                         public int IndexOf (object selectedObject)
3072                         {
3073                                 int idx = owner.items.IndexOf (selectedObject);
3074                                 return idx == -1 ? -1 : owner.selected_indices.IndexOf (idx);
3075                         }
3076
3077                         public IEnumerator GetEnumerator ()
3078                         {
3079                                 //FIXME: write an enumerator that uses selection.GetEnumerator
3080                                 //  so that invalidation is write on selection changes
3081                                 object [] items = new object [Count];
3082                                 for (int i = 0; i < Count; i++) {
3083                                         items [i] = owner.items [owner.selected_indices [i]];
3084                                 }
3085
3086                                 return items.GetEnumerator ();
3087                         }
3088
3089                         #endregion Public Methods
3090                 }
3091         }
3092 }