Re: [Mono-winforms-list] [Patch] CausesValidation handling

2009-03-25 Thread Carlos Alberto Cortez
On IRC Andreia pointed out the case when a Control is part of the pending
validation chain, and then this Control is removed. So the attached codes
adds the check to look for any control (or children) that could be int the
pending validation chain, and thus need to be removed (this is what .Net
does).

Comments?
Carlos.


2009/2/16 Carlos Alberto Cortez calberto.cor...@gmail.com

 Hey,

 The attached patch basically adds support for Control.CausesValidation,
 which means that in some scenarios the validation is postponed (when
 CausesValidation if false, basically).

 I'm concerned -specially- about the code readibility (it also includes the
 description of the algorithm in the patch). I mention this because I spent
 some time trying to understand this little documented algorithm (AFAIK) and
 want the code to be easily understandable.

 As test I used the very complete ones in
 https://bugzilla.novell.com/show_bug.cgi?id=457170 . One test is still
 failing, but that's due to the controls receiving focus/validation when
 closing (which needs to be fixed too, but it's a little different issue).

 Carlos.

Index: ContainerControl.cs
===
--- ContainerControl.cs	(revisiĆ³n: 129872)
+++ ContainerControl.cs	(copia de trabajo)
@@ -39,6 +39,7 @@
 	public class ContainerControl : ScrollableControl, IContainerControl {
 		private Control		active_control;
 		private Control		unvalidated_control;
+		private ArrayList	pending_validation_chain;
 
 		// This is an internal hack that allows some container controls
 		// to not auto select their child when they are activated
@@ -139,15 +140,33 @@
 	walk = walk.Parent;
 }
 
-validation_failed = false;
-for (int i = 0; i  validation_chain.Count; i ++) {
-	if (!ValidateControl ((Control)validation_chain[i])) {
-		active_control = value = (Control)validation_chain[i];
-		fire_enter = true;
-		validation_failed = true;
+// Validation can be postponed due to all the controls
+// in the enter chain not causing validation. If we don't have any
+// enter chain, it means that the selected control is a child and then
+// we need to validate the controls anyway
+bool postpone_validation;
+Control topmost_under_root = null; // topmost under root, in the *enter* chain
+if (value == root)
+	postpone_validation = false;
+else {
+	postpone_validation = true;
+	walk = value;
+	while (walk != root  walk != null) {
+		if (walk.CausesValidation)
+			postpone_validation = false;
+
+		topmost_under_root = walk;
+		walk = walk.Parent;
 	}
 }
 
+Control failed_validation_control = PerformValidation (form == null ? this : form, postpone_validation, 
+		validation_chain, topmost_under_root);
+if (failed_validation_control != null) {
+	active_control = value = failed_validation_control;
+	fire_enter = true;
+}
+
 if (fire_enter) {
 	walk = value;
 	while (walk != root  walk != null) {
@@ -196,6 +215,72 @@
 			}
 		}
 
+		// Return the control where validation failed, and null otherwise
+		// @topmost_under_root is the control under the root in the enter chain, if any
+		//
+		// The process of validation happens as described:
+		//
+		// 	1. Iterate over the nodes in the enter chain (walk down), looking for any node
+		// 	causing validation. If we can't find any, don't validate the current validation chain, but postpone it,
+		// 	saving it in the top_container.pending_validation_chain field, since we need to keep track of it later.
+		// 	If we have a previous pending_validation_chain, add the new nodes, making sure they are not repeated
+		// 	(this is computed in ActiveControl and we receive if as the postpone_validation parameter).
+		//
+		// 	2. If we found at least one node causing validation in the enter chain, try to validate the elements
+		// 	in pending_validation_chain, if any. Then continue with the ones receives as parameters.
+		//
+		// 	3. Return null if all the validation performed successfully, and return the control where the validation
+		// 	failed otherwise.
+		//
+		private Control PerformValidation (ContainerControl top_container, bool postpone_validation, ArrayList validation_chain, 
+Control topmost_under_root)
+		{
+			validation_failed = false;
+
+			if (postpone_validation) {
+AddValidationChain (top_container, validation_chain);
+return null;
+			}
+
+			// if not null, pending chain has always one element or more
+			if (top_container.pending_validation_chain != null) {
+// if the topmost node in the enter chain is exactly the topmost
+// int the validation chain, remove it, as .net does
+int last_idx = top_container.pending_validation_chain.Count - 1;
+if (topmost_under_root == top_container.pending_validation_chain [last_idx])
+	top_container.pending_validation_chain.RemoveAt (last_idx);
+
+AddValidationChain (top_container, 

[Mono-winforms-list] [Patch] CausesValidation handling

2009-02-16 Thread Carlos Alberto Cortez
Hey,

The attached patch basically adds support for Control.CausesValidation,
which means that in some scenarios the validation is postponed (when
CausesValidation if false, basically).

I'm concerned -specially- about the code readibility (it also includes the
description of the algorithm in the patch). I mention this because I spent
some time trying to understand this little documented algorithm (AFAIK) and
want the code to be easily understandable.

As test I used the very complete ones in
https://bugzilla.novell.com/show_bug.cgi?id=457170 . One test is still
failing, but that's due to the controls receiving focus/validation when
closing (which needs to be fixed too, but it's a little different issue).

Carlos.


container-validation.patch
Description: Binary data
___
Mono-winforms-list maillist  -  Mono-winforms-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-winforms-list