merged Sys.Web.Services 2.0 support in my branch:
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ComboBox.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 //      Daniel Nauck    (dna(at)mono-project(dot)de)
26
27 using System;
28 using System.Drawing;
29 using System.Collections;
30 using System.ComponentModel;
31 using System.Reflection;
32 using System.ComponentModel.Design;
33 using System.ComponentModel.Design.Serialization;
34 using System.Runtime.InteropServices;
35
36
37 namespace System.Windows.Forms
38 {
39         [DefaultProperty("Items")]
40         [DefaultEvent("SelectedIndexChanged")]
41         [Designer ("System.Windows.Forms.Design.ComboBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
42 #if NET_2_0
43         [DefaultBindingProperty ("Text")]
44         [ClassInterface (ClassInterfaceType.AutoDispatch)]
45         [ComVisible(true)]
46 #endif
47         public class ComboBox : ListControl
48         {
49                 private DrawMode draw_mode = DrawMode.Normal;
50                 private ComboBoxStyle dropdown_style = (ComboBoxStyle)(-1);
51                 private int dropdown_width = -1;                
52                 private int selected_index = -1;
53                 internal ObjectCollection items = null;
54                 private bool suspend_ctrlupdate;
55                 private int maxdrop_items = 8;                  
56                 private bool integral_height = true;
57                 private bool sorted;
58                 private int max_length;
59                 private ComboListBox listbox_ctrl;              
60                 private ComboTextBox textbox_ctrl;
61                 private bool process_textchanged_event = true;
62                 private bool item_height_specified = false;
63                 private int item_height;
64                 private int requested_height = -1;
65                 private Hashtable item_heights;
66                 private bool show_dropdown_button = false;
67                 private ButtonState button_state = ButtonState.Normal;
68                 private bool dropped_down;
69                 private Rectangle text_area;
70                 private Rectangle button_area;
71                 private Rectangle listbox_area;
72                 private const int button_width = 16;
73 #if NET_2_0
74                 private AutoCompleteStringCollection auto_complete_custom_source = null;
75                 private AutoCompleteMode auto_complete_mode = AutoCompleteMode.None;
76                 private AutoCompleteSource auto_complete_source = AutoCompleteSource.None;
77 #endif
78
79                 [ComVisible(true)]
80                 public class ChildAccessibleObject : AccessibleObject {
81
82                         public ChildAccessibleObject (ComboBox owner, IntPtr handle)
83                                 : base (owner)
84                         {
85                         }
86
87                         public override string Name {
88                                 get {
89                                         return base.Name;
90                                 }
91                         }
92                 }
93
94                 public ComboBox ()
95                 {
96                         items = new ObjectCollection (this);
97                         DropDownStyle = ComboBoxStyle.DropDown;
98                         item_height = FontHeight + 2;
99                         BackColor = ThemeEngine.Current.ColorWindow;
100                         border_style = BorderStyle.None;
101
102                         /* Events */
103                         MouseDown += new MouseEventHandler (OnMouseDownCB);
104                         MouseUp += new MouseEventHandler (OnMouseUpCB);
105                         MouseMove += new MouseEventHandler (OnMouseMoveCB);
106                         MouseWheel += new MouseEventHandler (OnMouseWheelCB);                           
107                         KeyDown +=new KeyEventHandler(OnKeyDownCB);
108                 }
109
110                 #region events
111                 
112                 [Browsable (false)]
113                 [EditorBrowsable (EditorBrowsableState.Never)]
114                 public new event EventHandler BackgroundImageChanged {
115                         add { base.BackgroundImageChanged += value; }
116                         remove { base.BackgroundImageChanged -= value; }
117                 }
118
119                 static object DrawItemEvent = new object ();
120                 static object DropDownEvent = new object ();
121                 static object DropDownStyleChangedEvent = new object ();
122                 static object MeasureItemEvent = new object ();
123                 static object SelectedIndexChangedEvent = new object ();
124                 static object SelectionChangeCommittedEvent = new object ();
125
126                 public event DrawItemEventHandler DrawItem {
127                         add { Events.AddHandler (DrawItemEvent, value); }
128                         remove { Events.RemoveHandler (DrawItemEvent, value); }
129                 }
130
131                 public event EventHandler DropDown {
132                         add { Events.AddHandler (DropDownEvent, value); }
133                         remove { Events.RemoveHandler (DropDownEvent, value); }
134                 }
135
136                 public event EventHandler DropDownStyleChanged {
137                         add { Events.AddHandler (DropDownStyleChangedEvent, value); }
138                         remove { Events.RemoveHandler (DropDownStyleChangedEvent, value); }
139                 }
140
141                 public event MeasureItemEventHandler MeasureItem {
142                         add { Events.AddHandler (MeasureItemEvent, value); }
143                         remove { Events.RemoveHandler (MeasureItemEvent, value); }
144                 }
145                 
146                 [Browsable (false)]
147                 [EditorBrowsable (EditorBrowsableState.Never)]
148                 public new event PaintEventHandler Paint {
149                         add { base.Paint += value; }
150                         remove { base.Paint -= value; }
151                 }
152                 
153                 public event EventHandler SelectedIndexChanged {
154                         add { Events.AddHandler (SelectedIndexChangedEvent, value); }
155                         remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
156                 }
157
158                 public event EventHandler SelectionChangeCommitted {
159                         add { Events.AddHandler (SelectionChangeCommittedEvent, value); }
160                         remove { Events.RemoveHandler (SelectionChangeCommittedEvent, value); }
161                 }
162
163                 #endregion Events
164
165                 #region Public Properties
166 #if NET_2_0
167                 [MonoTODO("AutoCompletion algorithm is currently not implemented.")]
168                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
169                 [Browsable (true)]
170                 [EditorBrowsable (EditorBrowsableState.Always)]
171                 [Localizable (true)]
172                 [Editor ("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + Consts.AssemblySystem_Design,
173                          "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
174                 public AutoCompleteStringCollection AutoCompleteCustomSource { 
175                         get {
176                                 if(auto_complete_custom_source == null) {
177                                         auto_complete_custom_source = new AutoCompleteStringCollection ();
178                                         auto_complete_custom_source.CollectionChanged += new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged);
179                                 }
180                                 return auto_complete_custom_source;
181                         }
182                         set {
183                                 if(auto_complete_custom_source == value)
184                                         return;
185
186                                 if(auto_complete_custom_source != null) //remove eventhandler from old collection
187                                         auto_complete_custom_source.CollectionChanged -= new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged);
188
189                                 auto_complete_custom_source = value;
190
191                                 if(auto_complete_custom_source != null)
192                                         auto_complete_custom_source.CollectionChanged += new CollectionChangeEventHandler (OnAutoCompleteCustomSourceChanged);
193                         }
194                 }
195
196                 [MonoTODO("AutoCompletion algorithm is currently not implemented.")]
197                 [Browsable (true)]
198                 [EditorBrowsable (EditorBrowsableState.Always)]
199                 [DefaultValue (AutoCompleteMode.None)]
200                 public AutoCompleteMode AutoCompleteMode {
201                         get { return auto_complete_mode; }
202                         set {
203                                 if(auto_complete_mode == value)
204                                         return;
205
206                                 if((value < AutoCompleteMode.None) || (value > AutoCompleteMode.SuggestAppend))
207                                         throw new InvalidEnumArgumentException (Locale.GetText ("Enum argument value '{0}' is not valid for AutoCompleteMode", value));
208
209                                 auto_complete_mode = value;
210                         }
211                 }
212
213                 [MonoTODO("AutoCompletion algorithm is currently not implemented.")]
214                 [Browsable (true)]
215                 [EditorBrowsable (EditorBrowsableState.Always)]
216                 [DefaultValue (AutoCompleteSource.None)]
217                 public AutoCompleteSource AutoCompleteSource {
218                         get { return auto_complete_source; }
219                         set {
220                                 if(auto_complete_source == value)
221                                         return;
222
223                                 if(!Enum.IsDefined (typeof (AutoCompleteSource), value))
224                                         throw new InvalidEnumArgumentException (Locale.GetText ("Enum argument value '{0}' is not valid for AutoCompleteSource", value));
225
226                                 auto_complete_source = value;
227                         }
228                 }
229 #endif
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                                 Refresh ();
238                         }
239                 }
240
241                 [Browsable (false)]
242                 [EditorBrowsable (EditorBrowsableState.Never)]
243                 public override Image BackgroundImage {
244                         get { return base.BackgroundImage; }
245                         set {
246                                 if (base.BackgroundImage == value)
247                                         return;
248
249                                 base.BackgroundImage = value;
250                                 Refresh ();
251                         }
252                 }
253
254                 protected override CreateParams CreateParams {
255                         get { return base.CreateParams;}
256                 }
257
258                 protected override Size DefaultSize {
259                         get { return new Size (121, 21); }
260                 }
261
262                 [RefreshProperties(RefreshProperties.Repaint)]
263                 [DefaultValue (DrawMode.Normal)]
264                 public DrawMode DrawMode {
265                         get { return draw_mode; }
266
267                         set {
268                                 if (!Enum.IsDefined (typeof (DrawMode), value))
269                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for DrawMode", value));
270
271                                 if (draw_mode == value)
272                                         return;
273
274                                 if (draw_mode == DrawMode.OwnerDrawVariable)
275                                         item_heights = null;
276                                 draw_mode = value;
277                                 if (draw_mode == DrawMode.OwnerDrawVariable)
278                                         item_heights = new Hashtable ();
279                                 Refresh ();
280                         }
281                 }
282
283                 [DefaultValue (ComboBoxStyle.DropDown)]
284                 [RefreshProperties(RefreshProperties.Repaint)]
285                 public ComboBoxStyle DropDownStyle {
286                         get { return dropdown_style; }
287
288                         set {
289                 
290                                 if (!Enum.IsDefined (typeof (ComboBoxStyle), value))
291                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for ComboBoxStyle", value));
292
293                                 if (dropdown_style == value)
294                                         return;                                 
295
296                                 SuspendLayout ();
297
298                                 if (dropdown_style == ComboBoxStyle.Simple) {
299                                         if (listbox_ctrl != null) {                                             
300                                                 Controls.RemoveImplicit (listbox_ctrl);
301                                                 listbox_ctrl.Dispose ();                                                
302                                                 listbox_ctrl = null;
303                                         }
304                                 }
305
306                                 dropdown_style = value;                                 
307                                 
308                                 if (dropdown_style == ComboBoxStyle.DropDownList && textbox_ctrl != null) {
309                                         Controls.RemoveImplicit (textbox_ctrl);
310                                         textbox_ctrl.Dispose ();                                                
311                                         textbox_ctrl = null;                                            
312                                 }                               
313
314                                 if (dropdown_style == ComboBoxStyle.Simple) {
315                                         show_dropdown_button = false;                                   
316                                         
317                                         CreateComboListBox ();
318
319                                         if (IsHandleCreated) {
320                                                 Controls.AddImplicit (listbox_ctrl);
321                                                 listbox_ctrl.Visible = true;
322                                         }
323                                 } else {
324                                         show_dropdown_button = true;
325                                         button_state = ButtonState.Normal;
326                                 }                               
327         
328                                 if (dropdown_style != ComboBoxStyle.DropDownList && textbox_ctrl == null) {
329                                         textbox_ctrl = new ComboTextBox (this);
330                                         object selected_item = SelectedItem;
331                                         if (selected_item != null)
332                                                 textbox_ctrl.Text = GetItemText (selected_item);
333                                         textbox_ctrl.BorderStyle = BorderStyle.None;
334                                         textbox_ctrl.TextChanged += new EventHandler (OnTextChangedEdit);
335                                         textbox_ctrl.Click += new EventHandler (OnTextBoxClick);
336
337                                         if (IsHandleCreated == true) {
338                                                 Controls.AddImplicit (textbox_ctrl);
339                                         }
340                                 }
341                                 
342                                 ResumeLayout ();
343                                 OnDropDownStyleChanged (EventArgs.Empty);
344                                 
345                                 LayoutComboBox ();
346                                 UpdateComboBoxBounds ();
347                                 Refresh ();
348                         }
349                 }
350
351                 public int DropDownWidth {
352                         get { 
353                                 if (dropdown_width == -1)
354                                         return Width;
355                                         
356                                 return dropdown_width; 
357                         }
358                         set {
359                                 if (dropdown_width == value)
360                                         return;
361                                         
362                                 if (value < 1)
363 #if NET_2_0
364                                         throw new ArgumentOutOfRangeException ("DropDownWidth",
365                                                 "The DropDownWidth value is less than one.");
366 #else
367                                         throw new ArgumentException ("The DropDownWidth value is less than one.");
368 #endif
369
370                                 dropdown_width = value;
371                         }
372                 }
373                 
374                 [Browsable (false)]
375                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
376                 public bool DroppedDown {
377                         get { 
378                                 if (dropdown_style == ComboBoxStyle.Simple)
379                                         return true;
380                                 
381                                 return dropped_down;
382                         }
383                         set {
384                                 if (dropdown_style == ComboBoxStyle.Simple || dropped_down == value)
385                                         return;
386                                         
387                                 if (value) 
388                                         DropDownListBox ();
389                                 else
390                                         listbox_ctrl.Hide ();
391                         }
392                 }               
393
394                 public override bool Focused {
395                         get { return base.Focused; }
396                 }
397
398                 public override Color ForeColor {
399                         get { return base.ForeColor; }
400                         set {
401                                 if (base.ForeColor == value)
402                                         return;
403
404                                 base.ForeColor = value;
405                                 Refresh ();
406                         }
407                 }
408
409                 [DefaultValue (true)]
410                 [Localizable (true)]            
411                 public bool IntegralHeight {
412                         get { return integral_height; }
413                         set {
414                                 if (integral_height == value)
415                                         return;
416
417                                 integral_height = value;
418                                 UpdateComboBoxBounds ();
419                                 Refresh ();
420                         }
421                 }
422
423                 [Localizable (true)]
424                 public int ItemHeight {
425                         get {
426                                 if (item_height == -1) {
427                                         SizeF sz = DeviceContext.MeasureString ("The quick brown Fox", Font);
428                                         item_height = (int) sz.Height;
429                                 }
430                                 return item_height;
431                         }
432                         set {
433                                 if (value < 1)
434 #if NET_2_0
435                                         throw new ArgumentOutOfRangeException ("ItemHeight",
436                                                 "The item height value is less than one.");
437 #else
438                                         throw new ArgumentException ("The item height value is less than one.");
439 #endif
440
441                                 item_height_specified = true;
442                                 item_height = value;
443                                 if (IntegralHeight)
444                                         UpdateComboBoxBounds ();
445                                 LayoutComboBox ();
446                                 Refresh ();
447                         }
448                 }
449
450                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
451                 [Localizable (true)]
452                 [Editor ("System.Windows.Forms.Design.ListControlStringCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
453 #if NET_2_0
454                 [MergableProperty (false)]
455 #endif
456                 public ComboBox.ObjectCollection Items {
457                         get { return items; }
458                 }
459
460                 [DefaultValue (8)]
461                 [Localizable (true)]
462                 public int MaxDropDownItems {
463                         get { return maxdrop_items; }
464                         set {
465                                 if (maxdrop_items == value)
466                                         return;
467
468                                 maxdrop_items = value;
469                         }
470                 }
471
472                 [DefaultValue (0)]
473                 [Localizable (true)]
474                 public int MaxLength {
475                         get { return max_length; }
476                         set {
477                                 if (max_length == value)
478                                         return;
479
480                                 max_length = value;
481                                 
482                                 if (dropdown_style != ComboBoxStyle.DropDownList) {
483                                         
484                                         if (value < 0) {
485                                                 value = 0;
486                                         }
487                                         
488                                         textbox_ctrl.MaxLength = value;
489                                 }                       
490                         }
491                 }
492
493                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
494                 [Browsable (false)]             
495                 public int PreferredHeight {
496                         get {
497                                 return ItemHeight + 5;
498                         }
499                 }
500
501                 [Browsable (false)]
502                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
503                 public override int SelectedIndex {
504                         get { return selected_index; }
505                         set {
506                                 if (selected_index == value)
507                                         return;
508
509                                 if (value <= -2 || value >= Items.Count)
510                                         throw new ArgumentOutOfRangeException ("Index of out range");
511                                 selected_index = value;
512
513                                 if (dropdown_style != ComboBoxStyle.DropDownList) {
514                                         if (value == -1)
515                                                 SetControlText("");
516                                         else
517                                                 SetControlText (GetItemText (Items [value]));
518                                 }
519
520                                 if (DropDownStyle == ComboBoxStyle.DropDownList)
521                                         Invalidate ();
522
523                                 if (listbox_ctrl != null)
524                                         listbox_ctrl.HighlightedIndex = value;
525
526                                 OnSelectedValueChanged (new EventArgs ());
527                                 OnSelectedIndexChanged (new EventArgs ());
528                                 OnSelectedItemChanged (new EventArgs ());
529                         }
530                 }
531
532                 [Browsable (false)]
533                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
534                 [Bindable(true)]
535                 public object SelectedItem {
536                         get { return selected_index == -1 ? null : Items [selected_index]; }
537                         set {                           
538                                 object item = selected_index == -1 ? null : Items [selected_index];
539                                 if (item == value)
540                                         return;
541
542                                 SelectedIndex = Items.IndexOf (value);
543                         }
544                 }
545                 
546                 [Browsable (false)]
547                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
548                 public string SelectedText {
549                         get {
550                                 if (dropdown_style == ComboBoxStyle.DropDownList)
551                                         return "";
552                                         
553                                 return textbox_ctrl.SelectedText;
554                         }
555                         set {
556                                 if (dropdown_style == ComboBoxStyle.DropDownList)
557                                         return;
558                                 
559                                 textbox_ctrl.SelectedText = value;
560                         }
561                 }
562
563                 [Browsable (false)]
564                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
565                 public int SelectionLength {
566                         get {
567                                 if (dropdown_style == ComboBoxStyle.DropDownList) 
568                                         return 0;
569                                 
570                                 int result = textbox_ctrl.SelectionLength;
571                                 return result == -1 ? 0 : result;
572                         }
573                         set {
574                                 if (dropdown_style == ComboBoxStyle.DropDownList) 
575                                         return;
576                                         
577                                 if (textbox_ctrl.SelectionLength == value)
578                                         return;
579                                         
580                                 textbox_ctrl.SelectionLength = value;
581                         }
582                 }
583
584                 [Browsable (false)]
585                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
586                 public int SelectionStart {
587                         get { 
588                                 if (dropdown_style == ComboBoxStyle.DropDownList) 
589                                         return 0;                                       
590                                 
591                                 return textbox_ctrl.SelectionStart;                             
592                         }
593                         set {
594                                 if (dropdown_style == ComboBoxStyle.DropDownList) 
595                                         return;
596                                 
597                                 if (textbox_ctrl.SelectionStart == value)
598                                         return;                                 
599                                 
600                                 textbox_ctrl.SelectionStart = value;
601                         }
602                 }
603
604                 [DefaultValue (false)]
605                 public bool Sorted {
606                         get { return sorted; }
607
608                         set {
609                                 if (sorted == value)
610                                         return;
611
612                                 sorted = value;
613                                 SelectedIndex = -1;
614                                 if (sorted) {
615                                         Items.Sort ();
616                                         LayoutComboBox ();
617                                 }
618                         }
619                 }
620
621                 [Bindable (true)]
622                 [Localizable (true)]
623                 public override string Text {
624                         get {
625                                 if (dropdown_style != ComboBoxStyle.DropDownList) {
626                                         if (textbox_ctrl != null) {
627                                                 return textbox_ctrl.Text;
628                                         }
629                                 }
630
631                                 if (SelectedItem != null)
632                                         return GetItemText (SelectedItem);
633                                                                 
634                                 return base.Text;                               
635                         }
636                         set {                           
637                                 if (value == null) {
638                                         SelectedIndex = -1;
639                                         return;
640                                 }
641                                 
642                                 int index = FindString (value);
643                                 
644                                 if (index != -1) {
645                                         SelectedIndex = index;
646                                         return;                                 
647                                 }
648                                 
649                                 if (dropdown_style != ComboBoxStyle.DropDownList)
650                                         textbox_ctrl.Text = GetItemText (value);
651                         }
652                 }
653
654                 #endregion Public Properties
655
656                 #region Public Methods
657 #if NET_2_0
658                 [Obsolete ("This method has been deprecated")]
659 #endif
660                 protected virtual void AddItemsCore (object[] value)
661                 {
662                         
663                 }
664
665                 public void BeginUpdate ()
666                 {
667                         suspend_ctrlupdate = true;
668                 }
669
670                 protected override void Dispose (bool disposing)
671                 {                                               
672                         if (disposing) {
673                                 if (listbox_ctrl != null) {
674                                         listbox_ctrl.Dispose ();
675                                         Controls.RemoveImplicit (listbox_ctrl);
676                                         listbox_ctrl = null;
677                                 }                       
678                         
679                                 if (textbox_ctrl != null) {
680                                         Controls.RemoveImplicit (textbox_ctrl);
681                                         textbox_ctrl.Dispose ();
682                                         textbox_ctrl = null;
683                                 }                       
684                         }
685                         
686                         base.Dispose (disposing);
687                 }
688
689                 public void EndUpdate ()
690                 {
691                         suspend_ctrlupdate = false;
692                         UpdatedItems ();
693                         Refresh ();
694                 }
695
696                 public int FindString (string s)
697                 {
698                         return FindString (s, -1);
699                 }
700
701                 public int FindString (string s, int startIndex)
702                 {
703                         if (Items.Count == 0) 
704                                 return -1; // No exception throwing if empty
705
706                         if (startIndex < -1 || startIndex >= Items.Count - 1)
707                                 throw new  ArgumentOutOfRangeException ("Index of out range");
708
709                         startIndex++;
710                         for (int i = startIndex; i < Items.Count; i++) {
711                                 if ((GetItemText (Items[i])).StartsWith (s))
712                                         return i;
713                         }
714
715                         return -1;
716                 }
717
718                 public int FindStringExact (string s)
719                 {
720                         return FindStringExact (s, -1);
721                 }
722
723                 public int FindStringExact (string s, int startIndex)
724                 {
725                         if (Items.Count == 0) 
726                                 return -1; // No exception throwing if empty
727
728                         if (startIndex < -1 || startIndex >= Items.Count - 1)
729                                 throw new ArgumentOutOfRangeException ("Index of out range");
730
731                         startIndex++;
732                         for (int i = startIndex; i < Items.Count; i++) {
733                                 if ((GetItemText (Items[i])).Equals (s))
734                                         return i;
735                         }
736
737                         return -1;
738                 }
739
740                 public int GetItemHeight (int index)
741                 {       
742                         if (DrawMode == DrawMode.OwnerDrawVariable && IsHandleCreated) {
743
744                                 if (index < 0 || index >= Items.Count )
745                                         throw new ArgumentOutOfRangeException ("The item height value is less than zero");
746                                 
747                                 object item = Items [index];
748                                 if (item_heights.Contains (item))
749                                         return (int) item_heights [item];
750                                 
751                                 MeasureItemEventArgs args = new MeasureItemEventArgs (DeviceContext, index, ItemHeight);
752                                 OnMeasureItem (args);
753                                 item_heights [item] = args.ItemHeight;
754                                 return args.ItemHeight;
755                         }
756
757                         return ItemHeight;
758                 }
759
760                 protected override bool IsInputKey (Keys keyData)
761                 {
762                         switch (keyData) {
763                         case Keys.Up:
764                         case Keys.Down:
765                         case Keys.Left:
766                         case Keys.Right:
767                         case Keys.PageUp:
768                         case Keys.PageDown:                     
769                                 return true;
770                         
771                         default:                                        
772                                 return false;
773                         }
774                 }
775
776                 protected override void OnBackColorChanged (EventArgs e)
777                 {
778                         base.OnBackColorChanged (e);
779                 }
780
781                 protected override void OnDataSourceChanged (EventArgs e)
782                 {
783                         base.OnDataSourceChanged (e);
784                         BindDataItems ();
785                         
786                         if (DataSource == null || DataManager == null) {
787                                 SelectedIndex = -1;
788                         } 
789                         else {
790                                 SelectedIndex = DataManager.Position;
791                         }
792                 }
793
794                 protected override void OnDisplayMemberChanged (EventArgs e)
795                 {
796                         base.OnDisplayMemberChanged (e);
797
798                         if (DataManager == null || !IsHandleCreated)
799                                return;
800
801                         BindDataItems ();
802                         SelectedIndex = DataManager.Position;
803                 }
804
805                 protected virtual void OnDrawItem (DrawItemEventArgs e)
806                 {
807                         switch (DrawMode) {
808                         case DrawMode.OwnerDrawFixed:
809                         case DrawMode.OwnerDrawVariable:
810                                 DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]);
811                                 if (eh != null)
812                                         eh (this, e);
813                                 break;
814                         default:
815                                 ThemeEngine.Current.DrawComboBoxItem (this, e);
816                                 break;
817                         }
818                 }               
819
820                 protected virtual void OnDropDown (EventArgs e)
821                 {
822                         EventHandler eh = (EventHandler)(Events [DropDownEvent]);
823                         if (eh != null)
824                                 eh (this, e);
825                 }
826
827                 protected virtual void OnDropDownStyleChanged (EventArgs e)
828                 {
829                         EventHandler eh = (EventHandler)(Events [DropDownStyleChangedEvent]);
830                         if (eh != null)
831                                 eh (this, e);
832                 }
833
834                 protected override void OnFontChanged (EventArgs e)
835                 {
836                         base.OnFontChanged (e);
837
838                         if (textbox_ctrl != null)
839                                 textbox_ctrl.Font = Font;
840                         
841                         if (!item_height_specified) {
842                                 SizeF sz = DeviceContext.MeasureString ("The quick brown Fox", Font);
843                                 item_height = (int) sz.Height;
844                         }
845
846                         if (IntegralHeight)
847                                 UpdateComboBoxBounds ();
848
849                         LayoutComboBox ();
850                 }
851
852                 protected override void OnForeColorChanged (EventArgs e)
853                 {
854                         base.OnForeColorChanged (e);
855                 }
856
857                 [EditorBrowsable(EditorBrowsableState.Advanced)]                
858                 protected override void OnGotFocus (EventArgs e)
859                 {
860                         if (dropdown_style == ComboBoxStyle.DropDownList) {
861                                 // We draw DDL styles manually, so they require a
862                                 // refresh to have their selection drawn
863                                 Invalidate ();
864                         }
865                         
866                         if (textbox_ctrl != null) {
867                                 textbox_ctrl.SetSelectable (false);
868                                 textbox_ctrl.ActivateCaret (true);
869                                 textbox_ctrl.ShowSelection = true;
870                                 textbox_ctrl.SelectAll ();
871                         }
872
873                         base.OnGotFocus (e);
874                 }
875
876                 [EditorBrowsable(EditorBrowsableState.Advanced)]                
877                 protected override void OnLostFocus (EventArgs e)
878                 {
879                         if (dropdown_style == ComboBoxStyle.DropDownList) {
880                                 // We draw DDL styles manually, so they require a
881                                 // refresh to have their selection drawn
882                                 Invalidate ();
883                         }
884
885                         if (listbox_ctrl != null && dropped_down) {
886                                 listbox_ctrl.HideWindow ();
887                         }
888
889                         if (textbox_ctrl != null) {
890                                 textbox_ctrl.SetSelectable (true);
891                                 textbox_ctrl.ActivateCaret (false);
892                                 textbox_ctrl.ShowSelection = false;
893                         }
894
895                         base.OnLostFocus (e);
896                 }
897
898                 protected override void OnHandleCreated (EventArgs e)
899                 {
900                         base.OnHandleCreated (e);
901
902                         if (listbox_ctrl != null) {
903                                 Controls.AddImplicit (listbox_ctrl);
904                                 listbox_ctrl.Visible = true;
905                         }
906
907                         if (textbox_ctrl != null)
908                                 Controls.AddImplicit (textbox_ctrl);
909
910                         LayoutComboBox ();
911                 }
912
913                 protected override void OnHandleDestroyed (EventArgs e)
914                 {
915                         base.OnHandleDestroyed (e);
916                 }
917
918                 protected override void OnKeyPress (KeyPressEventArgs e)
919                 {
920                         // int index = FindStringCaseInsensitive (e.KeyChar.ToString (), SelectedIndex);
921                         //if (index != -1)
922                         //      SelectedIndex = index;
923
924                         base.OnKeyPress (e);
925                 }
926
927                 protected virtual void OnMeasureItem (MeasureItemEventArgs e)
928                 {
929                         MeasureItemEventHandler eh = (MeasureItemEventHandler)(Events [MeasureItemEvent]);
930                         if (eh != null)
931                                 eh (this, e);
932                 }
933
934                 protected override void OnParentBackColorChanged (EventArgs e)
935                 {
936                         base.OnParentBackColorChanged (e);
937                 }
938
939                 protected override void OnResize (EventArgs e)
940                 {                       
941                         LayoutComboBox ();
942                         if (listbox_ctrl != null)
943                                 listbox_ctrl.CalcListBoxArea ();
944                 }
945
946                 protected override void OnSelectedIndexChanged (EventArgs e)
947                 {
948                         base.OnSelectedIndexChanged (e);
949
950                         EventHandler eh = (EventHandler)(Events [SelectedIndexChangedEvent]);
951                         if (eh != null)
952                                 eh (this, e);
953                 }
954
955                 protected virtual void OnSelectedItemChanged (EventArgs e)
956                 {
957                         
958                 }
959
960                 protected override void OnSelectedValueChanged (EventArgs e)
961                 {
962                         base.OnSelectedValueChanged (e);
963                 }
964
965                 protected virtual void OnSelectionChangeCommitted (EventArgs e)
966                 {
967                         EventHandler eh = (EventHandler)(Events [SelectionChangeCommittedEvent]);
968                         if (eh != null)
969                                 eh (this, e);
970                 }
971
972                 protected override void RefreshItem (int index)
973                 {
974                         if (index < 0 || index >= Items.Count)
975                                 throw new ArgumentOutOfRangeException ("Index of out range");
976                                 
977                         if (draw_mode == DrawMode.OwnerDrawVariable)
978                                 item_heights.Remove (Items [index]);
979                 }
980
981 #if NET_2_0
982                 protected override bool ProcessKeyEventArgs (ref Message m)
983                 {
984                         return base.ProcessKeyEventArgs (ref m);
985                 }
986
987                 [EditorBrowsable (EditorBrowsableState.Advanced)]
988                 protected override void OnKeyDown (KeyEventArgs e)
989                 {
990                         base.OnKeyDown (e);
991                 }
992
993                 [EditorBrowsable (EditorBrowsableState.Advanced)]
994                 protected override void OnValidating (CancelEventArgs e)
995                 {
996                         base.OnValidating (e);
997                 }
998
999                 [EditorBrowsable (EditorBrowsableState.Advanced)]
1000                 protected override void OnTextChanged (EventArgs e)
1001                 {
1002                         base.OnTextChanged (e);
1003                 }
1004
1005                 protected override void OnMouseLeave (EventArgs e)
1006                 {
1007                         base.OnMouseLeave (e);
1008                 }
1009                 
1010                 protected override void OnMouseEnter (EventArgs e)
1011                 {
1012                         base.OnMouseEnter (e);
1013                 }
1014 #endif
1015
1016                 public void Select (int start, int length)
1017                 {
1018                         if (start < 0)
1019                                 throw new ArgumentException ("Start cannot be less than zero");
1020                                 
1021                         if (length < 0)
1022                                 throw new ArgumentException ("length cannot be less than zero");
1023                                 
1024                         if (dropdown_style == ComboBoxStyle.DropDownList)
1025                                 return;
1026
1027                         textbox_ctrl.Select (start, length);
1028                 }
1029
1030                 public void SelectAll ()
1031                 {
1032                         if (dropdown_style == ComboBoxStyle.DropDownList)
1033                                 return;
1034
1035                         if (textbox_ctrl != null) {
1036                                 textbox_ctrl.ShowSelection = true;
1037                                 textbox_ctrl.SelectAll ();
1038                         }
1039                 }               
1040
1041                 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
1042                 {                       
1043                         if ((specified & BoundsSpecified.Height) != 0) {
1044                                 requested_height = height;
1045
1046                                 if (DropDownStyle == ComboBoxStyle.Simple && height > PreferredHeight) {
1047                                         if (IntegralHeight) {
1048                                                 int border = ThemeEngine.Current.Border3DSize.Height;
1049                                                 int lb_height = height - PreferredHeight - 2;
1050                                                 if (lb_height - 2 * border > ItemHeight) {
1051                                                         int partial = (lb_height - 2 * border) % ItemHeight;
1052                                                         height -= partial;
1053                                                 } else
1054                                                         height = PreferredHeight;
1055                                         }
1056                                 } else
1057                                         height = PreferredHeight;
1058                         }
1059
1060                         base.SetBoundsCore (x, y, width, height, specified);
1061                 }
1062
1063                 protected override void SetItemCore (int index, object value)
1064                 {
1065                         if (index < 0 || index >= Items.Count)
1066                                 return;
1067
1068                         Items[index] = value;
1069                 }
1070
1071                 protected override void SetItemsCore (IList value)
1072                 {
1073                         BeginUpdate ();
1074                         try {
1075                                 Items.Clear ();
1076                                 Items.AddRange (value);
1077                         } finally {
1078                                EndUpdate ();
1079                         }
1080                 }
1081
1082                 public override string ToString ()
1083                 {
1084                         return base.ToString () + ", Items.Count:" + Items.Count;
1085                 }
1086
1087                 protected override void WndProc (ref Message m)
1088                 {
1089                         switch ((Msg) m.Msg) {
1090                         case Msg.WM_KEYUP:
1091                         case Msg.WM_KEYDOWN:
1092                                 Keys keys = (Keys) m.WParam.ToInt32 ();
1093                                 if (keys == Keys.Up || keys == Keys.Down)
1094                                         break;
1095                                 goto case Msg.WM_CHAR;
1096                         case Msg.WM_CHAR:
1097                                 if (textbox_ctrl != null)
1098                                         XplatUI.SendMessage (textbox_ctrl.Handle, (Msg) m.Msg, m.WParam, m.LParam);
1099                                 break;
1100                         case Msg.WM_MOUSE_LEAVE:
1101                                 Point location = PointToClient (Control.MousePosition);
1102                                 if (ClientRectangle.Contains (location))
1103                                         return;
1104                                 break;
1105                         default:
1106                                 break;
1107                         }
1108                         base.WndProc (ref m);
1109                 }
1110
1111                 #endregion Public Methods
1112
1113                 #region Private Methods
1114 #if NET_2_0
1115                 void OnAutoCompleteCustomSourceChanged(object sender, CollectionChangeEventArgs e) {
1116                         if(auto_complete_source == AutoCompleteSource.CustomSource) {
1117                                 //FIXME: handle add, remove and refresh events in AutoComplete algorithm.
1118                         }
1119                 }
1120 #endif
1121
1122                 internal override bool InternalCapture {
1123                         get { return Capture; }
1124                         set {}
1125                 }
1126                 
1127                 void LayoutComboBox ()
1128                 {                       
1129                         int border = ThemeEngine.Current.Border3DSize.Width;
1130
1131                         text_area = ClientRectangle;
1132                         text_area.Height = PreferredHeight;
1133                         
1134                         listbox_area = ClientRectangle;
1135                         listbox_area.Y = text_area.Bottom + 3;
1136                         listbox_area.Height -= (text_area.Height + 2);
1137
1138                         Rectangle prev_button_area = button_area;
1139
1140                         if (DropDownStyle == ComboBoxStyle.Simple)
1141                                 button_area = Rectangle.Empty;
1142                         else {
1143                                 button_area = text_area;
1144                                 button_area.X = text_area.Right - button_width - border;
1145                                 button_area.Y = text_area.Y + border;
1146                                 button_area.Width = button_width;
1147                                 button_area.Height = text_area.Height - 2 * border;
1148                         }
1149
1150                         if (button_area != prev_button_area) {
1151                                 prev_button_area.Y -= border;
1152                                 prev_button_area.Width += border;
1153                                 prev_button_area.Height += 2 * border;
1154                                 Invalidate (prev_button_area);
1155                                 Invalidate (button_area);
1156                         }
1157
1158                         if (textbox_ctrl != null) {
1159                                 textbox_ctrl.Location = new Point (text_area.X + border, text_area.Y + border);
1160                                 textbox_ctrl.Width = text_area.Width - button_area.Width - border * 2;
1161                                 textbox_ctrl.Height = text_area.Height - border * 2;
1162                         }
1163
1164                         if (listbox_ctrl != null && dropdown_style == ComboBoxStyle.Simple) {
1165                                 listbox_ctrl.Location = listbox_area.Location;
1166                                 listbox_ctrl.CalcListBoxArea ();
1167                         }
1168                 }
1169
1170                 private void CreateComboListBox ()
1171                 {                       
1172                         listbox_ctrl = new ComboListBox (this);                 
1173                         listbox_ctrl.HighlightedIndex = SelectedIndex;
1174                 }
1175                 
1176                 internal void Draw (Rectangle clip, Graphics dc)
1177                 {                               
1178                         Theme theme = ThemeEngine.Current;
1179
1180                         if (DropDownStyle == ComboBoxStyle.Simple)
1181                                 dc.FillRectangle (theme.ResPool.GetSolidBrush (Parent.BackColor), ClientRectangle);
1182
1183                         if (clip.IntersectsWith (text_area))
1184                                 ControlPaint.DrawBorder3D (dc, text_area, Border3DStyle.Sunken);
1185
1186                         int border = theme.Border3DSize.Width;
1187
1188                         // No edit control, we paint the edit ourselves
1189                         if (dropdown_style == ComboBoxStyle.DropDownList) {
1190                                 DrawItemState state = DrawItemState.None;
1191                                 Rectangle item_rect = text_area;
1192                                 item_rect.X += border;
1193                                 item_rect.Y += border;
1194                                 item_rect.Width -= (button_area.Width + 2 * border);                            
1195                                 item_rect.Height -= 2 * border;                         
1196                                                                 
1197                                 if (Focused) {
1198                                         state = DrawItemState.Selected;
1199                                         state |= DrawItemState.Focus;
1200                                 }
1201                                 
1202                                 state |= DrawItemState.ComboBoxEdit;                            
1203                                 OnDrawItem (new DrawItemEventArgs (dc, Font, item_rect, SelectedIndex, state, ForeColor, BackColor));
1204                         }                                               
1205                         
1206                         if (show_dropdown_button) {
1207                                 dc.FillRectangle (theme.ResPool.GetSolidBrush (theme.ColorControl), button_area);
1208
1209                                 if (!is_enabled)
1210                                         button_state = ButtonState.Inactive;
1211                                 
1212                                 theme.CPDrawComboButton (dc, button_area, button_state);
1213                         }                       
1214                 }
1215
1216                 internal void DropDownListBox ()
1217                 {
1218                         if (DropDownStyle == ComboBoxStyle.Simple)
1219                                 return;                 
1220                         
1221                         if (listbox_ctrl == null)
1222                                 CreateComboListBox ();
1223
1224                         listbox_ctrl.Location = PointToScreen (new Point (text_area.X, text_area.Y + text_area.Height));
1225                                                 
1226                         if (listbox_ctrl.ShowWindow ())                                 
1227                                 dropped_down = true;                                    
1228                         
1229                         button_state = ButtonState.Pushed;                              
1230                         if (dropdown_style == ComboBoxStyle.DropDownList)
1231                                 Invalidate (text_area);
1232                 }
1233                 
1234                 internal void DropDownListBoxFinished ()
1235                 {
1236                         if (DropDownStyle == ComboBoxStyle.Simple)
1237                                 return;                 
1238                                 
1239                         button_state = ButtonState.Normal;
1240                         Invalidate (button_area);
1241                         dropped_down = false;
1242                 }
1243                 
1244                 private int FindStringCaseInsensitive (string search)
1245                 {                       
1246                         if (search.Length == 0) {
1247                                 return -1;
1248                         }
1249                         
1250                         for (int i = 0; i < Items.Count; i++) 
1251                         {                               
1252                                 if (String.Compare (GetItemText (Items[i]), 0, search, 0, search.Length, true) == 0)
1253                                         return i;
1254                         }
1255
1256                         return -1;
1257                 }
1258
1259                 internal int FindStringCaseInsensitive (string search, int start_index)
1260                 {
1261                         if (search.Length == 0) {
1262                                 return -1;
1263                         }
1264
1265                         for (int i = 0; i < Items.Count; i++) {
1266                                 int index = (i + start_index) % Items.Count;
1267                                 if (String.Compare (GetItemText (Items [index]), 0, search, 0, search.Length, true) == 0)
1268                                         return index;
1269                         }
1270
1271                         return -1;
1272                 }
1273
1274                 private void OnKeyDownCB(object sender, KeyEventArgs e)
1275                 {
1276                         if (Items.Count == 0)
1277                                 return;
1278
1279                         switch (e.KeyCode) 
1280                         {                       
1281                                 case Keys.Up:
1282                                         SelectedIndex = Math.Max(SelectedIndex-1, 0);
1283                                         break;                          
1284         
1285                                 case Keys.Down:
1286                                         SelectedIndex = Math.Min(SelectedIndex+1, Items.Count-1);
1287                                         break;
1288                                 
1289                                 case Keys.PageUp:
1290                                         if (listbox_ctrl != null)
1291                                                 SelectedIndex = Math.Max(SelectedIndex- (listbox_ctrl.page_size-1), 0);
1292                                         break;                          
1293         
1294                                 case Keys.PageDown:             
1295                                         if (listbox_ctrl != null)               
1296                                                 SelectedIndex = Math.Min(SelectedIndex+(listbox_ctrl.page_size-1), Items.Count-1);
1297                                         break;
1298                                 
1299                                 default:
1300                                         break;
1301                         }
1302                 }
1303                 
1304                 void OnMouseDownCB (object sender, MouseEventArgs e)
1305                 {
1306                         Rectangle area;
1307                         if (DropDownStyle == ComboBoxStyle.DropDownList)
1308                                 area = ClientRectangle;
1309                         else
1310                                 area = button_area;
1311
1312                         if (area.Contains (e.X, e.Y)) {
1313                                 DropDownListBox ();                                     
1314                                 Invalidate (button_area);
1315                                 Update ();
1316                         }
1317                         Capture = true;
1318                 }
1319
1320                 void OnMouseMoveCB (object sender, MouseEventArgs e)
1321                 {                       
1322                         if (DropDownStyle == ComboBoxStyle.Simple)
1323                                 return;
1324
1325                         if (listbox_ctrl != null && listbox_ctrl.Visible) {
1326                                 Point location = listbox_ctrl.PointToClient (Control.MousePosition);
1327                                 if (listbox_ctrl.ClientRectangle.Contains (location))
1328                                         listbox_ctrl.Capture = true;
1329                         }
1330                 }
1331
1332                 void OnMouseUpCB (object sender, MouseEventArgs e)
1333                 {
1334                         Capture = false;
1335                         OnClick (EventArgs.Empty);
1336
1337                         if (dropped_down)
1338                                 listbox_ctrl.Capture = true;
1339                 }
1340
1341                 private void OnMouseWheelCB (object sender, MouseEventArgs me)
1342                 {
1343                         if (Items.Count == 0)
1344                                 return;
1345
1346                         if (listbox_ctrl != null && listbox_ctrl.Visible) {
1347                                 int lines = me.Delta / 120 * SystemInformation.MouseWheelScrollLines;
1348                                 listbox_ctrl.Scroll (-lines);
1349                         } else {
1350                                 int lines = me.Delta / 120;
1351                                 int index = SelectedIndex - lines;
1352                                 if (index < 0)
1353                                         index = 0;
1354                                 else if (index >= Items.Count)
1355                                         index = Items.Count - 1;
1356                                 SelectedIndex = index;
1357                         }
1358                 }
1359
1360                 internal override void OnPaintInternal (PaintEventArgs pevent)
1361                 {
1362                         if (suspend_ctrlupdate)
1363                                 return;
1364                                 
1365                         Draw (ClientRectangle, pevent.Graphics);                        
1366                 }
1367                 
1368                 private void OnTextBoxClick (object sender, EventArgs e)
1369                 {
1370                         OnClick (e);
1371                 }
1372
1373                 private void OnTextChangedEdit (object sender, EventArgs e)
1374                 {
1375                         if (process_textchanged_event == false)
1376                                 return; 
1377                                 
1378                         OnTextChanged (EventArgs.Empty);
1379
1380                         int item = FindStringCaseInsensitive (textbox_ctrl.Text);
1381                         
1382                         if (item == -1)
1383                                 return;
1384
1385                         // TODO:  THIS IS BROKEN-ISH
1386                         // I don't think we should hilight, and setting the top item does weirdness
1387                         // when there is no scrollbar
1388                         
1389                         if (listbox_ctrl != null) {
1390                                 listbox_ctrl.SetTopItem (item);
1391                                 listbox_ctrl.HighlightedIndex = item;
1392                         }
1393
1394                         base.Text = textbox_ctrl.Text;
1395                 }
1396                 
1397                 internal void SetControlText (string s)
1398                 {               
1399                         process_textchanged_event = false;
1400                         textbox_ctrl.Text = s;
1401                         process_textchanged_event = true;
1402                 }
1403                 
1404                 void UpdateComboBoxBounds ()
1405                 {
1406                         if (requested_height == -1)
1407                                 return;
1408
1409                         // Save the requested height since set bounds can destroy it
1410                         int save_height = requested_height;
1411                         SetBounds (0, 0, 0, requested_height, BoundsSpecified.Height);
1412                         requested_height = save_height;
1413                 }
1414
1415                 private void UpdatedItems ()
1416                 {
1417                         if (listbox_ctrl != null) {
1418                                 listbox_ctrl.UpdateLastVisibleItem ();
1419                                 listbox_ctrl.CalcListBoxArea ();
1420                                 listbox_ctrl.Refresh ();
1421                         }
1422                 }
1423
1424                 #endregion Private Methods
1425
1426                 [ListBindableAttribute (false)]
1427                 public class ObjectCollection : IList, ICollection, IEnumerable
1428                 {
1429
1430                         private ComboBox owner;
1431                         internal ArrayList object_items = new ArrayList ();
1432
1433                         public ObjectCollection (ComboBox owner)
1434                         {
1435                                 this.owner = owner;
1436                         }
1437
1438                         #region Public Properties
1439                         public int Count {
1440                                 get { return object_items.Count; }
1441                         }
1442
1443                         public bool IsReadOnly {
1444                                 get { return false; }
1445                         }
1446
1447                         [Browsable (false)]
1448                         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
1449                         public virtual object this [int index] {
1450                                 get {
1451                                         if (index < 0 || index >= Count)
1452                                                 throw new ArgumentOutOfRangeException ("Index of out range");
1453
1454                                         return object_items[index];
1455                                 }
1456                                 set {
1457                                         if (index < 0 || index >= Count)
1458                                                 throw new ArgumentOutOfRangeException ("Index of out range");
1459                                         if (value == null)
1460                                                 throw new ArgumentNullException ("value");
1461
1462                                         object_items[index] = value;
1463                                         if (owner.listbox_ctrl != null)
1464                                                 owner.listbox_ctrl.InvalidateItem (index);
1465                                         if (index == owner.SelectedIndex) {
1466                                                 if (owner.textbox_ctrl == null)
1467                                                         owner.Refresh ();
1468                                                 else
1469                                                         owner.textbox_ctrl.SelectedText = value.ToString ();
1470                                         }
1471                                 }
1472                         }
1473
1474                         bool ICollection.IsSynchronized {
1475                                 get { return false; }
1476                         }
1477
1478                         object ICollection.SyncRoot {
1479                                 get { return this; }
1480                         }
1481
1482                         bool IList.IsFixedSize {
1483                                 get { return false; }
1484                         }
1485
1486                         #endregion Public Properties
1487                         
1488                         #region Public Methods
1489                         public int Add (object item)
1490                         {
1491                                 int idx;
1492
1493                                 idx = AddItem (item);
1494                                 owner.UpdatedItems ();
1495                                 return idx;
1496                         }
1497
1498                         public void AddRange (object[] items)
1499                         {
1500                                 if (items == null)
1501                                         throw new ArgumentNullException ("items");
1502
1503                                 foreach (object mi in items)
1504                                         AddItem (mi);
1505                                         
1506                                 owner.UpdatedItems ();
1507                         }
1508
1509                         public void Clear ()
1510                         {
1511                                 owner.selected_index = -1;
1512                                 object_items.Clear ();
1513                                 owner.UpdatedItems ();
1514                                 owner.Refresh ();
1515                         }
1516                         
1517                         public bool Contains (object obj)
1518                         {
1519                                 if (obj == null)
1520                                         throw new ArgumentNullException ("obj");
1521
1522                                 return object_items.Contains (obj);
1523                         }
1524
1525                         public void CopyTo (object[] dest, int arrayIndex)
1526                         {
1527                                 object_items.CopyTo (dest, arrayIndex);
1528                         }
1529
1530                         void ICollection.CopyTo (Array dest, int index)
1531                         {
1532                                 object_items.CopyTo (dest, index);
1533                         }
1534
1535                         public IEnumerator GetEnumerator ()
1536                         {
1537                                 return object_items.GetEnumerator ();
1538                         }
1539
1540                         int IList.Add (object item)
1541                         {
1542                                 return Add (item);
1543                         }
1544
1545                         public int IndexOf (object value)
1546                         {
1547                                 if (value == null)
1548                                         throw new ArgumentNullException ("value");
1549
1550                                 return object_items.IndexOf (value);
1551                         }
1552
1553                         public void Insert (int index,  object item)
1554                         {
1555                                 if (index < 0 || index > Count)
1556                                         throw new ArgumentOutOfRangeException ("Index of out range");                                   
1557                                 if (item == null)
1558                                         throw new ArgumentNullException ("item");
1559                                 
1560                                 owner.BeginUpdate ();
1561                                 
1562                                 if (owner.Sorted)
1563                                         AddItem (item);
1564                                 else
1565                                         object_items.Insert (index, item);
1566                                                                                                 
1567                                 owner.EndUpdate ();     // Calls UpdatedItems
1568                         }
1569
1570                         public void Remove (object value)
1571                         {                               
1572                                 if (value == null)
1573                                         return;
1574
1575                                 if (IndexOf (value) == owner.SelectedIndex)
1576                                         owner.SelectedIndex = -1;
1577                                 
1578                                 RemoveAt (IndexOf (value));                             
1579                         }
1580
1581                         public void RemoveAt (int index)
1582                         {
1583                                 if (index < 0 || index >= Count)
1584                                         throw new ArgumentOutOfRangeException ("Index of out range");
1585                                         
1586                                 if (index == owner.SelectedIndex)
1587                                         owner.SelectedIndex = -1;
1588
1589                                 object_items.RemoveAt (index);
1590                                 owner.UpdatedItems ();
1591                         }
1592                         #endregion Public Methods
1593
1594                         #region Private Methods
1595                         private int AddItem (object item)
1596                         {
1597                                 if (item == null)
1598                                         throw new ArgumentNullException ("item");
1599
1600                                 if (owner.Sorted) {
1601                                         int index = 0;
1602                                         foreach (object o in object_items) {
1603                                                 if (String.Compare (item.ToString (), o.ToString ()) < 0) {
1604                                                         object_items.Insert (index, item);
1605                                                         return index;
1606                                                 }
1607                                                 index++;
1608                                         }
1609                                 }
1610                                 object_items.Add (item);
1611                                 return object_items.Count - 1;
1612                         }
1613                         
1614                         internal void AddRange (IList items)
1615                         {
1616                                 foreach (object mi in items)
1617                                         AddItem (mi);
1618                                                                                 
1619                                 owner.UpdatedItems ();
1620                         }
1621
1622                         internal void Sort ()
1623                         {
1624                                 object_items.Sort ();
1625                         }
1626
1627                         #endregion Private Methods
1628                 }
1629
1630                 internal class ComboTextBox : TextBox {
1631
1632                         private ComboBox owner;
1633
1634                         public ComboTextBox (ComboBox owner)
1635                         {
1636                                 this.owner = owner;
1637                                 ShowSelection = false;
1638                         }
1639
1640                         internal void SetSelectable (bool selectable)
1641                         {
1642                                 SetStyle (ControlStyles.Selectable, selectable);
1643                         }
1644
1645                         internal void ActivateCaret (bool active)
1646                         {
1647                                 if (active)
1648                                         document.CaretHasFocus ();
1649                                 else
1650                                         document.CaretLostFocus ();
1651                         }
1652
1653                         internal override void OnGotFocusInternal (EventArgs e)
1654                         {
1655                                 owner.Select (false, true);
1656                         }
1657
1658                         internal override void OnLostFocusInternal (EventArgs e)
1659                         {
1660                                 owner.Select (false, true);
1661                         }                       
1662                 }
1663
1664                 internal class ComboListBox : Control
1665                 {
1666                         private ComboBox owner;                 
1667                         private VScrollBarLB vscrollbar_ctrl;
1668                         private int top_item;                   /* First item that we show the in the current page */
1669                         private int last_item;                  /* Last visible item */
1670                         internal int page_size;                 /* Number of listbox items per page */
1671                         private Rectangle textarea_drawable;    /* Rectangle of the drawable text area */
1672                         
1673                         internal enum ItemNavigation
1674                         {
1675                                 First,
1676                                 Last,
1677                                 Next,
1678                                 Previous,
1679                                 NextPage,
1680                                 PreviousPage,
1681                         }
1682                         
1683                         class VScrollBarLB : VScrollBar
1684                         {
1685                                 public VScrollBarLB ()
1686                                 {                                       
1687                                 }
1688                                 
1689                                 internal override bool InternalCapture {
1690                                         get { return Capture; }
1691                                         set { }
1692                                 }
1693
1694                                 public void FireMouseDown (MouseEventArgs e) 
1695                                 {
1696                                         if (!Visible) 
1697                                                 return;
1698
1699                                         e = TranslateEvent (e);
1700                                         OnMouseDown (e);
1701                                 }       
1702                                 
1703                                 public void FireMouseUp (MouseEventArgs e) 
1704                                 {
1705                                         if (!Visible)
1706                                                 return;
1707
1708                                         e = TranslateEvent (e);
1709                                         OnMouseUp (e);
1710                                 }
1711                                 
1712                                 public void FireMouseMove (MouseEventArgs e) 
1713                                 {
1714                                         if (!Visible)
1715                                                 return;
1716
1717                                         e = TranslateEvent (e);
1718                                         OnMouseMove (e);
1719                                 }                       
1720                                 
1721                                 MouseEventArgs TranslateEvent (MouseEventArgs e)
1722                                 {
1723                                         Point loc = PointToClient (Control.MousePosition);
1724                                         return new MouseEventArgs (e.Button, e.Clicks, loc.X, loc.Y, e.Delta);
1725                                 }
1726                         }
1727
1728                         public ComboListBox (ComboBox owner)
1729                         {                                       
1730                                 this.owner = owner;                                                             
1731                                 top_item = 0;
1732                                 last_item = 0;
1733                                 page_size = 0;
1734
1735                                 MouseWheel += new MouseEventHandler (OnMouseWheelCLB);
1736
1737                                 SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
1738                                 SetStyle (ControlStyles.ResizeRedraw | ControlStyles.Opaque, true);
1739
1740                                 this.is_visible = false;
1741                                 Hwnd.ObjectFromHandle (this.Handle).no_activate = true;
1742
1743                                 if (owner.DropDownStyle == ComboBoxStyle.Simple)
1744                                         InternalBorderStyle = BorderStyle.Fixed3D;
1745                                 else
1746                                         InternalBorderStyle = BorderStyle.FixedSingle;
1747                         }
1748
1749                         protected override CreateParams CreateParams
1750                         {
1751                                 get {
1752                                         CreateParams cp = base.CreateParams;                                    
1753                                         if (owner == null || owner.DropDownStyle == ComboBoxStyle.Simple)
1754                                                 return cp;
1755
1756                                         cp.Style ^= (int) WindowStyles.WS_CHILD;
1757                                         cp.Style |= (int) WindowStyles.WS_POPUP;
1758                                         cp.ExStyle |= (int) WindowExStyles.WS_EX_TOOLWINDOW | (int) WindowExStyles.WS_EX_TOPMOST;
1759                                         return cp;
1760                                 }
1761                         }
1762
1763                         protected override void Select (bool directed, bool forward)
1764                         {
1765                                 // Do nothing, we never want to be selected
1766                         }
1767
1768                         internal override bool InternalCapture {
1769                                 get {
1770                                         return Capture;
1771                                 }
1772
1773                                 set {
1774                                 }
1775                         }
1776
1777                         int BorderWidth {
1778                                 get {
1779                                         switch (border_style) {
1780                                         case BorderStyle.Fixed3D:
1781                                                 return ThemeEngine.Current.Border3DSize.Width;
1782                                         default:
1783                                                 return ThemeEngine.Current.BorderSize.Width;
1784                                         }
1785                                 }
1786                         }
1787
1788                         #region Private Methods                 
1789                         // Calcs the listbox area
1790                         internal void CalcListBoxArea ()
1791                         {                               
1792                                 int width, height;
1793                                 bool show_scrollbar = false;
1794                                 
1795                                 if (owner.DropDownStyle == ComboBoxStyle.Simple) {
1796                                         Rectangle area = owner.listbox_area;
1797                                         width = area.Width;
1798                                         height = area.Height;
1799                                 }
1800                                 else { // DropDown or DropDownList
1801                                         
1802                                         width = owner.DropDownWidth;
1803                                         int count = (owner.Items.Count <= owner.MaxDropDownItems) ? owner.Items.Count : owner.MaxDropDownItems;                         
1804                                         
1805                                         if (owner.DrawMode == DrawMode.OwnerDrawVariable) {                                             
1806                                                 height = 0;
1807                                                 for (int i = 0; i < count; i++) {
1808                                                         height += owner.GetItemHeight (i);
1809                                                 }
1810                                                 
1811                                         } else  {
1812                                                 height = owner.ItemHeight * count;
1813                                         }
1814                                 }
1815                                 
1816                                 page_size = height / owner.ItemHeight;
1817
1818                                 if (owner.Items.Count <= owner.MaxDropDownItems) {                                      
1819                                         if (vscrollbar_ctrl != null)
1820                                                 vscrollbar_ctrl.Visible = false;
1821                                 } else {                                        
1822                                         /* Need vertical scrollbar */
1823                                         if (vscrollbar_ctrl == null) {
1824                                                 vscrollbar_ctrl = new VScrollBarLB ();
1825                                                 vscrollbar_ctrl.Minimum = 0;
1826                                                 vscrollbar_ctrl.SmallChange = 1;
1827                                                 vscrollbar_ctrl.LargeChange = 1;
1828                                                 vscrollbar_ctrl.Maximum = 0;
1829                                                 vscrollbar_ctrl.ValueChanged += new EventHandler (VerticalScrollEvent);
1830                                                 Controls.AddImplicit (vscrollbar_ctrl);
1831                                         }
1832                                         
1833                                         vscrollbar_ctrl.Height = height - 2 * BorderWidth;
1834                                                         
1835                                         vscrollbar_ctrl.Location = new Point (width - vscrollbar_ctrl.Width - BorderWidth - 1, 0);
1836
1837                                         vscrollbar_ctrl.Maximum = owner.Items.Count - 2;
1838                                         int large = (owner.DropDownStyle == ComboBoxStyle.Simple ? page_size : owner.maxdrop_items) - 1;
1839                                         if (large < 0)
1840                                                 large = 0;
1841                                         vscrollbar_ctrl.LargeChange = large;
1842                                         show_scrollbar = vscrollbar_ctrl.Visible = true;
1843
1844                                         int hli = HighlightedIndex;
1845                                         if (hli > 0) {
1846                                                 hli = Math.Min (hli, vscrollbar_ctrl.Maximum);
1847                                                 vscrollbar_ctrl.Value = hli;
1848                                         }
1849                                 }
1850                                 
1851                                 Size = new Size (width, height);
1852                                 textarea_drawable = ClientRectangle;
1853                                 textarea_drawable.Width = width;
1854                                 textarea_drawable.Height = height;                              
1855                                 
1856                                 if (vscrollbar_ctrl != null && show_scrollbar)
1857                                         textarea_drawable.Width -= vscrollbar_ctrl.Width;
1858
1859                                 last_item = LastVisibleItem ();
1860                         }                       
1861
1862                         private void Draw (Rectangle clip, Graphics dc)
1863                         {       
1864                                 dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (owner.BackColor), clip);
1865
1866                                 if (owner.Items.Count > 0) {
1867                                         
1868                                         for (int i = top_item; i <= last_item; i++) {
1869                                                 Rectangle item_rect = GetItemDisplayRectangle (i, top_item);
1870
1871                                                 if (!clip.IntersectsWith (item_rect))
1872                                                         continue;
1873
1874                                                 DrawItemState state = DrawItemState.None;
1875
1876                                                 if (i == HighlightedIndex) {
1877                                                         state |= DrawItemState.Selected;
1878                                                         
1879                                                         if (owner.DropDownStyle == ComboBoxStyle.DropDownList) {
1880                                                                 state |= DrawItemState.Focus;
1881                                                         }                                                       
1882                                                 }
1883                                                         
1884                                                 owner.OnDrawItem (new DrawItemEventArgs (dc, owner.Font, item_rect,
1885                                                         i, state, owner.ForeColor, owner.BackColor));
1886                                         }
1887                                 }
1888                         }
1889
1890                         int highlighted_index = -1;
1891
1892                         public int HighlightedIndex {
1893                                 get { return highlighted_index; }
1894                                 set { 
1895                                         if (highlighted_index == value)
1896                                                 return;
1897
1898                                         if (highlighted_index != -1 && highlighted_index < this.owner.Items.Count)
1899                                                 Invalidate (GetItemDisplayRectangle (highlighted_index, top_item));
1900                                         highlighted_index = value;
1901                                         if (highlighted_index != -1)
1902                                                 Invalidate (GetItemDisplayRectangle (highlighted_index, top_item));
1903                                 }
1904                         }
1905
1906                         private Rectangle GetItemDisplayRectangle (int index, int top_index)
1907                         {
1908                                 if (index < 0 || index >= owner.Items.Count)
1909                                         throw new  ArgumentOutOfRangeException ("GetItemRectangle index out of range.");
1910
1911                                 Rectangle item_rect = new Rectangle ();
1912                                 int height = owner.GetItemHeight (index);
1913
1914                                 item_rect.X = 0;
1915                                 item_rect.Width = textarea_drawable.Width;
1916                                 if (owner.DrawMode == DrawMode.OwnerDrawVariable) {
1917                                         item_rect.Y = 0;
1918                                         for (int i = top_index; i < index; i++)
1919                                                 item_rect.Y += owner.GetItemHeight (i);
1920                                 } else
1921                                         item_rect.Y = height * (index - top_index);
1922
1923                                 item_rect.Height = height;
1924                                 return item_rect;
1925                         }
1926
1927                         public void HideWindow ()
1928                         {
1929                                 if (owner.DropDownStyle == ComboBoxStyle.Simple)
1930                                         return;
1931                                         
1932                                 Capture = false;
1933                                 Hide ();
1934                                 owner.DropDownListBoxFinished ();
1935                         }
1936
1937                         private int IndexFromPointDisplayRectangle (int x, int y)
1938                         {
1939                                 for (int i = top_item; i <= last_item; i++) {
1940                                         if (GetItemDisplayRectangle (i, top_item).Contains (x, y) == true)
1941                                                 return i;
1942                                 }
1943
1944                                 return -1;
1945                         }
1946
1947                         public void InvalidateItem (int index)
1948                         {
1949                                 if (Visible)
1950                                         Invalidate (GetItemDisplayRectangle (index, top_item));
1951                         }
1952
1953                         private int LastVisibleItem ()
1954                         {
1955                                 Rectangle item_rect;
1956                                 int top_y = textarea_drawable.Y + textarea_drawable.Height;
1957                                 int i = 0;                              
1958                                 
1959                                 for (i = top_item; i < owner.Items.Count; i++) {
1960                                         item_rect = GetItemDisplayRectangle (i, top_item);                              
1961                                         if (item_rect.Y + item_rect.Height > top_y) {
1962                                                 return i;
1963                                         }
1964                                 }
1965                                 return i - 1;
1966                         }
1967
1968                         public void SetTopItem (int item)
1969                         {
1970                                 if (top_item == item)
1971                                         return;
1972                                 top_item = item;
1973                                 UpdateLastVisibleItem ();
1974                                 Invalidate ();
1975                         }                       
1976
1977                         bool scrollbar_grabbed = false;
1978
1979                         bool InScrollBar {
1980                                 get {
1981                                         if (vscrollbar_ctrl == null || !vscrollbar_ctrl.is_visible)
1982                                                 return false;
1983
1984                                         return vscrollbar_ctrl.Bounds.Contains (PointToClient (Control.MousePosition));
1985                                 }
1986                         }
1987
1988                         protected override void OnMouseDown (MouseEventArgs e)
1989                         {
1990                                 if (InScrollBar) {
1991                                         vscrollbar_ctrl.FireMouseDown (e);
1992                                         scrollbar_grabbed = true;
1993                                 }
1994                         }
1995
1996                         protected override void OnMouseMove (MouseEventArgs e)
1997                         {                                               
1998                                 if (owner.DropDownStyle == ComboBoxStyle.Simple)
1999                                         return;
2000
2001                                 if (scrollbar_grabbed || (!Capture && InScrollBar)) {
2002                                         vscrollbar_ctrl.FireMouseMove (e);
2003                                         return;
2004                                 }
2005
2006                                 Point pt = PointToClient (Control.MousePosition);
2007                                 int index = IndexFromPointDisplayRectangle (pt.X, pt.Y);
2008
2009                                 if (index != -1)
2010                                         HighlightedIndex = index;
2011                         }
2012                         
2013                         protected override void OnMouseUp (MouseEventArgs e)
2014                         {
2015                                 int index = IndexFromPointDisplayRectangle (e.X, e.Y);
2016
2017                                 if (scrollbar_grabbed) {
2018                                         vscrollbar_ctrl.FireMouseUp (e);
2019                                         scrollbar_grabbed = false;
2020                                         if (index != -1)
2021                                                 HighlightedIndex = index;
2022                                         return;
2023                                 }
2024
2025                                 if (index == -1) {                                      
2026                                         HideWindow ();
2027                                         return;
2028                                 }
2029
2030                                 owner.SelectedIndex = index;
2031                                 owner.OnSelectionChangeCommitted (new EventArgs ());
2032                                 HideWindow ();
2033                         }
2034
2035                         internal override void OnPaintInternal (PaintEventArgs pevent)
2036                         {                               
2037                                 Draw (pevent.ClipRectangle,pevent.Graphics);
2038                         }
2039
2040                         public bool ShowWindow ()
2041                         {
2042                                 if (owner.DropDownStyle == ComboBoxStyle.Simple && owner.Items.Count == 0)
2043                                         return false;
2044
2045                                 HighlightedIndex = owner.SelectedIndex;
2046
2047                                 CalcListBoxArea ();                             
2048                                 Show ();
2049
2050                                 Refresh ();
2051                                 owner.OnDropDown (EventArgs.Empty);
2052                                 return true;
2053                         }
2054                         
2055                         public void UpdateLastVisibleItem ()
2056                         {
2057                                 last_item = LastVisibleItem ();
2058                         }
2059
2060                         public void Scroll (int delta)
2061                         {
2062                                 if (delta == 0 || vscrollbar_ctrl == null || !vscrollbar_ctrl.Visible)
2063                                         return;
2064
2065                                 int max = owner.Items.Count - page_size;
2066
2067                                 int val = vscrollbar_ctrl.Value + delta;
2068                                 if (val > max)
2069                                         val = max;
2070                                 else if (val < vscrollbar_ctrl.Minimum)
2071                                         val = vscrollbar_ctrl.Minimum;
2072                                 vscrollbar_ctrl.Value = val;
2073                         }
2074
2075                         private void OnMouseWheelCLB (object sender, MouseEventArgs me)
2076                         {
2077                                 if (owner.Items.Count == 0)
2078                                         return;
2079
2080                                 int lines = me.Delta / 120 * SystemInformation.MouseWheelScrollLines;
2081                                 Scroll (-lines);
2082                         }
2083
2084                         // Value Changed
2085                         private void VerticalScrollEvent (object sender, EventArgs e)
2086                         {                               
2087                                 if (top_item == vscrollbar_ctrl.Value)
2088                                         return;
2089
2090                                 top_item =  vscrollbar_ctrl.Value;
2091                                 UpdateLastVisibleItem ();
2092                                 Invalidate ();
2093                         }                       
2094                         
2095                         protected override void WndProc(ref Message m) {
2096                                 if (m.Msg == (int)Msg.WM_SETFOCUS) {
2097                                         if (m.WParam != IntPtr.Zero) {
2098                                                 XplatUI.SetFocus(m.WParam);
2099                                         }
2100                                 }
2101                                 base.WndProc (ref m);
2102                         }
2103
2104                         #endregion Private Methods
2105                 }
2106         }
2107 }
2108
2109