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