From cd53bba4690fef831e3cfafc91e493762675d575 Mon Sep 17 00:00:00 2001 From: "doronr%us.ibm.com" Date: Wed, 19 Jan 2005 16:05:31 +0000 Subject: [PATCH] landing xforms branch on trunk, not built by default. Bug 278896, sr=bryner on build config changes. If you build xforms, you now need to enable the schema-validation extension as well git-svn-id: svn://10.0.0.236/trunk@167986 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/configure.in | 9 +- mozilla/extensions/xforms/Makefile.in | 4 + .../xforms/nsIModelElementPrivate.idl | 9 + .../extensions/xforms/nsIXFormsControl.idl | 38 ++ mozilla/extensions/xforms/nsXFormsAtoms.cpp | 2 + mozilla/extensions/xforms/nsXFormsAtoms.h | 1 + .../xforms/nsXFormsContextContainer.cpp | 17 +- .../extensions/xforms/nsXFormsControlStub.cpp | 259 ++++++++ .../extensions/xforms/nsXFormsControlStub.h | 163 +++++ .../xforms/nsXFormsGroupElement.cpp | 158 +---- .../xforms/nsXFormsInputElement.cpp | 217 ++----- .../extensions/xforms/nsXFormsItemElement.cpp | 29 +- .../xforms/nsXFormsItemSetElement.cpp | 17 +- .../xforms/nsXFormsLabelElement.cpp | 102 +--- .../extensions/xforms/nsXFormsMDGEngine.cpp | 574 ++++++++++-------- mozilla/extensions/xforms/nsXFormsMDGEngine.h | 263 ++++---- mozilla/extensions/xforms/nsXFormsMDGSet.cpp | 7 +- mozilla/extensions/xforms/nsXFormsMDGSet.h | 2 + .../xforms/nsXFormsModelElement.cpp | 262 ++++++-- .../extensions/xforms/nsXFormsModelElement.h | 17 +- .../extensions/xforms/nsXFormsNodeState.cpp | 129 ++++ mozilla/extensions/xforms/nsXFormsNodeState.h | 196 ++++++ .../xforms/nsXFormsOutputElement.cpp | 219 +++---- .../xforms/nsXFormsRepeatElement.cpp | 235 ++++--- .../xforms/nsXFormsSchemaValidator.cpp | 79 +++ .../xforms/nsXFormsSchemaValidator.h | 57 ++ .../xforms/nsXFormsSelectElement.cpp | 158 ++--- .../xforms/nsXFormsSetValueElement.cpp | 107 ++-- .../xforms/nsXFormsSubmissionElement.cpp | 9 +- .../xforms/nsXFormsSwitchElement.cpp | 106 ++-- .../xforms/nsXFormsTriggerElement.cpp | 23 +- .../xforms/nsXFormsUploadElement.cpp | 176 +----- mozilla/extensions/xforms/nsXFormsUtils.cpp | 349 ++++++----- mozilla/extensions/xforms/nsXFormsUtils.h | 72 ++- .../xforms/nsXFormsValueElement.cpp | 17 +- .../xforms/nsXFormsXPathAnalyzer.cpp | 34 +- .../extensions/xforms/nsXFormsXPathAnalyzer.h | 22 +- .../extensions/xforms/nsXFormsXPathParser.cpp | 10 +- 38 files changed, 2391 insertions(+), 1757 deletions(-) create mode 100644 mozilla/extensions/xforms/nsXFormsControlStub.cpp create mode 100644 mozilla/extensions/xforms/nsXFormsControlStub.h create mode 100644 mozilla/extensions/xforms/nsXFormsNodeState.cpp create mode 100644 mozilla/extensions/xforms/nsXFormsNodeState.h create mode 100644 mozilla/extensions/xforms/nsXFormsSchemaValidator.cpp create mode 100644 mozilla/extensions/xforms/nsXFormsSchemaValidator.h diff --git a/mozilla/configure.in b/mozilla/configure.in index a5172ada0d6..ffdbb07a041 100644 --- a/mozilla/configure.in +++ b/mozilla/configure.in @@ -4110,7 +4110,7 @@ dnl ======================================================== dnl = Enable compilation of specific extension modules dnl ======================================================== -MOZ_EXTENSIONS_ALL=" cookie wallet content-packs xml-rpc xmlextras help p3p pref transformiix venkman inspector irc universalchardet typeaheadfind webservices spellcheck gnomevfs negotiateauth sroaming xmlterm datetime finger cview layout-debug tasks sql xforms permissions" +MOZ_EXTENSIONS_ALL=" cookie wallet content-packs xml-rpc xmlextras help p3p pref transformiix venkman inspector irc universalchardet typeaheadfind webservices spellcheck gnomevfs negotiateauth sroaming xmlterm datetime finger cview layout-debug tasks sql xforms permissions schema-validation" MOZ_ARG_ENABLE_STRING(extensions, [ --enable-extensions Enable extensions], @@ -4164,7 +4164,7 @@ if test `echo "$MOZ_EXTENSIONS" | grep -c tridentprofile` -ne 0; then fi fi -dnl xforms requires xtf and webservices +dnl xforms requires xtf and webservices and schema-validation if test -z "$MOZ_XTF" && test `echo "$MOZ_EXTENSIONS" | grep -c xforms` -ne 0; then AC_MSG_WARN([Cannot build XForms without XTF support. Removing XForms from MOZ_EXTENSIONS.]) MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|xforms||g'` @@ -4174,6 +4174,11 @@ if test `echo "$MOZ_EXTENSIONS" | grep -c xforms` -ne 0 && test `echo "$MOZ_EXTE MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|xforms||g'` fi +if test `echo "$MOZ_EXTENSIONS" | grep -c xforms` -ne 0 && test `echo "$MOZ_EXTENSIONS" | grep -c schema-validation` -eq 0; then + AC_MSG_WARN([Cannot build XForms without schema validation. Removing XForms from MOZ_EXTENSIONS.]) + MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|xforms||g'` +fi + MOZ_ENABLE_JAVAXPCOM= JAVAC= JAR= diff --git a/mozilla/extensions/xforms/Makefile.in b/mozilla/extensions/xforms/Makefile.in index f49757fd86d..58af1187bd2 100644 --- a/mozilla/extensions/xforms/Makefile.in +++ b/mozilla/extensions/xforms/Makefile.in @@ -65,6 +65,7 @@ REQUIRES = \ xpconnect \ js \ layout \ + schemavalidation \ $(NULL) XPIDLSRCS = \ @@ -125,6 +126,9 @@ CPPSRCS = \ nsXFormsValueElement.cpp \ nsXFormsChoicesElement.cpp \ nsXFormsItemSetElement.cpp \ + nsXFormsSchemaValidator.cpp \ + nsXFormsNodeState.cpp \ + nsXFormsControlStub.cpp \ $(NULL) EXTRA_DSO_LDOPTS = $(MOZ_COMPONENT_LIBS) diff --git a/mozilla/extensions/xforms/nsIModelElementPrivate.idl b/mozilla/extensions/xforms/nsIModelElementPrivate.idl index e544a2ec6d6..196b9cb672d 100644 --- a/mozilla/extensions/xforms/nsIModelElementPrivate.idl +++ b/mozilla/extensions/xforms/nsIModelElementPrivate.idl @@ -41,6 +41,7 @@ interface nsIXFormsControl; interface nsISchemaType; interface nsIInstanceElementPrivate; +interface nsXFormsMDGEngine; /** * Private interface implemented by the model element for other @@ -75,4 +76,12 @@ interface nsIModelElementPrivate : nsIXFormsModelElement * Locate the instance element child with the given id. */ nsIInstanceElementPrivate findInstanceElement(in AString id); + + /** + * The model's MDG. + * + * @bug nsXFormsMDGEngine is not an interface. + * @see https://bugzilla.mozilla.org/show_bug.cgi?id=278370 + */ + readonly attribute nsXFormsMDGEngine MDG; }; diff --git a/mozilla/extensions/xforms/nsIXFormsControl.idl b/mozilla/extensions/xforms/nsIXFormsControl.idl index f7bcd20fd8c..ebda77a9224 100644 --- a/mozilla/extensions/xforms/nsIXFormsControl.idl +++ b/mozilla/extensions/xforms/nsIXFormsControl.idl @@ -38,15 +38,53 @@ #include "nsISupports.idl" +interface nsIArray; +interface nsIDOMNode; +interface nsIDOMElement; + /** * Interface implemented by all XForms form control classes. */ [uuid(8377c845-5d55-4eee-9a76-0f86751dcbc8)] interface nsIXFormsControl : nsISupports { + /** + * This tells the form control to update its node binding based on the + * current instance data. + */ + void bind(); + /** * This tells the form control to update its state based on the current * instance data. */ void refresh(); + + /** + * The instance node that the control is bound to. + */ + readonly attribute nsIDOMNode boundNode; + + /** + * The instance nodes that the control depend on. + * + * In other words, all the instance nodes that could influence which node + * the control is bound to (mBoundNode). For example: + * If a node has @ref="/share[@owner = /me]", it depends on all /share + * nodes, all @owned attributes on /share nodes, and all /me nodes. + * + * @note The array MUST be sorted, pointer-order, ascending. + * + * @bug Should use nsCOMArray + * @see https://bugzilla.mozilla.org/show_bug.cgi?id=278369 + */ + readonly attribute nsIArray dependencies; + + /** + * Get the element that should receive events for the control. + * + * @todo This should not be necessary, we should send directly to the + * control (XXX) + */ + readonly attribute nsIDOMElement element; }; diff --git a/mozilla/extensions/xforms/nsXFormsAtoms.cpp b/mozilla/extensions/xforms/nsXFormsAtoms.cpp index 105a0488fbf..ed30d59a5b6 100644 --- a/mozilla/extensions/xforms/nsXFormsAtoms.cpp +++ b/mozilla/extensions/xforms/nsXFormsAtoms.cpp @@ -51,6 +51,7 @@ nsIAtom* nsXFormsAtoms::p3ptype; nsIAtom* nsXFormsAtoms::modelListProperty; nsIAtom* nsXFormsAtoms::uploadFileProperty; nsIAtom *nsXFormsAtoms::ref; +nsIAtom *nsXFormsAtoms::value; nsIAtom *nsXFormsAtoms::nodeset; nsIAtom *nsXFormsAtoms::model; nsIAtom *nsXFormsAtoms::selected; @@ -69,6 +70,7 @@ const nsStaticAtom nsXFormsAtoms::Atoms_info[] = { { "ModelListProperty", &nsXFormsAtoms::modelListProperty }, { "UploadFileProperty", &nsXFormsAtoms::uploadFileProperty }, { "ref", &nsXFormsAtoms::ref }, + { "value", &nsXFormsAtoms::value }, { "nodeset", &nsXFormsAtoms::nodeset }, { "model", &nsXFormsAtoms::model }, { "selected", &nsXFormsAtoms::selected }, diff --git a/mozilla/extensions/xforms/nsXFormsAtoms.h b/mozilla/extensions/xforms/nsXFormsAtoms.h index 661d3e90d3d..c4129a4dd8f 100644 --- a/mozilla/extensions/xforms/nsXFormsAtoms.h +++ b/mozilla/extensions/xforms/nsXFormsAtoms.h @@ -60,6 +60,7 @@ class nsXFormsAtoms static NS_HIDDEN_(nsIAtom *) model; static NS_HIDDEN_(nsIAtom *) selected; static NS_HIDDEN_(nsIAtom *) appearance; + static NS_HIDDEN_(nsIAtom *) value; static NS_HIDDEN_(void) InitAtoms(); diff --git a/mozilla/extensions/xforms/nsXFormsContextContainer.cpp b/mozilla/extensions/xforms/nsXFormsContextContainer.cpp index 84d34b41f0f..d4dd9fcc954 100644 --- a/mozilla/extensions/xforms/nsXFormsContextContainer.cpp +++ b/mozilla/extensions/xforms/nsXFormsContextContainer.cpp @@ -48,9 +48,8 @@ #include "nsIDOMSerializer.h" #include "nsIDOMXPathResult.h" -#include "nsIXFormsControl.h" +#include "nsXFormsControlStub.h" #include "nsIXFormsContextControl.h" -#include "nsXFormsStubElement.h" #include "nsXFormsUtils.h" #ifdef DEBUG @@ -64,20 +63,14 @@ * an "unrolled" \ or \. @see nsXFormsRepeatElement and * nsXFormsItemSetElement. * - * @todo Should this class inherit from nsIXFormsControl? (XXX) - * * @todo Support ::repeat-item and ::repeat-index pseudo-elements. (XXX) * @see http://www.w3.org/TR/xforms/sliceF.html#id2645142 * @see http://bugzilla.mozilla.org/show_bug.cgi?id=271724 */ -class nsXFormsContextContainer : public nsIXFormsControl, - public nsXFormsXMLVisualStub, - public nsIXFormsContextControl +class nsXFormsContextContainer : public nsXFormsControlStub, + public nsIXFormsContextControl { protected: - /** The DOM element for the node */ - nsCOMPtr mElement; - /** The HTML representation for the node */ nsCOMPtr mHTMLElement; @@ -98,7 +91,7 @@ public: NS_IMETHOD OnDestroyed(); // nsIXFormsControl - NS_DECL_NSIXFORMSCONTROL + NS_IMETHOD Refresh(); // nsIXFormsContextControl NS_DECL_NSIXFORMSCONTEXTCONTROL @@ -214,7 +207,7 @@ nsXFormsContextContainer::GetContext(nsAString& aModelID, return NS_OK; } -// nsXFormsControl +// nsIXFormsControl nsresult nsXFormsContextContainer::Refresh() { diff --git a/mozilla/extensions/xforms/nsXFormsControlStub.cpp b/mozilla/extensions/xforms/nsXFormsControlStub.cpp new file mode 100644 index 00000000000..eadd3b1c62b --- /dev/null +++ b/mozilla/extensions/xforms/nsXFormsControlStub.cpp @@ -0,0 +1,259 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla XForms support. + * + * The Initial Developer of the Original Code is + * Novell, Inc. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Allan Beaufour + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIModelElementPrivate.h" +#include "nsXFormsAtoms.h" +#include "nsXFormsControlStub.h" +#include "nsXFormsMDGEngine.h" + +#include "nsIDOMEvent.h" +#include "nsIDOMXPathResult.h" +#include "nsIXTFXMLVisualWrapper.h" + +NS_IMETHODIMP +nsXFormsControlStub::GetBoundNode(nsIDOMNode **aBoundNode) +{ + NS_IF_ADDREF(*aBoundNode = mBoundNode); + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsControlStub::GetDependencies(nsIArray **aDependencies) +{ + NS_IF_ADDREF(*aDependencies = mDependencies); + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsControlStub::GetElement(nsIDOMElement **aElement) +{ + NS_IF_ADDREF(*aElement = mElement); + return NS_OK; +} + +/** + * @note Refresh() is always called after a Bind(), so if a control decides to + * do all the work in Refresh() this function implements a NOP Bind(). + */ +NS_IMETHODIMP +nsXFormsControlStub::Bind() +{ + return NS_OK; +} + +nsresult +nsXFormsControlStub::ProcessNodeBinding(const nsString &aBindingAttr, + PRUint16 aResultType, + nsIDOMXPathResult **aResult, + nsIModelElementPrivate **aModel) +{ + nsresult rv; + + mMDG = nsnull; + if (!mDependencies) { + rv = NS_NewArray(getter_AddRefs(mDependencies)); + } else { + rv = mDependencies->Clear(); + } + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr modelNode; + rv = nsXFormsUtils::EvaluateNodeBinding(mElement, + kElementFlags, + aBindingAttr, + EmptyString(), + aResultType, + getter_AddRefs(modelNode), + aResult, + mDependencies); + + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr model = do_QueryInterface(modelNode); + if (model) { + model->AddFormControl(this); + model->GetMDG(&mMDG); + if (aModel) { + NS_ADDREF(*aModel = model); + } + } + + return NS_OK; +} + +PRBool +nsXFormsControlStub::GetReadOnlyState() +{ + PRBool res = PR_FALSE; + if (mBoundNode && mMDG) { + const nsXFormsNodeState* ns = mMDG->GetNodeState(mBoundNode); + if (ns) { + res = ns->IsReadonly(); + } + } + return res; +} + +void +nsXFormsControlStub::ToggleProperty(const nsAString &aOn, + const nsAString &aOff) +{ + mElement->SetAttribute(aOn, NS_LITERAL_STRING("1")); + mElement->RemoveAttribute(aOff); +} + +NS_IMETHODIMP +nsXFormsControlStub::HandleDefault(nsIDOMEvent *aEvent, + PRBool *aHandled) +{ + NS_ENSURE_ARG(aHandled); + + if (aEvent) { + nsAutoString type; + aEvent->GetType(type); + + *aHandled = PR_TRUE; + /// @todo Change to be less cut-n-paste-stylish. Everything can be extraced + /// from the sXFormsEventsEntries, only problem is the dash in + /// read-only/read-write... (XXX) + if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Valid].name)) { + ToggleProperty(NS_LITERAL_STRING("valid"), + NS_LITERAL_STRING("invalid")); + } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Invalid].name)) { + ToggleProperty(NS_LITERAL_STRING("invalid"), + NS_LITERAL_STRING("valid")); + } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Enabled].name)) { + ToggleProperty(NS_LITERAL_STRING("enabled"), + NS_LITERAL_STRING("disabled")); + } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Disabled].name)) { + ToggleProperty(NS_LITERAL_STRING("disabled"), + NS_LITERAL_STRING("enabled")); + } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Required].name)) { + ToggleProperty(NS_LITERAL_STRING("required"), + NS_LITERAL_STRING("optional")); + } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Optional].name)) { + ToggleProperty(NS_LITERAL_STRING("optional"), + NS_LITERAL_STRING("required")); + } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Readonly].name)) { + ToggleProperty(NS_LITERAL_STRING("read-only"), + NS_LITERAL_STRING("read-write")); + } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Readwrite].name)) { + ToggleProperty(NS_LITERAL_STRING("read-write"), + NS_LITERAL_STRING("read-only")); + } else { + *aHandled = PR_FALSE; + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsControlStub::OnCreated(nsIXTFXMLVisualWrapper *aWrapper) +{ + aWrapper->SetNotificationMask(kStandardNotificationMask); + + aWrapper->GetElementNode(getter_AddRefs(mElement)); + NS_ASSERTION(mElement, "Wrapper is not an nsIDOMElement, we'll crash soon"); + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsControlStub::OnDestroyed() +{ + mMDG = nsnull; + mElement = nsnull; + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsControlStub::DocumentChanged(nsIDOMDocument *aNewDocument) +{ + // We need to re-evaluate our instance data binding when our document + // changes, since our context can change + if (aNewDocument) { + Bind(); + Refresh(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsControlStub::ParentChanged(nsIDOMElement *aNewParent) +{ + // We need to re-evaluate our instance data binding when our parent changes, + // since xmlns declarations or our context could have changed. + if (aNewParent) { + Bind(); + Refresh(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsControlStub::WillSetAttribute(nsIAtom *aName, const nsAString &aValue) +{ + if (aName == nsXFormsAtoms::model || + aName == nsXFormsAtoms::bind || + aName == nsXFormsAtoms::ref) { + nsCOMPtr modelNode = nsXFormsUtils::GetModel(mElement); + + nsCOMPtr model = do_QueryInterface(modelNode); + if (model) + model->RemoveFormControl(this); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsControlStub::AttributeSet(nsIAtom *aName, const nsAString &aValue) +{ + if (aName == nsXFormsAtoms::model || + aName == nsXFormsAtoms::bind || + aName == nsXFormsAtoms::ref) { + Bind(); + Refresh(); + } + + return NS_OK; +} diff --git a/mozilla/extensions/xforms/nsXFormsControlStub.h b/mozilla/extensions/xforms/nsXFormsControlStub.h new file mode 100644 index 00000000000..3d2a893ca87 --- /dev/null +++ b/mozilla/extensions/xforms/nsXFormsControlStub.h @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla XForms support. + * + * The Initial Developer of the Original Code is + * Novell, Inc. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Allan Beaufour + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsXFormsControlStub_h_ +#define nsXFormsControlStub_h_ + +#include "nsArray.h" +#include "nsCOMPtr.h" +#include "nsString.h" + +#include "nsIDOMElement.h" +#include "nsIDOMNode.h" +#include "nsIXTFElement.h" + +#include "nsIXFormsControl.h" +#include "nsXFormsStubElement.h" +#include "nsXFormsUtils.h" + +class nsIDOMEvent; +class nsIDOMXPathResult; +class nsIModelElementPrivate; +class nsIXTFXMLVisualWrapper; +class nsXFormsMDGEngine; + +/** + * Common stub for all XForms controls that inherit from nsIXFormsControl and + * is bound to an instance node. + * + * It also inherits from nsXFormsXMLVisualStub, and overrides a couple of its + * functions. + * + * @todo nsIXFormsContextControl-stub should probably also be included here + * (mBoundNode is in fact also the context) (XXX) + * + * @todo I guess it would make sense to call + * nsIModelElementPrivate->RemoveFormControl in OnDestroyed()? (XXX) + * We should possible save the model as a member variable... + */ +class nsXFormsControlStub : public nsIXFormsControl, + public nsXFormsXMLVisualStub +{ +public: + /** The standard notification flags set on nsIXTFElement */ + const PRUint32 kStandardNotificationMask; + /** + * The element flags for the controls passed to + * nsXFormsUtils:EvaluateNodeBinding() + */ + const PRUint32 kElementFlags; + + // nsIXFormsControl + NS_IMETHOD GetBoundNode(nsIDOMNode **aBoundNode); + NS_IMETHOD GetDependencies(nsIArray **aDependencies); + NS_IMETHOD GetElement(nsIDOMElement **aElement); + NS_IMETHOD Bind(); + + // nsIXTFXMLVisual overrides + /** This sets the notification mask and initializes mElement */ + NS_IMETHOD OnCreated(nsIXTFXMLVisualWrapper *aWrapper); + + // nsIXTFElement overrides + NS_IMETHOD HandleDefault(nsIDOMEvent *aEvent, + PRBool *aHandled); + NS_IMETHOD OnDestroyed(); + NS_IMETHOD DocumentChanged(nsIDOMDocument *aNewDocument); + NS_IMETHOD ParentChanged(nsIDOMElement *aNewParent); + NS_IMETHOD WillSetAttribute(nsIAtom *aName, const nsAString &aValue); + NS_IMETHOD AttributeSet(nsIAtom *aName, const nsAString &aValue); + + /** Constructor */ + nsXFormsControlStub() : + kStandardNotificationMask(nsIXTFElement::NOTIFY_WILL_SET_ATTRIBUTE | + nsIXTFElement::NOTIFY_ATTRIBUTE_SET | + nsIXTFElement::NOTIFY_DOCUMENT_CHANGED | + nsIXTFElement::NOTIFY_PARENT_CHANGED | + nsIXTFElement::NOTIFY_HANDLE_DEFAULT), + kElementFlags(nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR), + mMDG(nsnull) + {}; + +protected: + /** The nsIXTFXMLVisualWrapper */ + nsCOMPtr mElement; + + /** + * The node that the controls is bound to. + * + * @note This needs to be set by the control. nsXFormsControlStub does not + * set it, it just uses it. + */ + nsCOMPtr mBoundNode; + + /** + * Array of nsIDOMNodes that the controls depends on. + * + * @note This needs to be set by the control. nsXFormsControlStub does not + * set it, it just uses it. + */ + nsCOMPtr mDependencies; + + /** The MDG for the control */ + nsXFormsMDGEngine *mMDG; + + /** Returns the read only state of the control (ie. mBoundNode) */ + PRBool GetReadOnlyState(); + + /** + * Processes the node binding of a control, get the current MDG (mMDG) and + * binds the control to its model. + */ + nsresult + ProcessNodeBinding(const nsString &aBindingAttr, + PRUint16 aResultType, + nsIDOMXPathResult **aResult, + nsIModelElementPrivate **aModel = nsnull); + + /** + * Toggles a property on the control (readonly, relevant, etc.) + * + * @todo This needs to be implemented using pseudo-classes instead of + * attributes (XXX) + */ + void ToggleProperty(const nsAString &aOn, + const nsAString &aOff); + +}; + +#endif diff --git a/mozilla/extensions/xforms/nsXFormsGroupElement.cpp b/mozilla/extensions/xforms/nsXFormsGroupElement.cpp index 04587abf27f..78e5c68dab9 100644 --- a/mozilla/extensions/xforms/nsXFormsGroupElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsGroupElement.cpp @@ -49,11 +49,9 @@ #include "nsIXTFXMLVisual.h" #include "nsIXTFXMLVisualWrapper.h" -#include "nsIXFormsControl.h" +#include "nsXFormsControlStub.h" #include "nsIXFormsContextControl.h" #include "nsIModelElementPrivate.h" -#include "nsXFormsAtoms.h" -#include "nsXFormsStubElement.h" #include "nsXFormsUtils.h" #ifdef DEBUG @@ -74,31 +72,18 @@ * * @bug If a group only has a model attribute, the group fails to set this for * children, as it is impossible to distinguish between a failure and absence - * of binding attributes when calling EvaluateNodeBinding(). + * of binding attributes when calling ProcessNodeBinding(). */ -class nsXFormsGroupElement : public nsIXFormsControl, - public nsXFormsXMLVisualStub, +class nsXFormsGroupElement : public nsXFormsControlStub, public nsIXFormsContextControl { protected: - /** The DOM element for the node */ - nsCOMPtr mElement; - /** The UI HTML element used to represent the tag */ nsCOMPtr mHTMLElement; - /** Have DoneAddingChildren() been called? */ - PRBool mDoneAddingChildren; - - /** The context node for the children of this element */ - nsCOMPtr mContextNode; - /** The current ID of the model node is bound to */ nsString mModelID; - /** Process element */ - nsresult Process(); - public: NS_DECL_ISUPPORTS_INHERITED @@ -115,12 +100,9 @@ public: // nsIXTFElement overrides NS_IMETHOD OnDestroyed(); - NS_IMETHOD WillSetAttribute(nsIAtom *aName, const nsAString &aValue); - NS_IMETHOD AttributeSet(nsIAtom *aName, const nsAString &aValue); - NS_IMETHOD DoneAddingChildren(); // nsIXFormsControl - NS_DECL_NSIXFORMSCONTROL + NS_IMETHOD Refresh(); // nsIXFormsContextControl NS_DECL_NSIXFORMSCONTEXTCONTROL @@ -134,7 +116,6 @@ NS_IMPL_ISUPPORTS_INHERITED2(nsXFormsGroupElement, MOZ_DECL_CTOR_COUNTER(nsXFormsGroupElement) nsXFormsGroupElement::nsXFormsGroupElement() - : mElement(nsnull) { MOZ_COUNT_CTOR(nsXFormsGroupElement); } @@ -152,17 +133,12 @@ nsXFormsGroupElement::OnCreated(nsIXTFXMLVisualWrapper *aWrapper) printf("nsXFormsGroupElement::OnCreated(aWrapper=%p)\n", (void*) aWrapper); #endif - // Initialize member(s) - nsCOMPtr node; - aWrapper->GetElementNode(getter_AddRefs(node)); - mElement = node; - NS_ASSERTION(mElement, "Wrapper is not an nsIDOMElement, we'll crash soon"); + nsresult rv = nsXFormsControlStub::OnCreated(aWrapper); + NS_ENSURE_SUCCESS(rv, rv); - mDoneAddingChildren = PR_FALSE; - // Create HTML tag nsCOMPtr domDoc; - node->GetOwnerDocument(getter_AddRefs(domDoc)); + mElement->GetOwnerDocument(getter_AddRefs(domDoc)); nsCOMPtr domElement; domDoc->CreateElementNS(NS_LITERAL_STRING(NS_NAMESPACE_XHTML), @@ -172,11 +148,6 @@ nsXFormsGroupElement::OnCreated(nsIXTFXMLVisualWrapper *aWrapper) mHTMLElement = do_QueryInterface(domElement); NS_ENSURE_TRUE(mHTMLElement, NS_ERROR_FAILURE); - // Setup which notifications to receive - aWrapper->SetNotificationMask(nsIXTFElement::NOTIFY_DONE_ADDING_CHILDREN | - nsIXTFElement::NOTIFY_ATTRIBUTE_SET | - nsIXTFElement::NOTIFY_WILL_SET_ATTRIBUTE); - return NS_OK; } @@ -200,103 +171,45 @@ NS_IMETHODIMP nsXFormsGroupElement::OnDestroyed() { mHTMLElement = nsnull; - mContextNode = nsnull; - mElement = nsnull; - - return NS_OK; + return nsXFormsControlStub::OnDestroyed(); } +// nsIXFormsControl + NS_IMETHODIMP -nsXFormsGroupElement::WillSetAttribute(nsIAtom *aName, const nsAString& aNewValue) -{ - if (aName == nsXFormsAtoms::bind || aName == nsXFormsAtoms::ref) { - nsCOMPtr modelNode = nsXFormsUtils::GetModel(mElement); - - nsCOMPtr model = do_QueryInterface(modelNode); - if (model) { - model->RemoveFormControl(this); - } - } - - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsGroupElement::AttributeSet(nsIAtom *aName, const nsAString& aNewValue) -{ - if (aName == nsXFormsAtoms::bind || aName == nsXFormsAtoms::ref) { - Refresh(); - } - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsGroupElement::DoneAddingChildren() -{ -#ifdef DEBUG_XF_GROUP - printf("nsXFormsGroupElement::DoneAddingChildren()\n"); -#endif - - mDoneAddingChildren = PR_TRUE; - Refresh(); - - return NS_OK; -} - -// nsXFormsControl -nsresult nsXFormsGroupElement::Refresh() { #ifdef DEBUG_XF_GROUP - printf("nsXFormsGroupElement::Refresh(mDoneAddingChildren=%d)\n", mDoneAddingChildren); + printf("nsXFormsGroupElement::Refresh()\n"); #endif - - nsresult rv = NS_OK; - if (mDoneAddingChildren) { - rv = Process(); - } - return rv; -} -// nsXFormsGroupElement -nsresult -nsXFormsGroupElement::Process() -{ -#ifdef DEBUG_XF_GROUP - printf("nsXFormsGroupElement::Process()\n"); -#endif + if (!mHTMLElement) + return NS_OK; mModelID.Truncate(); - nsCOMPtr modelNode; - nsCOMPtr bindElement; - nsCOMPtr result = - nsXFormsUtils::EvaluateNodeBinding(mElement, - nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR, - NS_LITERAL_STRING("ref"), - EmptyString(), - nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, - getter_AddRefs(modelNode), - getter_AddRefs(bindElement)); - - nsCOMPtr model = do_QueryInterface(modelNode); - - if (model) { - model->AddFormControl(this); - } - - if (!result) - return NS_ERROR_FAILURE; + nsCOMPtr modelNode; + nsCOMPtr result; + nsresult rv = + ProcessNodeBinding(NS_LITERAL_STRING("ref"), + nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, + getter_AddRefs(result), + getter_AddRefs(modelNode)); + NS_ENSURE_SUCCESS(rv, rv); + + if (!result) { + return NS_OK; + } + + // Get model ID nsCOMPtr modelElement = do_QueryInterface(modelNode); NS_ENSURE_TRUE(modelElement, NS_ERROR_FAILURE); modelElement->GetAttribute(NS_LITERAL_STRING("id"), mModelID); // Get context node, if any - nsCOMPtr singleNode; - result->GetSingleNodeValue(getter_AddRefs(singleNode)); - mContextNode = do_QueryInterface(singleNode); - NS_ENSURE_TRUE(mContextNode, NS_ERROR_FAILURE); + result->GetSingleNodeValue(getter_AddRefs(mBoundNode)); + NS_ENSURE_STATE(mBoundNode); return NS_OK; } @@ -319,19 +232,12 @@ nsXFormsGroupElement::GetContext(nsAString& aModelID, #endif NS_ENSURE_ARG(aContextSize); NS_ENSURE_ARG(aContextPosition); - - /** @todo Not too elegant to call Process() here, but DoneAddingChildren is, - * logically, called on children before us. We need a notification - * that goes from the document node and DOWN, where the controls - * should Refresh(). - */ + *aContextPosition = 1; *aContextSize = 1; - nsresult rv = Process(); - NS_ENSURE_SUCCESS(rv, rv); - - NS_IF_ADDREF(*aContextNode = mContextNode); + if (mBoundNode && aContextNode) + CallQueryInterface(mBoundNode, aContextNode); // addrefs aModelID = mModelID; return NS_OK; diff --git a/mozilla/extensions/xforms/nsXFormsInputElement.cpp b/mozilla/extensions/xforms/nsXFormsInputElement.cpp index ad4ab51fadf..fdc277f46cf 100644 --- a/mozilla/extensions/xforms/nsXFormsInputElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsInputElement.cpp @@ -36,7 +36,6 @@ * * ***** END LICENSE BLOCK ***** */ -#include "nsXFormsStubElement.h" #include "nsIDOMEventTarget.h" #include "nsIDOM3Node.h" #include "nsIDOMElement.h" @@ -46,10 +45,10 @@ #include "nsIXTFXMLVisualWrapper.h" #include "nsIDOMDocument.h" #include "nsIXFormsControl.h" +#include "nsXFormsControlStub.h" #include "nsISchema.h" #include "nsIDOMHTMLInputElement.h" #include "nsIDOMHTMLTextAreaElement.h" -#include "nsXFormsAtoms.h" #include "nsAutoPtr.h" #include "nsIDOMXPathResult.h" #include "nsIDOMFocusListener.h" @@ -57,13 +56,13 @@ #include "nsIModelElementPrivate.h" #include "nsIContent.h" #include "nsIDOMXPathExpression.h" +#include "nsXFormsMDGEngine.h" /** * Implementation of the \, \, and \ elements. */ -class nsXFormsInputElement : public nsXFormsXMLVisualStub, - public nsIDOMFocusListener, - public nsIXFormsControl +class nsXFormsInputElement : public nsIDOMFocusListener, + public nsXFormsControlStub { public: NS_DECL_ISUPPORTS_INHERITED @@ -77,13 +76,10 @@ public: // nsIXTFElement overrides NS_IMETHOD OnDestroyed(); - NS_IMETHOD DocumentChanged(nsIDOMDocument *aNewDocument); - NS_IMETHOD ParentChanged(nsIDOMElement *aNewParent); - NS_IMETHOD WillSetAttribute(nsIAtom *aName, const nsAString &aValue); - NS_IMETHOD AttributeSet(nsIAtom *aName, const nsAString &aValue); // nsIXFormsControl - NS_DECL_NSIXFORMSCONTROL + NS_IMETHOD Bind(); + NS_IMETHOD Refresh(); // nsIDOMEventListener NS_IMETHOD HandleEvent(nsIDOMEvent *aEvent); @@ -98,16 +94,15 @@ public: eType_TextArea }; + // nsXFormsInputElement nsXFormsInputElement(ControlType aType) - : mElement(nsnull) - , mType(aType) + : mType(aType) {} private: - nsCOMPtr mLabel; - nsCOMPtr mControl; - nsIDOMElement *mElement; - ControlType mType; + nsCOMPtr mLabel; + nsCOMPtr mControl; + ControlType mType; }; NS_IMPL_ISUPPORTS_INHERITED3(nsXFormsInputElement, @@ -121,20 +116,8 @@ NS_IMPL_ISUPPORTS_INHERITED3(nsXFormsInputElement, NS_IMETHODIMP nsXFormsInputElement::OnCreated(nsIXTFXMLVisualWrapper *aWrapper) { - aWrapper->SetNotificationMask(nsIXTFElement::NOTIFY_WILL_SET_ATTRIBUTE | - nsIXTFElement::NOTIFY_ATTRIBUTE_SET | - nsIXTFElement::NOTIFY_DOCUMENT_CHANGED | - nsIXTFElement::NOTIFY_PARENT_CHANGED); - - nsCOMPtr node; - aWrapper->GetElementNode(getter_AddRefs(node)); - - // It's ok to keep a weak pointer to mElement. mElement will have an - // owning reference to this object, so as long as we null out mElement in - // OnDestroyed, it will always be valid. - - mElement = node; - NS_ASSERTION(mElement, "Wrapper is not an nsIDOMElement, we'll crash soon"); + nsresult rv = nsXFormsControlStub::OnCreated(aWrapper); + NS_ENSURE_SUCCESS(rv, rv); // Our anonymous content structure will look like this: // @@ -144,7 +127,7 @@ nsXFormsInputElement::OnCreated(nsIXTFXMLVisualWrapper *aWrapper) // nsCOMPtr domDoc; - node->GetOwnerDocument(getter_AddRefs(domDoc)); + mElement->GetOwnerDocument(getter_AddRefs(domDoc)); domDoc->CreateElementNS(NS_LITERAL_STRING(NS_NAMESPACE_XHTML), NS_LITERAL_STRING("label"), @@ -218,53 +201,7 @@ nsXFormsInputElement::OnDestroyed() targ->RemoveEventListener(NS_LITERAL_STRING("blur"), this, PR_FALSE); } - mElement = nsnull; - - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsInputElement::DocumentChanged(nsIDOMDocument *aNewDocument) -{ - // We need to re-evaluate our instance data binding when our document - // changes, since our context can change - if (aNewDocument) - Refresh(); - - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsInputElement::ParentChanged(nsIDOMElement *aNewParent) -{ - // We need to re-evaluate our instance data binding when our parent changes, - // since xmlns declarations or our context could have changed. - if (aNewParent) - Refresh(); - - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsInputElement::WillSetAttribute(nsIAtom *aName, const nsAString &aValue) -{ - if (aName == nsXFormsAtoms::bind || aName == nsXFormsAtoms::ref) { - nsCOMPtr modelNode = nsXFormsUtils::GetModel(mElement); - - nsCOMPtr model = do_QueryInterface(modelNode); - if (model) - model->RemoveFormControl(this); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsInputElement::AttributeSet(nsIAtom *aName, const nsAString &aValue) -{ - if (aName == nsXFormsAtoms::bind || aName == nsXFormsAtoms::ref) { - Refresh(); - } + nsXFormsControlStub::OnDestroyed(); return NS_OK; } @@ -286,27 +223,7 @@ nsXFormsInputElement::Focus(nsIDOMEvent *aEvent) NS_IMETHODIMP nsXFormsInputElement::Blur(nsIDOMEvent *aEvent) { - if (!mControl) - return NS_OK; - - nsCOMPtr modelNode; - nsCOMPtr bindElement; - nsCOMPtr result = - nsXFormsUtils::EvaluateNodeBinding(mElement, - nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR, - NS_LITERAL_STRING("ref"), - EmptyString(), - nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, - getter_AddRefs(modelNode), - getter_AddRefs(bindElement)); - - if (!result) - return NS_OK; - - nsCOMPtr singleNode; - result->GetSingleNodeValue(getter_AddRefs(singleNode)); - - if (!singleNode) + if (!mControl && !mBoundNode && !mMDG) return NS_OK; nsAutoString value; @@ -330,82 +247,76 @@ nsXFormsInputElement::Blur(nsIDOMEvent *aEvent) } } - nsXFormsUtils::SetNodeValue(singleNode, value); + PRBool changed; + nsresult rv = mMDG->SetNodeValue(mBoundNode, value, PR_TRUE, &changed); + NS_ENSURE_SUCCESS(rv, rv); + if (changed) { + nsCOMPtr model = nsXFormsUtils::GetModel(mElement); + + if (model) { + rv = nsXFormsUtils::DispatchEvent(model, eEvent_Recalculate); + NS_ENSURE_SUCCESS(rv, rv); + rv = nsXFormsUtils::DispatchEvent(model, eEvent_Revalidate); + NS_ENSURE_SUCCESS(rv, rv); + rv = nsXFormsUtils::DispatchEvent(model, eEvent_Refresh); + NS_ENSURE_SUCCESS(rv, rv); + } + } + return NS_OK; } // nsIXFormsControl NS_IMETHODIMP -nsXFormsInputElement::Refresh() +nsXFormsInputElement::Bind() { if (!mControl) return NS_OK; - - nsCOMPtr modelNode; - nsCOMPtr bindElement; - nsCOMPtr result = - nsXFormsUtils::EvaluateNodeBinding(mElement, - nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR, - NS_LITERAL_STRING("ref"), - EmptyString(), - nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, - getter_AddRefs(modelNode), - getter_AddRefs(bindElement)); - - nsCOMPtr model = do_QueryInterface(modelNode); - - // @bug / todo: If \ has binding attributes that are invalid, we - // should clear the content. But the content should be left if the element - // is unbound. - // @see https://bugzilla.mozilla.org/show_bug.cgi?id=265216 - if (!model) - return NS_OK; - - model->AddFormControl(this); - - nsCOMPtr resultNode; - if (result) - result->GetSingleNodeValue(getter_AddRefs(resultNode)); - - if (!resultNode) - return NS_OK; - - // find out if the control should be made readonly - PRBool isReadOnly = PR_FALSE; - nsCOMPtr nodeContent = do_QueryInterface(resultNode); - if (nodeContent) { - nsIDOMXPathExpression *expr = - NS_STATIC_CAST(nsIDOMXPathExpression*, - nodeContent->GetProperty(nsXFormsAtoms::readonly)); - - if (expr) { - expr->Evaluate(mElement, - nsIDOMXPathResult::BOOLEAN_TYPE, nsnull, - getter_AddRefs(result)); - if (result) { - result->GetBooleanValue(&isReadOnly); - } - } + + mBoundNode = nsnull; + + nsCOMPtr result; + nsresult rv = ProcessNodeBinding(NS_LITERAL_STRING("ref"), + nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, + getter_AddRefs(result)); + + NS_ENSURE_SUCCESS(rv, rv); + + if (result) { + result->GetSingleNodeValue(getter_AddRefs(mBoundNode)); } - - // get the text value for the control + + return NS_OK; +} + +NS_IMETHODIMP +nsXFormsInputElement::Refresh() +{ + if (!mControl && !mMDG) + return NS_OK; + nsAutoString text; - nsXFormsUtils::GetNodeValue(resultNode, text); + PRBool readonly = GetReadOnlyState(); + if (mBoundNode) { + nsXFormsUtils::GetNodeValue(mBoundNode, text); + } if (mType == eType_TextArea) { nsCOMPtr textArea = do_QueryInterface(mControl); NS_ENSURE_STATE(textArea); textArea->SetValue(text); - textArea->SetReadOnly(isReadOnly); + textArea->SetReadOnly(readonly); } else { nsCOMPtr input = do_QueryInterface(mControl); NS_ENSURE_STATE(input); if (mType == eType_Input) { nsCOMPtr type; - model->GetTypeForControl(this, getter_AddRefs(type)); + /// @todo: Enable type support. This will be moved away from the model, + /// will it not? (XXX) + // model->GetTypeForControl(this, getter_AddRefs(type)); nsCOMPtr biType = do_QueryInterface(type); PRUint16 typeValue = nsISchemaBuiltinType::BUILTIN_TYPE_STRING; if (biType) @@ -425,7 +336,7 @@ nsXFormsInputElement::Refresh() input->SetValue(text); } - input->SetReadOnly(isReadOnly); + input->SetReadOnly(readonly); } return NS_OK; diff --git a/mozilla/extensions/xforms/nsXFormsItemElement.cpp b/mozilla/extensions/xforms/nsXFormsItemElement.cpp index cd6bdbcb447..417bc15302b 100644 --- a/mozilla/extensions/xforms/nsXFormsItemElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsItemElement.cpp @@ -51,6 +51,8 @@ #include "nsIDOMText.h" #include "nsIXTFXMLVisualWrapper.h" #include "nsIXFormsContextControl.h" +#include "nsIModelElementPrivate.h" +#include "nsXFormsMDGEngine.h" /** * nsXFormsItemElement implements the XForms \ element. @@ -311,7 +313,32 @@ nsXFormsItemElement::WriteSelectedItems(nsIDOMNode *aContainer) rv = GetValue(value); NS_ENSURE_SUCCESS(rv, rv); - return textNode->SetNodeValue(value); + nsCOMPtr modelNode = nsXFormsUtils::GetModel(mElement, + 0); + nsCOMPtr model = do_QueryInterface(modelNode); + NS_ENSURE_STATE(model); + + /// @todo beaufour: The update code should probably not be here. + /// @see https://bugzilla.mozilla.org/show_bug.cgi?id=278207 + /// Wherever its final resting place might be, it should be shared + /// with the code in nsXFormsInputElement + nsXFormsMDGEngine* MDG; + model->GetMDG(&MDG); + NS_ENSURE_STATE(MDG); + + PRBool changed; + rv = MDG->SetNodeValue(textNode, value, PR_TRUE, &changed); + NS_ENSURE_SUCCESS(rv, rv); + if (changed) { + rv = nsXFormsUtils::DispatchEvent(modelNode, eEvent_Recalculate); + NS_ENSURE_SUCCESS(rv, rv); + rv = nsXFormsUtils::DispatchEvent(modelNode, eEvent_Revalidate); + NS_ENSURE_SUCCESS(rv, rv); + rv = nsXFormsUtils::DispatchEvent(modelNode, eEvent_Refresh); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; } NS_IMETHODIMP diff --git a/mozilla/extensions/xforms/nsXFormsItemSetElement.cpp b/mozilla/extensions/xforms/nsXFormsItemSetElement.cpp index a44dff07f91..616a18ba232 100644 --- a/mozilla/extensions/xforms/nsXFormsItemSetElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsItemSetElement.cpp @@ -236,15 +236,14 @@ nsXFormsItemSetElement::Refresh() // content and insert the cloned content as children of the HTML option. nsCOMPtr modelNode; - nsCOMPtr bindElement; - nsCOMPtr result = - nsXFormsUtils::EvaluateNodeBinding(mElement, - nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR, - NS_LITERAL_STRING("nodeset"), - EmptyString(), - nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, - getter_AddRefs(modelNode), - getter_AddRefs(bindElement)); + nsCOMPtr result; + nsXFormsUtils::EvaluateNodeBinding(mElement, + nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR, + NS_LITERAL_STRING("nodeset"), + EmptyString(), + nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, + getter_AddRefs(modelNode), + getter_AddRefs(result)); if (!result) return; diff --git a/mozilla/extensions/xforms/nsXFormsLabelElement.cpp b/mozilla/extensions/xforms/nsXFormsLabelElement.cpp index b95c9c9084c..97e07512c25 100644 --- a/mozilla/extensions/xforms/nsXFormsLabelElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsLabelElement.cpp @@ -41,29 +41,24 @@ * This constructs an anonymous \ to hold the inline content. */ -#include "nsXFormsStubElement.h" -#include "nsXFormsAtoms.h" #include "nsXFormsUtils.h" -#include "nsIXFormsControl.h" -#include "nsIXTFXMLVisualWrapper.h" +#include "nsXFormsControlStub.h" #include "nsCOMPtr.h" #include "nsIDOMElement.h" #include "nsIDOMXPathResult.h" #include "nsIDOM3Node.h" #include "nsIDOMDocument.h" #include "nsIDOMText.h" +#include "nsIXTFXMLVisualWrapper.h" #include "nsString.h" -class nsXFormsLabelElement : public nsXFormsXMLVisualStub, - public nsIXFormsControl +class nsXFormsLabelElement : public nsXFormsControlStub { public: - nsXFormsLabelElement() : mElement(nsnull) { } - NS_DECL_ISUPPORTS_INHERITED // nsIXFormsControl - NS_DECL_NSIXFORMSCONTROL + NS_IMETHOD Refresh(); // nsIXTFXMLVisual overrides NS_IMETHOD OnCreated(nsIXTFXMLVisualWrapper *aWrapper); @@ -73,9 +68,6 @@ public: NS_IMETHOD GetInsertionPoint(nsIDOMElement **aPoint); // nsIXTFElement overrides - NS_IMETHOD AttributeSet(nsIAtom *aName, const nsAString &aNewValue); - NS_IMETHOD AttributeRemoved(nsIAtom *aName); - NS_IMETHOD ParentChanged(nsIDOMElement *aNewParent); NS_IMETHOD ChildInserted(nsIDOMNode *aChild, PRUint32 aIndex); NS_IMETHOD ChildAppended(nsIDOMNode *aChild); NS_IMETHOD ChildRemoved(PRUint32 aIndex); @@ -83,7 +75,6 @@ public: private: NS_HIDDEN_(void) RefreshLabel(); - nsIDOMElement *mElement; nsCOMPtr mOuterSpan; nsCOMPtr mInnerSpan; }; @@ -95,30 +86,21 @@ NS_IMPL_ISUPPORTS_INHERITED1(nsXFormsLabelElement, NS_IMETHODIMP nsXFormsLabelElement::OnCreated(nsIXTFXMLVisualWrapper *aWrapper) { - aWrapper->SetNotificationMask(nsIXTFElement::NOTIFY_PARENT_CHANGED | - nsIXTFElement::NOTIFY_ATTRIBUTE_SET | - nsIXTFElement::NOTIFY_ATTRIBUTE_REMOVED | + nsresult rv = nsXFormsControlStub::OnCreated(aWrapper); + NS_ENSURE_SUCCESS(rv, rv); + + aWrapper->SetNotificationMask(kStandardNotificationMask | nsIXTFElement::NOTIFY_CHILD_INSERTED | nsIXTFElement::NOTIFY_CHILD_APPENDED | nsIXTFElement::NOTIFY_CHILD_REMOVED); - nsCOMPtr node; - aWrapper->GetElementNode(getter_AddRefs(node)); - - // It's ok to keep a weak pointer to mElement. mElement will have an - // owning reference to this object, so as long as wel null out mElement in - // OnDestroyed, it will always be valid. - - mElement = node; - NS_ASSERTION(mElement, "Wrapper is not an nsIDOMElement, we'll crash soon"); - // Create the span that will hold our text. nsCOMPtr domDoc; - node->GetOwnerDocument(getter_AddRefs(domDoc)); + mElement->GetOwnerDocument(getter_AddRefs(domDoc)); - nsresult rv = domDoc->CreateElementNS(NS_LITERAL_STRING(NS_NAMESPACE_XHTML), - NS_LITERAL_STRING("span"), - getter_AddRefs(mOuterSpan)); + rv = domDoc->CreateElementNS(NS_LITERAL_STRING(NS_NAMESPACE_XHTML), + NS_LITERAL_STRING("span"), + getter_AddRefs(mOuterSpan)); NS_ENSURE_SUCCESS(rv, rv); @@ -154,39 +136,6 @@ nsXFormsLabelElement::GetInsertionPoint(nsIDOMElement **aPoint) return NS_OK; } -NS_IMETHODIMP -nsXFormsLabelElement::AttributeSet(nsIAtom *aName, const nsAString &aNewValue) -{ - if (aName == nsXFormsAtoms::ref || - aName == nsXFormsAtoms::model || - aName == nsXFormsAtoms::bind) { - RefreshLabel(); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsLabelElement::AttributeRemoved(nsIAtom *aName) -{ - if (aName == nsXFormsAtoms::ref || - aName == nsXFormsAtoms::model || - aName == nsXFormsAtoms::bind) { - RefreshLabel(); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsLabelElement::ParentChanged(nsIDOMElement *aNewParent) -{ - if (aNewParent) - RefreshLabel(); - - return NS_OK; -} - NS_IMETHODIMP nsXFormsLabelElement::ChildInserted(nsIDOMNode *aChild, PRUint32 aIndex) { @@ -219,27 +168,20 @@ nsXFormsLabelElement::RefreshLabel() // or linking attributes are present, we don't want to show the inline text // at all. - nsCOMPtr modelNode; - nsCOMPtr bindElement; - nsCOMPtr result = - nsXFormsUtils::EvaluateNodeBinding(mElement, - nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR, - NS_LITERAL_STRING("ref"), - EmptyString(), - nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, - getter_AddRefs(modelNode), - getter_AddRefs(bindElement)); - + nsCOMPtr result; + nsresult rv = + ProcessNodeBinding(NS_LITERAL_STRING("ref"), + nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, + getter_AddRefs(result)); nsAutoString labelValue; PRBool foundValue = PR_FALSE; - if (result) { - nsCOMPtr singleNode; - result->GetSingleNodeValue(getter_AddRefs(singleNode)); + if (NS_SUCCEEDED(rv) && result) { + result->GetSingleNodeValue(getter_AddRefs(mBoundNode)); - if (singleNode) { - nsXFormsUtils::GetNodeValue(singleNode, labelValue); + if (mBoundNode) { + nsXFormsUtils::GetNodeValue(mBoundNode, labelValue); foundValue = PR_TRUE; } } @@ -263,6 +205,8 @@ nsXFormsLabelElement::RefreshLabel() } } +// nsIXFormsControl + NS_IMETHODIMP nsXFormsLabelElement::Refresh() { diff --git a/mozilla/extensions/xforms/nsXFormsMDGEngine.cpp b/mozilla/extensions/xforms/nsXFormsMDGEngine.cpp index 94b4423e10e..f6a87b97e2d 100644 --- a/mozilla/extensions/xforms/nsXFormsMDGEngine.cpp +++ b/mozilla/extensions/xforms/nsXFormsMDGEngine.cpp @@ -47,7 +47,15 @@ #include "nsDeque.h" #ifdef DEBUG -// #define DEBUG_XF_MDG +//# define DEBUG_XF_MDG + const char* gMIPNames[] = {"type", + "r/o", + "req", + "rel", + "calc", + "const", + "p3ptype" + }; #endif /* ------------------------------------ */ @@ -55,9 +63,11 @@ /* ------------------------------------ */ MOZ_DECL_CTOR_COUNTER(nsXFormsMDGNode) -nsXFormsMDGNode::nsXFormsMDGNode(nsIDOMNode* aNode, const ModelItemPropName aType) - : mDirty (PR_TRUE), mHasExpr(PR_FALSE), mContextNode(aNode), mCount(0), mType(aType), - mContextSize(0), mContextPosition(0), mDynFunc(PR_FALSE), mNext(nsnull) +nsXFormsMDGNode::nsXFormsMDGNode(nsIDOMNode *aNode, + const ModelItemPropName aType) + : mDirty (PR_TRUE), mHasExpr(PR_FALSE), mContextNode(aNode), + mCount(0), mType(aType), mContextSize(0), mContextPosition(0), + mDynFunc(PR_FALSE), mNext(nsnull) { MOZ_COUNT_CTOR(nsXFormsMDGNode); } @@ -68,8 +78,10 @@ nsXFormsMDGNode::~nsXFormsMDGNode() } void -nsXFormsMDGNode::SetExpression(nsIDOMXPathExpression* aExpression, PRBool aDynFunc, - PRInt32 aContextPosition, PRInt32 aContextSize) +nsXFormsMDGNode::SetExpression(nsIDOMXPathExpression *aExpression, + PRBool aDynFunc, + PRInt32 aContextPosition, + PRInt32 aContextSize) { mHasExpr = PR_TRUE; mDynFunc = aDynFunc; @@ -126,7 +138,7 @@ nsresult nsXFormsMDGEngine::Init() { nsresult rv = NS_ERROR_FAILURE; - if (mNodeToFlag.Init() && mNodeToMDG.Init()) { + if (mNodeStates.Init() && mNodeToMDG.Init()) { rv = NS_OK; } @@ -134,9 +146,13 @@ nsXFormsMDGEngine::Init() } nsresult -nsXFormsMDGEngine::AddMIP(PRInt32 aType, nsIDOMXPathExpression* aExpression, - nsXFormsMDGSet* aDependencies, PRBool aDynFunc, nsIDOMNode* aContextNode, - PRInt32 aContextPos, PRInt32 aContextSize) +nsXFormsMDGEngine::AddMIP(PRInt32 aType, + nsIDOMXPathExpression *aExpression, + nsXFormsMDGSet *aDependencies, + PRBool aDynFunc, + nsIDOMNode *aContextNode, + PRInt32 aContextPos, + PRInt32 aContextSize) { NS_ENSURE_ARG(aContextNode); NS_ENSURE_ARG(aExpression); @@ -144,28 +160,31 @@ nsXFormsMDGEngine::AddMIP(PRInt32 aType, nsIDOMXPathExpression* aExpression, #ifdef DEBUG_XF_MDG nsAutoString nodename; aContextNode->GetNodeName(nodename); - printf("nsXFormsMDGEngine::AddMIP(aContextNode=%s, aExpression=n/a, aDependencies=|%d|,\n", + printf("nsXFormsMDGEngine::AddMIP(aContextNode=%s, aExpression=%p, aDependencies=|%d|,\n", NS_ConvertUCS2toUTF8(nodename).get(), + (void*) aExpression, aDependencies->Count()); - printf(" aContextPos=%d, aContextSize=%d, aType=%d, aType=%d,\n", - aContextPos, aContextSize, aType, aType); - printf(" aDynFunc=%d)\n", - aDynFunc); + printf(" aContextPos=%d, aContextSize=%d, aType=%s, aDynFunc=%d)\n", + aContextPos, aContextSize, gMIPNames[aType], aDynFunc); #endif - nsXFormsMDGNode* newnode = GetNode(aContextNode, (ModelItemPropName) aType, PR_TRUE); + nsXFormsMDGNode* newnode = GetNode(aContextNode, + (ModelItemPropName) aType, + PR_TRUE); if (!newnode) { return NS_ERROR_OUT_OF_MEMORY; } if (newnode->HasExpr()) { - // MIP already in the graph. That is. there is already a MIP of the same + // MIP already in the graph. That is, there is already a MIP of the same // type for this node, which is illegal. // Example: return NS_ERROR_ABORT; } - - newnode->SetExpression(aExpression, aDynFunc, aContextPos, aContextSize); + + if (aExpression) { + newnode->SetExpression(aExpression, aDynFunc, aContextPos, aContextSize); + } // Add dependencies if (aDependencies) { @@ -198,42 +217,88 @@ nsXFormsMDGEngine::AddMIP(PRInt32 aType, nsIDOMXPathExpression* aExpression, nsresult nsXFormsMDGEngine::MarkNodeAsChanged(nsIDOMNode* aContextNode) { - SetFlagBits(aContextNode, MDG_FLAG_ALL_DISPATCH, PR_TRUE); + nsXFormsNodeState* ns = GetNCNodeState(aContextNode); + NS_ENSURE_TRUE(ns, NS_ERROR_FAILURE); - nsXFormsMDGNode* n = GetNode(aContextNode, eModel_calculate); + ns->Set(kFlags_ALL_DISPATCH, PR_TRUE); + + nsXFormsMDGNode* n = GetNode(aContextNode, eModel_type, PR_FALSE); if (n) { - n->MarkDirty(); - } - - // Add constraint to trigger validation of node - n = GetNode(aContextNode, eModel_constraint, PR_FALSE); - if (!n) { + while (n) { + n->MarkDirty(); + n = n->mNext; + } + } else { + // Add constraint to trigger validation of node n = GetNode(aContextNode, eModel_constraint, PR_TRUE); if (!n) { return NS_ERROR_OUT_OF_MEMORY; } + n->MarkDirty(); NS_ENSURE_TRUE(mGraph.AppendElement(n), NS_ERROR_OUT_OF_MEMORY); } - n->MarkDirty(); - NS_ENSURE_TRUE(mMarkedNodes.AddNode(aContextNode), NS_ERROR_FAILURE); return NS_OK; } -nsresult -nsXFormsMDGEngine::Recalculate(nsXFormsMDGSet* * aChangedNodes) +#ifdef DEBUG_beaufour +#include +#include +#include + +void +nsXFormsMDGEngine::PrintDot(const char* aFile) { - NS_ENSURE_ARG_POINTER(aChangedNodes); + FILE *FD = stdout; + if (aFile) { + FD = fopen(aFile, "w"); + } + fprintf(FD, "digraph {\n"); + for (PRInt32 i = 0; i < mGraph.Count(); ++i) { + nsXFormsMDGNode* g = NS_STATIC_CAST(nsXFormsMDGNode*, mGraph[i]); + if (g) { + nsAutoString domNodeName; + g->mContextNode->GetNodeName(domNodeName); + + if (g->IsDirty()) { + fprintf(FD, "\t%s [color=red];\n", + NS_ConvertUCS2toUTF8(domNodeName).get()); + } - nsXFormsMDGSet* changedNodes = *aChangedNodes; - -#ifdef DEBUG_XF_MDG - printf("nsXFormsMDGEngine::Recalculcate(aChangedNodes=|%d|)\n", changedNodes->Count()); + for (PRInt32 j = 0; j < g->mSuc.Count(); ++j) { + nsXFormsMDGNode* sucnode = NS_STATIC_CAST(nsXFormsMDGNode*, + g->mSuc[j]); + if (sucnode) { + nsAutoString sucName; + sucnode->mContextNode->GetNodeName(sucName); + fprintf(FD, "\t%s -> %s [label=\"%s\"];\n", + NS_ConvertUCS2toUTF8(sucName).get(), + NS_ConvertUCS2toUTF8(domNodeName).get(), + gMIPNames[sucnode->mType]); + } + } + } + } + fprintf(FD, "}\n"); + if (FD) { + fclose(FD); + } +} #endif - NS_ENSURE_TRUE(changedNodes->AddSet(mMarkedNodes), NS_ERROR_OUT_OF_MEMORY); +nsresult +nsXFormsMDGEngine::Recalculate(nsXFormsMDGSet* aChangedNodes) +{ + NS_ENSURE_ARG(aChangedNodes); + +#ifdef DEBUG_XF_MDG + printf("nsXFormsMDGEngine::Recalculcate(aChangedNodes=|%d|)\n", + aChangedNodes->Count()); +#endif + + NS_ENSURE_TRUE(aChangedNodes->AddSet(mMarkedNodes), NS_ERROR_OUT_OF_MEMORY); mMarkedNodes.Clear(); @@ -242,9 +307,9 @@ nsXFormsMDGEngine::Recalculate(nsXFormsMDGSet* * aChangedNodes) mFirstCalculate = mJustRebuilt; #ifdef DEBUG_XF_MDG - printf("\taChangedNodes: %d\n", changedNodes->Count()); - printf("\tmNodeToMDG: %d\n", mNodeToFlag.Count()); - printf("\tmNodeToFlag: %d\n", mNodeToFlag.Count()); + printf("\taChangedNodes: %d\n", aChangedNodes->Count()); + printf("\tmNodeToMDG: %d\n", mNodeToMDG.Count()); + printf("\tmNodeStates: %d\n", mNodeStates.Count()); printf("\tGraph nodes: %d\n", mGraph.Count()); #endif @@ -259,19 +324,26 @@ nsXFormsMDGEngine::Recalculate(nsXFormsMDGSet* * aChangedNodes) continue; } + NS_ASSERTION(g->mCount == 0, + "nsXFormsMDGEngine::Calculcate(): Graph node with mCount != 0"); + #ifdef DEBUG_XF_MDG nsAutoString domNodeName; g->mContextNode->GetNodeName(domNodeName); - + printf("\tNode #%d: This=%p, Dirty=%d, DynFunc=%d, Type=%d, Count=%d, Suc=%d, CSize=%d, CPos=%d, Next=%p, domnode=%s\n", - i, (void*) g, g->IsDirty(), g->mDynFunc, g->mType, g->mCount, g->mSuc.Count(), - g->mContextSize, g->mContextPosition, (void*) g->mNext, NS_ConvertUCS2toUTF8(domNodeName).get()); + i, (void*) g, g->IsDirty(), g->mDynFunc, g->mType, + g->mCount, g->mSuc.Count(), g->mContextSize, g->mContextPosition, + (void*) g->mNext, NS_ConvertUCS2toUTF8(domNodeName).get()); #endif // Ignore node if it is not dirty if (!g->IsDirty()) { continue; } + + nsXFormsNodeState* ns = GetNCNodeState(g->mContextNode); + NS_ENSURE_TRUE(ns, NS_ERROR_FAILURE); PRBool constraint = PR_TRUE; // Find MIP-type and handle it accordingly @@ -279,7 +351,10 @@ nsXFormsMDGEngine::Recalculate(nsXFormsMDGSet* * aChangedNodes) case eModel_calculate: if (g->HasExpr()) { nsISupports* retval; - rv = g->mExpression->Evaluate(g->mContextNode, nsIDOMXPathResult::STRING_TYPE, nsnull, &retval); + rv = g->mExpression->Evaluate(g->mContextNode, + nsIDOMXPathResult::STRING_TYPE, + nsnull, + &retval); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr xpath_res = do_QueryInterface(retval); @@ -291,11 +366,12 @@ nsXFormsMDGEngine::Recalculate(nsXFormsMDGSet* * aChangedNodes) rv = SetNodeValue(g->mContextNode, nodeval, PR_FALSE, nsnull); if (NS_SUCCEEDED(rv)) { - NS_ENSURE_TRUE(changedNodes->AddNode(g->mContextNode), NS_ERROR_FAILURE); + NS_ENSURE_TRUE(aChangedNodes->AddNode(g->mContextNode), + NS_ERROR_FAILURE); } } - OrFlag(g->mContextNode, MDG_FLAG_DISPATCH_VALUE_CHANGED);// | MDG_FLAG_DISPATCH_READONLY_CHANGED | MDG_FLAG_DISPATCH_VALID_CHANGED | MDG_FLAG_DISPATCH_RELEVANT_CHANGED); + ns->Set(eFlag_DISPATCH_VALUE_CHANGED, PR_TRUE); break; case eModel_constraint: @@ -303,36 +379,52 @@ nsXFormsMDGEngine::Recalculate(nsXFormsMDGSet* * aChangedNodes) rv = BooleanExpression(g, constraint); NS_ENSURE_SUCCESS(rv, rv); } - // TODO: Schema validity should be checked here - - if ((GetFlag(g->mContextNode) & MDG_FLAG_CONSTRAINT) > 0 != constraint) { - SetFlagBits(g->mContextNode, MDG_FLAG_CONSTRAINT, constraint); - SetFlagBits(g->mContextNode, MDG_FLAG_DISPATCH_VALID_CHANGED, PR_TRUE); - NS_ENSURE_TRUE(changedNodes->AddNode(g->mContextNode), NS_ERROR_FAILURE); + /// + /// @todo Schema validity should be checked here (XXX) + + if (ns->IsConstraint() != constraint) { + ns->Set(eFlag_CONSTRAINT, constraint); + ns->Set(eFlag_DISPATCH_VALID_CHANGED, PR_TRUE); + NS_ENSURE_TRUE(aChangedNodes->AddNode(g->mContextNode), + NS_ERROR_FAILURE); } break; case eModel_readonly: if (g->HasExpr()) { - rv = ComputeMIPWithInheritance(MDG_FLAG_READONLY, MDG_FLAG_DISPATCH_READONLY_CHANGED, MDG_FLAG_INHERITED_READONLY, g, changedNodes); + rv = ComputeMIPWithInheritance(eFlag_READONLY, + eFlag_DISPATCH_READONLY_CHANGED, + eFlag_INHERITED_READONLY, + g, + aChangedNodes); NS_ENSURE_SUCCESS(rv, rv); } break; case eModel_relevant: if (g->HasExpr()) { - rv = ComputeMIPWithInheritance(MDG_FLAG_RELEVANT, MDG_FLAG_DISPATCH_RELEVANT_CHANGED, MDG_FLAG_INHERITED_RELEVANT, g, changedNodes); + rv = ComputeMIPWithInheritance(eFlag_RELEVANT, + eFlag_DISPATCH_RELEVANT_CHANGED, + eFlag_INHERITED_RELEVANT, + g, + aChangedNodes); NS_ENSURE_SUCCESS(rv, rv); } break; case eModel_required: - PRBool didChange; - rv = ComputeMIP(MDG_FLAG_REQUIRED, MDG_FLAG_DISPATCH_REQUIRED_CHANGED, g, didChange); - NS_ENSURE_SUCCESS(rv, rv); + if (g->HasExpr()) { + PRBool didChange; + rv = ComputeMIP(eFlag_REQUIRED, + eFlag_DISPATCH_REQUIRED_CHANGED, + g, + didChange); + NS_ENSURE_SUCCESS(rv, rv); - if (g->HasExpr() && didChange) { - NS_ENSURE_TRUE(changedNodes->AddNode(g->mContextNode), NS_ERROR_FAILURE); + if (didChange) { + NS_ENSURE_TRUE(aChangedNodes->AddNode(g->mContextNode), + NS_ERROR_FAILURE); + } } break; @@ -355,12 +447,12 @@ nsXFormsMDGEngine::Recalculate(nsXFormsMDGSet* * aChangedNodes) g->MarkClean(); } - changedNodes->MakeUnique(); + aChangedNodes->MakeUnique(); #ifdef DEBUG_XF_MDG - printf("\taChangedNodes: %d\n", changedNodes->Count()); - printf("\tmNodeToMDG: %d\n", mNodeToFlag.Count()); - printf("\tmNodeToFlag: %d\n", mNodeToFlag.Count()); + printf("\taChangedNodes: %d\n", aChangedNodes->Count()); + printf("\tmNodeToMDG: %d\n", mNodeToMDG.Count()); + printf("\tmNodeStates: %d\n", mNodeStates.Count()); printf("\tGraph nodes: %d\n", mGraph.Count()); #endif @@ -378,17 +470,17 @@ nsXFormsMDGEngine::Rebuild() mFirstCalculate = PR_FALSE; mGraph.Clear(); - mNodeToFlag.Clear(); + mNodeStates.Clear(); nsDeque sortedNodes(nsnull); #ifdef DEBUG_XF_MDG printf("\tmNodesInGraph: %d\n", mNodesInGraph); printf("\tmNodeToMDG: %d\n", mNodeToMDG.Count()); - printf("\tmNodeToFlag: %d\n", mNodeToFlag.Count()); + printf("\tmNodeStates: %d\n", mNodeStates.Count()); #endif - // Initial scan for nsXFormsMDGNodes with no dependencies (count == 0) + // Initial scan for nsXFormsMDGNodes with no dependencies (mCount == 0) PRUint32 entries = mNodeToMDG.EnumerateRead(AddStartNodes, &sortedNodes); if (entries != mNodeToMDG.Count()) { return NS_ERROR_OUT_OF_MEMORY; @@ -402,7 +494,8 @@ nsXFormsMDGEngine::Rebuild() nsXFormsMDGNode* node; while ((node = NS_STATIC_CAST(nsXFormsMDGNode*, sortedNodes.Pop()))) { for (PRInt32 i = 0; i < node->mSuc.Count(); ++i) { - nsXFormsMDGNode* sucNode = NS_STATIC_CAST(nsXFormsMDGNode*, node->mSuc[i]); + nsXFormsMDGNode* sucNode = NS_STATIC_CAST(nsXFormsMDGNode*, + node->mSuc[i]); NS_ASSERTION(sucNode, "XForms: NULL successor node"); sucNode->mCount--; @@ -432,7 +525,7 @@ nsresult nsXFormsMDGEngine::ClearDispatchFlags() { mJustRebuilt = PR_FALSE; - return AndFlags(MDG_FLAGMASK_NOT_DISPATCH) ? NS_OK : NS_ERROR_FAILURE; + return AndFlags(kFlags_NOT_DISPATCH) ? NS_OK : NS_ERROR_FAILURE; } nsresult @@ -446,7 +539,7 @@ nsXFormsMDGEngine::Clear() { mNodeToMDG.Clear(); - mNodeToFlag.Clear(); + mNodeStates.Clear(); mGraph.Clear(); @@ -456,7 +549,8 @@ nsXFormsMDGEngine::Clear() { } nsresult -nsXFormsMDGEngine::GetNodeValue(nsIDOMNode* aContextNode, nsAString& aNodeValue) +nsXFormsMDGEngine::GetNodeValue(nsIDOMNode *aContextNode, + nsAString &aNodeValue) { nsresult rv; nsCOMPtr childNode; @@ -497,8 +591,8 @@ nsXFormsMDGEngine::GetNodeValue(nsIDOMNode* aContextNode, nsAString& aNodeValue) break; default: - // Asked for a node which cannot have a text child - // TODO: Should return more specific error? + /// Asked for a node which cannot have a text child + /// @todo Should return more specific error? (XXX) return NS_ERROR_ILLEGAL_VALUE; break; } @@ -507,15 +601,21 @@ nsXFormsMDGEngine::GetNodeValue(nsIDOMNode* aContextNode, nsAString& aNodeValue) } nsresult -nsXFormsMDGEngine::SetNodeValue(nsIDOMNode* aContextNode, const nsAString& aNodeValue, - PRBool aMarkNode, PRBool* aNodeChanged) +nsXFormsMDGEngine::SetNodeValue(nsIDOMNode *aContextNode, + const nsAString &aNodeValue, + PRBool aMarkNode, + PRBool *aNodeChanged) { if (aNodeChanged) { *aNodeChanged = PR_FALSE; } - if (IsReadonly(aContextNode)) { - // TODO: Better feedback for readonly nodes? + const nsXFormsNodeState* ns = GetNodeState(aContextNode); + NS_ENSURE_TRUE(ns, NS_ERROR_FAILURE); + + if (ns->IsReadonly()) { + /// + /// @todo Better feedback for readonly nodes? (XXX) return NS_OK; } @@ -524,13 +624,21 @@ nsXFormsMDGEngine::SetNodeValue(nsIDOMNode* aContextNode, const nsAString& aNode nsresult rv = aContextNode->GetNodeType(&nodeType); NS_ENSURE_SUCCESS(rv, rv); + nsAutoString oldValue; + rv = GetNodeValue(aContextNode, oldValue); + NS_ENSURE_SUCCESS(rv, rv); + if (oldValue.Equals(aNodeValue)) { + return NS_OK; + } + switch(nodeType) { case nsIDOMNode::ATTRIBUTE_NODE: case nsIDOMNode::TEXT_NODE: case nsIDOMNode::CDATA_SECTION_NODE: case nsIDOMNode::PROCESSING_INSTRUCTION_NODE: case nsIDOMNode::COMMENT_NODE: - // TODO: Check existing value, and ignore if same?? + /// + /// @todo Check existing value, and ignore if same?? (XXX) rv = aContextNode->SetNodeValue(aNodeValue); NS_ENSURE_SUCCESS(rv, rv); @@ -561,8 +669,8 @@ nsXFormsMDGEngine::SetNodeValue(nsIDOMNode* aContextNode, const nsAString& aNode break; default: - // Unsupported nodeType - // TODO: Should return more specific error? + /// Unsupported nodeType + /// @todo Should return more specific error? (XXX) return NS_ERROR_ILLEGAL_VALUE; break; } @@ -578,79 +686,39 @@ nsXFormsMDGEngine::SetNodeValue(nsIDOMNode* aContextNode, const nsAString& aNode return NS_OK; } - -// Bit test functions -/** - * @TODO needs Schema support - */ -PRBool -nsXFormsMDGEngine::IsValid(nsIDOMNode* aContextNode) +const nsXFormsNodeState* +nsXFormsMDGEngine::GetNodeState(nsIDOMNode *aContextNode) { - return Test(aContextNode, MDG_FLAG_CONSTRAINT); + return GetNCNodeState(aContextNode); } -PRBool -nsXFormsMDGEngine::IsConstraint(nsIDOMNode* aContextNode) -{ - return Test(aContextNode, MDG_FLAG_CONSTRAINT); -} - -PRBool -nsXFormsMDGEngine::ShouldDispatchValid(nsIDOMNode* aContextNode) -{ - return Test(aContextNode, MDG_FLAG_DISPATCH_VALID_CHANGED); -} - -PRBool -nsXFormsMDGEngine::IsReadonly(nsIDOMNode* aContextNode) -{ - return Test(aContextNode, MDG_FLAG_READONLY | MDG_FLAG_INHERITED_READONLY); -} - -PRBool -nsXFormsMDGEngine::ShouldDispatchReadonly(nsIDOMNode* aContextNode) -{ - return Test(aContextNode, MDG_FLAG_DISPATCH_READONLY_CHANGED); -} - - -PRBool -nsXFormsMDGEngine::IsRelevant(nsIDOMNode* aContextNode) -{ - return Test(aContextNode, MDG_FLAG_RELEVANT | MDG_FLAG_INHERITED_RELEVANT); -} - -PRBool -nsXFormsMDGEngine::ShouldDispatchRelevant(nsIDOMNode* aContextNode) -{ - return Test(aContextNode, MDG_FLAG_DISPATCH_RELEVANT_CHANGED); -} - -PRBool -nsXFormsMDGEngine::IsRequired(nsIDOMNode* aContextNode) -{ - return Test(aContextNode, MDG_FLAG_REQUIRED); -} - -PRBool -nsXFormsMDGEngine::ShouldDispatchRequired(nsIDOMNode* aContextNode) -{ - return Test(aContextNode, MDG_FLAG_DISPATCH_REQUIRED_CHANGED); -} - -PRBool -nsXFormsMDGEngine::ShouldDispatchValueChanged(nsIDOMNode* aContextNode) -{ - return Test(aContextNode, MDG_FLAG_DISPATCH_VALUE_CHANGED); -} - - /**********************************************/ /* Private functions */ /**********************************************/ +nsXFormsNodeState* +nsXFormsMDGEngine::GetNCNodeState(nsIDOMNode *aContextNode) +{ + nsXFormsNodeState* ns = nsnull; + + if (aContextNode && !mNodeStates.Get(aContextNode, &ns)) { + ns = new nsXFormsNodeState(kFlags_DEFAULT | + ((mJustRebuilt && mFirstCalculate) ? kFlags_INITIAL_DISPATCH : 0)); + NS_ASSERTION(ns, "Could not create new nsXFormsNodeState"); + + if (!mNodeStates.Put(aContextNode, ns)) { + NS_ERROR("Could not insert new nsXFormsNodeState"); + delete ns; + return nsnull; + } + aContextNode->AddRef(); + } + return ns; +} + nsresult -nsXFormsMDGEngine::CreateNewChild(nsIDOMNode* aContextNode, const nsAString& aNodeValue, - nsIDOMNode* aBeforeNode) +nsXFormsMDGEngine::CreateNewChild(nsIDOMNode *aContextNode, + const nsAString &aNodeValue, + nsIDOMNode *aBeforeNode) { nsresult rv; @@ -664,16 +732,21 @@ nsXFormsMDGEngine::CreateNewChild(nsIDOMNode* aContextNode, const nsAString& aNo nsCOMPtr newNode; if (aBeforeNode) { - rv = aContextNode->InsertBefore(textNode, aBeforeNode, getter_AddRefs(newNode)); + rv = aContextNode->InsertBefore(textNode, + aBeforeNode, + getter_AddRefs(newNode)); } else { - rv = aContextNode->AppendChild(textNode, getter_AddRefs(newNode)); + rv = aContextNode->AppendChild(textNode, + getter_AddRefs(newNode)); } return rv; } PLDHashOperator -nsXFormsMDGEngine::DeleteLinkedNodes(nsISupports *aKey, nsAutoPtr& aNode, void* aArg) +nsXFormsMDGEngine::DeleteLinkedNodes(nsISupports *aKey, + nsAutoPtr &aNode, + void *aArg) { if (!aNode) { NS_WARNING("nsXFormsMDGEngine::DeleteLinkedNodes() called with aNode == nsnull!"); @@ -692,19 +765,22 @@ nsXFormsMDGEngine::DeleteLinkedNodes(nsISupports *aKey, nsAutoPtrmType != aType) { + if (mNodeToMDG.Get(nodeKey, &nd) && aType != eModel_type) { + while (nd && aType != nd->mType) { nd = nd->mNext; } } @@ -731,12 +807,12 @@ nsXFormsMDGEngine::GetNode(nsIDOMNode* aDomNode, ModelItemPropName aType, PRBool #endif nd_exists->mNext = nd; } else { - nodeKey->AddRef(); if (!mNodeToMDG.Put(nodeKey, nd)) { delete nd; NS_ERROR("Could not insert new node in HashTable!"); return nsnull; } + nodeKey->AddRef(); } mNodesInGraph++; @@ -745,10 +821,14 @@ nsXFormsMDGEngine::GetNode(nsIDOMNode* aDomNode, ModelItemPropName aType, PRBool } PLDHashOperator -nsXFormsMDGEngine::AddStartNodes(nsISupports *aKey, nsXFormsMDGNode* aNode, void* aDeque) +nsXFormsMDGEngine::AddStartNodes(nsISupports *aKey, + nsXFormsMDGNode *aNode, + void *aDeque) { #ifdef DEBUG_XF_MDG - printf("nsXFormsMDGEngine::AddStartNodes(aKey=n/a, aNode=%p, aDeque=%p)\n", (void*) aNode, aDeque); + printf("nsXFormsMDGEngine::AddStartNodes(aKey=n/a, aNode=%p, aDeque=%p)\n", + (void*) aNode, + aDeque); #endif nsDeque* deque = NS_STATIC_CAST(nsDeque*, aDeque); @@ -759,7 +839,8 @@ nsXFormsMDGEngine::AddStartNodes(nsISupports *aKey, nsXFormsMDGNode* aNode, void while (aNode) { if (aNode->mCount == 0) { - // Is it not possible to check error condition? + /// + /// @todo Is it not possible to check error condition? (XXX) deque->Push(aNode); } aNode = aNode->mNext; @@ -769,60 +850,23 @@ nsXFormsMDGEngine::AddStartNodes(nsISupports *aKey, nsXFormsMDGNode* aNode, void } PLDHashOperator -nsXFormsMDGEngine::AndFlag(nsISupports *aKey, PRUint16& aFlag, void* aMask) +nsXFormsMDGEngine::AndFlag(nsISupports *aKey, + nsAutoPtr &aState, + void *aMask) { PRUint16* andMask = NS_STATIC_CAST(PRUint16*, aMask); if (!andMask) { return PL_DHASH_STOP; } - aFlag &= *andMask; + *aState &= *andMask; return PL_DHASH_NEXT; } PRBool nsXFormsMDGEngine::AndFlags(PRUint16 aAndMask) { - PRUint32 entries = mNodeToFlag.Enumerate(AndFlag, &aAndMask); - return (entries == mNodeToFlag.Count()) ? PR_TRUE : PR_FALSE; -} - -PRUint16 -nsXFormsMDGEngine::GetFlag(nsIDOMNode* aDomNode) -{ - PRUint16 flag = MDG_FLAG_DEFAULT | (mJustRebuilt && mFirstCalculate ? MDG_FLAG_INITIAL_DISPATCH : 0); - - // If node is found, flag is modified, if not flag is untouched - mNodeToFlag.Get(aDomNode, &flag); - - return flag; -} - -void -nsXFormsMDGEngine::SetFlag(nsIDOMNode* aDomNode, PRUint16 aFlag) -{ - nsIDOMNode *nodeKey = aDomNode; - nodeKey->AddRef(); - mNodeToFlag.Put(nodeKey, aFlag); -} - -void -nsXFormsMDGEngine::OrFlag(nsIDOMNode* aDomNode, PRInt16 aFlag) -{ - PRUint16 fl = GetFlag(aDomNode); - fl |= aFlag; - SetFlag(aDomNode, fl); -} - -void -nsXFormsMDGEngine::SetFlagBits(nsIDOMNode* aDomNode, PRUint16 aBits, PRBool aOn) -{ - PRUint32 fl = GetFlag(aDomNode); - if (aOn) { - fl |= aBits; - } else { - fl &= ~aBits; - } - SetFlag(aDomNode, fl); + PRUint32 entries = mNodeStates.Enumerate(AndFlag, &aAndMask); + return (entries == mNodeStates.Count()) ? PR_TRUE : PR_FALSE; } @@ -830,12 +874,17 @@ nsresult nsXFormsMDGEngine::BooleanExpression(nsXFormsMDGNode* aNode, PRBool& state) { NS_ENSURE_ARG_POINTER(aNode); + NS_ENSURE_TRUE(aNode->mExpression, NS_ERROR_FAILURE); - // TODO: Use aNode->contextPosition and aNode->contextSize! + /// @todo Use aNode->contextPosition and aNode->contextSize (XXX) + /// @see https://bugzilla.mozilla.org/show_bug.cgi?id=265460 nsISupports* retval; nsresult rv; - rv = aNode->mExpression->Evaluate(aNode->mContextNode, nsIDOMXPathResult::BOOLEAN_TYPE, nsnull, &retval); + rv = aNode->mExpression->Evaluate(aNode->mContextNode, + nsIDOMXPathResult::BOOLEAN_TYPE, + nsnull, + &retval); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr xpath_res = do_QueryInterface(retval); @@ -847,35 +896,43 @@ nsXFormsMDGEngine::BooleanExpression(nsXFormsMDGNode* aNode, PRBool& state) } nsresult -nsXFormsMDGEngine::ComputeMIP(PRUint16 aStateFlag, PRUint16 aDispatchFlag, nsXFormsMDGNode* aNode, PRBool& aDidChange) +nsXFormsMDGEngine::ComputeMIP(eFlag_t aStateFlag, + eFlag_t aDispatchFlag, + nsXFormsMDGNode *aNode, + PRBool &aDidChange) { - NS_ENSURE_ARG_POINTER(aNode); + NS_ENSURE_ARG(aNode); + + aDidChange = PR_FALSE; + + if (!aNode->mExpression) + return NS_OK; + + nsXFormsNodeState* ns = GetNCNodeState(aNode->mContextNode); + NS_ENSURE_TRUE(ns, NS_ERROR_FAILURE); - PRUint32 word = GetFlag(aNode->mContextNode); PRBool state; nsresult rv = BooleanExpression(aNode, state); NS_ENSURE_SUCCESS(rv, rv); - PRBool cstate = ((word & aStateFlag) != 0) ? PR_TRUE : PR_FALSE; + PRBool cstate = ns->Test(aStateFlag); - if (state) { - word |= aStateFlag; - } else { - word &= ~aStateFlag; - } + ns->Set(aStateFlag, state); aDidChange = (state != cstate) ? PR_TRUE : PR_FALSE; if (aDidChange) { - word |= aDispatchFlag; + ns->Set(aDispatchFlag, PR_TRUE); } - - SetFlag(aNode->mContextNode, word); return NS_OK; } nsresult -nsXFormsMDGEngine::ComputeMIPWithInheritance(PRUint16 aStateFlag, PRUint16 aDispatchFlag, PRUint16 aInheritanceFlag, nsXFormsMDGNode* aNode, nsXFormsMDGSet* aSet) +nsXFormsMDGEngine::ComputeMIPWithInheritance(eFlag_t aStateFlag, + eFlag_t aDispatchFlag, + eFlag_t aInheritanceFlag, + nsXFormsMDGNode *aNode, + nsXFormsMDGSet *aSet) { nsresult rv; PRBool didChange; @@ -883,27 +940,32 @@ nsXFormsMDGEngine::ComputeMIPWithInheritance(PRUint16 aStateFlag, PRUint16 aDisp NS_ENSURE_SUCCESS(rv, rv); if (didChange) { - PRUint16 flag = GetFlag(aNode->mContextNode); - PRBool state = ((flag & aStateFlag) != 0) ? PR_TRUE : PR_FALSE; - if ( (aStateFlag == MDG_FLAG_READONLY && (flag & aInheritanceFlag) == 0) - || (aStateFlag == MDG_FLAG_RELEVANT && (flag & aInheritanceFlag) > 0) ) + nsXFormsNodeState* ns = GetNCNodeState(aNode->mContextNode); + NS_ENSURE_TRUE(ns, NS_ERROR_FAILURE); + if ( !(aStateFlag == eFlag_READONLY && ns->Test(aInheritanceFlag)) + || (aStateFlag == eFlag_RELEVANT && ns->Test(aInheritanceFlag)) ) { - NS_ENSURE_TRUE(aSet->AddNode(aNode->mContextNode), NS_ERROR_FAILURE); - rv = AttachInheritance(aSet, aNode->mContextNode, state, aStateFlag); + NS_ENSURE_TRUE(aSet->AddNode(aNode->mContextNode), + NS_ERROR_FAILURE); + rv = AttachInheritance(aSet, + aNode->mContextNode, + ns->Test(aStateFlag), + aStateFlag); } } - return NS_OK; + return rv; } nsresult -nsXFormsMDGEngine::AttachInheritance(nsXFormsMDGSet* aSet, nsIDOMNode* aSrc, PRBool aState, PRUint16 aStateFlag) +nsXFormsMDGEngine::AttachInheritance(nsXFormsMDGSet *aSet, + nsIDOMNode *aSrc, + PRBool aState, + eFlag_t aStateFlag) { NS_ENSURE_ARG(aSrc); nsCOMPtr node; - PRUint32 flag; - PRBool cstate; nsresult rv; PRBool updateNode = PR_FALSE; @@ -919,42 +981,44 @@ nsXFormsMDGEngine::AttachInheritance(nsXFormsMDGSet* aSet, nsIDOMNode* aSrc, PRB rv = childList->Item(i, getter_AddRefs(node)); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); - - flag = GetFlag(node); - cstate = ((flag & aStateFlag) != 0) ? PR_TRUE : PR_FALSE; + nsXFormsNodeState *ns = GetNCNodeState(node); + NS_ENSURE_TRUE(ns, NS_ERROR_FAILURE); - if (aStateFlag == MDG_FLAG_RELEVANT) { - if (aState == PR_FALSE) { // The nodes are getting irrelevant - if ((flag & MDG_FLAG_INHERITED_RELEVANT) != 0 && cstate) { - flag &= ~MDG_FLAG_INHERITED_RELEVANT; - flag |= MDG_FLAG_DISPATCH_RELEVANT_CHANGED; + PRBool curState = ns->Test(aStateFlag); + + if (aStateFlag == eFlag_RELEVANT) { + if (!aState) { // The nodes are getting irrelevant + if (ns->Test(eFlag_INHERITED_RELEVANT) && curState) { + ns->Set(eFlag_INHERITED_RELEVANT, PR_FALSE); + ns->Set(eFlag_DISPATCH_RELEVANT_CHANGED, PR_TRUE); updateNode = PR_TRUE; } } else { // The nodes are becoming relevant - if (cstate) { - flag |= MDG_FLAG_DISPATCH_RELEVANT_CHANGED; // Relevant has changed from inheritance - flag |= MDG_FLAG_INHERITED_RELEVANT; // Clear the flag for inheritance + if (curState) { + // Relevant has changed from inheritance + ns->Set(eFlag_DISPATCH_RELEVANT_CHANGED, PR_TRUE); + ns->Set(eFlag_INHERITED_RELEVANT, PR_TRUE); updateNode = PR_TRUE; } } - } else if (aStateFlag == MDG_FLAG_READONLY) { + } else if (aStateFlag == eFlag_READONLY) { if (aState) { // The nodes are getting readonly - if ((flag & MDG_FLAG_INHERITED_READONLY) == 0 && cstate == PR_FALSE) { - flag |= MDG_FLAG_INHERITED_READONLY | MDG_FLAG_DISPATCH_READONLY_CHANGED; + if (!ns->Test(eFlag_INHERITED_READONLY) && curState == PR_FALSE) { + ns->Set(eFlag_INHERITED_READONLY | eFlag_DISPATCH_READONLY_CHANGED, + PR_TRUE); updateNode = PR_TRUE; } } else { // The nodes are getting readwrite - if (cstate) { - flag |= MDG_FLAG_DISPATCH_READONLY_CHANGED; - flag &= ~MDG_FLAG_INHERITED_READONLY; + if (curState) { + ns->Set(eFlag_DISPATCH_READONLY_CHANGED, PR_TRUE); + ns->Set(eFlag_INHERITED_READONLY, PR_FALSE); updateNode = PR_TRUE; } } } if (updateNode) { - SetFlag(node, flag); rv = AttachInheritance(aSet, node, aState, aStateFlag); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(aSet->AddNode(node), NS_ERROR_FAILURE); @@ -977,29 +1041,3 @@ nsXFormsMDGEngine::Invalidate() return NS_OK; } -PRBool -nsXFormsMDGEngine::TestAndClear(nsIDOMNode* aDomNode, PRUint16 aFlag) -{ - PRUint16 fl = GetFlag(aDomNode); - PRUint16 test = fl & aFlag; - fl &= ~aFlag; - SetFlag(aDomNode, fl); - return (test != 0) ? PR_TRUE : PR_FALSE; -} - -PRBool -nsXFormsMDGEngine::TestAndSet(nsIDOMNode* aDomNode, PRUint16 aFlag) -{ - PRUint16 fl = GetFlag(aDomNode); - PRUint16 test = fl & aFlag; - fl |= aFlag; - SetFlag(aDomNode, fl); - return (test != 0) ? PR_TRUE : PR_FALSE; -} - -PRBool -nsXFormsMDGEngine::Test(nsIDOMNode* aDomNode, PRUint16 aFlag) -{ - PRUint16 fl = GetFlag(aDomNode); - return (fl & aFlag != 0) ? PR_TRUE : PR_FALSE; -} diff --git a/mozilla/extensions/xforms/nsXFormsMDGEngine.h b/mozilla/extensions/xforms/nsXFormsMDGEngine.h index 1225dc70159..b491c1ed13d 100644 --- a/mozilla/extensions/xforms/nsXFormsMDGEngine.h +++ b/mozilla/extensions/xforms/nsXFormsMDGEngine.h @@ -43,61 +43,16 @@ #include "nscore.h" #include "nsClassHashtable.h" #include "nsCOMPtr.h" -#include "nsDataHashtable.h" #include "nsVoidArray.h" #include "nsIDOMNode.h" #include "nsXFormsTypes.h" #include "nsXFormsMDGSet.h" +#include "nsXFormsNodeState.h" class nsIDOMXPathExpression; -/** - * Flags, etc. - * - * TODO: Convert to enum? - */ -const PRUint16 MDG_FLAG_READONLY = 1 << 1; -const PRUint16 MDG_FLAG_CONSTRAINT = 1 << 2; -const PRUint16 MDG_FLAG_RELEVANT = 1 << 3; -const PRUint16 MDG_FLAG_REQUIRED = 1 << 4; -const PRUint16 MDG_FLAG_SCHEMA_VALID = 1 << 5; -const PRUint16 MDG_FLAG_VALID = 1 << 6; -const PRUint16 MDG_FLAG_INHERITED_RELEVANT = 1 << 7; -const PRUint16 MDG_FLAG_INHERITED_READONLY = 1 << 8; -const PRUint16 MDG_FLAG_DISPATCH_VALUE_CHANGED = 1 << 9; -const PRUint16 MDG_FLAG_DISPATCH_READONLY_CHANGED = 1 << 10; -const PRUint16 MDG_FLAG_DISPATCH_VALID_CHANGED = 1 << 11; -const PRUint16 MDG_FLAG_DISPATCH_RELEVANT_CHANGED = 1 << 12; -const PRUint16 MDG_FLAG_DISPATCH_REQUIRED_CHANGED = 1 << 13; -const PRUint16 MDG_FLAG_DISPATCH_CONSTRAINT_CHANGED = 1 << 14; - -const PRUint16 MDG_FLAGMASK_NOT_DISPATCH = ~(MDG_FLAG_DISPATCH_VALUE_CHANGED | \ - MDG_FLAG_DISPATCH_READONLY_CHANGED |\ - MDG_FLAG_DISPATCH_VALID_CHANGED |\ - MDG_FLAG_DISPATCH_RELEVANT_CHANGED |\ - MDG_FLAG_DISPATCH_REQUIRED_CHANGED |\ - MDG_FLAG_DISPATCH_CONSTRAINT_CHANGED); - -const PRUint16 MDG_FLAG_DEFAULT = MDG_FLAG_CONSTRAINT | \ - MDG_FLAG_RELEVANT |\ - MDG_FLAG_INHERITED_RELEVANT; - -const PRUint16 MDG_FLAG_INITIAL_DISPATCH = MDG_FLAG_DISPATCH_READONLY_CHANGED |\ - MDG_FLAG_DISPATCH_VALID_CHANGED |\ - MDG_FLAG_DISPATCH_RELEVANT_CHANGED |\ - MDG_FLAG_DISPATCH_REQUIRED_CHANGED; - -const PRUint16 MDG_FLAG_ALL_DISPATCH = MDG_FLAG_DISPATCH_READONLY_CHANGED |\ - MDG_FLAG_DISPATCH_VALID_CHANGED |\ - MDG_FLAG_DISPATCH_RELEVANT_CHANGED |\ - MDG_FLAG_DISPATCH_REQUIRED_CHANGED |\ - MDG_FLAG_DISPATCH_VALUE_CHANGED |\ - MDG_FLAG_DISPATCH_CONSTRAINT_CHANGED; - - - /** * Data structure for nodes in the graph. * @@ -146,7 +101,8 @@ public: * @param aNode The context node * @param aType The type of node (calculate, readonly, etc.) */ - nsXFormsMDGNode(nsIDOMNode* aNode, const ModelItemPropName aType); + nsXFormsMDGNode(nsIDOMNode *aNode, + const ModelItemPropName aType); /** Destructor */ ~nsXFormsMDGNode(); @@ -159,8 +115,10 @@ public: * @param aContextPosition The context position for the expression * @param aContextSize The context size for the expression */ - void SetExpression(nsIDOMXPathExpression* aExpression, PRBool aDynFunc, - PRInt32 aContextPosition, PRInt32 aContextSize); + void SetExpression(nsIDOMXPathExpression *aExpression, + PRBool aDynFunc, + PRInt32 aContextPosition, + PRInt32 aContextSize); /** Does node have an expression? */ PRBool HasExpr() const; @@ -187,34 +145,34 @@ public: * each of the attributes (readonly, calculate, etc.) for a nsIDOMNode. These graph * nodes are owned by the mNodeToMDG hash table, which maps from a nsIDOMNode to * the first node in a single-linked list (mNext) of nodes for the same nsIDOMNode. + * + * @todo Merge SetNodeValue() with nsXFormsUtils::SetNodeValue() (XXX) */ class nsXFormsMDGEngine { protected: - /** - * Maps from nsIDOMNode to nsXFormsMDGNode(s) - */ + /** Maps from nsIDOMNode to nsXFormsMDGNode */ nsClassHashtable mNodeToMDG; - /** - * Maps from nsIDOMNode to flag (MDG_FLAG_*) - */ - nsDataHashtable mNodeToFlag; + /** Maps from nsIDOMNode to nsXFormsNodeState */ + nsClassHashtable mNodeStates; + + /** Default node state */ + nsXFormsNodeState mDefaultState; - /** - * True when Rebuild() has been run, but not ClearDispatchFlags() - */ + /** True when Rebuild() has been run, but not ClearDispatchFlags() */ PRBool mJustRebuilt; - /** - * True when last Calculate() was run when mJustRebuilded was true. - */ + /** True when last Calculate() was run when mJustRebuilt was true. */ PRBool mFirstCalculate; /** The actual MDG */ nsVoidArray mGraph; - /** Set of nodes that are marked as changed, and should be included in recalculation */ + /** + * Set of nodes that are marked as changed, and should be included in + * recalculation + */ nsXFormsMDGSet mMarkedNodes; /** Number of nodes in the graph */ @@ -227,18 +185,36 @@ protected: * Used by Clear() and ~ to delete the linked nodes in mNodeToMDG, the hash table * itself handles the main nodes. */ - static PLDHashOperator PR_CALLBACK DeleteLinkedNodes(nsISupports *aKey, nsAutoPtr& aNode, void* aArg); + static PLDHashOperator PR_CALLBACK + DeleteLinkedNodes(nsISupports *aKey, + nsAutoPtr &aNode, + void *aArg); /** * Used by Rebuild() to find the start nodes for mGraph, that is nodes * where mCount == 0. */ - static PLDHashOperator PR_CALLBACK AddStartNodes(nsISupports *aKey, nsXFormsMDGNode* aNode, void* aDeque); + static PLDHashOperator PR_CALLBACK + AddStartNodes(nsISupports *aKey, + nsXFormsMDGNode *aNode, + void *aDeque); /** - * Used by AndFlags() to boolean AND all flags with aMask. + * Used by AndFlags() to boolean AND _all_ flags with aMask. */ - static PLDHashOperator PR_CALLBACK AndFlag(nsISupports *aKey, PRUint16& aFlag, void* aMask); + static PLDHashOperator PR_CALLBACK + AndFlag(nsISupports *aKey, + nsAutoPtr &aState, + void *aMask); + + /** + * Get non-const (NC) node state for a node, create a new node state if + * necessary. + * + * @param aContextNode The node to get the state for + * @return The state (owned by nsXFormsMDGEngine) + */ + nsXFormsNodeState* GetNCNodeState(nsIDOMNode *aContextNode); /** * Inserts a new text child for aContextNode. @@ -247,58 +223,30 @@ protected: * @param aNodeValue The value of the new node * @param aBeforeNode If non-null, insert new node before this node */ - nsresult CreateNewChild(nsIDOMNode* aContextNode, const nsAString& aNodeValue, nsIDOMNode* aBeforeNode = nsnull); + nsresult CreateNewChild(nsIDOMNode *aContextNode, + const nsAString &aNodeValue, + nsIDOMNode *aBeforeNode = nsnull); /** * Retrieve a node from the graph. * * @param aDomNode The DOM node to retrieve * @param aType The type to retrieve (readonly, calculate, etc) - * @param aCreate Create the node and insert it into the graph if it does not exist? + * @param aCreate Create the node and insert it into the graph + * if it does not exist? * @return The node, nsnull if not found and aCreate != PR_TRUE */ - nsXFormsMDGNode* GetNode(nsIDOMNode* aDomNode, ModelItemPropName aType, PRBool aCreate = PR_TRUE); - - /** - * Sets the flag for a node. - * - * @param aDomNode The node - * @param aFlag The flag - */ - void SetFlag(nsIDOMNode* aDomNode, PRUint16 aFlag); - - /** - * Boolean OR the existing flag on the node with a new flag - * - * @param aDomNode The node - * @param aFlag The new flag - */ - void OrFlag(nsIDOMNode* aDomNode, PRInt16 aFlag); - - /** - * Retrieve the flag for a node. - * - * @param aDomNode The node - * @return The flag - */ - PRUint16 GetFlag(nsIDOMNode* aDomNode); + nsXFormsMDGNode* GetNode(nsIDOMNode *aDomNode, + ModelItemPropName aType, + PRBool aCreate = PR_TRUE); /** - * Sets a bit in the flag for a node - * - * @param aDomNode The node - * @param aBit The bit position to set - * @param aOn The bit value - */ - void SetFlagBits(nsIDOMNode* aDomNode, PRUint16 aBit, PRBool aOn); - - /** - * Boolean AND all flags with a mask. + * Boolean AND _all_ flags with a mask. * * @param aAndMask The mask * @return Did operation succeed? */ - PRBool AndFlags(PRUint16 aAndMask); + PRBool AndFlags(PRUint16 aAndMask); /** * Evaluates the expression for the given node and returns the boolean result. @@ -306,7 +254,8 @@ protected: * @param aNode The node to evaluate * @param res The result of the evaluation */ - nsresult BooleanExpression(nsXFormsMDGNode* aNode, PRBool& res); + nsresult BooleanExpression(nsXFormsMDGNode *aNode, + PRBool &aRes); /** * Compute MIP value for node types with boolean result (all except calculate) @@ -316,7 +265,10 @@ protected: * @param aNode The context node * @param aDidChange Was the node changed? */ - nsresult ComputeMIP(PRUint16 aStateFlag, PRUint16 aDispatchFlag, nsXFormsMDGNode* aNode, PRBool& aDidChange); + nsresult ComputeMIP(eFlag_t aStateFlag, + eFlag_t aDispatchFlag, + nsXFormsMDGNode *aNode, + PRBool &aDidChange); /** * Same as ComputeMIP(), but also handles any inheritance of attributes. @@ -327,7 +279,11 @@ protected: * @param aNode The context node * @param aSet Set of the nodes influenced by operation */ - nsresult ComputeMIPWithInheritance(PRUint16 aStateFlag, PRUint16 aDispatchFlag, PRUint16 aInheritanceFlag, nsXFormsMDGNode* aNode, nsXFormsMDGSet* aSet); + nsresult ComputeMIPWithInheritance(eFlag_t aStateFlag, + eFlag_t aDispatchFlag, + eFlag_t aInheritanceFlag, + nsXFormsMDGNode *aNode, + nsXFormsMDGSet *aSet); /** * Attaches inheritance to all children of a given node @@ -337,47 +293,23 @@ protected: * @param aState The state of the flag * @param aStateFlag The flag */ - nsresult AttachInheritance(nsXFormsMDGSet* aSet, nsIDOMNode* aSrc, PRBool aState, PRUint16 aStateFlag); + nsresult AttachInheritance(nsXFormsMDGSet *aSet, + nsIDOMNode *aSrc, + PRBool aState, + eFlag_t aStateFlag); /** * Invalidate the information, ie. mark all nodes as dirty. */ nsresult Invalidate(); - /** - * Get flag value for node and clear flag. - * - * @param aDomNode The node - * @param aFlag The flag - * @return The flag value - */ - PRBool TestAndClear(nsIDOMNode* aDomNode, PRUint16 aFlag); - - /** - * Get flag value for node and set flag. - * - * @param aDomNode The node - * @param aFlag The flag - * @return The flag value - */ - PRBool TestAndSet(nsIDOMNode* aDomNode, PRUint16 aFlag); - - /** - * Get flag value for node - * - * @param aDomNode The node - * @param aFlag The flag - * @return The flag value - */ - PRBool Test(nsIDOMNode* aDomNode, PRUint16 aFlag); - public: /** * Constructor */ nsXFormsMDGEngine(); - - /** + + /* * Destructor */ ~nsXFormsMDGEngine(); @@ -398,15 +330,22 @@ public: * @param aContextPos The context positions of aExpression * @param aContextSize The context size for aExpression */ - /* void addMIP (in long aType, in nsIDOMXPathExpression aExpression, in nsXFormsMDGSet aDependencies, in boolean aDynFunc, in nsIDOMNode aContextNode, in long aContextPos, in long aContextSize); */ - nsresult AddMIP(PRInt32 aType, nsIDOMXPathExpression *aExpression, nsXFormsMDGSet *aDependencies, PRBool aDynFunc, nsIDOMNode *aContextNode, PRInt32 aContextPos, PRInt32 aContextSize); + nsresult AddMIP(PRInt32 aType, + nsIDOMXPathExpression *aExpression, + nsXFormsMDGSet *aDependencies, + PRBool aDynFunc, + nsIDOMNode *aContextNode, + PRInt32 aContextPos, + PRInt32 aContextSize); /** * Recalculate the MDG. * * @param aChangedNodes Returns the nodes that was changed during recalculation. + * + * @note aChangedNodes are unique and sorted in pointer-order, ascending. */ - nsresult Recalculate(nsXFormsMDGSet **aChangedNodes); + nsresult Recalculate(nsXFormsMDGSet *aChangedNodes); /** * Rebuilds the MDG. @@ -438,7 +377,10 @@ public: * @param aMarkNode Whether to mark node as changed * @param aNodeChanged Was node changed? */ - nsresult SetNodeValue(nsIDOMNode *aContextNode, const nsAString & aNodeValue, PRBool aMarkNode, PRBool *aNodeChanged); + nsresult SetNodeValue(nsIDOMNode *aContextNode, + const nsAString &aNodeValue, + PRBool aMarkNode = PR_TRUE, + PRBool *aNodeChanged = nsnull); /** * Get the value of a node. (used by nsXFormsMDG) @@ -446,27 +388,26 @@ public: * @param aContextNode The node to get the value for * @param aNodeValue The value of the node */ - nsresult GetNodeValue(nsIDOMNode *aContextNode, nsAString & aNodeValue); + nsresult GetNodeValue(nsIDOMNode *aContextNode, + nsAString &aNodeValue); - PRBool IsConstraint(nsIDOMNode *aContextNode); + /** + * External interface of GetNCNodeState(), returns const pointer to the node + * state. + * + * @param aContextNode The node to get the state for + * @return The state (owned by nsXFormsMDGEngine) + */ + const nsXFormsNodeState* GetNodeState(nsIDOMNode *aContextNode); - PRBool IsValid(nsIDOMNode *aContextNode); - - PRBool ShouldDispatchValid(nsIDOMNode *aContextNode); - - PRBool IsReadonly(nsIDOMNode *aContextNode); - - PRBool ShouldDispatchReadonly(nsIDOMNode *aContextNode); - - PRBool IsRelevant(nsIDOMNode *aContextNode); - - PRBool ShouldDispatchRelevant(nsIDOMNode *aContextNode); - - PRBool IsRequired(nsIDOMNode *aContextNode); - - PRBool ShouldDispatchRequired(nsIDOMNode *aContextNode); - - PRBool ShouldDispatchValueChanged(nsIDOMNode *aContextNode); +#ifdef DEBUG_beaufour + /** + * Write MDG graph to a file in GraphViz dot format. + * + * @param aFile Filename to write to (nsnull = stdout) + */ + void PrintDot(const char* aFile = nsnull); +#endif }; #endif diff --git a/mozilla/extensions/xforms/nsXFormsMDGSet.cpp b/mozilla/extensions/xforms/nsXFormsMDGSet.cpp index 53456bcbde7..b5197a9d992 100644 --- a/mozilla/extensions/xforms/nsXFormsMDGSet.cpp +++ b/mozilla/extensions/xforms/nsXFormsMDGSet.cpp @@ -44,9 +44,6 @@ nsXFormsMDGSet::MakeUnique() { array.Sort(sortFunc, nsnull); - // TODO: Assuming that moving element x, will delete x, and move list "one to the left", - // ie. x = x+1, x+1=x+2, ... etc. - // Is that correct? PRInt32 pos = 0; nsIDOMNode* node; while (pos + 1 < array.Count()) { @@ -91,6 +88,10 @@ nsXFormsMDGSet::AddSet(nsXFormsMDGSet& aSet) return PR_TRUE; } + +/// +/// @todo Is in fact a getter, should addref? (XXX) +/// AddRef it, and use already_AddRefed nsIDOMNode* nsXFormsMDGSet::GetNode(const PRInt32 aIndex) const { return NS_STATIC_CAST(nsIDOMNode*, array[aIndex]); diff --git a/mozilla/extensions/xforms/nsXFormsMDGSet.h b/mozilla/extensions/xforms/nsXFormsMDGSet.h index e4d3abf58e9..ecd6858c6e8 100644 --- a/mozilla/extensions/xforms/nsXFormsMDGSet.h +++ b/mozilla/extensions/xforms/nsXFormsMDGSet.h @@ -52,6 +52,8 @@ * * The class owns the nsIDOMNodes that it stores, and manages the reference * counters automatically. + * + * @todo Use nsIMutableArray of some sort instead! (XXX) */ class nsXFormsMDGSet { private: diff --git a/mozilla/extensions/xforms/nsXFormsModelElement.cpp b/mozilla/extensions/xforms/nsXFormsModelElement.cpp index b31701066a9..5d0397feade 100644 --- a/mozilla/extensions/xforms/nsXFormsModelElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsModelElement.cpp @@ -72,9 +72,10 @@ #include "nsISchemaLoader.h" #include "nsISchema.h" #include "nsAutoPtr.h" +#include "nsArray.h" -#ifdef DEBUG_beaufour -#include "nsIDOMSerializer.h" +#ifdef DEBUG +//#define DEBUG_MODEL #endif //------------------------------------------------------------------------------ @@ -436,12 +437,44 @@ nsXFormsModelElement::Recalculate() printf("nsXFormsModelElement::Recalculate()\n"); #endif - nsAutoPtr changedNodes(new nsXFormsMDGSet()); - // TODO: Handle changed nodes. That is, dispatch events, etc. + return mMDG.Recalculate(&mChangedNodes); +} - nsXFormsMDGSet* ptr = changedNodes.get(); +void +nsXFormsModelElement::DispatchEvents(nsIXFormsControl *aControl, + nsIDOMNode *aNode) +{ + nsCOMPtr element; + aControl->GetElement(getter_AddRefs(element)); + + const nsXFormsNodeState* ns = mMDG.GetNodeState(aNode); - return mMDG.Recalculate(&ptr); + if (!element || !ns) { +#ifdef DEBUG_beaufour + printf("nsXFormsModelElement::DispatchEvents(): Could not get element or node state for node!\n"); +#endif + return; + } + + if (ns->ShouldDispatchValid()) { + nsXFormsUtils::DispatchEvent(element, + ns->IsValid() ? eEvent_Valid : eEvent_Invalid); + } + if (ns->ShouldDispatchReadonly()) { + nsXFormsUtils::DispatchEvent(element, + ns->IsReadonly() ? eEvent_Readonly : eEvent_Readwrite); + } + if (ns->ShouldDispatchRequired()) { + nsXFormsUtils::DispatchEvent(element, + ns->IsRequired() ? eEvent_Required : eEvent_Optional); + } + if (ns->ShouldDispatchRelevant()) { + nsXFormsUtils::DispatchEvent(element, + ns->IsRelevant() ? eEvent_Enabled : eEvent_Disabled); + } + if (ns->ShouldDispatchValueChanged()) { + nsXFormsUtils::DispatchEvent(element, eEvent_ValueChanged); + } } NS_IMETHODIMP @@ -451,20 +484,110 @@ nsXFormsModelElement::Revalidate() printf("nsXFormsModelElement::Revalidate()\n"); #endif -#ifdef DEBUG_beaufour - // Dump instance document to stdout - nsresult rv; - nsCOMPtr serializer(do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv)); - NS_ENSURE_SUCCESS(rv, rv); + /// @note Prerequisite: Both changed nodes and dependencies are sorted in + /// ascending order! - // TODO: Should use SerializeToStream and write directly to stdout... - nsAutoString instanceString; - rv = serializer->SerializeToString(mInstanceDocument, instanceString); - NS_ENSURE_SUCCESS(rv, rv); - - printf("Instance data:\n%s\n", NS_ConvertUCS2toUTF8(instanceString).get()); +#ifdef DEBUG_MODEL + printf("Changed nodes:\n"); + for (PRInt32 j = 0; j < mChangedNodes.Count(); ++j) { + nsCOMPtr node = mChangedNodes.GetNode(j); + nsAutoString name; + node->GetNodeName(name); + printf("\t%s\n", NS_ConvertUCS2toUTF8(name).get()); + } #endif + // Iterate over all form controls + PRInt32 controlCount = mFormControls.Count(); + for (PRInt32 i = 0; i < controlCount; ++i) { + nsIXFormsControl* control = NS_STATIC_CAST(nsIXFormsControl*, mFormControls[i]); + /// @todo If a control is removed because of previous control has been + /// refreshed, we do, obviously, not need to refresh it. So mFormControls + /// should have weak bindings to the controls I guess? (XXX) + /// + /// This could happen for \s for example. + if (!control) { + continue; + } + + // Get bound node + nsCOMPtr boundNode; + control->GetBoundNode(getter_AddRefs(boundNode)); + + // Get dependencies + nsCOMPtr deps; + control->GetDependencies(getter_AddRefs(deps)); + PRUint32 depCount = 0; + if (deps) { + deps->GetLength(&depCount); + } + +#ifdef DEBUG_MODEL + nsCOMPtr controlElement; + control->GetElement(getter_AddRefs(controlElement)); + if (controlElement) { + printf("Checking control: "); + //DBG_TAGINFO(controlElement); + nsAutoString boundName; + if (boundNode) + boundNode->GetNodeName(boundName); + printf("\tBound to: '%s', dependencies: %d\n", + NS_ConvertUCS2toUTF8(boundName).get(), + depCount); + } +#endif + + nsCOMPtr curDep, curChanged; + PRUint32 depPos = 0; + /// @bug This should be set to PR_FALSE! (XXX) + /// Setting it to PR_TRUE rebinds all controls all the time + /// @see https://bugzilla.mozilla.org/show_bug.cgi?id=278368 + PRBool rebind = PR_TRUE; + PRBool refresh = PR_FALSE; + + for (PRInt32 j = 0; j < mChangedNodes.Count(); ++j) { + curChanged = mChangedNodes.GetNode(j); + + if (curChanged == boundNode) { + refresh = PR_TRUE; + // We cannot break here, as we need to to check for any changed + // dependencies + } + + if (depPos == depCount) { + continue; + } + + while (depPos < depCount && (void*) curChanged > (void*) curDep) { + curDep = do_QueryElementAt(deps, depPos); + ++depPos; + } + + if (curDep == curChanged) { + rebind = PR_TRUE; + break; + } + } + +#ifdef DEBUG_MODEL + printf("\trebind: %d, refresh: %d\n", rebind, refresh); +#endif + + if (rebind) { + control->Bind(); + control->GetBoundNode(getter_AddRefs(boundNode)); + } + if (rebind || refresh) { + DispatchEvents(control, boundNode); + /// + /// @todo Should be moved to Refresh() (XXX) + control->Refresh(); + } + } + + mChangedNodes.Clear(); + mMDG.ClearDispatchFlags(); + return NS_OK; } @@ -475,11 +598,9 @@ nsXFormsModelElement::Refresh() printf("nsXFormsModelElement::Refresh()\n"); #endif - // refresh all of our form controls - PRInt32 controlCount = mFormControls.Count(); - for (PRInt32 i = 0; i < controlCount; ++i) { - NS_STATIC_CAST(nsIXFormsControl*, mFormControls[i])->Refresh(); - } + /// @todo Any refreshing is for the moment done in Revalidate(), so we do + /// not need to do anything here. But the refreshing part should probably + /// be moved to Refresh()... (XXX) return NS_OK; } @@ -649,6 +770,14 @@ nsXFormsModelElement::FindInstanceElement(const nsAString &aID, return NS_OK; } +nsresult +nsXFormsModelElement::GetMDG(nsXFormsMDGEngine **aMDG) +{ + if (aMDG) + *aMDG = &mMDG; + return NS_OK; +} + // internal methods already_AddRefed @@ -702,7 +831,7 @@ nsXFormsModelElement::FinishConstruction() if (localName.EqualsLiteral("bind")) { child->GetNamespaceURI(namespaceURI); if (namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS)) { - if (!ProcessBind(xpath, firstInstanceRoot, nsnull, + if (!ProcessBind(xpath, firstInstanceRoot, 1, 1, nsCOMPtr(do_QueryInterface(child)))) { return NS_OK; } @@ -768,7 +897,8 @@ ReleaseExpr(void *aElement, PRBool nsXFormsModelElement::ProcessBind(nsIDOMXPathEvaluator *aEvaluator, nsIDOMNode *aContextNode, - nsIDOMXPathResult *aOuterNodeset, + PRInt32 aContextPosition, + PRInt32 aContextSize, nsIDOMElement *aBindElement) { // Get the model item properties specified by this . @@ -803,27 +933,28 @@ nsXFormsModelElement::ProcessBind(nsIDOMXPathEvaluator *aEvaluator, nsAutoString expr; aBindElement->GetAttribute(NS_LITERAL_STRING("nodeset"), expr); if (expr.IsEmpty()) { - result = aOuterNodeset; - } else { - rv = aEvaluator->Evaluate(expr, aContextNode, resolver, - nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, - nsnull, getter_AddRefs(result)); - if (NS_FAILED(rv)) { - nsXFormsUtils::DispatchEvent(mElement, eEvent_BindingException); - return PR_FALSE; // dispatch a binding exception - } - + expr = NS_LITERAL_STRING("."); } + /// + /// @todo use aContextSize and aContextPosition in evaluation (XXX) + rv = aEvaluator->Evaluate(expr, aContextNode, resolver, + nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, + nsnull, getter_AddRefs(result)); + if (NS_FAILED(rv)) + return PR_FALSE; // dispatch a binding exception + NS_ENSURE_TRUE(result, PR_FALSE); PRUint32 snapLen; rv = result->GetSnapshotLength(&snapLen); NS_ENSURE_SUCCESS(rv, rv); + + // Iterate over resultset nsXFormsMDGSet set; nsCOMPtr node; - PRInt32 contextPosition = 1; - for (PRUint32 snapItem = 0; snapItem < snapLen; ++snapItem) { + PRUint32 snapItem; + for (snapItem = 0; snapItem < snapLen; ++snapItem) { rv = result->SnapshotItem(snapItem, getter_AddRefs(node)); NS_ENSURE_SUCCESS(rv, rv); @@ -832,10 +963,10 @@ nsXFormsModelElement::ProcessBind(nsIDOMXPathEvaluator *aEvaluator, continue; } + + // Apply MIPs nsXFormsXPathParser parser; nsXFormsXPathAnalyzer analyzer(aEvaluator, resolver); - - // We must check whether the properties already exist on the node. for (int j = 0; j < eModel__count; ++j) { if (props[j]) { nsCOMPtr content = do_QueryInterface(node, &rv); @@ -862,40 +993,39 @@ nsXFormsModelElement::ProcessBind(nsIDOMXPathEvaluator *aEvaluator, // Insert into MDG rv = mMDG.AddMIP((ModelItemPropName) j, expr, &set, parser.UsesDynamicFunc(), - node, contextPosition++, snapLen); + node, snapItem + 1, snapLen); NS_ENSURE_SUCCESS(rv, rv); } } - } - // Now evaluate any child elements. - nsCOMPtr childContext; - result->SnapshotItem(0, getter_AddRefs(childContext)); - nsCOMPtr children; - aBindElement->GetChildNodes(getter_AddRefs(children)); - if (children) { - PRUint32 childCount = 0; - children->GetLength(&childCount); - - nsCOMPtr child; - nsAutoString value; - - for (PRUint32 k = 0; k < childCount; ++k) { - children->Item(k, getter_AddRefs(child)); - if (child) { - child->GetLocalName(value); - if (!value.EqualsLiteral("bind")) - continue; - - child->GetNamespaceURI(value); - if (!value.EqualsLiteral(NS_NAMESPACE_XFORMS)) - continue; - - if (!ProcessBind(aEvaluator, childContext, result, - nsCOMPtr(do_QueryInterface(child)))) - return PR_FALSE; + // Now evaluate any child elements. + nsCOMPtr children; + aBindElement->GetChildNodes(getter_AddRefs(children)); + if (children) { + PRUint32 childCount = 0; + children->GetLength(&childCount); + + nsCOMPtr child; + nsAutoString value; + + for (PRUint32 k = 0; k < childCount; ++k) { + children->Item(k, getter_AddRefs(child)); + if (child) { + child->GetLocalName(value); + if (!value.EqualsLiteral("bind")) + continue; + + child->GetNamespaceURI(value); + if (!value.EqualsLiteral(NS_NAMESPACE_XFORMS)) + continue; + if (!ProcessBind(aEvaluator, node, + snapItem + 1, snapLen, + nsCOMPtr(do_QueryInterface(child)))) + return PR_FALSE; + + } } } } diff --git a/mozilla/extensions/xforms/nsXFormsModelElement.h b/mozilla/extensions/xforms/nsXFormsModelElement.h index b8b3578183b..8ea86ec0fbf 100644 --- a/mozilla/extensions/xforms/nsXFormsModelElement.h +++ b/mozilla/extensions/xforms/nsXFormsModelElement.h @@ -65,6 +65,9 @@ class nsXFormsControl; * initializing the model and its controls. * * @see http://www.w3.org/TR/xforms/slice3.html#structure-model + * + * @todo We need to dispatch the initial (default) events to controls (XXX) + * */ class nsXFormsModelElement : public nsXFormsStubElement, public nsIModelElementPrivate, @@ -103,11 +106,19 @@ private: NS_HIDDEN_(PRBool) ProcessBind(nsIDOMXPathEvaluator *aEvaluator, nsIDOMNode *aContextNode, - nsIDOMXPathResult *aOuterNodeset, + PRInt32 aContextPosition, + PRInt32 aContextSize, nsIDOMElement *aBindElement); NS_HIDDEN_(void) RemoveModelFromDocument(); + /** + * Dispatch the necessary events to a control, aControl, when the instance + * node, aNode, it is bound to changes state. + */ + NS_HIDDEN_(void) DispatchEvents(nsIXFormsControl *aControl, + nsIDOMNode *aNode); + // Returns true when all external documents have been loaded PRBool IsComplete() const { return (mSchemaTotal == mSchemaCount && mPendingInstanceCount == 0); } @@ -121,8 +132,12 @@ private: PRInt32 mSchemaTotal; PRInt32 mPendingInstanceCount; + /** The MDG for this model */ nsXFormsMDGEngine mMDG; + /** List of changed nodes, ie. nodes that have not been informed about changes yet */ + nsXFormsMDGSet mChangedNodes; + // This flag indicates whether or not the document fired DOMContentLoaded PRBool mDocumentLoaded; }; diff --git a/mozilla/extensions/xforms/nsXFormsNodeState.cpp b/mozilla/extensions/xforms/nsXFormsNodeState.cpp new file mode 100644 index 00000000000..cb40c36a48f --- /dev/null +++ b/mozilla/extensions/xforms/nsXFormsNodeState.cpp @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla XForms support. + * + * The Initial Developer of the Original Code is + * Novell, Inc. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Allan Beaufour + * David Landwehr + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsXFormsNodeState.h" + +void +nsXFormsNodeState::Set(PRUint16 aFlags, PRBool aVal) +{ + if (aVal) { + mState |= aFlags; + } else { + mState &= ~aFlags; + } +} + +nsXFormsNodeState& +nsXFormsNodeState::operator&=(PRUint16 aMask) +{ + mState &= aMask; + return *this; +} + +PRBool +nsXFormsNodeState::operator==(nsXFormsNodeState& aCmp) const +{ + return (mState == aCmp.mState) ? PR_TRUE : PR_FALSE; +} + +PRBool +nsXFormsNodeState::TestAndClear(eFlag_t aFlag) +{ + PRUint16 test = mState & aFlag; + mState &= ~aFlag; + return test ? PR_TRUE : PR_FALSE; +} + +PRBool +nsXFormsNodeState::TestAndSet(eFlag_t aFlag) +{ + PRUint16 test = mState & aFlag; + mState |= aFlag; + return test ? PR_TRUE : PR_FALSE; +} + +PRBool +nsXFormsNodeState::Test(eFlag_t aFlag) const +{ + return (mState & aFlag) ? PR_TRUE : PR_FALSE; +} + +PRBool +nsXFormsNodeState::IsValid() const +{ + // constraints determine the validity of a node + /// + /// @todo needs Schema support (XXX) + return Test(eFlag_CONSTRAINT); +} + +#ifdef DEBUG_XF_NODESTATE +const char* flagnames[] = {0, + "eFlag_READONLY", + "eFlag_CONSTRAINT", + "eFlag_RELEVANT", + "eFlag_REQUIRED", + "eFlag_SCHEMA_VALID", + "eFlag_VALID", + "eFlag_INHERITED_RELEVANT", + "eFlag_INHERITED_READONLY", + "eFlag_DISPATCH_VALUE_CHANGED", + "eFlag_DISPATCH_READONLY_CHANGED", + "eFlag_DISPATCH_VALID_CHANGED", + "eFlag_DISPATCH_RELEVANT_CHANGED", + "eFlag_DISPATCH_REQUIRED_CHANGED", + "eFlag_DISPATCH_CONSTRAINT_CHANGED", + 0}; + + + +#include + +void +nsXFormsNodeState::PrintFlags() const +{ + int pos = 1; + while (flagnames[pos]) { + if (mState & (1 << pos)) { + printf("\t%s\n", flagnames[pos]); + } + ++pos; + } +} +#endif diff --git a/mozilla/extensions/xforms/nsXFormsNodeState.h b/mozilla/extensions/xforms/nsXFormsNodeState.h new file mode 100644 index 00000000000..1693db41e73 --- /dev/null +++ b/mozilla/extensions/xforms/nsXFormsNodeState.h @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla XForms support. + * + * The Initial Developer of the Original Code is + * Novell, Inc. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Allan Beaufour + * David Landwehr + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef __NSXFORMSNODESTATE_H__ +#define __NSXFORMSNODESTATE_H__ + +#include "nscore.h" + +#ifdef DEBUG +#//define DEBUG_XF_NODESTATE +#endif + +/** Flags used in nsXFormsNodeState */ +enum eFlag_t { + // The different states + eFlag_READONLY = 1 << 1, + eFlag_CONSTRAINT = 1 << 2, + eFlag_RELEVANT = 1 << 3, + eFlag_REQUIRED = 1 << 4, + eFlag_SCHEMA_VALID = 1 << 5, + eFlag_INHERITED_RELEVANT = 1 << 6, + eFlag_INHERITED_READONLY = 1 << 7, + // Events to be dispatched + eFlag_DISPATCH_VALUE_CHANGED = 1 << 8, + eFlag_DISPATCH_READONLY_CHANGED = 1 << 9, + eFlag_DISPATCH_VALID_CHANGED = 1 << 10, + eFlag_DISPATCH_RELEVANT_CHANGED = 1 << 11, + eFlag_DISPATCH_REQUIRED_CHANGED = 1 << 12, + eFlag_DISPATCH_CONSTRAINT_CHANGED = 1 << 13 +}; + +// Default flags set for new states +const PRUint16 kFlags_DEFAULT = + (eFlag_CONSTRAINT | // The node is valid + eFlag_RELEVANT | // The node is relevant + eFlag_INHERITED_RELEVANT); // Children should inherit relevant + +// The events dispatched for newly created models +const PRUint16 kFlags_INITIAL_DISPATCH = + (eFlag_DISPATCH_READONLY_CHANGED | + eFlag_DISPATCH_VALID_CHANGED | + eFlag_DISPATCH_RELEVANT_CHANGED | + eFlag_DISPATCH_REQUIRED_CHANGED); + +// All dispatch flags +const PRUint16 kFlags_ALL_DISPATCH = + (eFlag_DISPATCH_READONLY_CHANGED | + eFlag_DISPATCH_VALID_CHANGED | + eFlag_DISPATCH_RELEVANT_CHANGED | + eFlag_DISPATCH_REQUIRED_CHANGED | + eFlag_DISPATCH_VALUE_CHANGED | + eFlag_DISPATCH_CONSTRAINT_CHANGED); + +// All but dispatch flags +const PRUint16 kFlags_NOT_DISPATCH = ~kFlags_ALL_DISPATCH; + +/** + * Holds the current state of a MDG node. + * + * That is, whether the node is readonly, relevant, etc., and also information + * about which events that should be dispatched to any controls bound to the + * node. + */ +class nsXFormsNodeState +{ +private: + /** The node state, bit vector of eFlag_t */ + PRUint16 mState; + +public: + /** + * Constructor. + * + * @param aInitialState The initial state of this + */ + nsXFormsNodeState(PRUint16 aInitialState = kFlags_DEFAULT) + : mState(aInitialState) {}; + + /** + * Sets flag(s) on or off + * + * @param aFlags The flag(s) to set + * @param aVal The flag value + */ + void Set(PRUint16 aFlags, + PRBool aVal); + + /** + * And own state with a bit mask. + * + * @param aMask Bit mask + * @return New value + */ + nsXFormsNodeState& operator&=(PRUint16 aMask); + + /** + * Comparator. + * + * @param aCmp Object to compare with + * @return Objects equal? + */ + PRBool operator==(nsXFormsNodeState& aCmp) const; + + /** + * Get flag state and clear flag. + * + * @param aFlag The flag + * @return The flag state + */ + PRBool TestAndClear(eFlag_t aFlags); + + /** + * Get flag state and set flag. + * + * @param aFlag The flag + * @return The flag state + */ + PRBool TestAndSet(eFlag_t aFlags); + + /** + * Get flag state + * + * @param aFlag The flag + * @return The flag state + */ + PRBool Test(eFlag_t aFlags) const; + + // Check states + PRBool IsValid() const; + + PRBool IsConstraint() const + { return Test(eFlag_CONSTRAINT); }; + PRBool IsReadonly() const + { return Test(eFlag_READONLY) | + Test(eFlag_INHERITED_READONLY); }; + PRBool IsRelevant() const + { return Test(eFlag_RELEVANT) && + Test(eFlag_INHERITED_RELEVANT); }; + PRBool IsRequired() const + { return Test(eFlag_REQUIRED); }; + + // Check events + PRBool ShouldDispatchReadonly() const + { return Test(eFlag_DISPATCH_READONLY_CHANGED); }; + PRBool ShouldDispatchRelevant() const + { return Test(eFlag_DISPATCH_RELEVANT_CHANGED); }; + PRBool ShouldDispatchValid() const + { return Test(eFlag_DISPATCH_VALID_CHANGED); }; + PRBool ShouldDispatchRequired() const + { return Test(eFlag_DISPATCH_REQUIRED_CHANGED); }; + PRBool ShouldDispatchValueChanged() const + { return Test(eFlag_DISPATCH_VALUE_CHANGED); }; + +#ifdef DEBUG_XF_NODESTATE + /** Print the flags currently set to stdout */ + void PrintFlags() const; +#endif +}; + +#endif diff --git a/mozilla/extensions/xforms/nsXFormsOutputElement.cpp b/mozilla/extensions/xforms/nsXFormsOutputElement.cpp index 5b44f0b25d9..825bd4ffa8b 100755 --- a/mozilla/extensions/xforms/nsXFormsOutputElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsOutputElement.cpp @@ -40,7 +40,6 @@ //#define DEBUG_XF_OUTPUT #endif -#include "nsXFormsStubElement.h" #include "nsIXTFXMLVisualWrapper.h" #include "nsAutoPtr.h" @@ -57,7 +56,7 @@ #include "nsISchema.h" #include "nsIModelElementPrivate.h" -#include "nsIXFormsControl.h" +#include "nsXFormsControlStub.h" #include "nsXFormsAtoms.h" #include "nsXFormsUtils.h" @@ -66,8 +65,7 @@ * * @see http://www.w3.org/TR/xforms/slice8.html#ui-output */ -class nsXFormsOutputElement : public nsXFormsXMLVisualStub, - public nsIXFormsControl +class nsXFormsOutputElement : public nsXFormsControlStub { public: NS_DECL_ISUPPORTS_INHERITED @@ -81,19 +79,18 @@ public: // nsIXTFElement overrides NS_IMETHOD OnDestroyed(); - NS_IMETHOD DocumentChanged(nsIDOMDocument *aNewDocument); - NS_IMETHOD ParentChanged(nsIDOMElement *aNewParent); NS_IMETHOD WillSetAttribute(nsIAtom *aName, const nsAString &aValue); NS_IMETHOD AttributeSet(nsIAtom *aName, const nsAString &aValue); // nsIXFormsControl - NS_DECL_NSIXFORMSCONTROL - - nsXFormsOutputElement() : mElement(nsnull) {} + NS_IMETHOD Bind(); + NS_IMETHOD Refresh(); private: - nsCOMPtr mHTMLElement; - nsIDOMElement *mElement; + nsCOMPtr mLabel; + nsCOMPtr mContainer; + nsCOMPtr mValue; + PRBool mHasBinding; }; NS_IMPL_ISUPPORTS_INHERITED1(nsXFormsOutputElement, @@ -108,33 +105,45 @@ nsXFormsOutputElement::OnCreated(nsIXTFXMLVisualWrapper *aWrapper) #ifdef DEBUG_XF_OUTPUT printf("nsXFormsOutputElement::OnCreated()\n"); #endif - aWrapper->SetNotificationMask(nsIXTFElement::NOTIFY_WILL_SET_ATTRIBUTE | - nsIXTFElement::NOTIFY_ATTRIBUTE_SET | - nsIXTFElement::NOTIFY_DOCUMENT_CHANGED | - nsIXTFElement::NOTIFY_PARENT_CHANGED); - nsresult rv; - - nsCOMPtr node; - rv = aWrapper->GetElementNode(getter_AddRefs(node)); + nsresult rv = nsXFormsControlStub::OnCreated(aWrapper); NS_ENSURE_SUCCESS(rv, rv); - // It's ok to keep a weak pointer to mElement. mElement will have an - // owning reference to this object, so as long as we null out mElement in - // OnDestroyed, it will always be valid. + /* input uses as the container, but output does't need the + additional features html:label gives, so just use a html:span. + */ - mElement = node; - NS_ASSERTION(mElement, "Wrapper is not an nsIDOMElement, we'll crash soon"); + // Our anonymous content structure will look like this: + // + // (mContainer) + // (mLabel) + // (mValue) + // + + nsCOMPtr childReturn; nsCOMPtr domDoc; - rv = node->GetOwnerDocument(getter_AddRefs(domDoc)); + rv = mElement->GetOwnerDocument(getter_AddRefs(domDoc)); NS_ENSURE_SUCCESS(rv, rv); + domDoc->CreateElementNS(NS_LITERAL_STRING(NS_NAMESPACE_XHTML), + NS_LITERAL_STRING("span"), + getter_AddRefs(mContainer)); + NS_ENSURE_STATE(mContainer); + rv = domDoc->CreateElementNS(NS_LITERAL_STRING(NS_NAMESPACE_XHTML), NS_LITERAL_STRING("span"), - getter_AddRefs(mHTMLElement)); + getter_AddRefs(mLabel)); + NS_ENSURE_STATE(mLabel); - NS_ENSURE_SUCCESS(rv, rv); + mContainer->AppendChild(mLabel, getter_AddRefs(childReturn)); + + rv = domDoc->CreateElementNS(NS_LITERAL_STRING(NS_NAMESPACE_XHTML), + NS_LITERAL_STRING("span"), + getter_AddRefs(mValue)); + NS_ENSURE_STATE(mValue); + + mContainer->AppendChild(mValue, getter_AddRefs(childReturn)); return NS_OK; } @@ -144,15 +153,16 @@ nsXFormsOutputElement::OnCreated(nsIXTFXMLVisualWrapper *aWrapper) NS_IMETHODIMP nsXFormsOutputElement::GetVisualContent(nsIDOMElement **aElement) { - NS_IF_ADDREF(*aElement = mHTMLElement); + NS_IF_ADDREF(*aElement = mContainer); return NS_OK; } NS_IMETHODIMP nsXFormsOutputElement::GetInsertionPoint(nsIDOMElement **aElement) { - NS_IF_ADDREF(*aElement = mHTMLElement); - return NS_OK; + nsCOMPtr childNode; + mContainer->GetFirstChild(getter_AddRefs(childNode)); + return CallQueryInterface(childNode, aElement); } // nsIXTFElement @@ -160,39 +170,20 @@ nsXFormsOutputElement::GetInsertionPoint(nsIDOMElement **aElement) NS_IMETHODIMP nsXFormsOutputElement::OnDestroyed() { - mElement = nsnull; - mHTMLElement = nsnull; - - return NS_OK; -} + mLabel = nsnull; + mContainer = nsnull; + mValue = nsnull; -NS_IMETHODIMP -nsXFormsOutputElement::DocumentChanged(nsIDOMDocument *aNewDocument) -{ - // We need to re-evaluate our instance data binding when our document - // changes, since our context can change - if (aNewDocument) - Refresh(); - - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsOutputElement::ParentChanged(nsIDOMElement *aNewParent) -{ - // We need to re-evaluate our instance data binding when our parent changes, - // since xmlns declarations or our context could have changed. - if (aNewParent) { - Refresh(); - } - - return NS_OK; + return nsXFormsControlStub::OnDestroyed(); } NS_IMETHODIMP nsXFormsOutputElement::WillSetAttribute(nsIAtom *aName, const nsAString &aValue) { - if (aName == nsXFormsAtoms::bind || aName == nsXFormsAtoms::ref) { + if (aName == nsXFormsAtoms::bind || + aName == nsXFormsAtoms::ref || + aName == nsXFormsAtoms::model || + aName == nsXFormsAtoms::value) { nsCOMPtr modelNode = nsXFormsUtils::GetModel(mElement); nsCOMPtr model = do_QueryInterface(modelNode); @@ -206,7 +197,11 @@ nsXFormsOutputElement::WillSetAttribute(nsIAtom *aName, const nsAString &aValue) NS_IMETHODIMP nsXFormsOutputElement::AttributeSet(nsIAtom *aName, const nsAString &aValue) { - if (aName == nsXFormsAtoms::bind || aName == nsXFormsAtoms::ref) { + if (aName == nsXFormsAtoms::bind || + aName == nsXFormsAtoms::ref || + aName == nsXFormsAtoms::model || + aName == nsXFormsAtoms::value) { + Bind(); Refresh(); } @@ -215,67 +210,77 @@ nsXFormsOutputElement::AttributeSet(nsIAtom *aName, const nsAString &aValue) // nsIXFormsControl -NS_IMETHODIMP -nsXFormsOutputElement::Refresh() +nsresult +nsXFormsOutputElement::Bind() { -#ifdef DEBUG_XF_OUTPUT - printf("nsXFormsOutputElement::Refresh()\n"); -#endif - if (!mHTMLElement) + if (!mValue) return NS_OK; + + mBoundNode = nsnull; nsresult rv; - PRBool hasRef; - rv = mElement->HasAttribute(NS_LITERAL_STRING("ref"), &hasRef); + rv = mElement->HasAttribute(NS_LITERAL_STRING("ref"), &mHasBinding); NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr modelNode; - nsCOMPtr bindElement; - nsCOMPtr result; - if (hasRef) { - result = nsXFormsUtils::EvaluateNodeBinding(mElement, - nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR, - NS_LITERAL_STRING("ref"), - EmptyString(), - nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, - getter_AddRefs(modelNode), - getter_AddRefs(bindElement)); - } else { - result = nsXFormsUtils::EvaluateNodeBinding(mElement, - nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR, - NS_LITERAL_STRING("value"), - EmptyString(), - nsIDOMXPathResult::STRING_TYPE, - getter_AddRefs(modelNode), - getter_AddRefs(bindElement)); + if (!mHasBinding) { + rv = mElement->HasAttribute(NS_LITERAL_STRING("bind"), &mHasBinding); + NS_ENSURE_SUCCESS(rv, rv); } - nsCOMPtr model = do_QueryInterface(modelNode); + nsCOMPtr result; + if (mHasBinding) { + rv = ProcessNodeBinding(NS_LITERAL_STRING("ref"), + nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, + getter_AddRefs(result)); + } else { + rv = ProcessNodeBinding(NS_LITERAL_STRING("value"), + nsIDOMXPathResult::STRING_TYPE, + getter_AddRefs(result)); + } + + NS_ENSURE_SUCCESS(rv, rv); - if (model) { - model->AddFormControl(this); - if (result) { - nsAutoString text; - - if (hasRef) { - nsCOMPtr resultNode; - rv = result->GetSingleNodeValue(getter_AddRefs(resultNode)); - if (resultNode) - nsXFormsUtils::GetNodeValue(resultNode, text); - } else { - rv = result->GetStringValue(text); - } - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr dom3Node = do_QueryInterface(mHTMLElement); - NS_ENSURE_STATE(dom3Node); - rv = dom3Node->SetTextContent(text); - NS_ENSURE_SUCCESS(rv, rv); - } + if (result) { + result->GetSingleNodeValue(getter_AddRefs(mBoundNode)); } return NS_OK; } + +NS_IMETHODIMP +nsXFormsOutputElement::Refresh() +{ + if (!mValue) + return NS_OK; + + nsAutoString text; + nsresult rv; + if (mHasBinding) { + if (mBoundNode) { + nsXFormsUtils::GetNodeValue(mBoundNode, text); + } + } else { + /// + /// @todo Update mBoundNode? (XXX) + nsCOMPtr result; + rv = ProcessNodeBinding(NS_LITERAL_STRING("value"), + nsIDOMXPathResult::STRING_TYPE, + getter_AddRefs(result)); + NS_ENSURE_SUCCESS(rv, rv); + + if (result) { + rv = result->GetStringValue(text); + NS_ENSURE_SUCCESS(rv, rv); + } + } + + nsCOMPtr dom3Node = do_QueryInterface(mValue); + NS_ENSURE_STATE(dom3Node); + + rv = dom3Node->SetTextContent(text); + + return rv; +} + NS_HIDDEN_(nsresult) NS_NewXFormsOutputElement(nsIXTFElement **aResult) diff --git a/mozilla/extensions/xforms/nsXFormsRepeatElement.cpp b/mozilla/extensions/xforms/nsXFormsRepeatElement.cpp index a777d2b4f64..c7f6fec0978 100644 --- a/mozilla/extensions/xforms/nsXFormsRepeatElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsRepeatElement.cpp @@ -56,11 +56,10 @@ #include "nsIDOMHTMLDivElement.h" #include "nsIDOMXPathResult.h" -#include "nsIXFormsControl.h" +#include "nsXFormsControlStub.h" #include "nsIXFormsContextControl.h" #include "nsXFormsAtoms.h" #include "nsXFormsModelElement.h" -#include "nsXFormsStubElement.h" #include "nsXFormsUtils.h" #ifdef DEBUG @@ -121,13 +120,9 @@ * \ * @see http://www.w3.org/TR/xforms/index-all.html#ui.repeat.via.attrs */ -class nsXFormsRepeatElement : public nsIXFormsControl, - public nsXFormsXMLVisualStub +class nsXFormsRepeatElement : public nsXFormsControlStub { protected: - /** The DOM element for the node */ - nsCOMPtr mElement; - /** The HTML representation for the node */ nsCOMPtr mHTMLElement; @@ -148,9 +143,6 @@ protected: public: NS_DECL_ISUPPORTS_INHERITED - /** Constructor */ - nsXFormsRepeatElement(); - // nsIXTFXMLVisual overrides NS_IMETHOD OnCreated(nsIXTFXMLVisualWrapper *aWrapper); @@ -164,7 +156,7 @@ public: NS_IMETHOD DoneAddingChildren(); // nsIXFormsControl - NS_DECL_NSIXFORMSCONTROL + NS_IMETHOD Refresh(); }; NS_IMPL_ISUPPORTS_INHERITED1(nsXFormsRepeatElement, @@ -172,11 +164,6 @@ NS_IMPL_ISUPPORTS_INHERITED1(nsXFormsRepeatElement, nsIXFormsControl) -nsXFormsRepeatElement::nsXFormsRepeatElement() - : mElement(nsnull) -{ -} - // nsIXTFXMLVisual NS_IMETHODIMP nsXFormsRepeatElement::OnCreated(nsIXTFXMLVisualWrapper *aWrapper) @@ -246,7 +233,9 @@ nsXFormsRepeatElement::WillSetAttribute(nsIAtom *aName, const nsAString &aValue) printf("nsXFormsRepeatElement::WillSetAttribute(aName=%p, aValue='%s')\n", (void*) aName, NS_ConvertUCS2toUTF8(aValue).get()); #endif - if (aName == nsXFormsAtoms::bind || aName == nsXFormsAtoms::ref) { + if (aName == nsXFormsAtoms::bind || + aName == nsXFormsAtoms::nodeset || + aName == nsXFormsAtoms::model) { nsCOMPtr modelNode = nsXFormsUtils::GetModel(mElement); nsCOMPtr model = do_QueryInterface(modelNode); @@ -265,7 +254,9 @@ nsXFormsRepeatElement::AttributeSet(nsIAtom *aName, const nsAString &aValue) printf("nsXFormsRepeatElement::AttributeSet(aName=%p, aValue=%s)\n", (void*) aName, NS_ConvertUCS2toUTF8(aValue).get()); #endif - if (aName == nsXFormsAtoms::bind || aName == nsXFormsAtoms::nodeset) { + if (aName == nsXFormsAtoms::bind || + aName == nsXFormsAtoms::nodeset || + aName == nsXFormsAtoms::model) { Refresh(); } @@ -288,7 +279,8 @@ nsXFormsRepeatElement::DoneAddingChildren() // nsXFormsControl -nsresult + +NS_IMETHODIMP nsXFormsRepeatElement::Refresh() { #ifdef DEBUG_XF_REPEAT @@ -310,134 +302,125 @@ nsXFormsRepeatElement::Refresh() } // Get the nodeset we are bound to - nsCOMPtr modelNode; - nsCOMPtr bindElement; - nsCOMPtr result = - nsXFormsUtils::EvaluateNodeBinding(mElement, - nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR, - NS_LITERAL_STRING("nodeset"), - EmptyString(), - nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, - getter_AddRefs(modelNode), - getter_AddRefs(bindElement)); + nsCOMPtr result; + nsCOMPtr model; + rv = ProcessNodeBinding(NS_LITERAL_STRING("nodeset"), + nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, + getter_AddRefs(result), + getter_AddRefs(model)); - if (!result) { - return NS_OK; + if (NS_FAILED(rv) | !result) { + return rv; } - nsCOMPtr model = do_QueryInterface(modelNode); - /// @todo The result should be a _homogenous_ collection (spec. 9.3.1), /// do/can/should we check this? (XXX) PRUint32 contextSize; rv = result->GetSnapshotLength(&contextSize); NS_ENSURE_SUCCESS(rv, rv); - if (model) { - model->AddFormControl(this); - if (result && contextSize > 0) { - // Get model ID - nsCOMPtr modelElement = do_QueryInterface(modelNode); - NS_ENSURE_TRUE(modelElement, NS_ERROR_FAILURE); - nsAutoString modelID; - modelElement->GetAttribute(NS_LITERAL_STRING("id"), modelID); + if (model && contextSize > 0) { + // Get model ID + nsCOMPtr modelElement = do_QueryInterface(model); + NS_ENSURE_TRUE(modelElement, NS_ERROR_FAILURE); + nsAutoString modelID; + modelElement->GetAttribute(NS_LITERAL_STRING("id"), modelID); - // Get attributes - PRUint32 startIndex; - rv = GetIntAttr(NS_LITERAL_STRING("startIndex"), - (PRInt32*) &startIndex, - nsISchemaBuiltinType::BUILTIN_TYPE_POSITIVEINTEGER); - if (NS_FAILED(rv)) { - if (rv == NS_ERROR_NOT_AVAILABLE) { - startIndex = 1; - } else { - return rv; - } + // Get attributes + PRUint32 startIndex; + rv = GetIntAttr(NS_LITERAL_STRING("startIndex"), + (PRInt32*) &startIndex, + nsISchemaBuiltinType::BUILTIN_TYPE_POSITIVEINTEGER); + if (NS_FAILED(rv)) { + if (rv == NS_ERROR_NOT_AVAILABLE) { + startIndex = 1; + } else { + return rv; } + } - PRUint32 number; - rv = GetIntAttr(NS_LITERAL_STRING("number"), - (PRInt32*) &number, - nsISchemaBuiltinType::BUILTIN_TYPE_NONNEGATIVEINTEGER); - if (NS_FAILED(rv)) { - if (rv == NS_ERROR_NOT_AVAILABLE) { - number = contextSize; - } else { - return rv; - } + PRUint32 number; + rv = GetIntAttr(NS_LITERAL_STRING("number"), + (PRInt32*) &number, + nsISchemaBuiltinType::BUILTIN_TYPE_NONNEGATIVEINTEGER); + if (NS_FAILED(rv)) { + if (rv == NS_ERROR_NOT_AVAILABLE) { + number = contextSize; + } else { + return rv; } - // Get DOM document - nsCOMPtr domDoc; - rv = mHTMLElement->GetOwnerDocument(getter_AddRefs(domDoc)); + } + // Get DOM document + nsCOMPtr domDoc; + rv = mHTMLElement->GetOwnerDocument(getter_AddRefs(domDoc)); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString strSize; + strSize.AppendInt(contextSize); + + // The spec. states the following for startIndex: "Optional 1-based + // initial value of the repeat index", I interpret this as "start + // showing element at position |startIndex|". So I iterate over the + // interval [max(1, startIndex),min(contextSize, number + startIndex)[ + for (PRUint32 i = NS_MAX((PRUint32) 1, startIndex); + i < NS_MIN(contextSize + 1, number + startIndex); + ++i) { + // Create + nsCOMPtr riElement; + rv = domDoc->CreateElementNS(NS_LITERAL_STRING("http://www.w3.org/2002/xforms"), + NS_LITERAL_STRING("contextcontainer"), + getter_AddRefs(riElement)); + NS_ENSURE_SUCCESS(rv, rv); + + // Set context size, context position, and model as attributes + if (!modelID.IsEmpty()) { + riElement->SetAttribute(NS_LITERAL_STRING("model"), modelID); + } + nsAutoString strPos; strPos.AppendInt(i); + riElement->SetAttribute(NS_LITERAL_STRING("contextposition"), strPos); + riElement->SetAttribute(NS_LITERAL_STRING("contextsize"), strSize); + + // Get and set context node + nsCOMPtr riContext = do_QueryInterface(riElement); + NS_ENSURE_TRUE(riContext, NS_ERROR_FAILURE); + + nsCOMPtr contextNode; + rv = result->SnapshotItem(i - 1, getter_AddRefs(contextNode)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr contextElement = do_QueryInterface(contextNode); + NS_ENSURE_TRUE(contextElement, NS_ERROR_FAILURE); + + rv = riContext->SetContextNode(contextElement); NS_ENSURE_SUCCESS(rv, rv); - nsAutoString strSize; - strSize.AppendInt(contextSize); - - // The spec. states the following for startIndex: "Optional 1-based - // initial value of the repeat index", I interpret this as "start - // showing element at position |startIndex|". So I iterate over the - // interval [max(1, startIndex),min(contextSize, number + startIndex)[ - for (PRUint32 i = NS_MAX((PRUint32) 1, startIndex); - i < NS_MIN(contextSize + 1, number + startIndex); - ++i) { - // Create - nsCOMPtr riElement; - rv = domDoc->CreateElementNS(NS_LITERAL_STRING("http://www.w3.org/2002/xforms"), - NS_LITERAL_STRING("contextcontainer"), - getter_AddRefs(riElement)); - NS_ENSURE_SUCCESS(rv, rv); - - // Set context size, context position, and model as attributes - if (!modelID.IsEmpty()) { - riElement->SetAttribute(NS_LITERAL_STRING("model"), modelID); - } - nsAutoString strPos; strPos.AppendInt(i); - riElement->SetAttribute(NS_LITERAL_STRING("contextposition"), strPos); - riElement->SetAttribute(NS_LITERAL_STRING("contextsize"), strSize); - - // Get and set context node - nsCOMPtr riContext = do_QueryInterface(riElement); - NS_ENSURE_TRUE(riContext, NS_ERROR_FAILURE); - - nsCOMPtr contextNode; - rv = result->SnapshotItem(i - 1, getter_AddRefs(contextNode)); + // Iterate over template children, clone them, and append them to + nsCOMPtr child; + rv = mElement->GetFirstChild(getter_AddRefs(child)); + NS_ENSURE_SUCCESS(rv, rv); + while (child) { + nsCOMPtr childClone; + rv = child->CloneNode(PR_TRUE, getter_AddRefs(childClone)); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr contextElement = do_QueryInterface(contextNode); - NS_ENSURE_TRUE(contextElement, NS_ERROR_FAILURE); - - rv = riContext->SetContextNode(contextElement); + nsCOMPtr newNode; + rv = riElement->AppendChild(childClone, getter_AddRefs(newNode)); NS_ENSURE_SUCCESS(rv, rv); - - // Iterate over template children, clone them, and append them to - nsCOMPtr child; - rv = mElement->GetFirstChild(getter_AddRefs(child)); - NS_ENSURE_SUCCESS(rv, rv); - while (child) { - nsCOMPtr childClone; - rv = child->CloneNode(PR_TRUE, getter_AddRefs(childClone)); - NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr newNode; - rv = riElement->AppendChild(childClone, getter_AddRefs(newNode)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = child->GetNextSibling(getter_AddRefs(newNode)); - NS_ENSURE_SUCCESS(rv, rv); - child = newNode; - } - - // Append node - nsCOMPtr domNode; - rv = mHTMLElement->AppendChild(riElement, getter_AddRefs(domNode)); + rv = child->GetNextSibling(getter_AddRefs(newNode)); NS_ENSURE_SUCCESS(rv, rv); - - // There is an awfull lot of evaluating being done by all the - // children, as they are created and inserted into the different - // places in the DOM, the only refresh necessary is the one when they - // are appended in mHTMLElement. + child = newNode; } + + // Append node + nsCOMPtr domNode; + rv = mHTMLElement->AppendChild(riElement, getter_AddRefs(domNode)); + NS_ENSURE_SUCCESS(rv, rv); + + // There is an awfull lot of evaluating being done by all the + // children, as they are created and inserted into the different + // places in the DOM, the only refresh necessary is the one when they + // are appended in mHTMLElement. } } diff --git a/mozilla/extensions/xforms/nsXFormsSchemaValidator.cpp b/mozilla/extensions/xforms/nsXFormsSchemaValidator.cpp new file mode 100644 index 00000000000..77edb01d0bc --- /dev/null +++ b/mozilla/extensions/xforms/nsXFormsSchemaValidator.cpp @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla XForms Schema Validation. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Doron Rosenberg (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// XPCOM includes +#include "nsIServiceManager.h" + +#include "nsISchemaValidator.h" +#include "nsXFormsSchemaValidator.h" + +#define NS_SCHEMAVALIDATOR_CONTRACTID "@mozilla.org/schemavalidator;1" + +nsXFormsSchemaValidator::nsXFormsSchemaValidator() +{ + mSchemaValidator = do_GetService(NS_SCHEMAVALIDATOR_CONTRACTID); +} + +nsresult nsXFormsSchemaValidator::LoadSchema(nsISchema* aSchema) +{ + NS_ENSURE_TRUE(mSchemaValidator, NS_ERROR_UNEXPECTED); + + return mSchemaValidator->LoadSchema(aSchema); +} + +PRBool nsXFormsSchemaValidator::ValidateString(const nsAString & aValue, + const nsAString & aType, const nsAString & aNamespace) +{ + PRBool isValid = PR_FALSE; + + NS_ENSURE_TRUE(mSchemaValidator, isValid); + mSchemaValidator->ValidateString(aValue, aType, aNamespace, &isValid); + + return isValid; +} + +PRBool nsXFormsSchemaValidator::Validate(nsIDOMNode* aElement) +{ + PRBool isValid = PR_FALSE; + + NS_ENSURE_TRUE(mSchemaValidator, isValid); + mSchemaValidator->Validate(aElement, &isValid); + + return isValid; +} + diff --git a/mozilla/extensions/xforms/nsXFormsSchemaValidator.h b/mozilla/extensions/xforms/nsXFormsSchemaValidator.h new file mode 100644 index 00000000000..a77720f2f98 --- /dev/null +++ b/mozilla/extensions/xforms/nsXFormsSchemaValidator.h @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Schema Validation. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Doron Rosenberg (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsCOMPtr.h" +#include "nsISchemaValidator.h" + +class nsXFormsSchemaValidator +{ +public: + + nsXFormsSchemaValidator(); + ~nsXFormsSchemaValidator(); + + nsresult LoadSchema(nsISchema* aSchema); + PRBool ValidateString(const nsAString & aValue, const nsAString & aType, + const nsAString & aNamespace); + PRBool Validate(nsIDOMNode* aElement); + +protected: + nsCOMPtr mSchemaValidator; +}; + diff --git a/mozilla/extensions/xforms/nsXFormsSelectElement.cpp b/mozilla/extensions/xforms/nsXFormsSelectElement.cpp index ed6d1c8eb9f..7764618bc90 100644 --- a/mozilla/extensions/xforms/nsXFormsSelectElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsSelectElement.cpp @@ -36,8 +36,7 @@ * * ***** END LICENSE BLOCK ***** */ -#include "nsXFormsStubElement.h" -#include "nsIXFormsControl.h" +#include "nsXFormsControlStub.h" #include "nsIXTFXMLVisualWrapper.h" #include "nsIDOMFocusListener.h" #include "nsVoidArray.h" @@ -55,13 +54,10 @@ #include "nsIDOMEventListener.h" #include "nsIDOMEventTarget.h" -class nsXFormsSelectElement : public nsXFormsXMLVisualStub, - public nsIXFormsControl, +class nsXFormsSelectElement : public nsXFormsControlStub, public nsIDOMEventListener { public: - nsXFormsSelectElement() : mElement(nsnull) {} - NS_DECL_ISUPPORTS_INHERITED // nsIXTFXMLVisual overrides @@ -73,9 +69,7 @@ public: // nsIXTFElement overrides NS_IMETHOD OnDestroyed(); - NS_IMETHOD ParentChanged(nsIDOMElement *aNewParent); NS_IMETHOD WillSetAttribute(nsIAtom *aName, const nsAString &aValue); - NS_IMETHOD AttributeSet(nsIAtom *aName, const nsAString &aValue); NS_IMETHOD ChildInserted(nsIDOMNode *aChild, PRUint32 aIndex); NS_IMETHOD ChildAppended(nsIDOMNode *aChild); NS_IMETHOD WillRemoveChild(PRUint32 aIndex); @@ -84,7 +78,7 @@ public: NS_IMETHOD DoneAddingChildren(); // nsIXFormsControl - NS_DECL_NSIXFORMSCONTROL + NS_IMETHOD Refresh(); // nsIDOMEventListener NS_DECL_NSIDOMEVENTLISTENER @@ -97,7 +91,6 @@ private: nsCOMPtr mLabel; nsCOMPtr mSelect; - nsIDOMElement *mElement; nsVoidArray mOptions; }; @@ -111,25 +104,15 @@ NS_IMPL_ISUPPORTS_INHERITED2(nsXFormsSelectElement, NS_IMETHODIMP nsXFormsSelectElement::OnCreated(nsIXTFXMLVisualWrapper *aWrapper) { - aWrapper->SetNotificationMask(nsIXTFElement::NOTIFY_PARENT_CHANGED | - nsIXTFElement::NOTIFY_WILL_SET_ATTRIBUTE | - nsIXTFElement::NOTIFY_ATTRIBUTE_SET | + nsXFormsControlStub::OnCreated(aWrapper); + + aWrapper->SetNotificationMask(kStandardNotificationMask | nsIXTFElement::NOTIFY_CHILD_INSERTED | nsIXTFElement::NOTIFY_CHILD_REMOVED | nsIXTFElement::NOTIFY_WILL_REMOVE_CHILD | nsIXTFElement::NOTIFY_BEGIN_ADDING_CHILDREN | nsIXTFElement::NOTIFY_DONE_ADDING_CHILDREN); - nsCOMPtr node; - aWrapper->GetElementNode(getter_AddRefs(node)); - - // It's ok to keep pointer to mElement. mElement will have an - // owning reference to this object, so as long as we null out mElement in - // OnDestroyed, it will always be valid. - - mElement = node; - NS_ASSERTION(mElement, "Wrapper is not an nsIDOMElement, we'll crash soon"); - // Our anonymous content structure will look like this: // // nsCOMPtr domDoc; - node->GetOwnerDocument(getter_AddRefs(domDoc)); + mElement->GetOwnerDocument(getter_AddRefs(domDoc)); domDoc->CreateElementNS(NS_LITERAL_STRING(NS_NAMESPACE_XHTML), NS_LITERAL_STRING("label"), @@ -213,53 +192,7 @@ nsXFormsUploadElement::OnDestroyed() targ->RemoveEventListener(NS_LITERAL_STRING("blur"), this, PR_FALSE); } - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsUploadElement::DocumentChanged(nsIDOMDocument *aNewDocument) -{ - // We need to re-evaluate our instance data binding when our document - // changes, since our context can change - if (aNewDocument) - Refresh(); - - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsUploadElement::ParentChanged(nsIDOMElement *aNewParent) -{ - // We need to re-evaluate our instance data binding when our parent changes, - // since xmlns declarations or our context could have changed. - if (aNewParent) - Refresh(); - - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsUploadElement::WillSetAttribute(nsIAtom *aName, const nsAString &aValue) -{ - if (aName == nsXFormsAtoms::bind || aName == nsXFormsAtoms::ref) { - nsCOMPtr modelNode = nsXFormsUtils::GetModel(mElement); - - nsCOMPtr model = do_QueryInterface(modelNode); - if (model) - model->RemoveFormControl(this); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsXFormsUploadElement::AttributeSet(nsIAtom *aName, const nsAString &aValue) -{ - if (aName == nsXFormsAtoms::bind || aName == nsXFormsAtoms::ref) { - Refresh(); - } - - return NS_OK; + return nsXFormsControlStub::OnDestroyed(); } // nsIDOMEventListener @@ -279,27 +212,7 @@ nsXFormsUploadElement::Focus(nsIDOMEvent *aEvent) NS_IMETHODIMP nsXFormsUploadElement::Blur(nsIDOMEvent *aEvent) { - if (!mInput) - return NS_OK; - - nsCOMPtr modelNode; - nsCOMPtr bindElement; - nsCOMPtr result = - nsXFormsUtils::EvaluateNodeBinding(mElement, - nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR, - NS_LITERAL_STRING("ref"), - EmptyString(), - nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, - getter_AddRefs(modelNode), - getter_AddRefs(bindElement)); - - if (!result) - return NS_OK; - - nsCOMPtr singleNode; - result->GetSingleNodeValue(getter_AddRefs(singleNode)); - - if (!singleNode) + if (!mInput || mBoundNode || mMDG) return NS_OK; nsAutoString value; @@ -308,7 +221,7 @@ nsXFormsUploadElement::Blur(nsIDOMEvent *aEvent) // store the file as a property on the selected content node. the submission // code will read this value. - nsCOMPtr content = do_QueryInterface(singleNode); + nsCOMPtr content = do_QueryInterface(mBoundNode); NS_ENSURE_STATE(content); nsILocalFile *file = nsnull; @@ -322,7 +235,7 @@ nsXFormsUploadElement::Blur(nsIDOMEvent *aEvent) // sync with what is actually submitted. nsCAutoString spec; NS_GetURLSpecFromFile(file, spec); - nsXFormsUtils::SetNodeValue(singleNode, NS_ConvertUTF8toUTF16(spec)); + mMDG->SetNodeValue(mBoundNode, NS_ConvertUTF8toUTF16(spec)); return NS_OK; } @@ -334,54 +247,23 @@ nsXFormsUploadElement::Refresh() if (!mInput) return NS_OK; - nsCOMPtr modelNode; - nsCOMPtr bindElement; - nsCOMPtr result = - nsXFormsUtils::EvaluateNodeBinding(mElement, - nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR, - NS_LITERAL_STRING("ref"), - EmptyString(), - nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, - getter_AddRefs(modelNode), - getter_AddRefs(bindElement)); + mBoundNode = nsnull; - nsCOMPtr model = do_QueryInterface(modelNode); - - // @bug / todo: If \ has binding attributes that are invalid, we - // should clear the content. But the content should be left if the element - // is unbound. - // @see https://bugzilla.mozilla.org/show_bug.cgi?id=265216 - if (!model) - return NS_OK; - - model->AddFormControl(this); - - nsCOMPtr resultNode; - if (result) - result->GetSingleNodeValue(getter_AddRefs(resultNode)); - - if (!resultNode) - return NS_OK; - - // find out if the control should be made readonly - PRBool isReadOnly = PR_FALSE; - nsCOMPtr nodeContent = do_QueryInterface(resultNode); - if (nodeContent) { - nsIDOMXPathExpression *expr = - NS_STATIC_CAST(nsIDOMXPathExpression*, - nodeContent->GetProperty(nsXFormsAtoms::readonly)); - - if (expr) { - expr->Evaluate(mElement, - nsIDOMXPathResult::BOOLEAN_TYPE, nsnull, - getter_AddRefs(result)); - if (result) { - result->GetBooleanValue(&isReadOnly); - } - } - } - - nsCOMPtr content = do_QueryInterface(resultNode); + nsCOMPtr result; + nsresult rv = + ProcessNodeBinding(NS_LITERAL_STRING("ref"), + nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, + getter_AddRefs(result)); + NS_ENSURE_SUCCESS(rv, rv); + + + if (result) + result->GetSingleNodeValue(getter_AddRefs(mBoundNode)); + + if (!mBoundNode) + return NS_OK; + + nsCOMPtr content = do_QueryInterface(mBoundNode); NS_ENSURE_STATE(content); nsILocalFile *file = @@ -394,7 +276,7 @@ nsXFormsUploadElement::Refresh() file->GetPath(value); mInput->SetValue(value); - mInput->SetReadOnly(isReadOnly); + mInput->SetReadOnly(GetReadOnlyState()); return NS_OK; } diff --git a/mozilla/extensions/xforms/nsXFormsUtils.cpp b/mozilla/extensions/xforms/nsXFormsUtils.cpp index 8118272257c..863a806a7be 100644 --- a/mozilla/extensions/xforms/nsXFormsUtils.cpp +++ b/mozilla/extensions/xforms/nsXFormsUtils.cpp @@ -50,7 +50,9 @@ #include "nsIDOMXPathNSResolver.h" #include "nsIDOMDocument.h" #include "nsIDOMText.h" +#include "nsIModelElementPrivate.h" #include "nsIXFormsModelElement.h" +#include "nsIXFormsControl.h" #include "nsIXFormsContextControl.h" #include "nsIDOMDocumentEvent.h" @@ -58,21 +60,22 @@ #include "nsIDOMEventTarget.h" #include "nsDataHashtable.h" +#include "nsAutoPtr.h" +#include "nsXFormsXPathAnalyzer.h" +#include "nsXFormsXPathParser.h" +#include "nsXFormsXPathNode.h" +#include "nsXFormsMDGSet.h" +#include "nsIDOMXPathExpression.h" +#include "nsArray.h" + #include "nsIScriptSecurityManager.h" #include "nsIPermissionManager.h" #include "nsServiceManagerUtils.h" -struct EventData -{ - const char *name; - PRBool canCancel; - PRBool canBubble; -}; - #define CANCELABLE 0x01 #define BUBBLES 0x02 -static const EventData sXFormsEventsEntries[] = { +const EventData sXFormsEventsEntries[41] = { { "xforms-model-construct", PR_FALSE, PR_TRUE }, { "xforms-model-construct-done", PR_FALSE, PR_TRUE }, { "xforms-ready", PR_FALSE, PR_TRUE }, @@ -184,13 +187,15 @@ nsXFormsUtils::Init() return NS_OK; } -/* static */ void -nsXFormsUtils::GetParentModel(nsIDOMElement *aElement, nsIDOMNode **aModel) +/* static */ PRBool +nsXFormsUtils::GetParentModel(nsIDOMElement *aBindElement, + nsIDOMNode **aModel) { + PRBool res = PR_TRUE; nsCOMPtr modelWrapper; // Walk up the tree looking for the containing model. - aElement->GetParentNode(getter_AddRefs(modelWrapper)); + aBindElement->GetParentNode(getter_AddRefs(modelWrapper)); nsAutoString localName, namespaceURI; nsCOMPtr temp; @@ -205,9 +210,15 @@ nsXFormsUtils::GetParentModel(nsIDOMElement *aElement, nsIDOMNode **aModel) temp.swap(modelWrapper); temp->GetParentNode(getter_AddRefs(modelWrapper)); + + // Model is not the immediate parent, this is a reference to a nested + // (invalid) bind + res = PR_FALSE; } *aModel = nsnull; modelWrapper.swap(*aModel); + + return res; } /** @@ -223,12 +234,14 @@ nsXFormsUtils::GetNodeContext(nsIDOMElement *aElement, PRUint32 aElementFlags, nsIDOMNode **aModel, nsIDOMElement **aBindElement, + PRBool *aOuterBind, nsIDOMElement **aContextNode, PRInt32 *aContextPosition, PRInt32 *aContextSize) { *aBindElement = nsnull; NS_ENSURE_ARG(aElement); + NS_ENSURE_ARG(aOuterBind); NS_ENSURE_ARG_POINTER(aContextNode); // Find correct model element @@ -238,18 +251,24 @@ nsXFormsUtils::GetNodeContext(nsIDOMElement *aElement, nsAutoString bindId; aElement->GetAttribute(NS_LITERAL_STRING("bind"), bindId); - /// - /// @todo: Is there a need for ELEMENT_WITH_BIND_ATTR? if (!bindId.IsEmpty()) { // CASE 1: Use @bind domDoc->GetElementById(bindId, aBindElement); + NS_ENSURE_STATE(*aBindElement); - if (*aBindElement) - GetParentModel(*aBindElement, aModel); + // Context size and position are always 1 + if (aContextSize) + *aContextSize = 1; + if (aContextPosition) + *aContextPosition = 1; + + return FindBindContext(*aBindElement, + aOuterBind, + aModel, + aContextNode); + } - // Error: There was a bind attribute, but it did not lead us to a model. - NS_ENSURE_TRUE(*aModel, NS_ERROR_FAILURE); - } else if (aElementFlags & ELEMENT_WITH_MODEL_ATTR) { + if (aElementFlags & ELEMENT_WITH_MODEL_ATTR) { // CASE 2: Use @model // If bind did not set model, and the element has a model attribute we use this nsAutoString modelId; @@ -259,12 +278,13 @@ nsXFormsUtils::GetNodeContext(nsIDOMElement *aElement, nsCOMPtr modelElement; domDoc->GetElementById(modelId, getter_AddRefs(modelElement)); NS_IF_ADDREF(*aModel = modelElement); - + // Not tag found for that ID NS_ENSURE_TRUE(*aModel, NS_ERROR_FAILURE); } } + // Search for a parent setting context for us nsresult rv = FindParentContext(aElement, aModel, aContextNode, @@ -273,8 +293,10 @@ nsXFormsUtils::GetNodeContext(nsIDOMElement *aElement, // CASE 3/4: Use parent's model / first model in document. // If FindParentContext() does not find a parent context but |aModel| is not // set, it sets the model to the first model in the document. + + NS_ENSURE_SUCCESS(rv, rv); - return rv; + return NS_OK; } /* static */ already_AddRefed @@ -286,14 +308,16 @@ nsXFormsUtils::GetModel(nsIDOMElement *aElement, nsCOMPtr model; nsCOMPtr contextNode; nsCOMPtr bind; - - nsresult rv = GetNodeContext(aElement, - aElementFlags, - getter_AddRefs(model), - getter_AddRefs(bind), - getter_AddRefs(contextNode)); + PRBool outerbind; - NS_ENSURE_SUCCESS(rv, nsnull); + GetNodeContext(aElement, + aElementFlags, + getter_AddRefs(model), + getter_AddRefs(bind), + &outerbind, + getter_AddRefs(contextNode)); + + NS_ENSURE_TRUE(model, nsnull); nsIDOMNode *result = nsnull; if (model) @@ -307,7 +331,8 @@ nsXFormsUtils::EvaluateXPath(const nsAString &aExpression, nsIDOMNode *aResolverNode, PRUint16 aResultType, PRInt32 aContextPosition, - PRInt32 aContextSize) + PRInt32 aContextSize, + nsXFormsMDGSet *aSet) { nsCOMPtr doc; aContextNode->GetOwnerDocument(getter_AddRefs(doc)); @@ -320,177 +345,164 @@ nsXFormsUtils::EvaluateXPath(const nsAString &aExpression, eval->CreateNSResolver(aResolverNode, getter_AddRefs(resolver)); NS_ENSURE_TRUE(resolver, nsnull); + nsCOMPtr expression; + eval->CreateExpression(aExpression, + resolver, + getter_AddRefs(expression)); + NS_ENSURE_TRUE(expression, nsnull); + /// /// @todo Evaluate() should use aContextPosition and aContextSize nsCOMPtr supResult; - eval->Evaluate(aExpression, aContextNode, resolver, aResultType, nsnull, - getter_AddRefs(supResult)); + expression->Evaluate(aContextNode, + aResultType, + nsnull, + getter_AddRefs(supResult)); nsIDOMXPathResult *result = nsnull; - if (supResult) + if (supResult) { + /// @todo beaufour: This is somewhat "hackish". Hopefully, this will + /// improve when we integrate properly with Transformiix (XXX) + /// @see http://bugzilla.mozilla.org/show_bug.cgi?id=265212 + if (aSet) { + nsXFormsXPathParser parser; + nsXFormsXPathAnalyzer analyzer(eval, resolver); + nsAutoPtr xNode(parser.Parse(aExpression)); + + nsresult rv = analyzer.Analyze(aContextNode, + xNode, + expression, + &aExpression, + aSet); + NS_ENSURE_SUCCESS(rv, nsnull); + } CallQueryInterface(supResult, &result); // addrefs + } + return result; } -/* static */ already_AddRefed -nsXFormsUtils::FindBindContext(nsIDOMElement *aElement, - nsIXFormsModelElement *aModel) +/* static */ nsresult +nsXFormsUtils::FindBindContext(nsIDOMElement *aBindElement, + PRBool *aOuterBind, + nsIDOMNode **aModel, + nsIDOMElement **aContextNode) { - // Figure out the context node for this . - // The outermost bind has the root element of the [first] instance document - // as its context node. For inner binds, the first node in the nodeset - // of the parent is used as the context node. + // 1) Find the model for the bind + *aOuterBind = GetParentModel(aBindElement, aModel); + NS_ENSURE_STATE(*aModel); - nsCOMPtr modelNode = do_QueryInterface(aModel); + // 2) Find the context node + nsCOMPtr modelInt = do_QueryInterface(*aModel); + NS_ENSURE_STATE(modelInt); - nsCOMPtr parentNode; - aElement->GetParentNode(getter_AddRefs(parentNode)); - if (!parentNode) - return nsnull; // illegal, a bind must be contained in a model. - - if (parentNode == modelNode) { - // This is the outermost bind. - nsCOMPtr instanceDoc; - aModel->GetInstanceDocument(EmptyString(), + nsCOMPtr instanceDoc; + modelInt->GetInstanceDocument(NS_LITERAL_STRING(""), getter_AddRefs(instanceDoc)); - if (!instanceDoc) - return nsnull; + NS_ENSURE_STATE(instanceDoc); - nsIDOMElement *docElement = nsnull; - instanceDoc->GetDocumentElement(&docElement); // addrefs - return docElement; - } + instanceDoc->GetDocumentElement(aContextNode); // addrefs + NS_ENSURE_STATE(*aContextNode); - // The context node is the first node in the nodeset of the parent bind. - nsCOMPtr parentNodeSet = - EvaluateNodeset(nsCOMPtr(do_QueryInterface(parentNode)), - nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE); - - nsIDOMNode *nodeResult = nsnull; - if (parentNodeSet) - parentNodeSet->GetSingleNodeValue(&nodeResult); // addrefs - - return nodeResult; + return NS_OK; } -/* static */ already_AddRefed -nsXFormsUtils::EvaluateNodeset(nsIDOMElement *aElement, PRUint16 aResultType) +/* static */ nsresult +nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement *aElement, + PRUint32 aElementFlags, + const nsString &aBindingAttr, + const nsString &aDefaultRef, + PRUint16 aResultType, + nsIDOMNode **aModel, + nsIDOMXPathResult **aResult, + nsIMutableArray *aDeps) { - // The first thing we need to do is ensure that we have a nodeset attribute. - // If we don't, we walk up and check for it on outer bind elements. - // While we're walking up, we also locate the model element. - - nsCOMPtr model; - nsCOMPtr bindElement, element = aElement; - nsCOMPtr temp; - nsAutoString nodeset; - - while (element) { - model = do_QueryInterface(element); - if (model) - break; - - if (!bindElement) { - element->GetAttribute(NS_LITERAL_STRING("nodeset"), nodeset); - if (!nodeset.IsEmpty()) { - // Verify that this is a element; - nsAutoString value; - element->GetNamespaceURI(value); - if (value.EqualsLiteral(NS_NAMESPACE_XFORMS)) { - element->GetLocalName(value); - if (value.EqualsLiteral("bind")) { - bindElement = element; - } - } - } - } - - element->GetParentNode(getter_AddRefs(temp)); - element = do_QueryInterface(temp); - } - - if (!bindElement || !model) - return nsnull; - - nsCOMPtr contextNode = FindBindContext(bindElement, model); - if (!contextNode) - return nsnull; - - return EvaluateXPath(nodeset, contextNode, bindElement, aResultType); -} - -/* static */ already_AddRefed -nsXFormsUtils::EvaluateNodeBinding(nsIDOMElement *aElement, - PRUint32 aElementFlags, - const nsString &aBindingAttr, - const nsString &aDefaultRef, - PRUint16 aResultType, - nsIDOMNode **aModel, - nsIDOMElement **aBind) -{ - if (!aElement || !aBind || !aModel) { + if (!aElement || !aModel || !aResult) { return nsnull; } - *aBind = nsnull; *aModel = nsnull; + *aResult = nsnull; nsCOMPtr contextNode; + nsCOMPtr bindElement; + PRBool outerBind; PRInt32 contextPosition; PRInt32 contextSize; nsresult rv = GetNodeContext(aElement, aElementFlags, aModel, - aBind, + getter_AddRefs(bindElement), + &outerBind, getter_AddRefs(contextNode), &contextPosition, &contextSize); - NS_ENSURE_SUCCESS(rv, nsnull); + NS_ENSURE_SUCCESS(rv, rv); - // If there is a bind element, we just evaluate its nodeset. - if (*aBind) - return EvaluateNodeset(*aBind, aResultType); - - // If not, we expect there to be a |aBindingAttr| attribute. nsAutoString expr; - aElement->GetAttribute(aBindingAttr, expr); + if (bindElement) { + if (!outerBind) { + // "When you refer to @id on a nested bind it returns an emtpy nodeset + // because it has no meaning. The XForms WG will assign meaning in the + // future." + // @see http://www.w3.org/MarkUp/Group/2004/11/f2f/2004Nov11#resolution6 - if (expr.IsEmpty()) - { - if (aDefaultRef.IsEmpty()) - return nsnull; - expr.Assign(aDefaultRef); - } - - if (!contextNode) { - nsCOMPtr instanceDoc; - nsCOMPtr model = do_QueryInterface(*aModel); - if (!model) { - // The referenced model is not actually a model element, or does not exist. - return nsnull; + return NS_OK; + } else { + // If there is a (outer) bind element, we retrive its nodeset. + bindElement->GetAttribute(NS_LITERAL_STRING("nodeset"), expr); } - - model->GetInstanceDocument(EmptyString(), - getter_AddRefs(instanceDoc)); - - if (!instanceDoc) - return nsnull; - - instanceDoc->GetDocumentElement(getter_AddRefs(contextNode)); - + } else { + // If there's no bind element, we expect there to be a |aBindingAttr| attribute. + aElement->GetAttribute(aBindingAttr, expr); + + if (expr.IsEmpty()) + { + if (aDefaultRef.IsEmpty()) + return NS_OK; + + expr.Assign(aDefaultRef); + } + if (!contextNode) { - return nsnull; // this will happen if the doc is still loading + nsCOMPtr instanceDoc; + nsCOMPtr model = do_QueryInterface(*aModel); + + NS_ENSURE_STATE(model); // The referenced model is not actually a model element, or does not exist. + + model->GetInstanceDocument(NS_LITERAL_STRING(""), + getter_AddRefs(instanceDoc)); + + NS_ENSURE_STATE(instanceDoc); + + instanceDoc->GetDocumentElement(getter_AddRefs(contextNode)); + + if (!contextNode) { + return NS_OK; // this will happen if the doc is still loading + } } } // Evaluate |expr| - return EvaluateXPath(expr, - contextNode, - aElement, - aResultType, - contextSize, - contextPosition); + nsXFormsMDGSet set; + nsCOMPtr res = EvaluateXPath(expr, + contextNode, + aElement, + aResultType, + contextSize, + contextPosition, + aDeps ? &set : nsnull); + + if (res && aDeps) { + for (PRInt32 i = 0; i < set.Count(); ++i) { + aDeps->AppendElement(set.GetNode(i), PR_FALSE); + } + } + + res.swap(*aResult); // exchanges ref + + return NS_OK; } /* static */ void @@ -645,6 +657,8 @@ nsXFormsUtils::SetNodeValue(nsIDOMNode* aDataNode, const nsString& aNodeValue) } } +/// +/// @todo Use this consistently, or delete? (XXX) /* static */ PRBool nsXFormsUtils::GetSingleNodeBindingValue(nsIDOMElement* aElement, nsString& aValue) @@ -652,16 +666,17 @@ nsXFormsUtils::GetSingleNodeBindingValue(nsIDOMElement* aElement, if (!aElement) return PR_FALSE; nsCOMPtr model; - nsCOMPtr bindElement; - nsCOMPtr result = - EvaluateNodeBinding(aElement, - nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR, - NS_LITERAL_STRING("ref"), - EmptyString(), - nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, - getter_AddRefs(model), - getter_AddRefs(bindElement)); - if (!result) + nsCOMPtr result; + + nsresult rv = EvaluateNodeBinding(aElement, + nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR, + NS_LITERAL_STRING("ref"), + EmptyString(), + nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, + getter_AddRefs(model), + getter_AddRefs(result)); + + if (NS_FAILED(rv) || !result) return PR_FALSE; nsCOMPtr singleNode; diff --git a/mozilla/extensions/xforms/nsXFormsUtils.h b/mozilla/extensions/xforms/nsXFormsUtils.h index c022a7df034..90b15fee2f4 100644 --- a/mozilla/extensions/xforms/nsXFormsUtils.h +++ b/mozilla/extensions/xforms/nsXFormsUtils.h @@ -49,6 +49,8 @@ class nsIDOMElement; class nsIXFormsModelElement; class nsIURI; class nsString; +class nsXFormsMDGSet; +class nsIMutableArray; #define NS_NAMESPACE_XFORMS "http://www.w3.org/2002/xforms" #define NS_NAMESPACE_XHTML "http://www.w3.org/1999/xhtml" @@ -105,6 +107,15 @@ enum nsXFormsEvent { eEvent_ComputeException }; +struct EventData +{ + const char *name; + PRBool canCancel; + PRBool canBubble; +}; + +extern const EventData sXFormsEventsEntries[41]; + /** * This class has static helper methods that don't fit into a specific place * in the class hierarchy. @@ -131,11 +142,14 @@ public: Init(); /** - * Locate the model that is a parent of |aElement|. This method walks up the - * content tree looking for the containing model. + * Locate the model that is a parent of |aBindElement|. This method walks + * up the content tree looking for the containing model. + * + * @return Whether it's a reference to an outermost bind */ - static NS_HIDDEN_(void) - GetParentModel(nsIDOMElement *aElement, nsIDOMNode **aModel); + static NS_HIDDEN_(PRBool) + GetParentModel(nsIDOMElement *aBindElement, + nsIDOMNode **aModel); /** * Find the evaluation context for an element. @@ -148,13 +162,17 @@ public: * @param aElementFlags Flags describing characteristics of aElement * @param aModel The \ for the element * @param aBindElement The \ the element is bound to (if any) + * @param aOuterBind Whether the \ is an outermost bind * @param aContextNode The context node for the element + * @param aContextPosition The context position for the element + * @param aContextSize The context size for the element */ static NS_HIDDEN_(nsresult) GetNodeContext(nsIDOMElement *aElement, PRUint32 aElementFlags, nsIDOMNode **aModel, nsIDOMElement **aBindElement, + PRBool *aOuterBind, nsIDOMElement **aContextNode, PRInt32 *aContextPosition = nsnull, PRInt32 *aContextSize = nsnull); @@ -175,38 +193,33 @@ public: /** * Evaluate a 'bind' or |aBindingAttr| attribute on |aElement|. * |aResultType| is used as the desired result type for the XPath evaluation. - * The model and bind elements (if applicable) are located as part of this - * evaluation, and are returned (addrefed) in |aModel| and |aBind|. + * + * The model element (if applicable) is located as part of this evaluation, + * and returned (addrefed) in |aModel| * * The return value is an XPathResult as returned from * nsIDOMXPathEvaluator::Evaluate(). */ - static NS_HIDDEN_(already_AddRefed) - EvaluateNodeBinding(nsIDOMElement *aElement, - PRUint32 aElementFlags, - const nsString &aBindingAttr, - const nsString &aDefaultRef, - PRUint16 aResultType, - nsIDOMNode **aModel, - nsIDOMElement **aBind); - + static NS_HIDDEN_(nsresult) + EvaluateNodeBinding(nsIDOMElement *aElement, + PRUint32 aElementFlags, + const nsString &aBindingAttr, + const nsString &aDefaultRef, + PRUint16 aResultType, + nsIDOMNode **aModel, + nsIDOMXPathResult **aResult, + nsIMutableArray *aDeps = nsnull); /** - * Given a bind element |aElement|, return the nodeset that it applies to. - * |aResultType| is used as the desired result type for the XPath - * evaluation. + * Given a bind element |aBindElement|, find the model and the context node + * for it. |aOuterBind| tells whether the bind element is an outermost bind. */ - static NS_HIDDEN_(already_AddRefed) - EvaluateNodeset(nsIDOMElement *aElement, PRUint16 aResultType); - - /** - * Given a bind element |aElement|, find the context node to be used - * for evaluating its nodeset. - */ - static NS_HIDDEN_(already_AddRefed) + static NS_HIDDEN_(nsresult) FindBindContext(nsIDOMElement *aBindElement, - nsIXFormsModelElement *aModelElement); - + PRBool *aOuterBind, + nsIDOMNode **aModel, + nsIDOMElement **aContextNode); + /** * Convenience method for doing XPath evaluations. This gets a * nsIDOMXPathEvaluator from |aContextNode|'s ownerDocument, and calls @@ -219,7 +232,8 @@ public: nsIDOMNode *aResolverNode, PRUint16 aResultType, PRInt32 aContextPosition = 1, - PRInt32 aContextSize = 1); + PRInt32 aContextSize = 1, + nsXFormsMDGSet *aSet = nsnull); /** * Given a node in the instance data, get its string value according diff --git a/mozilla/extensions/xforms/nsXFormsValueElement.cpp b/mozilla/extensions/xforms/nsXFormsValueElement.cpp index b8bba6e946a..bde355ea4bf 100644 --- a/mozilla/extensions/xforms/nsXFormsValueElement.cpp +++ b/mozilla/extensions/xforms/nsXFormsValueElement.cpp @@ -95,15 +95,14 @@ NS_IMETHODIMP nsXFormsValueElement::GetValue(nsAString &aValue) { nsCOMPtr modelNode; - nsCOMPtr bindElement; - nsCOMPtr result = - nsXFormsUtils::EvaluateNodeBinding(mElement, - nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR, - NS_LITERAL_STRING("ref"), - EmptyString(), - nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, - getter_AddRefs(modelNode), - getter_AddRefs(bindElement)); + nsCOMPtr result; + nsXFormsUtils::EvaluateNodeBinding(mElement, + nsXFormsUtils::ELEMENT_WITH_MODEL_ATTR, + NS_LITERAL_STRING("ref"), + EmptyString(), + nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE, + getter_AddRefs(modelNode), + getter_AddRefs(result)); if (result) { nsCOMPtr singleNode; diff --git a/mozilla/extensions/xforms/nsXFormsXPathAnalyzer.cpp b/mozilla/extensions/xforms/nsXFormsXPathAnalyzer.cpp index e2a1c942c8d..90890506b16 100644 --- a/mozilla/extensions/xforms/nsXFormsXPathAnalyzer.cpp +++ b/mozilla/extensions/xforms/nsXFormsXPathAnalyzer.cpp @@ -41,13 +41,15 @@ #include "nsIDOMXPathResult.h" #ifdef DEBUG -// #define DEBUG_XF_ANALYZER +//#define DEBUG_XF_ANALYZER #endif MOZ_DECL_CTOR_COUNTER(nsXFormsXPathAnalyzer) -nsXFormsXPathAnalyzer::nsXFormsXPathAnalyzer(nsIDOMXPathEvaluator* aEvaluator, nsIDOMXPathNSResolver* aResolver) - : mEvaluator(aEvaluator), mResolver(aResolver) +nsXFormsXPathAnalyzer::nsXFormsXPathAnalyzer(nsIDOMXPathEvaluator *aEvaluator, + nsIDOMXPathNSResolver *aResolver) + : mEvaluator(aEvaluator), + mResolver(aResolver) { MOZ_COUNT_CTOR(nsXFormsXPathAnalyzer); } @@ -58,15 +60,17 @@ nsXFormsXPathAnalyzer::~nsXFormsXPathAnalyzer() } nsresult -nsXFormsXPathAnalyzer::Analyze(nsIDOMNode* aContextNode, const nsXFormsXPathNode* aNode, - nsIDOMXPathExpression* aExpression, const nsAString* aExprString, - nsXFormsMDGSet* aSet) +nsXFormsXPathAnalyzer::Analyze(nsIDOMNode *aContextNode, + const nsXFormsXPathNode *aNode, + nsIDOMXPathExpression *aExpression, + const nsAString *aExprString, + nsXFormsMDGSet *aSet) { - NS_ENSURE_TRUE(aContextNode, NS_ERROR_INVALID_ARG); - NS_ENSURE_TRUE(aNode, NS_ERROR_INVALID_ARG); - NS_ENSURE_TRUE(aExpression, NS_ERROR_INVALID_ARG); - NS_ENSURE_TRUE(aExprString, NS_ERROR_INVALID_ARG); - NS_ENSURE_TRUE(aSet, NS_ERROR_INVALID_ARG); + NS_ENSURE_ARG(aContextNode); + NS_ENSURE_ARG(aNode); + NS_ENSURE_ARG(aExpression); + NS_ENSURE_ARG(aExprString); + NS_ENSURE_ARG(aSet); mCurExpression = aExpression; mCurExprString = aExprString; @@ -84,13 +88,17 @@ nsXFormsXPathAnalyzer::Analyze(nsIDOMNode* aContextNode, const nsXFormsXPathNode #endif NS_ENSURE_SUCCESS(rv, rv); + // Besides making the set a set, it also makes it sorted. + aSet->MakeUnique(); + return NS_OK; } nsresult -nsXFormsXPathAnalyzer::AnalyzeRecursively(nsIDOMNode* aContextNode, const nsXFormsXPathNode* aNode, - PRUint32 aIndent) +nsXFormsXPathAnalyzer::AnalyzeRecursively(nsIDOMNode *aContextNode, + const nsXFormsXPathNode *aNode, + PRUint32 aIndent) { nsXFormsXPathNode* t; nsAutoString xp; diff --git a/mozilla/extensions/xforms/nsXFormsXPathAnalyzer.h b/mozilla/extensions/xforms/nsXFormsXPathAnalyzer.h index 9e6ea389b2c..a832b6b99e0 100644 --- a/mozilla/extensions/xforms/nsXFormsXPathAnalyzer.h +++ b/mozilla/extensions/xforms/nsXFormsXPathAnalyzer.h @@ -57,21 +57,25 @@ */ class nsXFormsXPathAnalyzer { private: - nsCOMPtr mEvaluator; + nsCOMPtr mEvaluator; nsCOMPtr mResolver; - nsXFormsMDGSet* mCurSet; + nsXFormsMDGSet *mCurSet; nsCOMPtr mCurExpression; - const nsAString* mCurExprString; + const nsAString *mCurExprString; - nsresult AnalyzeRecursively(nsIDOMNode* aContextNode, const nsXFormsXPathNode* aNode, - PRUint32 aIndent); + nsresult AnalyzeRecursively(nsIDOMNode *aContextNode, + const nsXFormsXPathNode *aNode, + PRUint32 aIndent); public: - nsXFormsXPathAnalyzer(nsIDOMXPathEvaluator* aEvaluator, nsIDOMXPathNSResolver* aResolver); + nsXFormsXPathAnalyzer(nsIDOMXPathEvaluator *aEvaluator, + nsIDOMXPathNSResolver *aResolver); ~nsXFormsXPathAnalyzer(); - nsresult Analyze(nsIDOMNode* aContextNode, const nsXFormsXPathNode* aNode, - nsIDOMXPathExpression* aExpression, const nsAString* aExprString, - nsXFormsMDGSet* aSet); + nsresult Analyze(nsIDOMNode *aContextNode, + const nsXFormsXPathNode *aNode, + nsIDOMXPathExpression *aExpression, + const nsAString *aExprString, + nsXFormsMDGSet *aSet); }; diff --git a/mozilla/extensions/xforms/nsXFormsXPathParser.cpp b/mozilla/extensions/xforms/nsXFormsXPathParser.cpp index 16d33b48278..cfb500f9943 100644 --- a/mozilla/extensions/xforms/nsXFormsXPathParser.cpp +++ b/mozilla/extensions/xforms/nsXFormsXPathParser.cpp @@ -41,11 +41,15 @@ #include "nscore.h" /* - * (TODO) GIANT hack. Without exceptions everything had to be rewritten, and - * that was to overdo it a bit, when the code probably does not survive... + * @todo GIANT hack. Without exceptions everything had to be rewritten, and + * that was to overdo it a bit, when the code probably does not survive... (XXX) */ void -XPathCompilerException(const char* aMsg, nsAString& aExpression, PRInt32 aOffset = -1, PRInt32 aLength = -1) { +XPathCompilerException(const char *aMsg, + nsAString &aExpression, + PRInt32 aOffset = -1, + PRInt32 aLength = -1) +{ printf("XPathCompilerException: %s, %s [o: %d, l: %d]\n", aMsg, NS_ConvertUCS2toUTF8(aExpression).get(), aOffset, aLength);