2008-03-27 Carlos Alberto Cortez <calberto.cortez@gmail.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TabControl.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2004-2005 Novell, Inc.
21 //
22 // Authors:
23 //      Jackson Harper (jackson@ximian.com)
24
25
26 using System;
27 using System.Collections;
28 using System.ComponentModel;
29 using System.ComponentModel.Design;
30 using System.Drawing;
31 using System.Runtime.InteropServices;
32
33 namespace System.Windows.Forms {
34 #if NET_2_0
35         [ComVisibleAttribute (true)]
36         [ClassInterfaceAttribute (ClassInterfaceType.AutoDispatch)]
37 #endif
38         [DefaultEvent("SelectedIndexChanged")]
39         [DefaultProperty("TabPages")]
40         [Designer("System.Windows.Forms.Design.TabControlDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
41         public class TabControl : Control {
42                 #region Fields
43                 private int selected_index = -1;
44                 private TabAlignment alignment;
45                 private TabAppearance appearance;
46                 private TabDrawMode draw_mode;
47                 private bool multiline;
48                 private ImageList image_list;
49                 private Size item_size = Size.Empty;
50                 private Point padding;
51                 private int row_count = 0;
52                 private bool hottrack;
53                 private TabPageCollection tab_pages;
54                 private bool show_tool_tips;
55                 private TabSizeMode size_mode;
56                 private bool show_slider = false;
57                 private ButtonState right_slider_state;
58                 private ButtonState left_slider_state;
59                 private int slider_pos = 0;
60 #if NET_2_0
61                 private bool rightToLeftLayout;
62 #endif          
63                 #endregion      // Fields
64
65                 #region Public Constructors
66                 public TabControl ()
67                 {
68                         tab_pages = new TabPageCollection (this);
69                         SetStyle (ControlStyles.UserPaint, false);
70                         padding = ThemeEngine.Current.TabControlDefaultPadding;
71                         item_size = ThemeEngine.Current.TabControlDefaultItemSize;
72
73                         MouseDown += new MouseEventHandler (MouseDownHandler);
74                         MouseUp += new MouseEventHandler (MouseUpHandler);
75                         SizeChanged += new EventHandler (SizeChangedHandler);
76                 }
77
78                 #endregion      // Public Constructors
79
80                 #region Public Instance Properties
81                 [DefaultValue(TabAlignment.Top)]
82                 [Localizable(true)]
83                 [RefreshProperties(RefreshProperties.All)]
84                 public TabAlignment Alignment {
85                         get { return alignment; }
86                         set {
87                                 if (alignment == value)
88                                         return;
89                                 alignment = value;
90                                 if (alignment == TabAlignment.Left || alignment == TabAlignment.Right)
91                                         multiline = true;
92                                 Redraw ();
93                         }
94                 }
95
96                 [DefaultValue(TabAppearance.Normal)]
97                 [Localizable(true)]
98                 public TabAppearance Appearance {
99                         get { return appearance; }
100                         set {
101                                 if (appearance == value)
102                                         return;
103                                 appearance = value;
104                                 Redraw ();
105                         }
106                 }
107
108                 [Browsable(false)]
109                 [EditorBrowsable(EditorBrowsableState.Never)]
110                 public override Color BackColor {
111                         get { return ThemeEngine.Current.ColorControl; }
112                         set { /* nothing happens on set on MS */ }
113                 }
114
115                 [Browsable(false)]
116                 [EditorBrowsable(EditorBrowsableState.Never)]
117                 public override Image BackgroundImage {
118                         get { return base.BackgroundImage; }
119                         set { base.BackgroundImage = value; }
120                 }
121
122 #if NET_2_0
123                 [Browsable (false)]
124                 [EditorBrowsable (EditorBrowsableState.Never)]
125                 public override ImageLayout BackgroundImageLayout {
126                         get { return base.BackgroundImageLayout; }
127                         set { base.BackgroundImageLayout = value; }
128                 }
129 #endif
130                 
131                 public override Rectangle DisplayRectangle {
132                         get {
133                                 return ThemeEngine.Current.TabControlGetDisplayRectangle (this);
134                         }
135                 }
136
137 #if NET_2_0
138                 [EditorBrowsable (EditorBrowsableState.Never)]
139                 protected override bool DoubleBuffered {
140                         get { return base.DoubleBuffered; }
141                         set { base.DoubleBuffered = value; }
142                 }
143 #endif
144
145                 [DefaultValue(TabDrawMode.Normal)]
146                 public TabDrawMode DrawMode {
147                         get { return draw_mode; }
148                         set {
149                                 if (draw_mode == value)
150                                         return;
151                                 draw_mode = value;
152                                 Redraw ();
153                         }
154                 }
155
156                 [Browsable(false)]
157                 [EditorBrowsable(EditorBrowsableState.Never)]
158                 public override Color ForeColor {
159                         get { return base.ForeColor; }
160                         set { base.ForeColor = value; }
161                 }
162
163                 [DefaultValue(false)]
164                 public bool HotTrack {
165                         get { return hottrack; }
166                         set {
167                                 if (hottrack == value)
168                                         return;
169                                 hottrack = value;
170                                 Redraw ();
171                         }
172                 }
173
174 #if NET_2_0
175                 [RefreshProperties (RefreshProperties.Repaint)]
176 #endif
177                 [DefaultValue(null)]
178                 public ImageList ImageList {
179                         get { return image_list; }
180                         set { image_list = value; }
181                 }
182
183                 [Localizable(true)]
184                 public Size ItemSize {
185                         get {
186                                 return item_size;
187                         }
188                         set {
189                                 if (value.Height < 0 || value.Width < 0)
190                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'ItemSize'.");
191                                 item_size = value;
192                                 Redraw ();
193                         }
194                 }
195
196                 [DefaultValue(false)]
197                 public bool Multiline {
198                         get { return multiline; }
199                         set {
200                                 if (multiline == value)
201                                         return;
202                                 multiline = value;
203                                 if (!multiline && alignment == TabAlignment.Left || alignment == TabAlignment.Right)
204                                         alignment = TabAlignment.Top;
205                                 Redraw ();
206                         }
207                 }
208
209                 [Localizable(true)]
210                 public new Point Padding {
211                         get { return padding; }
212                         set {
213                                 if (value.X < 0 || value.Y < 0)
214                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'Padding'.");
215                                 if (padding == value)
216                                         return;
217                                 padding = value;
218                                 Redraw ();
219                         }
220
221                 }
222
223 #if NET_2_0
224                 [MonoTODO ("Saves the value and raises event, but needs actual implementation call")]
225                 [Localizable (true)]
226                 [DefaultValue (false)]
227                 public virtual bool RightToLeftLayout {
228                         get { return this.rightToLeftLayout; }
229                         set {
230                                 if (value != this.rightToLeftLayout) {
231                                         this.rightToLeftLayout = value;
232                                         this.OnRightToLeftLayoutChanged (EventArgs.Empty);
233                                 }
234                         }
235                 }
236 #endif
237
238                 [Browsable(false)]
239                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
240                 public int RowCount {
241                         get { return row_count; }
242                 }
243
244                 [DefaultValue(-1)]
245                 [Browsable(false)]
246                 public int SelectedIndex {
247                         get { return selected_index; }
248                         set {
249
250                                 if (value < -1) {
251 #if NET_2_0
252                                         throw new ArgumentOutOfRangeException ("SelectedIndex", "Value of '" + value + "' is valid for 'SelectedIndex'. " +
253                                                 "'SelectedIndex' must be greater than or equal to -1.");
254 #else
255                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
256                                                 "'value' must be greater than or equal to -1.");
257 #endif
258                                 }
259                                 if (!this.IsHandleCreated) {
260                                         if (selected_index != value) {
261                                                 selected_index = value;
262 #if !NET_2_0
263                                                 OnSelectedIndexChanged (EventArgs.Empty);
264 #endif
265                                         }
266                                         return;
267                                 }
268
269                                 if (value >= TabCount) {
270                                         if (value != selected_index)
271                                                 OnSelectedIndexChanged (EventArgs.Empty);
272                                         return;
273                                 }
274
275                                 if (value == selected_index) {
276                                         if (selected_index > -1)
277                                                 Invalidate(GetTabRect (selected_index));
278                                         return;
279                                 }
280
281 #if NET_2_0
282                                 TabControlCancelEventArgs ret = new TabControlCancelEventArgs (SelectedTab, selected_index, false, TabControlAction.Deselecting);
283                                 OnDeselecting (ret);
284                                 if (ret.Cancel)
285                                         return;
286
287 #endif
288                                 int old_index = selected_index;
289                                 int new_index = value;
290
291                                 selected_index = new_index;
292
293 #if NET_2_0
294                                 ret = new TabControlCancelEventArgs (SelectedTab, selected_index, false, TabControlAction.Selecting);
295                                 OnSelecting (ret);
296                                 if (ret.Cancel) {
297                                         selected_index = old_index;
298                                         return;
299                                 }
300 #endif
301
302                                 SuspendLayout ();
303
304                                 Rectangle invalid = Rectangle.Empty;
305                                 bool refresh = false;
306
307                                 if (new_index != -1 && show_slider && new_index < slider_pos) {
308                                         slider_pos = new_index;
309                                         refresh = true;
310                                 }
311
312                                 if (new_index != -1) {
313                                         int le = TabPages[new_index].TabBounds.Right;
314                                         int re = ThemeEngine.Current.TabControlGetLeftScrollRect (this).Left;
315                                         if (show_slider && le > re) {
316                                                 int i = 0;
317                                                 for (i = 0; i < new_index - 1; i++) {
318                                                         if (TabPages [i].TabBounds.Left < 0) // tab scrolled off the visible area, ignore
319                                                                 continue;
320
321                                                         if (TabPages [new_index].TabBounds.Right - TabPages[i].TabBounds.Right < re) {
322                                                                 i++;
323                                                                 break;
324                                                         }
325                                                 }
326                                                 slider_pos = i;
327                                                 refresh = true;
328                                         }
329                                 }
330
331                                 if (old_index != -1 && new_index != -1) {
332                                         if (!refresh)
333                                                 invalid = GetTabRect (old_index);
334                                         ((TabPage) Controls[old_index]).SetVisible (false);
335                                 }
336
337                                 TabPage selected = null;
338
339                                 if (new_index != -1) {
340                                         selected = (TabPage) Controls[new_index];
341                                         invalid = Rectangle.Union (invalid, GetTabRect (new_index));
342                                         selected.SetVisible (true);
343                                 }
344
345                                 OnSelectedIndexChanged (EventArgs.Empty);
346
347                                 ResumeLayout ();
348
349                                 if (refresh) {
350                                         SizeTabs ();
351                                         Refresh ();
352                                 } else if (new_index != -1 && selected.Row != BottomRow) {
353                                         DropRow (TabPages[new_index].Row);
354                                         // calculating what to invalidate here seems to be slower then just
355                                         // refreshing the whole thing
356                                         SizeTabs ();
357                                         Refresh ();
358                                 } else {
359                                         SizeTabs ();
360                                         // The lines are drawn on the edges of the tabs so the invalid area should
361                                         // needs to include the extra pixels of line width.
362                                         if (appearance == TabAppearance.Normal) {
363                                                 invalid.Inflate (6, 4);
364                                         }
365                                         Invalidate (invalid);
366                                 }
367                         }
368                 }
369
370                 [Browsable(false)]
371                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
372                 public TabPage SelectedTab {
373                         get {
374                                 if (selected_index == -1)
375                                         return null;
376                                 return tab_pages [selected_index];
377                         }
378                         set {
379                                 int index = IndexForTabPage (value);
380                                 if (index == selected_index)
381                                         return;
382                                 SelectedIndex = index;
383                         }
384                 }
385
386                 [DefaultValue(false)]
387                 [Localizable(true)]
388                 public bool ShowToolTips {
389                         get { return show_tool_tips; }
390                         set {
391                                 if (show_tool_tips == value)
392                                         return;
393                                 show_tool_tips = value;
394                                 Redraw ();
395                         }
396                 }
397
398                 [DefaultValue(TabSizeMode.Normal)]
399                 [RefreshProperties(RefreshProperties.Repaint)]
400                 public TabSizeMode SizeMode {
401                         get { return size_mode; }
402                         set {
403                                 if (size_mode == value)
404                                         return;
405                                 size_mode = value;
406                                 Redraw ();
407                         }
408                 }
409
410                 [Browsable(false)]
411                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
412                 public int TabCount {
413                         get {
414                                 return tab_pages.Count;
415                         }
416                 }
417
418 #if NET_2_0
419                 [Editor ("System.Windows.Forms.Design.TabPageCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
420 #else
421                 [DefaultValue(null)]
422 #endif
423                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
424                 [MergableProperty(false)]
425                 public TabPageCollection TabPages {
426                         get { return tab_pages; }
427                 }
428
429                 [Browsable(false)]
430                 [Bindable(false)]
431                 [EditorBrowsable(EditorBrowsableState.Never)]
432                 public override string Text {
433                         get { return base.Text; }
434                         set { base.Text = value; }
435                 }
436                 #endregion      // Public Instance Properties
437
438                 #region Internal Properties
439                 internal bool ShowSlider {
440                         get { return show_slider; }
441                         set { show_slider = value; }
442                 }
443
444                 internal int SliderPos {
445                         get { return slider_pos; }
446                 }
447
448                 internal ButtonState RightSliderState {
449                         get { return right_slider_state; }
450                 }
451
452                 internal ButtonState LeftSliderState {
453                         get { return left_slider_state; }
454                 }
455
456                 #endregion      // Internal Properties
457
458                 #region Protected Instance Properties
459                 protected override CreateParams CreateParams {
460                         get {
461                                 CreateParams c = base.CreateParams;
462                                 return c;
463                         }
464                 }
465
466                 protected override Size DefaultSize {
467                         get { return new Size (200, 100); }  
468                 }
469
470                 #endregion      // Protected Instance Properties
471
472                 #region Public Instance Methods
473                 public Rectangle GetTabRect (int index)
474                 {
475                         TabPage page = GetTab (index);
476                         return page.TabBounds;
477                 }
478
479                 public Control GetControl (int index)
480                 {
481                         return GetTab (index);
482                 }
483
484 #if NET_2_0
485                 public void SelectTab (TabPage tabPage)
486                 {
487                         if (tabPage == null)
488                                 throw new ArgumentNullException ("tabPage");
489
490                         SelectTab (this.tab_pages [tabPage]);
491                 }
492
493                 public void SelectTab (string tabPageName)
494                 {
495                         if (tabPageName == null)
496                                 throw new ArgumentNullException ("tabPageName");
497
498                         SelectTab (this.tab_pages [tabPageName]);
499                 }
500
501                 public void SelectTab (int index)
502                 {
503                         if (index < 0 || index > this.tab_pages.Count - 1)
504                                 throw new ArgumentOutOfRangeException ("index");
505                                 
506                         SelectedIndex = index;
507                 }
508
509                 public void DeselectTab (TabPage tabPage)
510                 {
511                         if (tabPage == null)
512                                 throw new ArgumentNullException ("tabPage");
513
514                         DeselectTab (this.tab_pages [tabPage]);
515                 }
516
517                 public void DeselectTab (string tabPageName)
518                 {
519                         if (tabPageName == null)
520                                 throw new ArgumentNullException ("tabPageName");
521
522                         DeselectTab (this.tab_pages [tabPageName]);
523                 }
524
525                 public void DeselectTab (int index)
526                 {
527                         if (index == SelectedIndex) {
528                                 if (index >= 0 && index < this.tab_pages.Count - 1)
529                                         SelectedIndex = ++index;
530                                 else
531                                         SelectedIndex = 0;
532                         }
533                 }
534
535 #endif
536
537                 public override string ToString ()
538                 {
539                         string res = String.Concat (base.ToString (),
540                                         ", TabPages.Count: ",
541                                         TabCount);
542                         if (TabCount > 0)
543                                 res = String.Concat (res, ", TabPages[0]: ",
544                                                 TabPages [0]);
545                         return res;
546                 }
547
548                 #endregion      // Public Instance Methods
549
550                 #region Protected Instance Methods
551
552                 #region Handles
553                 protected override Control.ControlCollection CreateControlsInstance ()
554                 {
555                         return new TabControl.ControlCollection (this);
556                 }
557
558                 protected override void CreateHandle ()
559                 {
560                         base.CreateHandle ();
561                         selected_index = (selected_index >= TabCount ? (TabCount > 0 ? 0 : -1) : selected_index);
562
563                         if (TabCount > 0) {
564                                 if (selected_index > -1)
565                                         this.SelectedTab.SetVisible(true);
566                                 else
567                                         tab_pages[0].SetVisible(true);
568                         }
569                         ResizeTabPages ();
570                 }
571
572                 protected override void OnHandleCreated (EventArgs e)
573                 {
574                         base.OnHandleCreated (e);
575                 }
576
577                 protected override void OnHandleDestroyed (EventArgs e)
578                 {
579                         base.OnHandleDestroyed (e);
580                 }
581
582                 protected override void Dispose (bool disposing)
583                 {
584                         base.Dispose (disposing);
585                 }
586
587                 #endregion
588
589                 #region Events
590                 protected virtual void OnDrawItem (DrawItemEventArgs e)
591                 {
592                         if (DrawMode != TabDrawMode.OwnerDrawFixed)
593                                 return;
594
595                         DrawItemEventHandler eh = (DrawItemEventHandler)(Events [DrawItemEvent]);
596                         if (eh != null)
597                                 eh (this, e);
598                 }
599
600                 internal void OnDrawItemInternal (DrawItemEventArgs e)
601                 {
602                         OnDrawItem (e);
603                 }
604
605                 protected override void OnFontChanged (EventArgs e)
606                 {
607                         base.OnFontChanged (e);
608                         ResizeTabPages ();
609                 }
610
611                 protected override void OnResize (EventArgs e)
612                 {
613                         base.OnResize (e);
614                 }
615
616                 protected override void OnStyleChanged (EventArgs e)
617                 {
618                         base.OnStyleChanged (e);
619                 }
620
621                 protected virtual void OnSelectedIndexChanged (EventArgs e)
622                 {
623                         EventHandler eh = (EventHandler) (Events[SelectedIndexChangedEvent]);
624                         if (eh != null)
625                                 eh (this, e);
626                 }
627
628                 internal override void OnPaintInternal (PaintEventArgs pe)
629                 {
630                         Draw (pe.Graphics, pe.ClipRectangle);
631                         pe.Handled = true;
632                 }
633
634 #if NET_2_0
635                 protected override void OnEnter (EventArgs e)
636                 {
637                         base.OnEnter (e);
638                         if (SelectedTab != null)
639                                 SelectedTab.FireEnter ();
640                 }
641
642                 protected override void OnLeave (EventArgs e)
643                 {
644                         if (SelectedTab != null)
645                                 SelectedTab.FireLeave ();
646                         base.OnLeave (e);
647                 }
648
649                 [EditorBrowsable (EditorBrowsableState.Advanced)]
650                 protected virtual void OnRightToLeftLayoutChanged (EventArgs e)
651                 {
652                         EventHandler eh = (EventHandler) (Events[RightToLeftLayoutChangedEvent]);
653                         if (eh != null)
654                                 eh (this, e);
655                 }
656
657                 [EditorBrowsable (EditorBrowsableState.Never)]
658                 protected override void ScaleCore (float dx, float dy)
659                 {
660                         base.ScaleCore (dx, dy);
661                 }
662
663                 protected virtual void OnDeselecting (TabControlCancelEventArgs e)
664                 {
665                         TabControlCancelEventHandler eh = (TabControlCancelEventHandler) (Events[DeselectingEvent]);
666                         if (eh != null)
667                                 eh (this, e);
668
669                         if (!e.Cancel)
670                                 OnDeselected (new TabControlEventArgs (SelectedTab, selected_index, TabControlAction.Deselected));
671                 }
672
673                 protected virtual void OnDeselected (TabControlEventArgs e)
674                 {
675                         TabControlEventHandler eh = (TabControlEventHandler) (Events[DeselectedEvent]);
676                         if (eh != null)
677                                 eh (this, e);
678
679                         if (this.SelectedTab != null)
680                                 this.SelectedTab.FireLeave ();
681                 }
682
683                 protected virtual void OnSelecting (TabControlCancelEventArgs e)
684                 {
685                         TabControlCancelEventHandler eh = (TabControlCancelEventHandler) (Events[SelectingEvent]);
686                         if (eh != null)
687                                 eh (this, e);
688
689                         if (!e.Cancel)
690                                 OnSelected (new TabControlEventArgs (SelectedTab, selected_index, TabControlAction.Selected));
691                 }
692
693                 protected virtual void OnSelected (TabControlEventArgs e)
694                 {
695                         TabControlEventHandler eh = (TabControlEventHandler) (Events[SelectedEvent]);
696                         if (eh != null)
697                                 eh (this, e);
698
699                         if (this.SelectedTab != null)
700                                 this.SelectedTab.FireEnter ();
701                 }
702 #endif
703
704                 #endregion
705
706                 #region Keys
707                 protected override bool ProcessKeyPreview (ref Message m)
708                 {
709                         return base.ProcessKeyPreview (ref m);
710                 }
711
712                 protected override void OnKeyDown (KeyEventArgs ke)
713                 {
714                         if (ke.KeyCode == Keys.Tab && (ke.KeyData & Keys.Control) != 0) {
715                                 if ((ke.KeyData & Keys.Shift) == 0)
716                                         SelectedIndex = (SelectedIndex + 1) % TabCount;
717                                 else
718                                         SelectedIndex = (SelectedIndex + TabCount - 1) % TabCount;
719                                 ke.Handled = true;
720                         } else if (ke.KeyCode == Keys.Home) {
721                                 SelectedIndex = 0;
722                                 ke.Handled = true;
723                         } else if (ke.KeyCode == Keys.End) {
724                                 SelectedIndex = TabCount - 1;
725                                 ke.Handled = true;
726                         } else if (ke.KeyCode == Keys.Left && SelectedIndex > 0) {
727                                 SelectedIndex--;
728                                 ke.Handled = true;
729                         } else if (ke.KeyCode == Keys.Right && SelectedIndex < TabCount - 1) {
730                                 SelectedIndex++;
731                                 ke.Handled = true;
732                         }
733
734                         base.OnKeyDown (ke);
735                 }
736
737                 protected override bool IsInputKey (Keys keyData)
738                 {
739                         switch (keyData & Keys.KeyCode) {
740                         case Keys.Home:
741                         case Keys.End:
742                         case Keys.Left:
743                         case Keys.Right:
744                                 return true;
745                         }
746                         return base.IsInputKey (keyData);
747                 }
748                 #endregion
749
750                 #region Pages Collection
751                 protected void RemoveAll ()
752                 {
753                         Controls.Clear ();
754                 }
755
756                 protected virtual object [] GetItems ()
757                 {
758                         TabPage [] pages = new TabPage [Controls.Count];
759                         Controls.CopyTo (pages, 0);
760                         return pages;
761                 }
762
763                 protected virtual object [] GetItems (Type baseType)
764                 {
765                         object[] pages = (object[])Array.CreateInstance (baseType, Controls.Count);
766                         Controls.CopyTo (pages, 0);
767                         return pages;
768                 }
769                 #endregion
770
771                 protected void UpdateTabSelection (bool updateFocus)
772                 {
773                         ResizeTabPages ();
774                 }
775
776                 protected string GetToolTipText (object item)
777                 {
778                         TabPage page = (TabPage) item;
779                         return page.ToolTipText;
780                 }
781
782                 protected override void WndProc (ref Message m)
783                 {
784                         switch ((Msg)m.Msg) {
785                         case Msg.WM_SETFOCUS:
786                                 if (selected_index == -1 && this.TabCount > 0)
787                                         this.SelectedIndex = 0;
788                                 if (selected_index != -1)
789                                         Invalidate(GetTabRect(selected_index));
790                                 base.WndProc (ref m);
791                                 break;
792                         case Msg.WM_KILLFOCUS:
793                                 if (selected_index != -1)
794                                         Invalidate(GetTabRect(selected_index));
795                                 base.WndProc (ref m);
796                                 break;
797                         default:
798                                 base.WndProc (ref m);
799                                 break;
800                         }
801                 }
802
803                 #endregion      // Protected Instance Methods
804
805                 #region Internal & Private Methods
806                 private bool CanScrollRight {
807                         get {
808                                 return (slider_pos < TabCount - 1);
809                         }
810                 }
811
812                 private bool CanScrollLeft {
813                         get { return slider_pos > 0; }
814                 }
815
816                 private void MouseDownHandler (object sender, MouseEventArgs e)
817                 {
818                         if (ShowSlider) {
819                                 Rectangle right = ThemeEngine.Current.TabControlGetRightScrollRect (this);
820                                 Rectangle left = ThemeEngine.Current.TabControlGetLeftScrollRect (this);
821                                 if (right.Contains (e.X, e.Y)) {
822                                         right_slider_state = ButtonState.Pushed;
823                                         if (CanScrollRight) {
824                                                 slider_pos++;
825                                                 SizeTabs ();
826
827                                                 switch (this.Alignment) {
828                                                         case TabAlignment.Top:
829                                                                 Invalidate (new Rectangle (0, 0, Width, ItemSize.Height));
830                                                                 break;
831                                                         case TabAlignment.Bottom:
832                                                                 Invalidate (new Rectangle (0, DisplayRectangle.Bottom, Width, Height - DisplayRectangle.Bottom));
833                                                                 break;
834                                                         case TabAlignment.Left:
835                                                                 Invalidate (new Rectangle (0, 0, DisplayRectangle.Left, Height));
836                                                                 break;
837                                                         case TabAlignment.Right:
838                                                                 Invalidate (new Rectangle (DisplayRectangle.Right, 0, Width - DisplayRectangle.Right, Height));
839                                                                 break;
840                                                 }
841                                                 
842                                         } else {
843                                                 Invalidate (right);
844                                         }
845                                         return;
846                                 } else if (left.Contains (e.X, e.Y)) {
847                                         left_slider_state = ButtonState.Pushed;
848                                         if (CanScrollLeft) {
849                                                 slider_pos--;
850                                                 SizeTabs ();
851
852                                                 switch (this.Alignment) {
853                                                         case TabAlignment.Top:
854                                                                 Invalidate (new Rectangle (0, 0, Width, ItemSize.Height));
855                                                                 break;
856                                                         case TabAlignment.Bottom:
857                                                                 Invalidate (new Rectangle (0, DisplayRectangle.Bottom, Width, Height - DisplayRectangle.Bottom));
858                                                                 break;
859                                                         case TabAlignment.Left:
860                                                                 Invalidate (new Rectangle (0, 0, DisplayRectangle.Left, Height));
861                                                                 break;
862                                                         case TabAlignment.Right:
863                                                                 Invalidate (new Rectangle (DisplayRectangle.Right, 0, Width - DisplayRectangle.Right, Height));
864                                                                 break;
865                                                 }
866                                         } else {
867                                                 Invalidate (left);
868                                         }
869                                         return;
870                                 }
871                         }
872
873                         int count = Controls.Count;
874                         for (int i = SliderPos; i < count; i++) {
875                                 if (!GetTabRect (i).Contains (e.X, e.Y))
876                                         continue;
877                                 SelectedIndex = i;
878                                 break;
879                         }
880                 }
881
882                 private void MouseUpHandler (object sender, MouseEventArgs e)
883                 {
884                         if (ShowSlider && (left_slider_state == ButtonState.Pushed || right_slider_state == ButtonState.Pushed)) {
885                                 Rectangle invalid;
886                                 if (left_slider_state == ButtonState.Pushed)
887                                         invalid = ThemeEngine.Current.TabControlGetLeftScrollRect (this);
888                                 else
889                                         invalid = ThemeEngine.Current.TabControlGetRightScrollRect (this);
890                                 left_slider_state = ButtonState.Normal;
891                                 right_slider_state = ButtonState.Normal;
892
893                                 Invalidate (invalid);
894                         }
895                 }
896
897                 private void SizeChangedHandler (object sender, EventArgs e)
898                 {
899                         Redraw ();
900                 }
901
902                 internal int IndexForTabPage (TabPage page)
903                 {
904                         for (int i = 0; i < tab_pages.Count; i++) {
905                                 if (page == tab_pages [i])
906                                         return i;
907                         }
908                         return -1;
909                 }
910
911                 private void ResizeTabPages ()
912                 {
913                         CalcTabRows ();
914                         SizeTabs ();
915                         Rectangle r = DisplayRectangle;
916                         foreach (TabPage page in Controls) {
917                                 page.Bounds = r;
918                         }
919                 }
920
921                 private int MinimumTabWidth {
922                         get {
923                                 return ThemeEngine.Current.TabControlMinimumTabWidth;
924                         }
925                 }
926
927                 private Size TabSpacing {
928                         get {
929                                 return ThemeEngine.Current.TabControlGetSpacing (this);
930                         }
931                 }
932
933                 private void CalcTabRows ()
934                 {
935                         switch (Alignment) {
936                         case TabAlignment.Right:
937                         case TabAlignment.Left:
938                                 CalcTabRows (Height);
939                                 break;
940                         default:
941                                 CalcTabRows (Width);
942                                 break;
943                         }
944                 }
945
946                 private void CalcTabRows (int row_width)
947                 {
948                         int xpos = 0;
949                         int ypos = 0;
950                         Size spacing = TabSpacing;
951
952                         if (TabPages.Count > 0)
953                                 row_count = 1;
954                         show_slider = false;
955                         
956                         int scrollerWidth = ThemeEngine.Current.TabControlScrollerWidth * 2;
957
958                         for (int i = 0; i < TabPages.Count; i++) {
959                                 TabPage page = TabPages [i];
960                                 int aux = 0;
961                                 SizeTab (page, i, row_width - scrollerWidth, ref xpos, ref ypos, spacing, 0, ref aux, true);
962                         }
963
964                         if (SelectedIndex != -1 && TabPages.Count > SelectedIndex && TabPages[SelectedIndex].Row != BottomRow)
965                                 DropRow (TabPages [SelectedIndex].Row);
966                 }
967
968                 private int BottomRow {
969                         get { return 1; }
970                 }
971
972                 private int Direction
973                 {
974                         get {
975                                 switch (Alignment) {
976                                 case TabAlignment.Right:
977                                 case TabAlignment.Bottom:
978                                         return -1;
979                                 default:
980                                         return 1;
981                                 }
982                         }
983                 }
984
985                 private void DropRow (int row)
986                 {
987                         if (Appearance != TabAppearance.Normal)
988                                 return;
989
990                         int bottom = BottomRow;
991                         int direction = Direction;
992
993                         foreach (TabPage page in TabPages) {
994                                 if (page.Row == row) {
995                                         page.Row = bottom;
996                                 } else if (direction == 1 && page.Row < row) {
997                                         page.Row += direction;
998                                 } else if (direction == -1 && page.Row > row) {
999                                         page.Row += direction;
1000                                 }
1001                         }
1002                 }
1003
1004                 private int CalcYPos ()
1005                 {
1006                         if (Alignment == TabAlignment.Bottom || Alignment == TabAlignment.Left)
1007                                 return ThemeEngine.Current.TabControlGetPanelRect (this).Bottom;
1008
1009                         if (Appearance == TabAppearance.Normal)
1010                                 return this.ClientRectangle.Y + ThemeEngine.Current.TabControlSelectedDelta.Y;
1011
1012                         return this.ClientRectangle.Y;
1013
1014                 }
1015
1016                 private int CalcXPos ()
1017                 {
1018                         if (Alignment == TabAlignment.Right)
1019                                 return ThemeEngine.Current.TabControlGetPanelRect (this).Right;
1020
1021                         if (Appearance == TabAppearance.Normal)
1022                                 return this.ClientRectangle.X + ThemeEngine.Current.TabControlSelectedDelta.X;
1023
1024                         return this.ClientRectangle.X;
1025                 }
1026
1027                 private void SizeTabs ()
1028                 {
1029                         switch (Alignment) {
1030                         case TabAlignment.Right:
1031                         case TabAlignment.Left:
1032                                 SizeTabs (Height, true);
1033                                 break;
1034                         default:
1035                                 SizeTabs (Width, false);
1036                                 break;
1037                         }
1038                 }
1039                 
1040                 private void SizeTabs (int row_width, bool vertical)
1041                 {
1042                         int ypos = 0;
1043                         int xpos = 0;
1044                         int prev_row = 1;
1045                         Size spacing = TabSpacing;
1046                         int begin_prev = 0;
1047
1048                         row_width -= ThemeEngine.Current.TabControlScrollerWidth * 2;
1049                         if (TabPages.Count == 0)
1050                                 return;
1051
1052                         prev_row = TabPages [0].Row;
1053
1054                         // Reset the slider position if the slider isn't needed
1055                         // anymore (ie window size was increased so all tabs are visible)
1056                         if (!show_slider)
1057                                 slider_pos = 0;
1058                         else {
1059                                 // set X = -1 for marking tabs that are not visible due to scrolling
1060                                 for (int i = 0; i < slider_pos; i++) {
1061                                         TabPage page = TabPages[i];
1062                                         Rectangle x = page.TabBounds;
1063                                         x.X = -1;
1064                                         page.TabBounds = x;
1065                                 }
1066                         }
1067                         
1068                         for (int i = slider_pos; i < TabPages.Count; i++) {
1069                                 TabPage page = TabPages[i];
1070                                 SizeTab (page, i, row_width, ref xpos, ref ypos, spacing, prev_row, ref begin_prev, false);
1071                                 prev_row = page.Row;
1072                         }
1073
1074                         if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) {
1075                                 FillRow (begin_prev, TabPages.Count - 1,
1076                                                 ((row_width - TabPages [TabPages.Count - 1].TabBounds.Right) / (TabPages.Count - begin_prev)), 
1077                                                 spacing, vertical);
1078                         }
1079
1080                         if (SelectedIndex != -1) {
1081                                 ExpandSelected (TabPages [SelectedIndex], 0, row_width - 1);
1082                         }
1083                 }
1084                 
1085                 private void SizeTab (TabPage page, int i, int row_width, ref int xpos, ref int ypos, 
1086                                                                 Size spacing, int prev_row, ref int begin_prev, bool widthOnly) 
1087                 {                               
1088                         int width, height = 0;
1089
1090                         if (SizeMode == TabSizeMode.Fixed) {
1091                                 width = item_size.Width;
1092                         } else {                        
1093                                 width = MeasureStringWidth (DeviceContext, page.Text, Font);
1094                                 width += (Padding.X * 2) + 2;
1095
1096                                 if (ImageList != null && page.ImageIndex >= 0 && page.ImageIndex < ImageList.Images.Count) {
1097                                         width += ImageList.ImageSize.Width + ThemeEngine.Current.TabControlImagePadding.X;
1098
1099                                         int image_size = ImageList.ImageSize.Height + ThemeEngine.Current.TabControlImagePadding.Y;
1100                                         if (item_size.Height < image_size)
1101                                                 item_size.Height = image_size;
1102                                 }
1103                         }
1104
1105                         height = item_size.Height - ThemeEngine.Current.TabControlSelectedDelta.Height; // full height only for selected tab
1106
1107                         if (width < MinimumTabWidth)
1108                                 width = MinimumTabWidth;
1109
1110                         if (i == SelectedIndex)
1111                                 width += ThemeEngine.Current.TabControlSelectedSpacing;
1112                         
1113                         if (widthOnly) {
1114                                 page.TabBounds = new Rectangle (xpos, 0, width, 0);
1115                                 page.Row = row_count;
1116                                 if (xpos + width > row_width && multiline) {
1117                                         xpos = 0;
1118                                         row_count++;
1119                                 } else if (xpos + width > row_width) {
1120                                         show_slider = true;     
1121                                 }
1122                                 if (i == selected_index && show_slider) {
1123                                         for (int j = i-1; j >= 0; j--) {
1124                                                 if (TabPages [j].TabBounds.Left < xpos + width - row_width) {
1125                                                         slider_pos = j+1;
1126                                                         break;
1127                                                 }
1128                                         }
1129                                 }
1130                         } else {
1131                                 if (page.Row != prev_row) {
1132                                         xpos = 0;
1133                                 }
1134
1135                                 switch (Alignment) {
1136                                         case TabAlignment.Top:
1137                                                 page.TabBounds = new Rectangle (
1138                                                         xpos + CalcXPos (),
1139                                                         ypos + (height + spacing.Height) * (row_count - page.Row) + CalcYPos (),
1140                                                         width, 
1141                                                         height);
1142                                                 break;
1143                                         case TabAlignment.Bottom:
1144                                                 page.TabBounds = new Rectangle (
1145                                                         xpos + CalcXPos (),
1146                                                         ypos + (height + spacing.Height) * (row_count - page.Row) + CalcYPos (),
1147                                                         width, 
1148                                                         height);
1149                                                 break;
1150                                         case TabAlignment.Left:
1151                                                 if (Appearance == TabAppearance.Normal) {
1152                                                         // tab rows are positioned right to left
1153                                                         page.TabBounds = new Rectangle (
1154                                                                 ypos + (height + spacing.Height) * (row_count - page.Row) + CalcXPos (),
1155                                                                 xpos,
1156                                                                 height, 
1157                                                                 width);
1158                                                 } else {
1159                                                         // tab rows are positioned left to right
1160                                                         page.TabBounds = new Rectangle (
1161                                                                 ypos + (height + spacing.Height) * (page.Row - 1) + CalcXPos (),
1162                                                                 xpos,
1163                                                                 height, 
1164                                                                 width);
1165                                                 }
1166
1167                                                 break;
1168                                         case TabAlignment.Right:
1169                                                 if (Appearance == TabAppearance.Normal) {
1170                                                         // tab rows are positioned left to right
1171                                                         page.TabBounds = new Rectangle (
1172                                                                 ypos + (height + spacing.Height) * (page.Row - 1) + CalcXPos (),
1173                                                                 xpos,
1174                                                                 height, 
1175                                                                 width);
1176                                                 } else {
1177                                                         // tab rows are positioned right to left
1178                                                         page.TabBounds = new Rectangle (
1179                                                                 ypos + (height + spacing.Height) * (row_count - page.Row) + CalcXPos (),
1180                                                                 xpos,
1181                                                                 height, 
1182                                                                 width);
1183                                                 }
1184
1185                                                 break;
1186                                 }
1187                         
1188                                 if (page.Row != prev_row) {
1189                                         if (SizeMode == TabSizeMode.FillToRight && !ShowSlider) {
1190                                                 FillRow (begin_prev, i - 1, ((row_width - TabPages [i - 1].TabBounds.Right) / (i - begin_prev)), spacing);
1191                                         }
1192                                         begin_prev = i;
1193                                 }       
1194                         }
1195
1196                         xpos += width + spacing.Width + ThemeEngine.Current.TabControlColSpacing;
1197                 }
1198
1199                 private void FillRow (int start, int end, int amount, Size spacing, bool vertical) 
1200                 {
1201                         if (vertical)
1202                                 FillRowV (start, end, amount, spacing);
1203                         else
1204                                 FillRow (start, end, amount, spacing);
1205                 }
1206
1207                 private void FillRow (int start, int end, int amount, Size spacing)
1208                 {
1209                         int xpos = TabPages [start].TabBounds.Left;
1210                         for (int i = start; i <= end; i++) {
1211                                 TabPage page = TabPages [i];
1212                                 int left = xpos;
1213                                 int width = (i == end ? Width - left - 3 : page.TabBounds.Width + amount);
1214
1215                                 page.TabBounds = new Rectangle (left, page.TabBounds.Top,
1216                                                 width, page.TabBounds.Height);
1217                                 xpos = page.TabBounds.Right + 1 + spacing.Width;
1218                         }
1219                 }
1220
1221                 private void FillRowV (int start, int end, int amount, Size spacing)
1222                 {
1223                         int ypos = TabPages [start].TabBounds.Top;
1224                         for (int i = start; i <= end; i++) {
1225                                 TabPage page = TabPages [i];
1226                                 int top = ypos;
1227                                 int height = (i == end ? Height - top - 5 : page.TabBounds.Height + amount);
1228
1229                                 page.TabBounds = new Rectangle (page.TabBounds.Left, top,
1230                                                 page.TabBounds.Width, height);
1231                                 ypos = page.TabBounds.Bottom + 1;
1232                         }
1233                 }
1234
1235                 private void ExpandSelected (TabPage page, int left_edge, int right_edge)
1236                 {
1237                         if (Appearance != TabAppearance.Normal)
1238                                 return;
1239
1240                         Rectangle r = page.TabBounds;
1241                         switch (Alignment) {
1242                                 case TabAlignment.Top:
1243                                 case TabAlignment.Left:
1244                                         r.Y -= ThemeEngine.Current.TabControlSelectedDelta.Y;
1245                                         r.X -= ThemeEngine.Current.TabControlSelectedDelta.X;
1246                                         break;
1247                                 case TabAlignment.Bottom:
1248                                         r.Y -= ThemeEngine.Current.TabControlSelectedDelta.Y;
1249                                         r.X -= ThemeEngine.Current.TabControlSelectedDelta.X;
1250                                         break;
1251                                 case TabAlignment.Right:
1252                                         r.Y -= ThemeEngine.Current.TabControlSelectedDelta.Y;
1253                                         r.X += ThemeEngine.Current.TabControlSelectedDelta.X;
1254                                         break;
1255                         }
1256
1257                         r.Width += ThemeEngine.Current.TabControlSelectedDelta.Width;
1258                         r.Height += ThemeEngine.Current.TabControlSelectedDelta.Height;
1259                         if (r.Left < left_edge)
1260                                 r.X = left_edge;
1261                         if (r.Right > right_edge && SizeMode != TabSizeMode.Normal)
1262                                 r.Width = right_edge - r.X;
1263                         page.TabBounds = r;
1264                 }
1265
1266                 private void Draw (Graphics dc, Rectangle clip)
1267                 {
1268                         ThemeEngine.Current.DrawTabControl (dc, clip, this);
1269                 }
1270
1271                 private TabPage GetTab (int index)
1272                 {
1273                         return Controls [index] as TabPage;
1274                 }
1275
1276                 private void SetTab (int index, TabPage value)
1277                 {
1278                         if (!tab_pages.Contains (value)) {
1279                                 this.Controls.Add (value);
1280                         }
1281                         this.Controls.RemoveAt (index);
1282                         this.Controls.SetChildIndex (value, index);
1283                         Redraw ();
1284                 }
1285 #if NET_2_0
1286                 private void InsertTab (int index, TabPage value)
1287                 {
1288                         if (!tab_pages.Contains (value)) {
1289                                 this.Controls.Add (value);
1290                         }
1291                         this.Controls.SetChildIndex (value, index);
1292                         Redraw ();
1293                 }
1294 #endif
1295                 internal void Redraw ()
1296                 {
1297                         if (!IsHandleCreated)
1298                                 return;
1299
1300                         ResizeTabPages ();
1301                         Refresh ();
1302                 }
1303
1304                 private int MeasureStringWidth (Graphics graphics, string text, Font font) 
1305                 {
1306                         if (text == String.Empty)
1307                                 return 0;
1308                         StringFormat format = new StringFormat();
1309                         RectangleF rect = new RectangleF(0, 0, 1000, 1000);
1310                         CharacterRange[] ranges = { new CharacterRange(0, text.Length) };
1311                         Region[] regions = new Region[1];
1312
1313                         format.SetMeasurableCharacterRanges(ranges);
1314                         format.FormatFlags = StringFormatFlags.NoClip;
1315                         format.FormatFlags |= StringFormatFlags.NoWrap;
1316                         regions = graphics.MeasureCharacterRanges(text + "I", font, rect, format);
1317                         rect = regions[0].GetBounds(graphics);
1318
1319                         return (int)(rect.Width);
1320                 }
1321
1322                 #endregion      // Internal & Private Methods
1323
1324                 #region Events
1325                 [Browsable(false)]
1326                 [EditorBrowsable(EditorBrowsableState.Never)]
1327                 public new event EventHandler BackColorChanged {
1328                         add { base.BackColorChanged += value; }
1329                         remove { base.BackColorChanged -= value; }
1330                 }
1331
1332                 [Browsable(false)]
1333                 [EditorBrowsable(EditorBrowsableState.Never)]
1334                 public new event EventHandler BackgroundImageChanged {
1335                         add { base.BackgroundImageChanged += value; }
1336                         remove { base.BackgroundImageChanged -= value; }
1337                 }
1338
1339 #if NET_2_0
1340                 [Browsable (false)]
1341                 [EditorBrowsable (EditorBrowsableState.Never)]
1342                 public new event EventHandler BackgroundImageLayoutChanged
1343                 {
1344                         add { base.BackgroundImageLayoutChanged += value; }
1345                         remove { base.BackgroundImageLayoutChanged -= value; }
1346                 }
1347 #endif
1348
1349                 [Browsable(false)]
1350                 [EditorBrowsable(EditorBrowsableState.Never)]
1351                 public new event EventHandler ForeColorChanged {
1352                         add { base.ForeColorChanged += value; }
1353                         remove { base.ForeColorChanged -= value; }
1354                 }
1355
1356                 [Browsable(false)]
1357                 [EditorBrowsable(EditorBrowsableState.Never)]
1358                 public new event PaintEventHandler Paint {
1359                         add { base.Paint += value; }
1360                         remove { base.Paint -= value; }
1361                 }
1362
1363                 [Browsable(false)]
1364                 [EditorBrowsable(EditorBrowsableState.Never)]
1365                 public new event EventHandler TextChanged {
1366                         add { base.TextChanged += value; }
1367                         remove { base.TextChanged -= value; }
1368                 }
1369
1370                 static object DrawItemEvent = new object ();
1371                 static object SelectedIndexChangedEvent = new object ();
1372
1373                 public event DrawItemEventHandler DrawItem {
1374                         add { Events.AddHandler (DrawItemEvent, value); }
1375                         remove { Events.RemoveHandler (DrawItemEvent, value); }
1376                 }
1377
1378                 public event EventHandler SelectedIndexChanged {
1379                         add { Events.AddHandler (SelectedIndexChangedEvent, value); }
1380                         remove { Events.RemoveHandler (SelectedIndexChangedEvent, value); }
1381                 }
1382                 
1383 #if NET_2_0
1384                 static object SelectedEvent = new object ();
1385                 
1386                 public event TabControlEventHandler Selected {
1387                         add { Events.AddHandler (SelectedEvent, value); }
1388                         remove { Events.RemoveHandler (SelectedEvent, value); }
1389                 }
1390
1391                 static object DeselectedEvent = new object ();
1392
1393                 public event TabControlEventHandler Deselected
1394                 {
1395                         add { Events.AddHandler (DeselectedEvent, value); }
1396                         remove { Events.RemoveHandler (DeselectedEvent, value); }
1397                 }
1398
1399                 static object SelectingEvent = new object ();
1400
1401                 public event TabControlCancelEventHandler Selecting
1402                 {
1403                         add { Events.AddHandler (SelectingEvent, value); }
1404                         remove { Events.RemoveHandler (SelectingEvent, value); }
1405                 }
1406
1407                 static object DeselectingEvent = new object ();
1408
1409                 public event TabControlCancelEventHandler Deselecting
1410                 {
1411                         add { Events.AddHandler (DeselectingEvent, value); }
1412                         remove { Events.RemoveHandler (DeselectingEvent, value); }
1413                 }
1414
1415                 static object RightToLeftLayoutChangedEvent = new object ();
1416                 public event EventHandler RightToLeftLayoutChanged
1417                 {
1418                         add { Events.AddHandler (RightToLeftLayoutChangedEvent, value); }
1419                         remove { Events.RemoveHandler (RightToLeftLayoutChangedEvent, value); }
1420                 }
1421 #endif
1422                 #endregion      // Events
1423
1424
1425                 #region Class TaControl.ControlCollection
1426 #if NET_2_0
1427                 [ComVisible (false)]
1428 #endif
1429                 public new class ControlCollection : System.Windows.Forms.Control.ControlCollection {
1430
1431                         private TabControl owner;
1432
1433                         public ControlCollection (TabControl owner) : base (owner)
1434                         {
1435                                 this.owner = owner;
1436                         }
1437
1438                         public override void Add (Control value)
1439                         {
1440                                 TabPage page = value as TabPage;
1441                                 if (page == null)
1442                                         throw new ArgumentException ("Cannot add " +
1443                                                 value.GetType ().Name + " to TabControl. " +
1444                                                 "Only TabPages can be directly added to TabControls.");
1445
1446                                 page.SetVisible (false);
1447                                 base.Add (value);
1448                                 if (owner.TabCount == 1 && owner.selected_index < 0)
1449                                         owner.SelectedIndex = 0;
1450                                 owner.Redraw ();
1451                         }
1452
1453                         public override void Remove (Control value)
1454                         {
1455                                 TabPage page = value as TabPage;
1456                                 if (page != null) {
1457                                         int index = owner.IndexForTabPage (page);
1458                                         if (index < owner.SelectedIndex || owner.SelectedIndex == Count - 1)
1459                                                 owner.SelectedIndex--;
1460                                 }
1461                                 base.Remove (value);
1462                         }
1463                 }
1464                 #endregion      // Class TabControl.ControlCollection
1465
1466                 #region Class TabPage.TabPageCollection
1467                 public class TabPageCollection  : IList, ICollection, IEnumerable {
1468
1469                         private TabControl owner;
1470
1471                         public TabPageCollection (TabControl owner)
1472                         {
1473                                 if (owner == null)
1474                                         throw new ArgumentNullException ("Value cannot be null.");
1475                                 this.owner = owner;
1476                         }
1477
1478                         [Browsable(false)]
1479                         public int Count {
1480                                 get { return owner.Controls.Count; }
1481                         }
1482
1483                         public bool IsReadOnly {
1484                                 get { return false; }
1485                         }
1486
1487                         public virtual TabPage this [int index] {
1488                                 get {
1489                                         return owner.GetTab (index);
1490                                 }
1491                                 set {
1492                                         owner.SetTab (index, value);
1493                                 }    
1494                         }
1495 #if NET_2_0
1496                         public virtual TabPage this [string key] {
1497                                 get {
1498                                         if (string.IsNullOrEmpty (key))
1499                                                 return null;
1500
1501                                         int index = this.IndexOfKey (key);
1502                                         if (index < 0 || index >= this.Count)
1503                                                 return null;
1504                                         
1505                                         return this[index];
1506                                 }
1507                         }
1508 #endif
1509
1510                         internal int this[TabPage tabPage] {
1511                                 get {
1512                                         if (tabPage == null)
1513                                                 return -1;
1514
1515                                         for (int i = 0; i < this.Count; i++)
1516                                                 if (this[i].Equals (tabPage))
1517                                                         return i;
1518
1519                                         return -1;
1520                                 }
1521                         }
1522
1523                         bool ICollection.IsSynchronized {
1524                                 get { return false; }
1525                         }
1526
1527                         object ICollection.SyncRoot {
1528                                 get { return this; }
1529                         }
1530
1531                         bool IList.IsFixedSize {
1532                                 get { return false; }
1533                         }
1534
1535                         object IList.this [int index] {
1536                                 get {
1537                                         return owner.GetTab (index);
1538                                 }
1539                                 set {
1540                                         owner.SetTab (index, (TabPage) value);
1541                                 }
1542                         }
1543
1544                         public void Add (TabPage value)
1545                         {
1546                                 if (value == null)
1547                                         throw new ArgumentNullException ("Value cannot be null.");
1548                                 owner.Controls.Add (value);
1549                         }
1550
1551 #if NET_2_0
1552                         public void Add (string text)
1553                         {
1554                                 TabPage page = new TabPage (text);
1555                                 this.Add (page);
1556                         }
1557
1558                         public void Add (string key, string text)
1559                         {
1560                                 TabPage page = new TabPage (text);
1561                                 page.Name = key;
1562                                 this.Add (page);
1563                         }
1564
1565                         public void Add (string key, string text, int imageIndex)
1566                         {
1567                                 TabPage page = new TabPage (text);
1568                                 page.Name = key;
1569                                 page.ImageIndex = imageIndex;
1570                                 this.Add (page);
1571                         }
1572
1573                         // .Net sets the ImageKey, but does not show the image when this is used
1574                         public void Add (string key, string text, string imageKey)
1575                         {
1576                                 TabPage page = new TabPage (text);
1577                                 page.Name = key;
1578                                 page.ImageKey = imageKey;
1579                                 this.Add (page);
1580                         }
1581 #endif
1582
1583                         public void AddRange (TabPage [] pages)
1584                         {
1585                                 if (pages == null)
1586                                         throw new ArgumentNullException ("Value cannot be null.");
1587                                 owner.Controls.AddRange (pages);
1588                         }
1589
1590                         public virtual void Clear ()
1591                         {
1592                                 owner.Controls.Clear ();
1593                         }
1594
1595                         public bool Contains (TabPage page)
1596                         {
1597                                 if (page == null)
1598                                         throw new ArgumentNullException ("Value cannot be null.");
1599                                 return owner.Controls.Contains (page);
1600                         }
1601
1602 #if NET_2_0
1603                         public virtual bool ContainsKey (string key)
1604                         {
1605                                 int index = this.IndexOfKey (key);
1606                                 return (index >= 0 && index < this.Count);
1607                         }
1608 #endif
1609
1610                         public IEnumerator GetEnumerator ()
1611                         {
1612                                 return owner.Controls.GetEnumerator ();
1613                         }
1614
1615                         public int IndexOf (TabPage page)
1616                         {
1617                                 return owner.Controls.IndexOf (page);
1618                         }
1619
1620 #if NET_2_0
1621                         public virtual int IndexOfKey(string key)
1622                         {
1623                                 if (string.IsNullOrEmpty (key))
1624                                         return -1;
1625
1626                                 for (int i = 0; i < this.Count; i++) {
1627                                         if (string.Compare (this[i].Name, key, true, 
1628                                                 System.Globalization.CultureInfo.InvariantCulture) == 0) {
1629                                                 return i;
1630                                         }
1631                                 }
1632
1633                                 return -1;
1634                         }
1635 #endif
1636
1637                         public void Remove (TabPage value)
1638                         {
1639                                 owner.Controls.Remove (value);
1640                         }
1641
1642                         public void RemoveAt (int index)
1643                         {
1644                                 owner.Controls.RemoveAt (index);
1645                         }
1646
1647 #if NET_2_0
1648                         public virtual void RemoveByKey (string key)
1649                         {
1650                                 int index = this.IndexOfKey (key);
1651                                 if (index >= 0 && index < this.Count)
1652                                         this.RemoveAt (index);
1653                         }
1654 #endif
1655
1656                         void ICollection.CopyTo (Array dest, int index)
1657                         {
1658                                 owner.Controls.CopyTo (dest, index);
1659                         }
1660
1661                         int IList.Add (object value)
1662                         {
1663                                 TabPage page = value as TabPage;
1664                                 if (value == null)
1665                                         throw new ArgumentException ("value");
1666                                 owner.Controls.Add (page);
1667                                 return owner.Controls.IndexOf (page);
1668                         }
1669
1670                         bool IList.Contains (object value)
1671                         {
1672                                 TabPage page = value as TabPage;
1673                                 if (page == null)
1674                                         return false;
1675                                 return Contains (page);
1676                         }
1677
1678                         int IList.IndexOf (object value)
1679                         {
1680                                 TabPage page = value as TabPage;
1681                                 if (page == null)
1682                                         return -1;
1683                                 return IndexOf ((TabPage) page);
1684                         }
1685
1686                         void IList.Insert (int index, object value)
1687                         {
1688                                 throw new NotSupportedException ();
1689                         }
1690
1691 #if NET_2_0
1692                         public void Insert (int index, string text)
1693                         {
1694                                 owner.InsertTab (index, new TabPage (text));
1695                         }
1696                         
1697                         public void Insert (int index, TabPage tabPage)
1698                         {
1699                                 owner.InsertTab (index, tabPage);
1700                         }
1701
1702                         public void Insert (int index, string key, string text)
1703                         {
1704                                 TabPage page = new TabPage(text);
1705                                 page.Name = key;
1706                                 owner.InsertTab (index, page);
1707                         }
1708
1709                         public void Insert (int index, string key, string text, int imageIndex) 
1710                         {
1711                                 TabPage page = new TabPage(text);
1712                                 page.Name = key;
1713                                 owner.InsertTab (index, page);
1714                                 page.ImageIndex = imageIndex;
1715                         }
1716
1717                         public void Insert (int index, string key, string text, string imageKey) 
1718                         {
1719                                 TabPage page = new TabPage(text);
1720                                 page.Name = key;
1721                                 owner.InsertTab (index, page);
1722                                 page.ImageKey = imageKey;
1723                         }
1724 #endif
1725                         void IList.Remove (object value)
1726                         {
1727                                 TabPage page = value as TabPage;
1728                                 if (page == null)
1729                                         return;
1730                                 Remove ((TabPage) value);
1731                         }
1732                 }
1733                 #endregion      // Class TabPage.TabPageCollection
1734         }
1735 }
1736
1737