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