* X11Keyboard.cs: Detect and use the num lock mask.
[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 Novell, Inc.
21 //
22 // Authors:
23 //      Jackson Harper (jackson@ximian.com)
24
25
26 using System;
27 using System.Drawing;
28 using System.Collections;
29
30
31 namespace System.Windows.Forms {
32
33         public class TabControl : Control {
34
35                 private int selected_index = -1;
36                 private TabAlignment alignment;
37                 private TabAppearance appearance;
38                 private TabDrawMode draw_mode;
39                 private bool multiline;
40                 private ImageList image_list;
41                 private Size item_size = Size.Empty;
42                 private Point padding;
43                 private int row_count = 1;
44                 private bool hottrack;
45                 private TabPageCollection tab_pages;
46                 private bool show_tool_tips;
47                 private TabSizeMode size_mode;
48                 private bool redraw;
49                 private Rectangle display_rect;
50                 private bool show_slider = false;
51                 private ButtonState right_slider_state;
52                 private ButtonState left_slider_state;
53                 private int slider_pos = 0;
54                 
55                 public TabControl ()
56                 {
57                         tab_pages = new TabPageCollection (this);
58                         SetStyle (ControlStyles.UserPaint, true);
59                         padding = ThemeEngine.Current.TabControlDefaultPadding;
60                         item_size = ThemeEngine.Current.TabControlDefaultItemSize;
61
62                         MouseDown += new MouseEventHandler (MouseDownHandler);
63                         MouseUp += new MouseEventHandler (MouseUpHandler);
64                         SizeChanged += new EventHandler (SizeChangedHandler);
65                 }
66
67                 public TabAlignment Alignment {
68                         get { return alignment; }
69                         set {
70                                 if (alignment == value)
71                                         return;
72                                 alignment = value;
73                                 if (alignment == TabAlignment.Left || alignment == TabAlignment.Right)
74                                         multiline = true;
75                                 Refresh ();
76                         }
77                 }
78
79                 public TabAppearance Appearance {
80                         get { return appearance; }
81                         set {
82                                 if (appearance == value)
83                                         return;
84                                 appearance = value;
85                                 Refresh ();
86                         }
87                 }
88
89                 public override Color BackColor {
90                         get { return base.BackColor; }
91                         set { /* nothing happens on set on MS */ }
92                 }
93
94                 public override Image BackgroundImage {
95                         get { return base.BackgroundImage; }
96                         set { base.BackgroundImage = value; }
97                 }
98
99                 public override Rectangle DisplayRectangle {
100                         get {
101                                 return ThemeEngine.Current.GetTabControlDisplayRectangle (this);
102                         }
103                 }
104
105                 public TabDrawMode DrawMode {
106                         get { return draw_mode; }
107                         set {
108                                 if (draw_mode == value)
109                                         return;
110                                 draw_mode = value;
111                                 Refresh ();
112                         }
113                 }
114
115                 public override Color ForeColor {
116                         get { return base.ForeColor; }
117                         set { base.ForeColor = value; }
118                 }
119
120                 public bool HotTrack {
121                         get { return hottrack; }
122                         set {
123                                 if (hottrack == value)
124                                         return;
125                                 hottrack = value;
126                                 Refresh ();
127                         }
128                 }
129
130                 public ImageList ImageList {
131                         get { return image_list; }
132                         set { image_list = value; }
133                 }
134
135                 public Size ItemSize {
136                         get {
137                                 return item_size;
138                         }
139                         set {
140                                 if (value.Height < 0 || value.Width < 0)
141                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'ItemSize'.");
142                                 item_size = value;
143                                 Refresh ();
144                         }
145                 }
146
147                 public bool Multiline {
148                         get { return multiline; }
149                         set {
150                                 if (multiline == value)
151                                         return;
152                                 multiline = value;
153                                 if (!multiline && alignment == TabAlignment.Left || alignment == TabAlignment.Right)
154                                         alignment = TabAlignment.Top;
155                                 Refresh ();
156                         }
157                 }
158
159                 public Point Padding {
160                         get { return padding; }
161                         set {
162                                 if (value.X < 0 || value.Y < 0)
163                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'Padding'.");
164                                 if (padding == value)
165                                         return;
166                                 padding = value;
167                                 Refresh ();
168                         }
169
170                 }
171
172                 public int RowCount {
173                         get { return row_count; }
174                 }
175
176                 public int SelectedIndex {
177                         get { return selected_index; }
178                         set {
179                                 if (selected_index == value)
180                                         return;
181                                 if (selected_index < -1) {
182                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
183                                                         "'value' must be greater than or equal to -1.");
184                                 }
185
186                                 SuspendLayout ();
187                                 if (selected_index != -1)
188                                         Controls [selected_index].Visible = false;
189                                 selected_index = value;
190                                 if (selected_index != -1) 
191                                         Controls [selected_index].Visible = true;
192                                 ResumeLayout ();
193
194                                 if (SelectedIndex != -1 && TabPages [SelectedIndex].Row != BottomRow) 
195                                         DropRow (TabPages [selected_index].Row);
196                                 SizeTabs ();
197                                 
198                                 Refresh ();
199                         }
200                 }
201
202                 public TabPage SelectedTab {
203                         get {
204                                 if (selected_index == -1)
205                                         return null;
206                                 return tab_pages [selected_index];
207                         }
208                         set {
209                                 int index = IndexForTabPage (value);
210                                 if (index == selected_index)
211                                         return;
212                                 selected_index = index;
213                                 Refresh ();
214                         }
215                 }
216
217                 public bool ShowToolTips {
218                         get { return show_tool_tips; }
219                         set {
220                                 if (show_tool_tips == value)
221                                         return;
222                                 show_tool_tips = value;
223                                 Refresh ();
224                         }
225                 }
226
227                 public TabSizeMode SizeMode {
228                         get { return size_mode; }
229                         set {
230                                 if (size_mode == value)
231                                         return;
232                                 size_mode = value;
233                                 Refresh ();
234                         }
235                 }
236
237                 public int TabCount {
238                         get {
239                                 return tab_pages.Count;
240                         }
241                 }
242
243                 public TabPageCollection TabPages {
244                         get { return tab_pages; }
245                 }
246
247                 public override string Text {
248                         get { return base.Text; }
249                         set { base.Text = value; }
250                 }
251
252                 internal bool ShowSlider {
253                         get { return show_slider; }
254                         set { show_slider = value; }
255                 }
256
257                 internal int SliderPos {
258                         get { return slider_pos; }
259                 }
260
261                 internal ButtonState RightSliderState {
262                         get { return right_slider_state; }
263                 }
264
265                 internal ButtonState LeftSliderState {
266                         get { return left_slider_state; }
267                 }
268
269                 [MonoTODO ("Anything special need to be done?")]
270                 protected override CreateParams CreateParams {
271                         get {
272                                 CreateParams c = base.CreateParams;
273                                 // Do we need to do anything here?
274                                 return c;
275                         }
276                 }
277
278                 protected override Size DefaultSize {
279                         get { return new Size (200, 100); }  
280                 }
281
282                 private Size DefaultItemSize {
283                         get {
284                                 return ThemeEngine.Current.TabControlDefaultItemSize;
285                         }
286                 }
287
288                 public new event EventHandler BackColorChanged {
289                         add { base.BackColorChanged += value; }
290                         remove { base.BackColorChanged -= value; }
291                 }
292
293                 public new event EventHandler BackgroundImageChanged {
294                         add { base.BackgroundImageChanged += value; }
295                         remove { base.BackgroundImageChanged -= value; }
296                 }
297
298                 public new event EventHandler ForeColorChanged {
299                         add { base.ForeColorChanged += value; }
300                         remove { base.ForeColorChanged -= value; }
301                 }
302
303                 public new event PaintEventHandler Paint {
304                         add { base.Paint += value; }
305                         remove { base.Paint -= value; }
306                 }
307
308                 public new event EventHandler TextChanged {
309                         add { base.TextChanged += value; }
310                         remove { base.TextChanged -= value; }
311                 }
312
313                 public event DrawItemEventHandler DrawItem;
314                 public event EventHandler SelectedIndexChanged;
315
316                 public Rectangle GetTabRect (int index)
317                 {
318                         TabPage page = GetTab (index);
319                         return page.TabBounds;
320                 }
321
322                 public Control GetControl (int index)
323                 {
324                         return GetTab (index);
325                 }
326
327                 protected override Control.ControlCollection CreateControlsInstance ()
328                 {
329                         return new TabControl.ControlCollection (this);
330                 }
331
332                 protected override void CreateHandle ()
333                 {
334                         ResizeTabPages ();
335                         base.CreateHandle ();
336                 }
337
338                 protected override void Dispose (bool disposing)
339                 {
340                         base.Dispose (disposing);
341                 }
342
343                 protected virtual object [] GetItems ()
344                 {
345                         TabPage [] pages = new TabPage [Controls.Count];
346                         Controls.CopyTo (pages, 0);
347                         return pages;
348                 }
349
350                 protected virtual object [] GetItems (Type type)
351                 {
352                         object [] pages = (object []) Array.CreateInstance (type, Controls.Count);
353                         Controls.CopyTo (pages, 0);
354                         return pages;
355                 }
356
357                 protected string GetToolTipText (object item)
358                 {
359                         TabPage page = (TabPage) item;
360                         return page.ToolTipText;
361                 }
362
363                 protected override void WndProc (ref Message m)
364                 {
365                         switch ((Msg) m.Msg) {
366                         case Msg.WM_PAINT:
367                                 PaintEventArgs  paint_event;
368                                 paint_event = XplatUI.PaintEventStart (Handle);
369                                 PaintInternal (paint_event);
370                                 XplatUI.PaintEventEnd (Handle);
371                                 break;
372                         default:
373                                 base.WndProc (ref m);
374                                 break;
375                         }
376                 }
377
378                 private bool CanScrollRight {
379                         get {
380                                 if (TabPages [TabCount - 1].TabBounds.Right > ClientRectangle.Right - 40)
381                                         return true;
382                                 return false;
383                         }
384                 }
385
386                 private bool CanScrollLeft {
387                         get { return slider_pos > 0; }
388                 }
389
390                 private void MouseDownHandler (object sender, MouseEventArgs e)
391                 {
392                         if (ShowSlider) {
393                                 Rectangle right = ThemeEngine.Current.GetTabControlRightScrollRect (this);
394                                 Rectangle left = ThemeEngine.Current.GetTabControlLeftScrollRect (this);
395                                 if (right.Contains (e.X, e.Y)) {
396                                         right_slider_state = ButtonState.Pushed;
397                                         if (CanScrollRight) {
398                                                 slider_pos++;
399                                                 SizeTabs ();
400                                         }
401                                         Refresh ();
402                                         return;
403                                 } else if (left.Contains (e.X, e.Y)) {
404                                         left_slider_state = ButtonState.Pushed;
405                                         if (CanScrollLeft) {
406                                                 slider_pos--;
407                                                 SizeTabs ();
408                                         }
409                                         Refresh ();
410                                         return;
411                                 }
412
413                         }
414
415                         int count = Controls.Count;
416                         for (int i = SliderPos; i < count; i++) {
417                                 if (!GetTabRect (i).Contains (e.X, e.Y))
418                                         continue;
419                                 SelectedIndex = i;
420                                 break;
421                         }
422                 }
423
424                 private void MouseUpHandler (object sender, MouseEventArgs e)
425                 {
426                         left_slider_state = ButtonState.Normal;
427                         right_slider_state = ButtonState.Normal;
428                         Refresh ();
429                 }
430
431                 private void SizeChangedHandler (object sender, EventArgs e)
432                 {
433                         ResizeTabPages ();
434                 }
435
436                 internal void UpdateTabpage (TabPage page)
437                 {
438
439                 }
440
441                 internal int IndexForTabPage (TabPage page)
442                 {
443                         for (int i = 0; i < tab_pages.Count; i++) {
444                                 if (page == tab_pages [i])
445                                         return i;
446                         }
447                         return -1;
448                 }
449
450                 private void ResizeTabPages ()
451                 {
452                         CalcTabRows ();
453                         SizeTabs ();
454                         Rectangle r = DisplayRectangle;
455                         foreach (TabPage page in Controls) {
456                                 page.Bounds = r;
457                         }
458                 }
459
460                 private int MinimumTabWidth {
461                         get {
462                                 return ThemeEngine.Current.TabControlMinimumTabWidth;
463                         }
464                 }
465
466                 private Size TabSpacing {
467                         get {
468                                 return ThemeEngine.Current.TabControlGetSpacing (this);
469                         }
470                 }
471
472                 private void CalcTabRows ()
473                 {
474                         switch (Alignment) {
475                         case TabAlignment.Right:
476                         case TabAlignment.Left:
477                                 CalcTabRows (Height);
478                                 break;
479                         default:
480                                 CalcTabRows (Width);
481                                 break;
482                         }
483                 }
484
485                 private void CalcTabRows (int row_width)
486                 {
487                         int xpos = 4;
488                         Size spacing = TabSpacing;
489
490                         row_count = 1;
491                         show_slider = false;
492                         
493                         for (int i = 0; i < TabPages.Count; i++) {
494                                 TabPage page = TabPages [i];
495                                 int width;
496
497                                 page.Row = 1;
498
499                                 if (SizeMode == TabSizeMode.Fixed) {
500                                         width = item_size.Width;
501                                 } else {
502                                         width = (int) DeviceContext.MeasureString (page.Text, Font).Width + (Padding.X * 2);
503                                 }
504
505                                 if (i == SelectedIndex)
506                                         width += 8;
507                                 if (width < MinimumTabWidth)
508                                         width = MinimumTabWidth;
509
510                                 if (xpos + width > row_width && multiline) {
511                                         xpos = 4;
512                                         for (int j = 0; j < i; j++) {
513                                                 TabPages [j].Row++;
514                                         }
515                                         row_count++;
516                                 } else if (xpos + width > row_width) {
517                                         show_slider = true;
518                                 }
519
520                                 xpos += width + 1 + spacing.Width;
521                         }
522
523                         if (SelectedIndex != -1 && TabPages [SelectedIndex].Row != BottomRow)
524                                 DropRow (TabPages [SelectedIndex].Row);
525                 }
526
527                 private int BottomRow {
528                         get {
529                                 switch (Alignment) {
530                                 case TabAlignment.Right:
531                                 case TabAlignment.Bottom:
532                                         return row_count;
533                                 default:
534                                         return 1;
535                                 }
536                         }
537                 }
538
539                 private int Direction
540                 {
541                         get {
542                                 switch (Alignment) {
543                                 case TabAlignment.Right:
544                                 case TabAlignment.Bottom:
545                                         return -1;
546                                 default:
547                                         return 1;
548                                 }
549                         }
550                 }
551
552                 private void DropRow (int row)
553                 {
554                         int bottom = BottomRow;
555                         int direction = Direction;
556
557                         foreach (TabPage page in TabPages) {
558                                 if (page.Row == row) {
559                                         page.Row = bottom;
560                                 } else if (direction == 1 && page.Row < row) {
561                                         page.Row += direction;
562                                 } else if (direction == -1 && page.Row > row) {
563                                         page.Row += direction;
564                                 }
565                         }
566                 }
567
568                 private int CalcYPos ()
569                 {
570                         if (Alignment == TabAlignment.Bottom) {
571                                 Rectangle r = ThemeEngine.Current.GetTabControlDisplayRectangle (this);
572                                 return r.Bottom + 3;
573                         }
574                         return 1;
575                 }
576
577                 private int CalcXPos ()
578                 {
579                         if (Alignment == TabAlignment.Right) {
580                                 Rectangle r = ThemeEngine.Current.GetTabControlDisplayRectangle (this);
581                                 return r.Right + 4;
582                         }
583                         return 4;
584
585                 }
586
587                 private void SizeTabs ()
588                 {
589                         switch (Alignment) {
590                         case TabAlignment.Right:
591                         case TabAlignment.Left:
592                                 SizeTabsV (Height);
593                                 break;
594                         default:
595                                 SizeTabs (Width);
596                                 break;
597                         }
598                 }
599
600                 private void SizeTabsV (int row_width)
601                 {
602                         int ypos = 1;
603                         int prev_row = 1;
604                         Size spacing = TabSpacing;
605                         int size = item_size.Height + 2 + spacing.Width;
606                         int xpos = CalcXPos ();
607
608                         if (TabPages.Count == 0)
609                                 return;
610
611                         prev_row = TabPages [0].Row;
612
613                         for (int i = 0; i < TabPages.Count; i++) {
614                                 TabPage page = TabPages [i];
615                                 int width;
616
617                                 if (SizeMode == TabSizeMode.Fixed) {
618                                         width = item_size.Width;
619                                 } else {
620                                         width = (int) DeviceContext.MeasureString (page.Text, Font).Width + (Padding.X * 2);
621                                 }
622
623                                 if (width < MinimumTabWidth)
624                                         width = MinimumTabWidth;
625                                 if (page.Row != prev_row)
626                                         ypos = 1;
627
628                                 page.TabBounds = new Rectangle (xpos + (row_count - page.Row) * ((item_size.Height - 2) + spacing.Width),
629                                                 ypos, item_size.Height - 2, width);
630
631                                 ypos += width + spacing.Width;
632                                 prev_row = page.Row;
633                         }
634
635                         if (SelectedIndex != -1) {
636                                 TabPage page = TabPages [SelectedIndex];
637                                 ExpandSelected (TabPages [SelectedIndex], 1, row_width - 1);
638                         }
639                 }
640
641                 private void SizeTabs (int row_width)
642                 {
643                         int ypos = CalcYPos ();
644                         int prev_row = 1;
645                         Size spacing = TabSpacing;
646                         int size = item_size.Width + 2 + (spacing.Width * 2);
647                         int xpos = 4;
648                         int begin_prev = 0;
649
650                         if (TabPages.Count == 0)
651                                 return;
652
653                         prev_row = TabPages [0].Row;
654
655                         for (int i = slider_pos; i < TabPages.Count; i++) {
656                                 TabPage page = TabPages [i];
657                                 int width;
658  
659                                 if (SizeMode == TabSizeMode.Fixed) {
660                                         width = item_size.Width;
661                                 } else {
662                                         width = (int) DeviceContext.MeasureString (page.Text, Font).Width + (Padding.X * 2);
663                                 }
664
665                                 if (width < MinimumTabWidth)
666                                         width = MinimumTabWidth;
667                                 if (page.Row != prev_row)
668                                         xpos = 4;
669
670                                 page.TabBounds = new Rectangle (xpos,
671                                                 ypos + (row_count - page.Row) * (item_size.Height + spacing.Height),
672                                                 width, item_size.Height);
673                                 
674                                 if (page.Row != prev_row) {
675                                         if (SizeMode == TabSizeMode.FillToRight) {
676                                                 FillRow (begin_prev, i - 1, ((row_width - TabPages [i - 1].TabBounds.Right) / (i - begin_prev)), spacing);
677                                         }
678                                         begin_prev = i;
679                                 }
680
681                                 xpos += width + 1 + spacing.Width;
682                                 prev_row = page.Row;                                
683                         }
684
685                         if (SizeMode == TabSizeMode.FillToRight) {
686                                 FillRow (begin_prev, TabPages.Count - 1,
687                                                 ((row_width - TabPages [TabPages.Count - 1].TabBounds.Right) / (TabPages.Count - begin_prev)), spacing);
688                         }
689
690                         if (SelectedIndex != -1) {
691                                 TabPage page = TabPages [SelectedIndex];
692                                 ExpandSelected (TabPages [SelectedIndex], 2, row_width - 1);
693                         }
694                 }
695                 
696                 private void FillRow (int start, int end, int amount, Size spacing)
697                 {
698                         int xpos = TabPages [start].TabBounds.Left;
699                         for (int i = start; i <= end; i++) {
700                                 TabPage page = TabPages [i];
701                                 int left = xpos;
702                                 int width = (i == end ? Width - left - 3 : page.TabBounds.Width + amount);
703
704                                 page.TabBounds = new Rectangle (left, page.TabBounds.Top,
705                                                 width, page.TabBounds.Height);
706                                 xpos = page.TabBounds.Right + 1 + spacing.Width;
707                         }
708                 }
709
710                 private void ExpandSelected (TabPage page, int left_edge, int right_edge)
711                 {
712                         if (Appearance != TabAppearance.Normal)
713                                 return;
714
715                         if (Alignment == TabAlignment.Top || Alignment == TabAlignment.Bottom) {
716                                 int l = page.TabBounds.Left - 4;
717                                 int r = page.TabBounds.Right + 4;
718                                 int y = page.TabBounds.Y;
719                                 int h = page.TabBounds.Height + 2;
720
721                                 if (l < left_edge)
722                                         l = left_edge;
723                                 if (r > right_edge && SizeMode != TabSizeMode.Normal)
724                                         r = right_edge;
725                                 if (Alignment == TabAlignment.Top)
726                                         y -= 1;
727                                 if (Alignment == TabAlignment.Bottom)
728                                         y -= 2;
729
730                                 page.TabBounds = new Rectangle (l, y, r - l, h);
731                         } else {
732                                 int l = page.TabBounds.Left - 3;
733                                 int r = page.TabBounds.Right + 3;
734                                 int t = page.TabBounds.Top - 3;
735                                 int b = page.TabBounds.Bottom + 3;
736
737                                 if (t < left_edge)
738                                         t = left_edge;
739                                 if (b > right_edge)
740                                         b = right_edge;
741
742                                 page.TabBounds = new Rectangle (l, t, r - l, b - t);
743                         }
744                 }
745
746                 private void PaintInternal (PaintEventArgs pe)
747                 {
748                         if (this.Width <= 0 || this.Height <=  0 || this.Visible == false)
749                                 return;
750
751                         Draw ();
752                         pe.Graphics.DrawImageUnscaled (ImageBuffer, 0, 0);
753                         ImageBuffer.Save ("ImageBuffer.bmp");
754                         // On MS the Paint event never seems to be raised
755                 }
756
757                 private void Redraw (bool recalculate)
758                 {
759                         if (recalculate) {
760                                 
761                         }
762                         redraw = true;
763                         Refresh ();
764                 }
765
766                 private void Draw ()
767                 {
768                         ThemeEngine.Current.DrawTabControl (DeviceContext, ClientRectangle, this);
769                         redraw = false;
770                 }
771
772                 private TabPage GetTab (int index)
773                 {
774                         return Controls [index] as TabPage;
775                 }
776
777                 private void SetTab (int index, TabPage value)
778                 {
779                         ((IList) Controls).Insert (index, value);
780                         Refresh ();
781                 }
782
783                 public class ControlCollection : System.Windows.Forms.Control.ControlCollection {
784
785                         private TabControl owner;
786                         private ArrayList list = new ArrayList ();
787
788                         public ControlCollection (TabControl owner) : base (owner)
789                         {
790                                 this.owner = owner;
791                         }
792
793                         public override void Add (Control value)
794                         {
795                                 if (!(value is TabPage))
796                                         throw new ArgumentException ("Cannot add " +
797                                                 value.GetType ().Name + " to TabControl. " +
798                                                 "Only TabPages can be directly added to TabControls.");
799
800                                 value.Visible = false;
801                                 base.Add (value);
802                                 if (Count == 1) {
803                                         owner.SelectedIndex = 0;
804                                 } else {
805                                         // Setting the selected index will calc the tab rows so
806                                         // we don't need to do it again
807                                         owner.CalcTabRows ();
808                                 }
809                         }
810                 }
811
812                 public class TabPageCollection  : IList, ICollection, IEnumerable {
813
814                         private TabControl owner;
815                         private IList controls;
816
817                         public TabPageCollection (TabControl owner)
818                         {
819                                 if (owner == null)
820                                         throw new ArgumentNullException ("Value cannot be null.");
821                                 this.owner = owner;
822                                 controls = owner.Controls;
823                         }
824
825                         public virtual int Count {
826                                 get { return owner.Controls.Count; }
827                         }
828
829                         public virtual bool IsReadOnly {
830                                 get { return false; }
831                         }
832
833                         public virtual TabPage this [int index] {
834                                 get {
835                                         return owner.GetTab (index);
836                                 }
837                                 set {
838                                         owner.SetTab (index, value);
839                                 }    
840                         }
841
842                         bool ICollection.IsSynchronized {
843                                 get { return false; }
844                         }
845
846                         object ICollection.SyncRoot {
847                                 get { return this; }
848                         }
849
850                         bool IList.IsFixedSize {
851                                 get { return false; }
852                         }
853
854                         object IList.this [int index] {
855                                 get {
856                                         return owner.GetTab (index);
857                                 }
858                                 set {
859                                         owner.SetTab (index, (TabPage) value);
860                                 }
861                         }
862
863                         public void Add (TabPage page)
864                         {
865                                 if (page == null)
866                                         throw new ArgumentNullException ("Value cannot be null.");
867                                 owner.Controls.Add (page);
868                         }
869
870                         public void AddRange (TabPage [] pages)
871                         {
872                                 if (pages == null)
873                                         throw new ArgumentNullException ("Value cannot be null.");
874                                 owner.Controls.AddRange (pages);
875                         }
876
877                         public virtual void Clear ()
878                         {
879                                 owner.Controls.Clear ();
880                         }
881
882                         public bool Contains (TabPage page)
883                         {
884                                 if (page == null)
885                                         throw new ArgumentNullException ("Value cannot be null.");
886                                 return owner.Controls.Contains (page);
887                         }
888
889                         public virtual IEnumerator GetEnumerator ()
890                         {
891                                 return owner.Controls.GetEnumerator ();
892                         }
893
894                         public int IndexOf (TabPage page)
895                         {
896                                 return owner.Controls.IndexOf (page);
897                         }
898
899                         public void Remove (TabPage page)
900                         {
901                                 owner.Controls.Remove (page);
902                         }
903
904                         public virtual void RemoveAt (int index)
905                         {
906                                 owner.Controls.RemoveAt (index);
907                         }
908
909                         void ICollection.CopyTo (Array dest, int index)
910                         {
911                                 owner.Controls.CopyTo (dest, index);
912                         }
913
914                         int IList.Add (object value)
915                         {
916                                 //       return owner.Controls.Add ((TabPage) value);
917                                 return -1;
918                         }
919
920                         bool IList.Contains (object page)
921                         {
922                                 return Contains ((TabPage) page);
923                         }
924
925                         int IList.IndexOf (object page)
926                         {
927                                 return IndexOf ((TabPage) page);
928                         }
929
930                         void IList.Insert (int index, object value)
931                         {
932                                 controls.Insert (index, (TabPage) value);
933                         }
934
935                         void IList.Remove (object value)
936                         {
937                                 Remove ((TabPage) value);
938                         }
939                 }
940         }
941 }
942
943