2009-05-21 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ContainerControl.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 //      Peter Bartok    pbartok@novell.com
24 //
25 //
26
27
28 using System.Collections;
29 using System.ComponentModel;
30 using System.ComponentModel.Design;
31 using System.Drawing;
32 using System.Runtime.InteropServices;
33
34 namespace System.Windows.Forms {
35 #if NET_2_0
36         [ClassInterface (ClassInterfaceType.AutoDispatch)]
37         [ComVisible (true)]
38 #endif
39         public class ContainerControl : ScrollableControl, IContainerControl {
40                 private Control         active_control;
41                 private Control         unvalidated_control;
42                 private ArrayList       pending_validation_chain;
43
44                 // This is an internal hack that allows some container controls
45                 // to not auto select their child when they are activated
46                 internal bool           auto_select_child = true;
47 #if NET_2_0
48                 private SizeF           auto_scale_dimensions;
49                 private AutoScaleMode   auto_scale_mode;
50                 private bool            auto_scale_mode_set;
51                 private bool            auto_scale_pending;
52                 private bool            is_auto_scaling;
53 #endif
54
55                 internal bool validation_failed; //track whether validation was cancelled by a validating control
56
57                 #region Public Constructors
58                 public ContainerControl() {
59                         active_control = null;
60                         unvalidated_control = null;
61                         ControlRemoved += new ControlEventHandler(OnControlRemoved);
62 #if NET_2_0
63                         auto_scale_dimensions = SizeF.Empty;
64                         auto_scale_mode = AutoScaleMode.Inherit;
65 #endif
66                 }
67                 #endregion      // Public Constructors
68
69                 #region Public Instance Properties
70                 [Browsable (false)]
71                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
72                 public Control ActiveControl {
73                         get {
74                                 return active_control;
75                         }
76
77                         set {
78                                 if (value==null || (active_control == value && active_control.Focused)) {
79                                         return;
80                                 }
81
82                                 if (!Contains(value)) {
83                                         throw new ArgumentException("Cannot activate invisible or disabled control.");
84                                 }
85
86                                 // Fire the enter and leave events if possible
87                                 Form form = FindForm ();
88                                 Control active = GetMostDeeplyNestedActiveControl (form == null ? this : form);
89                                 Control common_ancestor = GetCommonContainer (active, value);
90                                 ArrayList chain = new ArrayList ();
91                                 ArrayList validation_chain = new ArrayList ();
92                                 Control walk = active;
93
94                                 // we split this up into three steps:
95                                 //    1. walk up the tree (if we need to) to our root, firing leave events.
96                                 //    2. validate.
97                                 //    3. walk down the tree (if we need to), firing enter events.
98
99                                 // "our root" is either the common ancestor of the current active
100                                 // control and the new active control, or the current active control,
101                                 // or the new active control.  That is, it's either one of these three
102                                 // configurations:
103
104                                 //  (1)     root            (2)  new          (3)  current
105                                 //          /  \                /   \               /   \
106                                 //        ...   ...           ...   ...           ...   ...
107                                 //        /      \            /                           \
108                                 //     current   new       current                        new
109
110
111                                 // note (3) doesn't require any upward walking, and no leave events are generated.
112                                 //      (2) doesn't require any downward walking, and no enter events are generated.
113
114                                 // as we walk up the tree, we generate a list of all controls which cause
115                                 // validation.  After firing the leave events, we invoke (in order starting from
116                                 // the most deeply nested) their Validating event.  If one sets CancelEventArgs.Cancel
117                                 // to true, we ignore the control the user wanted to set ActiveControl to, and use
118                                 // the Validating control instead.
119
120                                 bool fire_enter = true;
121                                 Control root = common_ancestor;
122
123                                 active_control = value;
124
125                                 // Generate the leave messages
126                                 while (walk != common_ancestor && walk != null) {
127                                         if (walk == value) {
128                                                 root = value;
129                                                 fire_enter = false;
130                                                 break;
131                                         }
132                                         walk.FireLeave ();
133                                         /* clear our idea of the active control as we go back up */
134                                         if (walk is ContainerControl)
135                                                 ((ContainerControl)walk).active_control = null;
136
137                                         if (walk.CausesValidation)
138                                                 validation_chain.Add (walk);
139
140                                         walk = walk.Parent;
141                                 }
142
143                                 // Validation can be postponed due to all the controls
144                                 // in the enter chain not causing validation. If we don't have any
145                                 // enter chain, it means that the selected control is a child and then
146                                 // we need to validate the controls anyway
147                                 bool postpone_validation;
148                                 Control topmost_under_root = null; // topmost under root, in the *enter* chain
149                                 if (value == root)
150                                         postpone_validation = false;
151                                 else {
152                                         postpone_validation = true;
153                                         walk = value;
154                                         while (walk != root && walk != null) {
155                                                 if (walk.CausesValidation)
156                                                         postpone_validation = false;
157
158                                                 topmost_under_root = walk;
159                                                 walk = walk.Parent;
160                                         }
161                                 }
162
163                                 Control failed_validation_control = PerformValidation (form == null ? this : form, postpone_validation, 
164                                                 validation_chain, topmost_under_root);
165                                 if (failed_validation_control != null) {
166                                         active_control = value = failed_validation_control;
167                                         fire_enter = true;
168                                 }
169
170                                 if (fire_enter) {
171                                         walk = value;
172                                         while (walk != root && walk != null) {
173                                                 chain.Add (walk);
174                                                 walk = walk.Parent;
175                                         }
176
177                                         if (root != null && walk == root && !(root is ContainerControl))
178                                                 chain.Add (walk);
179
180                                         for (int i = chain.Count - 1; i >= 0; i--) {
181                                                 walk = (Control) chain [i];
182                                                 walk.FireEnter ();
183                                         }
184                                 }
185
186                                 walk = this;
187                                 Control ctl = this;
188                                 while (walk != null) {
189                                         if (walk.Parent is ContainerControl) {
190                                                 ((ContainerControl) walk.Parent).active_control = ctl;
191                                                 ctl = walk.Parent;
192                                         }
193                                         walk = walk.Parent;
194                                 }
195
196                                 if (this is Form)
197                                         CheckAcceptButton();
198
199                                 // Scroll control into view
200                                 ScrollControlIntoView(active_control);
201                                 
202                                 
203                                 walk = this;
204                                 ctl = this;
205                                 while (walk != null) {
206                                         if (walk.Parent is ContainerControl) {
207                                                 ctl = walk.Parent;
208                                         }
209                                         walk = walk.Parent;
210                                 }
211                                 
212                                 // Let the control know it's selected
213                                 if (ctl.InternalContainsFocus)
214                                         SendControlFocus (active_control);
215                         }
216                 }
217
218                 // Return the control where validation failed, and null otherwise
219                 // @topmost_under_root is the control under the root in the enter chain, if any
220                 //
221                 // The process of validation happens as described:
222                 //
223                 //      1. Iterate over the nodes in the enter chain (walk down), looking for any node
224                 //      causing validation. If we can't find any, don't validate the current validation chain, but postpone it,
225                 //      saving it in the top_container.pending_validation_chain field, since we need to keep track of it later.
226                 //      If we have a previous pending_validation_chain, add the new nodes, making sure they are not repeated
227                 //      (this is computed in ActiveControl and we receive if as the postpone_validation parameter).
228                 //
229                 //      2. If we found at least one node causing validation in the enter chain, try to validate the elements
230                 //      in pending_validation_chain, if any. Then continue with the ones receives as parameters.
231                 //
232                 //      3. Return null if all the validation performed successfully, and return the control where the validation
233                 //      failed otherwise.
234                 //
235                 private Control PerformValidation (ContainerControl top_container, bool postpone_validation, ArrayList validation_chain, 
236                                 Control topmost_under_root)
237                 {
238                         validation_failed = false;
239
240                         if (postpone_validation) {
241                                 AddValidationChain (top_container, validation_chain);
242                                 return null;
243                         }
244
245                         // if not null, pending chain has always one element or more
246                         if (top_container.pending_validation_chain != null) {
247                                 // if the topmost node in the enter chain is exactly the topmost
248                                 // int the validation chain, remove it, as .net does
249                                 int last_idx = top_container.pending_validation_chain.Count - 1;
250                                 if (topmost_under_root == top_container.pending_validation_chain [last_idx])
251                                         top_container.pending_validation_chain.RemoveAt (last_idx);
252
253                                 AddValidationChain (top_container, validation_chain);
254                                 validation_chain = top_container.pending_validation_chain;
255                                 top_container.pending_validation_chain = null;
256                         }
257
258                         for (int i = 0; i < validation_chain.Count; i ++) {
259                                 if (!ValidateControl ((Control)validation_chain[i])) {
260                                         validation_failed = true;
261                                         return (Control)validation_chain[i];
262                                 }
263                         }
264
265                         return null;
266                 }
267
268                 // Add the elements in validation_chain to the pending validation chain stored in top_container
269                 private void AddValidationChain (ContainerControl top_container, ArrayList validation_chain)
270                 {
271                         if (validation_chain.Count == 0)
272                                 return;
273
274                         if (top_container.pending_validation_chain == null || top_container.pending_validation_chain.Count == 0) {
275                                 top_container.pending_validation_chain = validation_chain;
276                                 return;
277                         }
278
279                         foreach (Control c in validation_chain)
280                                 if (!top_container.pending_validation_chain.Contains (c))
281                                         top_container.pending_validation_chain.Add (c);
282                 }       
283
284                 private bool ValidateControl (Control c)
285                 {
286                         CancelEventArgs e = new CancelEventArgs ();
287
288                         c.FireValidating (e);
289
290                         if (e.Cancel)
291                                 return false;
292
293                         c.FireValidated ();
294                         return true;
295                 }
296
297                 private Control GetMostDeeplyNestedActiveControl (ContainerControl container)
298                 {
299                         Control active = container.ActiveControl;
300                         while (active is ContainerControl) {
301                                 if (((ContainerControl)active).ActiveControl == null)
302                                         break;
303                                 active = ((ContainerControl)active).ActiveControl;
304                         }
305                         return active;
306                 }
307
308                 // Just in a separate method to make debugging a little easier,
309                 // should eventually be rolled into ActiveControl setter
310                 private Control GetCommonContainer (Control active_control, Control value)
311                 {
312                         Control new_container = null;
313                         Control prev_container = active_control;
314
315                         while (prev_container != null) {
316                                 new_container = value.Parent;
317                                 while (new_container != null) {
318                                         if (new_container == prev_container)
319                                                 return new_container;
320                                         new_container = new_container.Parent;
321                                 }
322
323                                 prev_container = prev_container.Parent;
324                         }
325
326                         return null;
327                 }
328
329                 internal void SendControlFocus (Control c)
330                 {
331                         if (c.IsHandleCreated) {
332                                 XplatUI.SetFocus (c.window.Handle);
333                         }
334                 }
335
336 #if NET_2_0
337                 [Browsable (false)]
338                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
339                 [EditorBrowsable (EditorBrowsableState.Advanced)]
340                 [Localizable (true)]
341                 public SizeF AutoScaleDimensions {
342                         get {
343                                 return auto_scale_dimensions;
344                         }
345
346                         set {
347                                 if (auto_scale_dimensions != value) {
348                                         auto_scale_dimensions = value;
349                                         
350                                         PerformAutoScale ();
351                                 }
352                         }
353                 }
354
355                 protected SizeF AutoScaleFactor {
356                         get {
357                                 if (auto_scale_dimensions.IsEmpty)
358                                         return new SizeF (1f, 1f);
359
360                                 return new SizeF(CurrentAutoScaleDimensions.Width / auto_scale_dimensions.Width,
361                                         CurrentAutoScaleDimensions.Height / auto_scale_dimensions.Height);
362                         }
363                 }
364
365
366                 [Browsable (false)]
367                 [EditorBrowsable (EditorBrowsableState.Advanced)]
368                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
369                 public AutoScaleMode AutoScaleMode {
370                         get {
371                                 return auto_scale_mode;
372                         }
373                         set {
374                                 if (this is Form)
375                                         (this as Form).AutoScale = false;
376
377                                 if (auto_scale_mode != value) {
378                                         auto_scale_mode = value;
379
380                                         if (auto_scale_mode_set)
381                                                 auto_scale_dimensions = SizeF.Empty;
382
383                                         auto_scale_mode_set = true;
384
385                                         PerformAutoScale ();
386                                 }
387                         }
388                 }
389 #endif // NET_2_0
390
391                 [Browsable (false)]
392                 public override BindingContext BindingContext {
393                         get {
394                                 if (base.BindingContext == null) {
395                                         base.BindingContext = new BindingContext();
396                                 }
397                                 return base.BindingContext;
398                         }
399
400                         set {
401                                 base.BindingContext = value;
402                         }
403                 }
404
405 #if NET_2_0
406                 [Browsable (false)]
407                 [EditorBrowsable (EditorBrowsableState.Advanced)]
408                 public SizeF CurrentAutoScaleDimensions {
409                         get {
410                                 switch(auto_scale_mode) {
411                                         case AutoScaleMode.Dpi:
412                                                 return TextRenderer.GetDpi ();
413
414                                         case AutoScaleMode.Font:
415                                                 Size s = TextRenderer.MeasureText ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890", Font);
416                                                 int width = (int)Math.Round ((float)s.Width / 62f);
417                                                 
418                                                 return new SizeF (width, s.Height);
419                                 }
420
421                                 return auto_scale_dimensions;
422                         }
423                 }
424 #endif
425
426                 [Browsable (false)]
427                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
428                 public Form ParentForm {
429                         get {
430                                 Control parent;
431
432                                 parent = this.Parent;
433
434                                 while (parent != null) {
435                                         if (parent is Form) {
436                                                 return (Form)parent;
437                                         }
438                                         parent = parent.Parent;
439                                 }
440
441                                 return null;
442                         }
443                 }
444                 #endregion      // Public Instance Properties
445
446                 #region Protected Instance Methods
447 #if NET_2_0
448                 protected override bool CanEnableIme {
449                         get { return false; }
450                 }
451 #endif
452                 protected override CreateParams CreateParams {
453                         get {
454                                 return base.CreateParams;
455                         }
456                 }
457                 #endregion      // Public Instance Methods
458
459                 #region Public Instance Methods
460 #if NET_2_0
461                 internal void PerformAutoScale (bool called_by_scale)
462                 {
463                         if ((AutoScaleMode == AutoScaleMode.Inherit) && !called_by_scale)
464                                 return;
465
466                         if ((layout_suspended > 0) && !called_by_scale) {
467                                 auto_scale_pending = true;
468                                 return;
469                         }
470                         // Set this first so we don't get called again from
471                         // PerformDelayedAutoScale after ResumeLayout
472                         auto_scale_pending = false;
473
474                         SizeF factor = AutoScaleFactor;
475                         if (AutoScaleMode == AutoScaleMode.Inherit) {
476                                 ContainerControl cc = FindContainer (this.Parent);
477                                 if (cc != null)
478                                         factor = cc.AutoScaleFactor;
479                         }
480                         if (factor != new SizeF (1F, 1F)) {
481                                 is_auto_scaling = true;
482                                 SuspendLayout ();
483                                 Scale (factor);
484                                 ResumeLayout (false);
485                                 is_auto_scaling = false;
486                         }
487
488                         auto_scale_dimensions = CurrentAutoScaleDimensions;
489                 }
490
491                 public void PerformAutoScale ()
492                 {
493                         PerformAutoScale (false);
494                 }
495
496                 internal void PerformDelayedAutoScale ()
497                 {
498                         if (auto_scale_pending)
499                                 PerformAutoScale ();
500                 }
501
502                 internal bool IsAutoScaling {
503                         get { return is_auto_scaling; }
504                 }
505 #endif
506
507                 [MonoTODO ("Stub, not implemented")]
508                 static bool ValidateWarned;
509                 public bool Validate() {
510                         //throw new NotImplementedException();
511                         if (!ValidateWarned) {
512                                 Console.WriteLine("ContainerControl.Validate is not yet implemented");
513                                 ValidateWarned = true;
514                         }
515                         return true;
516                 }
517
518 #if NET_2_0
519                 public bool Validate (bool checkAutoValidate)
520                 {
521                         if ((checkAutoValidate && (AutoValidate != AutoValidate.Disable)) || !checkAutoValidate)
522                                 return Validate ();
523                                 
524                         return true;
525                 }
526                 
527                 [Browsable (false)]
528                 [EditorBrowsable (EditorBrowsableState.Never)]
529                 public virtual bool ValidateChildren ()
530                 {
531                         return ValidateChildren (ValidationConstraints.Selectable);
532                 }
533
534                 [Browsable (false)]
535                 [EditorBrowsable (EditorBrowsableState.Never)]
536                 public virtual bool ValidateChildren (ValidationConstraints validationConstraints)
537                 {
538                         bool recurse = !((validationConstraints & ValidationConstraints.ImmediateChildren) == ValidationConstraints.ImmediateChildren);
539                         
540                         foreach (Control control in Controls)
541                                 if (!ValidateNestedControls (control, validationConstraints, recurse))
542                                         return false;
543
544                         return true;
545                 }
546 #endif
547
548                 bool IContainerControl.ActivateControl(Control control) {
549                         return Select(control);
550                 }
551                 #endregion      // Public Instance Methods
552
553                 #region Protected Instance Methods
554                 [EditorBrowsable (EditorBrowsableState.Advanced)]
555                 protected override void AdjustFormScrollbars(bool displayScrollbars) {
556                         base.AdjustFormScrollbars(displayScrollbars);
557                 }
558
559                 protected override void Dispose(bool disposing) {
560                         base.Dispose(disposing);
561                 }
562
563                 // LAMESPEC This used to be documented, but it's not in code
564                 // and no longer listed in MSDN2
565                 // [EditorBrowsable (EditorBrowsableState.Advanced)]
566                 // protected override void OnControlRemoved(ControlEventArgs e) {
567                 private void OnControlRemoved(object sender, ControlEventArgs e) {
568                         if (e.Control == this.unvalidated_control) {
569                                 this.unvalidated_control = null;
570                         }
571
572                         if (e.Control == this.active_control) {
573                                 this.unvalidated_control = null;
574                         }
575
576                         // base.OnControlRemoved(e);
577                 }
578
579                 protected override void OnCreateControl() {
580                         base.OnCreateControl();
581                         // MS seems to call this here, it gets the whole databinding process started
582                         OnBindingContextChanged (EventArgs.Empty);
583                 }
584
585 #if NET_2_0
586                 protected override bool ProcessCmdKey (ref Message msg, Keys keyData)
587                 {
588                         if (ToolStripManager.ProcessCmdKey (ref msg, keyData) == true)
589                                 return true;
590                                 
591                         return base.ProcessCmdKey (ref msg, keyData);
592                 }
593 #endif
594
595                 [EditorBrowsable (EditorBrowsableState.Advanced)]
596                 protected override bool ProcessDialogChar(char charCode) {
597                         if (GetTopLevel()) {
598                                 if (ProcessMnemonic(charCode)) {
599                                         return true;
600                                 }
601                         }
602                         return base.ProcessDialogChar(charCode);
603                 }
604
605                 protected override bool ProcessDialogKey(Keys keyData) {
606                         Keys    key;
607                         bool    forward;
608
609                         key = keyData & Keys.KeyCode;
610                         forward = true;
611
612                         switch (key) {
613                                 case Keys.Tab: {
614                                         if ((keyData & (Keys.Alt | Keys.Control)) == Keys.None) {
615                                                 if (ProcessTabKey ((Control.ModifierKeys & Keys.Shift) == 0)) {
616                                                         return true;
617                                                 }
618                                         }
619                                         break;
620                                 }
621
622                                 case Keys.Left: {
623                                         forward = false;
624                                         goto case Keys.Down;
625                                 }
626
627                                 case Keys.Up: {
628                                         forward = false;
629                                         goto case Keys.Down;
630                                 }
631
632                                 case Keys.Right: {
633                                         goto case Keys.Down;
634                                 }
635                                 case Keys.Down: {
636                                         if (SelectNextControl(active_control, forward, false, false, true)) {
637                                                 return true;
638                                         }
639                                         break;
640                                 }
641
642
643                         }
644                         return base.ProcessDialogKey(keyData);
645                 }
646
647                 protected override bool ProcessMnemonic(char charCode) {
648                         bool    wrapped;
649                         Control c;
650
651                         wrapped = false;
652                         c = active_control;
653
654 #if NET_2_0
655                         System.Collections.Generic.List<MenuStrip> strips = new System.Collections.Generic.List<MenuStrip> ();
656 #endif
657
658                         do {
659                                 c = GetNextControl(c, true);
660 #if NET_2_0
661                                 if (c is MenuStrip)
662                                         strips.Add ((MenuStrip)c);
663 #endif
664                                 if (c != null) {
665                                         // This is stupid. I want to be able to call c.ProcessMnemonic directly
666                                         if (c.ProcessControlMnemonic(charCode)) {
667                                                 return(true);
668                                         }
669                                         continue;
670                                 } else {
671                                         if (wrapped) {
672                                                 break;
673                                         }
674                                         wrapped = true;
675                                 }
676                         } while (c != active_control);
677
678 #if NET_2_0
679                         // No one has an explicit mnemonic for this key.
680                         // Let MenuStrips have a chance at implicit mnemonics.
681                         foreach (MenuStrip ms in strips)
682                                 if (ms.ProcessImplicitMnemonic (charCode))
683                                         return true;
684 #endif
685
686                         return false;
687                 }
688
689                 protected virtual bool ProcessTabKey(bool forward) {
690                         return SelectNextControl(active_control, forward, true, true, false);
691                 }
692
693                 protected override void Select(bool directed, bool forward)
694                 {
695                         if (Parent != null) {
696                                 IContainerControl parent = Parent.GetContainerControl ();
697                                 if (parent != null) {
698                                         parent.ActiveControl = this;
699                                 }
700                         }
701
702                         if (directed && auto_select_child) {
703                                 SelectNextControl (null, forward, true, true, false);
704                         }
705                 }
706
707                 protected virtual void UpdateDefaultButton() {
708                         // MS Internal
709                 }
710
711                 [EditorBrowsable (EditorBrowsableState.Advanced)]
712                 protected override void WndProc(ref Message m) {
713                         switch ((Msg) m.Msg) {
714
715                                 case Msg.WM_SETFOCUS:
716                                         if (active_control != null)
717                                                 Select (active_control);
718                                         else
719                                                 base.WndProc (ref m);
720 #if false
721                                         else
722                                                 SelectNextControl (null, true, true, true, false);
723 #endif
724                                 break;
725
726                                 default:
727                                         base.WndProc(ref m);
728                                         break;
729                         }
730                 }
731                 #endregion      // Protected Instance Methods
732
733                 #region Internal Methods
734                 internal void ChildControlRemoved (Control control)
735                 {
736                         ContainerControl top_container = FindForm ();
737                         if (top_container == null)
738                                 top_container = this;
739
740                         // Remove controls -as well as any sub control- that was in the pending validation chain
741                         ArrayList pending_validation_chain = top_container.pending_validation_chain;
742                         if (pending_validation_chain != null) {
743                                 RemoveChildrenFromValidation (pending_validation_chain, control);
744
745                                 if (pending_validation_chain.Count == 0)
746                                         top_container.pending_validation_chain = null;
747                         }
748
749                         if (control == active_control || control.Contains (active_control)) {
750                                 SelectNextControl (this, true, true, true, true);
751                                 if (control == active_control || control.Contains (active_control)) {
752                                         active_control = null;
753                                 }
754                         }
755                 }
756
757                 // Check that this control (or any child) is included in the pending validation chain
758                 bool RemoveChildrenFromValidation (ArrayList validation_chain, Control c)
759                 {
760                         if (RemoveFromValidationChain (validation_chain, c))
761                                 return true;
762
763                         foreach (Control child in c.Controls)
764                                 if (RemoveChildrenFromValidation (validation_chain, child))
765                                         return true;
766
767                         return false;
768                 }
769
770                 // Remove the top most control in the pending validation chain, as well as any children there,
771                 // taking advantage of the fact that the chain is in reverse order of the control's hierarchy
772                 bool RemoveFromValidationChain (ArrayList validation_chain, Control c)
773                 {
774                         int idx = validation_chain.IndexOf (c);
775                         if (idx > -1) {
776                                 pending_validation_chain.RemoveAt (idx--);
777                                 return true;
778                         }
779
780                         return false;
781                 }
782
783                 internal virtual void CheckAcceptButton()
784                 {
785                         // do nothing here, only called if it is a Form
786                 }
787
788 #if NET_2_0
789                 private bool ValidateNestedControls (Control c, ValidationConstraints constraints, bool recurse)
790                 {
791                         bool validate_result = true;
792
793                         if (!c.CausesValidation)
794                                 validate_result = true;
795                         else if (!ValidateThisControl (c, constraints))
796                                 validate_result = true;
797                         else if (!ValidateControl (c))
798                                 validate_result = false;
799
800                         if (recurse)
801                                 foreach (Control control in c.Controls)
802                                         if (!ValidateNestedControls (control, constraints, recurse))
803                                                 return false;
804
805                         return validate_result;
806                 }
807
808                 private bool ValidateThisControl (Control c, ValidationConstraints constraints)
809                 {
810                         if (constraints == ValidationConstraints.None)
811                                 return true;
812
813                         if ((constraints & ValidationConstraints.Enabled) == ValidationConstraints.Enabled && !c.Enabled)
814                                 return false;
815
816                         if ((constraints & ValidationConstraints.Selectable) == ValidationConstraints.Selectable && !c.GetStyle (ControlStyles.Selectable))
817                                 return false;
818
819                         if ((constraints & ValidationConstraints.TabStop) == ValidationConstraints.TabStop && !c.TabStop)
820                                 return false;
821
822                         if ((constraints & ValidationConstraints.Visible) == ValidationConstraints.Visible && !c.Visible)
823                                 return false;
824
825                         return true;
826                 }
827 #endif
828                 #endregion      // Internal Methods
829
830 #if NET_2_0
831                 protected override void OnParentChanged (EventArgs e)
832                 {
833                         base.OnParentChanged (e);
834                 }
835
836                 [EditorBrowsable (EditorBrowsableState.Advanced)]
837                 protected override void OnFontChanged (EventArgs e)
838                 {
839                         base.OnFontChanged (e);
840                         
841                         if (AutoScaleMode == AutoScaleMode.Font)
842                                 PerformAutoScale ();
843                 }
844
845                 protected override void OnLayout (LayoutEventArgs e)
846                 {
847                         base.OnLayout (e);
848                 }
849                 
850                 AutoValidate auto_validate = AutoValidate.Inherit;
851
852                 [Browsable (false)]
853                 [AmbientValue (AutoValidate.Inherit)]
854                 [EditorBrowsable (EditorBrowsableState.Never)]
855                 public virtual AutoValidate AutoValidate {
856                         get {
857                                 return auto_validate;
858                         }
859
860                         [MonoTODO("Currently does nothing with the setting")]
861                         set {
862                                 if (auto_validate != value){
863                                         auto_validate = value;
864                                         OnAutoValidateChanged (new EventArgs ());
865                                 }
866                         }
867                 }
868
869                 internal bool ShouldSerializeAutoValidate ()
870                 {
871                         return this.AutoValidate != AutoValidate.Inherit;
872                 }
873
874                 static object OnValidateChanged = new object ();
875
876                 protected virtual void OnAutoValidateChanged (EventArgs e)
877                 {
878                         EventHandler eh = (EventHandler) (Events [OnValidateChanged]);
879                         if (eh != null)
880                                 eh (this, e);
881                 }
882
883                 [Browsable (false)]
884                 [EditorBrowsable (EditorBrowsableState.Never)]
885                 public event EventHandler AutoValidateChanged {
886                         add { Events.AddHandler (OnValidateChanged, value); }
887                         remove { Events.RemoveHandler (OnValidateChanged, value); }
888                 }
889 #endif
890         }
891 }