[XForms] Setting a type on instance data makes rebuild() throw exception. Bug 310138, r=aaronr+smaug

This commit is contained in:
allan%beaufour.dk 2006-02-17 10:14:10 +00:00
Родитель acbab68e7c
Коммит e58de7c058
7 изменённых файлов: 153 добавлений и 117 удалений

Просмотреть файл

@ -148,4 +148,14 @@ interface nsIModelElementPrivate : nsIXFormsModelElement
* This attribute is set when the model handled xforms-ready event
*/
readonly attribute boolean isReady;
/**
* Retrieves the type for an instance data node
*
* @param aInstanceData The instance data node
* @param aType The type of the node
* @param aNSURI The namespace of the type
*/
void GetTypeFromNode(in nsIDOMNode aInstanceData, out AString aType,
out AString aNSUri);
};

Просмотреть файл

@ -604,6 +604,10 @@ nsXFormsModelElement::OnCreated(nsIXTFGenericElementWrapper *aWrapper)
mInstanceDocuments = new nsXFormsModelInstanceDocuments();
NS_ASSERTION(mInstanceDocuments, "could not create mInstanceDocuments?!");
// Initialize hash tables
NS_ENSURE_TRUE(mNodeToType.Init(), NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_TRUE(mNodeToP3PType.Init(), NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
}
@ -640,6 +644,12 @@ nsXFormsModelElement::Rebuild()
rv = mMDG.Clear();
NS_ENSURE_SUCCESS(rv, rv);
// Clear any type information
NS_ENSURE_TRUE(mNodeToType.IsInitialized() && mNodeToP3PType.IsInitialized(),
NS_ERROR_FAILURE);
mNodeToType.Clear();
mNodeToP3PType.Clear();
// 2. Re-attach all elements
if (mDocumentLoaded) { // if it's not during initializing phase
// Copy the form control list as it stands right now.
@ -1004,9 +1014,9 @@ nsXFormsModelElement::GetTypeForControl(nsIXFormsControl *aControl,
nsXFormsModelElement::GetTypeAndNSFromNode(nsIDOMNode *aInstanceData,
nsAString &aType, nsAString &aNSUri)
{
nsresult rv = nsXFormsUtils::ParseTypeFromNode(aInstanceData, aType, aNSUri);
nsresult rv = GetTypeFromNode(aInstanceData, aType, aNSUri);
if(rv == NS_ERROR_NOT_AVAILABLE) {
if (rv == NS_ERROR_NOT_AVAILABLE) {
// if there is no type assigned, then assume that the type is 'string'
aNSUri.Assign(NS_LITERAL_STRING(NS_NAMESPACE_XML_SCHEMA));
aType.Assign(NS_LITERAL_STRING("string"));
@ -1185,6 +1195,79 @@ nsXFormsModelElement::GetIsReady(PRBool *aIsReady)
return NS_OK;
}
NS_IMETHODIMP
nsXFormsModelElement::GetTypeFromNode(nsIDOMNode *aInstanceData,
nsAString &aType,
nsAString &aNSUri)
{
// aInstanceData could be an instance data node or it could be an attribute
// on an instance data node (basically the node that a control is bound to).
nsString *typeVal = nsnull;
// Get type stored directly on instance node
nsAutoString typeAttribute;
nsCOMPtr<nsIDOMElement> nodeElem(do_QueryInterface(aInstanceData));
if (nodeElem) {
nodeElem->GetAttributeNS(NS_LITERAL_STRING(NS_NAMESPACE_XML_SCHEMA_INSTANCE),
NS_LITERAL_STRING("type"), typeAttribute);
if (!typeAttribute.IsEmpty()) {
typeVal = &typeAttribute;
}
}
// If there was no type information on the node itself, check for a type
// bound to the node via \<xforms:bind\>
if (!typeVal && !mNodeToType.Get(aInstanceData, &typeVal)) {
// No type information found
return NS_ERROR_NOT_AVAILABLE;
}
// split type (ns:type) into namespace and type.
nsAutoString prefix;
PRInt32 separator = typeVal->FindChar(':');
if ((PRUint32) separator == (typeVal->Length() - 1)) {
const PRUnichar *strings[] = { typeVal->get() };
nsXFormsUtils::ReportError(NS_LITERAL_STRING("missingTypeName"), strings, 1,
mElement, nsnull);
return NS_ERROR_UNEXPECTED;
}
if (separator == kNotFound) {
// no namespace prefix, which is valid;
prefix = EmptyString();
aType.Assign(*typeVal);
} else {
prefix.Assign(Substring(*typeVal, 0, separator));
aType.Assign(Substring(*typeVal, ++separator, typeVal->Length()));
}
if (prefix.IsEmpty()) {
aNSUri = EmptyString();
return NS_OK;
}
// get the namespace url from the prefix using instance data node
nsresult rv;
nsCOMPtr<nsIDOM3Node> domNode3 = do_QueryInterface(aInstanceData, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = domNode3->LookupNamespaceURI(prefix, aNSUri);
if (DOMStringIsNull(aNSUri)) {
// if not found using instance data node, use <xf:instance> node
nsCOMPtr<nsIDOMNode> instanceNode;
rv = nsXFormsUtils::GetInstanceNodeForData(aInstanceData,
getter_AddRefs(instanceNode));
NS_ENSURE_SUCCESS(rv, rv);
domNode3 = do_QueryInterface(instanceNode, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = domNode3->LookupNamespaceURI(prefix, aNSUri);
}
return rv;
}
// nsIXFormsContextControl
NS_IMETHODIMP
@ -1487,15 +1570,6 @@ nsXFormsModelElement::MaybeNotifyCompletion()
}
}
static void
DeleteAutoString(void *aObject,
nsIAtom *aPropertyName,
void *aPropertyValue,
void *aData)
{
delete NS_STATIC_CAST(nsAutoString*, aPropertyValue);
}
nsresult
nsXFormsModelElement::ProcessBind(nsIXFormsXPathEvaluator *aEvaluator,
nsIDOMNode *aContextNode,
@ -1582,33 +1656,24 @@ nsXFormsModelElement::ProcessBind(nsIXFormsXPathEvaluator *aEvaluator,
// type and p3ptype are stored as properties on the instance node
if (j == eModel_type || j == eModel_p3ptype) {
nsAutoPtr<nsAutoString> prop (new nsAutoString(propStrings[j]));
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
if (content) {
rv = content->SetProperty(sModelPropsList[j],
prop,
DeleteAutoString);
} else {
nsCOMPtr<nsIAttribute> attribute = do_QueryInterface(node);
if (attribute) {
rv = attribute->SetProperty(sModelPropsList[j],
prop,
DeleteAutoString);
} else {
NS_WARNING("node is neither nsIContent or nsIAttribute");
continue;
}
}
if (NS_SUCCEEDED(rv)) {
prop.forget();
} else {
return rv;
}
if (rv == NS_PROPTABLE_PROP_OVERWRITTEN) {
nsClassHashtable<nsISupportsHashKey, nsString> *table;
table = j == eModel_type ? &mNodeToType : &mNodeToP3PType;
NS_ENSURE_TRUE(table->IsInitialized(), NS_ERROR_FAILURE);
// Check for existing value
if (table->Get(node, nsnull)) {
multiMIP = PR_TRUE;
break;
}
// Insert value
nsAutoPtr<nsString> newString(new nsString(propStrings[j]));
NS_ENSURE_TRUE(newString, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_TRUE(table->Put(node, newString), NS_ERROR_OUT_OF_MEMORY);
// string is succesfully stored in the table, we should not dealloc it
newString.forget();
if (j == eModel_type) {
// Inform MDG that it needs to check type. The only arguments
// actually used are |eModel_constraint| and |node|.

Просмотреть файл

@ -288,6 +288,21 @@ private:
// Indicates whether the model's instance was built by lazy authoring
PRBool mLazyModel;
/**
* Type information for nodes, with their type set through \<xforms:bind\>.
*
* @see http://www.w3.org/TR/xforms/slice6.html#model-prop-type
*/
nsClassHashtable<nsISupportsHashKey, nsString> mNodeToType;
/**
* P3P type information for nodes, with their type set through
* \<xforms:bind\>.
* @see http://www.w3.org/TR/xforms/slice6.html#model-prop-p3ptype
*/
nsClassHashtable<nsISupportsHashKey, nsString> mNodeToP3PType;
};
/**

Просмотреть файл

@ -1279,7 +1279,7 @@ nsXFormsSubmissionElement::CopyChildren(nsIDOMNode *source, nsIDOMNode *dest,
PRUint32 encType;
if (attachments &&
NS_SUCCEEDED(GetElementEncodingType(currentNode, &encType)) &&
NS_SUCCEEDED(GetElementEncodingType(currentNode, &encType, model)) &&
encType == ELEMENT_ENCTYPE_URI)
{
// ok, looks like we have a local file to upload
@ -1744,7 +1744,9 @@ nsXFormsSubmissionElement::AppendPostDataChunk(nsCString &postDataChunk,
}
nsresult
nsXFormsSubmissionElement::GetElementEncodingType(nsIDOMNode *node, PRUint32 *encType)
nsXFormsSubmissionElement::GetElementEncodingType(nsIDOMNode *node,
PRUint32 *encType,
nsIModelElementPrivate *aModel)
{
*encType = ELEMENT_ENCTYPE_STRING; // default
@ -1753,7 +1755,12 @@ nsXFormsSubmissionElement::GetElementEncodingType(nsIDOMNode *node, PRUint32 *en
// check for 'xsd:base64Binary', 'xsd:hexBinary', or 'xsd:anyURI'
nsAutoString type, nsuri;
nsresult rv = nsXFormsUtils::ParseTypeFromNode(node, type, nsuri);
nsresult rv;
if (aModel) {
rv = aModel->GetTypeFromNode(node, type, nsuri);
} else {
rv = nsXFormsUtils::ParseTypeFromNode(node, type, nsuri);
}
if (NS_SUCCEEDED(rv) &&
nsuri.EqualsLiteral(NS_NAMESPACE_XML_SCHEMA) &&
!type.IsEmpty())

Просмотреть файл

@ -112,7 +112,7 @@ public:
NS_HIDDEN_(nsresult) SerializeDataMultipartFormData(nsIDOMNode *data, nsIInputStream **, nsCString &contentType);
NS_HIDDEN_(nsresult) AppendMultipartFormData(nsIDOMNode *data, const nsCString &boundary, nsCString &buf, nsIMultiplexInputStream *);
NS_HIDDEN_(nsresult) AppendPostDataChunk(nsCString &postDataChunk, nsIMultiplexInputStream *multiStream);
NS_HIDDEN_(nsresult) GetElementEncodingType(nsIDOMNode *data, PRUint32 *encType);
NS_HIDDEN_(nsresult) GetElementEncodingType(nsIDOMNode *data, PRUint32 *encType, nsIModelElementPrivate* aModel = nsnull);
NS_HIDDEN_(nsresult) CreateFileStream(const nsString &absURI, nsIFile **file, nsIInputStream **stream);
NS_HIDDEN_(nsresult) SendData(const nsCString &uri, nsIInputStream *stream, const nsCString &contentType);

Просмотреть файл

@ -146,10 +146,12 @@ nsBoundType
nsXFormsUploadElement::GetBoundType()
{
nsBoundType result = TYPE_DEFAULT;
if (!mModel)
return result;
// get type bound to node
nsAutoString type, nsuri;
nsresult rv = nsXFormsUtils::ParseTypeFromNode(mBoundNode, type, nsuri);
nsresult rv = mModel->GetTypeFromNode(mBoundNode, type, nsuri);
if (NS_SUCCEEDED(rv) && nsuri.EqualsLiteral(NS_NAMESPACE_XML_SCHEMA)) {
if (type.EqualsLiteral("anyURI")) {
result = TYPE_ANYURI;

Просмотреть файл

@ -1261,88 +1261,25 @@ nsXFormsUtils::GetInstanceNodeForData(nsIDOMNode *aInstanceDataNode,
/* static */ nsresult
nsXFormsUtils::ParseTypeFromNode(nsIDOMNode *aInstanceData,
nsAString &aType, nsAString &aNSUri)
nsAString &aType,
nsAString &aNSUri)
{
nsresult rv = NS_OK;
nsresult rv;
// aInstanceData could be an instance data node or it could be an attribute
// on an instance data node (basically the node that a control is bound to).
nsAutoString *typeVal = nsnull;
// Get type stored directly on instance node
nsAutoString typeAttribute;
nsCOMPtr<nsIDOMElement> nodeElem(do_QueryInterface(aInstanceData));
if (nodeElem) {
nodeElem->GetAttributeNS(NS_LITERAL_STRING(NS_NAMESPACE_XML_SCHEMA_INSTANCE),
NS_LITERAL_STRING("type"), typeAttribute);
if (!typeAttribute.IsEmpty()) {
typeVal = &typeAttribute;
}
}
if (!typeVal) {
// Get MIP type bound to node
nsCOMPtr<nsIContent> nodeContent(do_QueryInterface(aInstanceData));
if (nodeContent) {
typeVal =
NS_STATIC_CAST(nsAutoString*,
nodeContent->GetProperty(nsXFormsAtoms::type, &rv));
} else {
nsCOMPtr<nsIAttribute> nodeAttribute(do_QueryInterface(aInstanceData));
if (!nodeAttribute)
// node is neither content or attribute!
return NS_ERROR_FAILURE;
typeVal =
NS_STATIC_CAST(nsAutoString*,
nodeAttribute->GetProperty(nsXFormsAtoms::type, &rv));
}
}
if (NS_FAILED(rv) || !typeVal) {
return NS_ERROR_NOT_AVAILABLE;
}
// split type (ns:type) into namespace and type.
nsAutoString prefix;
PRInt32 separator = typeVal->FindChar(':');
if ((PRUint32) separator == (typeVal->Length() - 1)) {
const PRUnichar *strings[] = { typeVal->get() };
// XXX: get an element from the document this came from
ReportError(NS_LITERAL_STRING("missingTypeName"), strings, 1, nsnull, nsnull);
return NS_ERROR_UNEXPECTED;
} else if (separator == kNotFound) {
// no namespace prefix, which is valid;
prefix.AssignLiteral("");
aType.Assign(*typeVal);
} else {
prefix.Assign(Substring(*typeVal, 0, separator));
aType.Assign(Substring(*typeVal, ++separator, typeVal->Length()));
}
if (prefix.IsEmpty()) {
aNSUri.AssignLiteral("");
} else {
// get the namespace url from the prefix using instance data node
nsCOMPtr<nsIDOM3Node> domNode3 = do_QueryInterface(aInstanceData, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = domNode3->LookupNamespaceURI(prefix, aNSUri);
if (DOMStringIsNull(aNSUri)) {
// if not found using instance data node, use <xf:instance> node
// Find the model for the instance data node
nsCOMPtr<nsIDOMNode> instanceNode;
rv = nsXFormsUtils::GetInstanceNodeForData(aInstanceData,
getter_AddRefs(instanceNode));
NS_ENSURE_SUCCESS(rv, rv);
domNode3 = do_QueryInterface(instanceNode, &rv);
nsCOMPtr<nsIDOMNode> modelNode;
rv = instanceNode->GetParentNode(getter_AddRefs(modelNode));
NS_ENSURE_SUCCESS(rv, rv);
rv = domNode3->LookupNamespaceURI(prefix, aNSUri);
}
}
return rv;
nsCOMPtr<nsIModelElementPrivate> model(do_QueryInterface(modelNode));
NS_ENSURE_STATE(model);
return model->GetTypeFromNode(aInstanceData, aType, aNSUri);
}
/* static */ void