Back to index

lightning-sunbird  0.9+nobinonly
nsXFormsModelElement.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla XForms support.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * IBM Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Brian Ryner <bryner@brianryner.com>
00024  *  Allan Beaufour <abeaufour@novell.com>
00025  *  Darin Fisher <darin@meer.net>
00026  *  Olli Pettay <Olli.Pettay@helsinki.fi>
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either the GNU General Public License Version 2 or later (the "GPL"), or
00030  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include "nsXFormsModelElement.h"
00043 #include "nsIXTFGenericElementWrapper.h"
00044 #include "nsMemory.h"
00045 #include "nsIDOMElement.h"
00046 #include "nsIDOM3Node.h"
00047 #include "nsIDOMNodeList.h"
00048 #include "nsIVariant.h"
00049 #include "nsString.h"
00050 #include "nsIDocument.h"
00051 #include "nsXFormsAtoms.h"
00052 #include "nsINameSpaceManager.h"
00053 #include "nsIServiceManager.h"
00054 #include "nsIDOMEvent.h"
00055 #include "nsIDOMDOMImplementation.h"
00056 #include "nsIDOMXMLDocument.h"
00057 #include "nsIDOMEventReceiver.h"
00058 #include "nsIDOMXPathResult.h"
00059 #include "nsIXFormsXPathEvaluator.h"
00060 #include "nsIDOMXPathNSResolver.h"
00061 #include "nsIDOMNSXPathExpression.h"
00062 #include "nsIContent.h"
00063 #include "nsIURL.h"
00064 #include "nsNetUtil.h"
00065 #include "nsIXFormsControl.h"
00066 #include "nsXFormsTypes.h"
00067 #include "nsXFormsXPathParser.h"
00068 #include "nsXFormsXPathAnalyzer.h"
00069 #include "nsIInstanceElementPrivate.h"
00070 #include "nsXFormsUtils.h"
00071 #include "nsXFormsSchemaValidator.h"
00072 #include "nsIXFormsUIWidget.h"
00073 #include "nsIAttribute.h"
00074 #include "nsISchemaLoader.h"
00075 #include "nsISchema.h"
00076 #include "nsAutoPtr.h"
00077 #include "nsIDOMDocumentXBL.h"
00078 #include "nsIProgrammingLanguage.h"
00079 #include "nsDOMError.h"
00080 #include "nsIDOMXPathException.h"
00081 #include "nsXFormsControlStub.h"
00082 #include "nsIPrefService.h"
00083 #include "nsIPrefBranch.h"
00084 #include "nsIEventStateManager.h"
00085 #include "nsStringEnumerator.h"
00086 
00087 #define XFORMS_LAZY_INSTANCE_BINDING \
00088   "chrome://xforms/content/xforms.xml#xforms-lazy-instance"
00089 
00090 #ifdef DEBUG
00091 //#define DEBUG_MODEL
00092 #endif
00093 
00094 //------------------------------------------------------------------------------
00095 
00096 // Helper function for using XPath to locate an <xsd:schema> element by
00097 // matching its "id" attribute.  This is necessary since <xsd:schema> is
00098 // treated as an ordinary XML data node without an "ID" attribute.
00099 static void
00100 GetSchemaElementById(nsIDOMElement *contextNode,
00101                      const nsString &id,
00102                      nsIDOMElement **resultNode)
00103 {
00104   // search for an element with the given "id" attribute, and then verify
00105   // that the element is in the XML Schema namespace.
00106 
00107   nsAutoString expr;
00108   expr.AssignLiteral("//*[@id=\"");
00109   expr.Append(id);
00110   expr.AppendLiteral("\"]");
00111 
00112   nsCOMPtr<nsIDOMXPathResult> xpRes;
00113   nsresult rv =
00114     nsXFormsUtils::EvaluateXPath(expr,
00115                                  contextNode,
00116                                  contextNode,
00117                                  nsIDOMXPathResult::FIRST_ORDERED_NODE_TYPE,
00118                                  getter_AddRefs(xpRes));
00119   if (NS_SUCCEEDED(rv) && xpRes) {
00120     nsCOMPtr<nsIDOMNode> node;
00121     xpRes->GetSingleNodeValue(getter_AddRefs(node));
00122     if (node) {
00123       nsAutoString ns;
00124       node->GetNamespaceURI(ns);
00125       if (ns.EqualsLiteral(NS_NAMESPACE_XML_SCHEMA))
00126         CallQueryInterface(node, resultNode);
00127     }
00128   }
00129 }
00130 
00131 //------------------------------------------------------------------------------
00132 
00133 static void
00134 DeleteVoidArray(void    *aObject,
00135                 nsIAtom *aPropertyName,
00136                 void    *aPropertyValue,
00137                 void    *aData)
00138 {
00139   delete NS_STATIC_CAST(nsVoidArray *, aPropertyValue);
00140 }
00141 
00142 static nsresult
00143 AddToModelList(nsIDOMDocument *domDoc, nsXFormsModelElement *model)
00144 {
00145   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
00146 
00147   nsVoidArray *models =
00148       NS_STATIC_CAST(nsVoidArray *,
00149                      doc->GetProperty(nsXFormsAtoms::modelListProperty));
00150   if (!models) {
00151     models = new nsVoidArray(16);
00152     if (!models)
00153       return NS_ERROR_OUT_OF_MEMORY;
00154     doc->SetProperty(nsXFormsAtoms::modelListProperty, models, DeleteVoidArray);
00155   }
00156   models->AppendElement(model);
00157   return NS_OK;
00158 }
00159 
00160 static void
00161 RemoveFromModelList(nsIDOMDocument *domDoc, nsXFormsModelElement *model)
00162 {
00163   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
00164 
00165   nsVoidArray *models =
00166       NS_STATIC_CAST(nsVoidArray *,
00167                      doc->GetProperty(nsXFormsAtoms::modelListProperty));
00168   if (models)
00169     models->RemoveElement(model);
00170 }
00171 
00172 static const nsVoidArray *
00173 GetModelList(nsIDOMDocument *domDoc)
00174 {
00175   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
00176 
00177   return NS_STATIC_CAST(nsVoidArray *,
00178                         doc->GetProperty(nsXFormsAtoms::modelListProperty));
00179 }
00180 
00181 static void
00182 SupportsDtorFunc(void *aObject, nsIAtom *aPropertyName,
00183                  void *aPropertyValue, void *aData)
00184 {
00185   nsISupports *propertyValue = NS_STATIC_CAST(nsISupports*, aPropertyValue);
00186   NS_IF_RELEASE(propertyValue);
00187 }
00188 
00189 
00190 //------------------------------------------------------------------------------
00191 // --- nsXFormsControlListItem  ---
00192 
00193 
00194 nsXFormsControlListItem::iterator::iterator()
00195   : mCur(0)
00196 {
00197 }
00198 
00199 nsXFormsControlListItem::iterator::iterator(const nsXFormsControlListItem::iterator& aCopy)
00200   : mCur(aCopy.mCur)
00201 {
00202   mStack = aCopy.mStack;
00203 }
00204 
00205 nsXFormsControlListItem::iterator
00206 nsXFormsControlListItem::iterator::operator=(nsXFormsControlListItem* aCnt)
00207 {
00208   mCur = aCnt;
00209   return *this;
00210 }
00211 
00212 bool
00213 nsXFormsControlListItem::iterator::operator!=(const nsXFormsControlListItem* aCnt)
00214 {
00215   return mCur != aCnt;
00216 }
00217 
00218 nsXFormsControlListItem::iterator
00219 nsXFormsControlListItem::iterator::operator++()
00220 {
00221   if (!mCur)
00222     return *this;
00223 
00224   if (mCur->mFirstChild) {
00225     if (!mCur->mNextSibling) {
00226       mCur = mCur->mFirstChild;
00227       return *this;
00228     }
00229     mStack.AppendElement(mCur->mFirstChild);
00230   }
00231 
00232   if (mCur->mNextSibling) {
00233     mCur = mCur->mNextSibling;
00234   } else if (mStack.Count()) {
00235     mCur = (nsXFormsControlListItem*) mStack[mStack.Count() - 1];
00236     mStack.RemoveElementAt(mStack.Count() - 1);
00237   } else {
00238     mCur = nsnull;
00239   }
00240 
00241   return *this;
00242 }
00243 
00244 nsXFormsControlListItem*
00245 nsXFormsControlListItem::iterator::operator*()
00246 {
00247   return mCur;
00248 }
00249 
00250 nsXFormsControlListItem::nsXFormsControlListItem(
00251   nsIXFormsControl* aControl,
00252   nsRefPtrHashtable<nsISupportsHashKey,nsXFormsControlListItem>* aHashtable)
00253   : mNode(aControl),
00254     mNextSibling(nsnull),
00255     mFirstChild(nsnull),
00256     mControlListHash(aHashtable)
00257 {
00258 
00259 }
00260 
00261 nsXFormsControlListItem::~nsXFormsControlListItem()
00262 {
00263   Clear();
00264 }
00265 
00266 nsXFormsControlListItem::nsXFormsControlListItem(const nsXFormsControlListItem& aCopy)
00267   : mNode(aCopy.mNode)
00268 {
00269   if (aCopy.mNextSibling) {
00270     mNextSibling = new nsXFormsControlListItem(*aCopy.mNextSibling);
00271     NS_WARN_IF_FALSE(mNextSibling, "could not new?!");
00272   } else {
00273     mNextSibling = nsnull;
00274   }
00275 
00276   if (aCopy.mFirstChild) {
00277     mFirstChild = new nsXFormsControlListItem(*aCopy.mFirstChild);
00278     NS_WARN_IF_FALSE(mFirstChild, "could not new?!");
00279   } else {
00280     mFirstChild = nsnull;
00281   }
00282 }
00283 
00284 void
00285 nsXFormsControlListItem::Clear()
00286 {
00287   if (mFirstChild) {
00288     mFirstChild->Clear();
00289     NS_ASSERTION(!(mFirstChild->mFirstChild || mFirstChild->mNextSibling),
00290                  "child did not clear members!!");
00291     mFirstChild = nsnull;
00292   }
00293   if (mNextSibling) {
00294     mNextSibling->Clear();
00295     NS_ASSERTION(!(mNextSibling->mFirstChild || mNextSibling->mNextSibling),
00296                  "sibling did not clear members!!");
00297     mNextSibling = nsnull;
00298   }
00299   if (mNode) {
00300     /* we won't bother removing each item one by one from the hashtable.  This
00301      * approach assumes that we are clearing the whole model's list of controls
00302      * due to the model going away.  After the model clears this list, it will
00303      * clear the hashtable all at once.
00304      */
00305     mControlListHash = nsnull;
00306     mNode = nsnull;
00307   }
00308 }
00309 
00310 nsresult
00311 nsXFormsControlListItem::AddControl(nsIXFormsControl *aControl,
00312                                     nsIXFormsControl *aParent)
00313 {
00314   // Four insertion posibilities:
00315 
00316   // 1) Delegate to first child from root node
00317   if (!mNode && mFirstChild) {
00318     return mFirstChild->AddControl(aControl, aParent);
00319   }
00320 
00321   // 2) control with no parent
00322   if (!aParent) {
00323     nsRefPtr<nsXFormsControlListItem> newNode =
00324       new nsXFormsControlListItem(aControl, mControlListHash);
00325     NS_ENSURE_TRUE(newNode, NS_ERROR_OUT_OF_MEMORY);
00326 
00327     // Empty tree (we have already checked mFirstChild)
00328     if (!mNode) {
00329       mFirstChild = newNode;
00330       nsCOMPtr<nsIDOMElement> ele;
00331       aControl->GetElement(getter_AddRefs(ele));
00332       mControlListHash->Put(ele, newNode);
00333       return NS_OK;
00334     }
00335 
00336     if (mNextSibling) {
00337       newNode->mNextSibling = mNextSibling;
00338     }
00339     mNextSibling = newNode;
00340     nsCOMPtr<nsIDOMElement> ele;
00341     aControl->GetElement(getter_AddRefs(ele));
00342     mControlListHash->Put(ele, newNode);
00343 #ifdef DEBUG
00344     nsXFormsControlListItem* next = newNode->mNextSibling;
00345     while (next) {
00346       NS_ASSERTION(aControl != next->mNode,
00347                    "Node already in tree!!");
00348       next = next->mNextSibling;
00349     }
00350 #endif
00351 
00352     return NS_OK;
00353   }
00354 
00355   // Locate parent
00356   nsXFormsControlListItem* parentControl = FindControl(aParent);
00357   NS_ASSERTION(parentControl, "Parent not found?!");
00358 
00359   // 3) parentControl has a first child, insert as sibling to that
00360   if (parentControl->mFirstChild) {
00361     return parentControl->mFirstChild->AddControl(aControl, nsnull);
00362   }
00363 
00364   // 4) first child for parentControl
00365   nsRefPtr<nsXFormsControlListItem> newNode =
00366     new nsXFormsControlListItem(aControl, mControlListHash);
00367   NS_ENSURE_TRUE(newNode, NS_ERROR_OUT_OF_MEMORY);
00368 
00369   parentControl->mFirstChild = newNode;
00370   nsCOMPtr<nsIDOMElement> ele;
00371   aControl->GetElement(getter_AddRefs(ele));
00372   mControlListHash->Put(ele, newNode);
00373 
00374   return NS_OK;
00375 }
00376 
00377 nsresult
00378 nsXFormsControlListItem::RemoveControl(nsIXFormsControl *aControl,
00379                                        PRBool           &aRemoved)
00380 {
00381   nsXFormsControlListItem* deleteMe = nsnull;
00382   aRemoved = PR_FALSE;
00383 
00384   // Try children
00385   if (mFirstChild) {
00386     // The control to remove is our first child
00387     if (mFirstChild->mNode == aControl) {
00388       deleteMe = mFirstChild;
00389 
00390       // Fix siblings
00391       if (deleteMe->mNextSibling) {
00392         mFirstChild = deleteMe->mNextSibling;
00393         deleteMe->mNextSibling = nsnull;
00394       } else {
00395         mFirstChild = nsnull;
00396       }
00397 
00398       // Fix children
00399       if (deleteMe->mFirstChild) {
00400         if (!mFirstChild) {
00401           mFirstChild = deleteMe->mFirstChild;
00402         } else {
00403           nsXFormsControlListItem *insertPos = mFirstChild;
00404           while (insertPos->mNextSibling) {
00405             insertPos = insertPos->mNextSibling;
00406           }
00407           insertPos->mNextSibling = deleteMe->mFirstChild;
00408         }
00409         deleteMe->mFirstChild = nsnull;
00410       }
00411     } else {
00412       // Run through children
00413       nsresult rv = mFirstChild->RemoveControl(aControl, aRemoved);
00414       NS_ENSURE_SUCCESS(rv, rv);
00415       if (aRemoved)
00416         return rv;
00417     }
00418   }
00419 
00420   // Try siblings
00421   if (!deleteMe && mNextSibling) {
00422     if (mNextSibling->mNode == aControl) {
00423       deleteMe = mNextSibling;
00424       // Fix siblings
00425       if (deleteMe->mNextSibling) {
00426         mNextSibling = deleteMe->mNextSibling;
00427         deleteMe->mNextSibling = nsnull;
00428       } else {
00429         mNextSibling = nsnull;
00430       }
00431       // Fix children
00432       if (deleteMe->mFirstChild) {
00433         if (!mNextSibling) {
00434           mNextSibling = deleteMe->mFirstChild;
00435         } else {
00436           nsXFormsControlListItem *insertPos = mNextSibling;
00437           while (insertPos->mNextSibling) {
00438             insertPos = insertPos->mNextSibling;
00439           }
00440           insertPos->mNextSibling = deleteMe->mFirstChild;
00441         }
00442         deleteMe->mFirstChild = nsnull;
00443       }
00444     } else {
00445       // run through siblings
00446       return mNextSibling->RemoveControl(aControl, aRemoved);
00447     }
00448   }
00449 
00450   if (deleteMe) {
00451     NS_ASSERTION(!(deleteMe->mNextSibling),
00452                  "Deleted control should not have siblings!");
00453     NS_ASSERTION(!(deleteMe->mFirstChild),
00454                  "Deleted control should not have children!");
00455     nsCOMPtr<nsIDOMElement> element;
00456     deleteMe->mNode->GetElement(getter_AddRefs(element));
00457     mControlListHash->Remove(element);
00458     aRemoved = PR_TRUE;
00459   }
00460 
00461   return NS_OK;
00462 }
00463 
00464 nsXFormsControlListItem*
00465 nsXFormsControlListItem::FindControl(nsIXFormsControl *aControl)
00466 {
00467   if (!aControl)
00468     return nsnull;
00469 
00470   nsRefPtr<nsXFormsControlListItem> listItem;
00471   nsCOMPtr<nsIDOMElement> element;
00472   aControl->GetElement(getter_AddRefs(element));
00473   mControlListHash->Get(element, getter_AddRefs(listItem));
00474   return listItem;
00475 }
00476 
00477 already_AddRefed<nsIXFormsControl>
00478 nsXFormsControlListItem::Control()
00479 {
00480   nsIXFormsControl* res = nsnull;
00481   if (mNode)
00482     NS_ADDREF(res = mNode);
00483   NS_WARN_IF_FALSE(res, "Returning nsnull for a control. Bad sign.");
00484   return res;
00485 }
00486 
00487 nsXFormsControlListItem*
00488 nsXFormsControlListItem::begin()
00489 {
00490   // handle root
00491   if (!mNode)
00492     return mFirstChild;
00493 
00494   return this;
00495 }
00496 
00497 nsXFormsControlListItem*
00498 nsXFormsControlListItem::end()
00499 {
00500   return nsnull;
00501 }
00502 
00503 
00504 //------------------------------------------------------------------------------
00505 
00506 static const nsIID sScriptingIIDs[] = {
00507   NS_IDOMELEMENT_IID,
00508   NS_IDOMEVENTTARGET_IID,
00509   NS_IDOM3NODE_IID,
00510   NS_IXFORMSMODELELEMENT_IID,
00511   NS_IXFORMSNSMODELELEMENT_IID
00512 };
00513 
00514 static nsIAtom* sModelPropsList[eModel__count];
00515 
00516 // This can be nsVoidArray because elements will remove
00517 // themselves from the list if they are deleted during refresh.
00518 static nsVoidArray* sPostRefreshList = nsnull;
00519 static nsVoidArray* sContainerPostRefreshList = nsnull;
00520 
00521 static PRInt32 sRefreshing = 0;
00522 
00523 nsPostRefresh::nsPostRefresh()
00524 {
00525 #ifdef DEBUG_smaug
00526   printf("nsPostRefresh\n");
00527 #endif
00528   ++sRefreshing;
00529 }
00530 
00531 nsPostRefresh::~nsPostRefresh()
00532 {
00533 #ifdef DEBUG_smaug
00534   printf("~nsPostRefresh\n");
00535 #endif
00536 
00537   if (sRefreshing != 1) {
00538     --sRefreshing;
00539     return;
00540   }
00541 
00542   if (sPostRefreshList) {
00543     while (sPostRefreshList->Count()) {
00544       // Iterating this way because refresh can lead to
00545       // additions/deletions in sPostRefreshList.
00546       // Iterating from last to first saves possibly few memcopies,
00547       // see nsVoidArray::RemoveElementsAt().
00548       PRInt32 last = sPostRefreshList->Count() - 1;
00549       nsIXFormsControl* control =
00550         NS_STATIC_CAST(nsIXFormsControl*, sPostRefreshList->ElementAt(last));
00551       sPostRefreshList->RemoveElementAt(last);
00552       if (control)
00553         control->Refresh();
00554     }
00555     if (sRefreshing == 1) {
00556       delete sPostRefreshList;
00557       sPostRefreshList = nsnull;
00558     }
00559   }
00560 
00561   --sRefreshing;
00562 
00563   // process sContainerPostRefreshList after we've decremented sRefreshing.
00564   // container->refresh below could ask for ContainerNeedsPostRefresh which
00565   // will add an item to the sContainerPostRefreshList if sRefreshing > 0.
00566   // So keeping this under sRefreshing-- will avoid an infinite loop.
00567   while (sContainerPostRefreshList && sContainerPostRefreshList->Count()) {
00568     PRInt32 last = sContainerPostRefreshList->Count() - 1;
00569     nsIXFormsControl* container =
00570       NS_STATIC_CAST(nsIXFormsControl*, sContainerPostRefreshList->ElementAt(last));
00571     sContainerPostRefreshList->RemoveElementAt(last);
00572     if (container) {
00573       container->Refresh();
00574     }
00575   }
00576   delete sContainerPostRefreshList;
00577   sContainerPostRefreshList = nsnull;
00578 }
00579 
00580 const nsVoidArray*
00581 nsPostRefresh::PostRefreshList()
00582 {
00583   return sPostRefreshList;
00584 }
00585 
00586 nsresult
00587 nsXFormsModelElement::NeedsPostRefresh(nsIXFormsControl* aControl)
00588 {
00589   if (sRefreshing) {
00590     if (!sPostRefreshList) {
00591       sPostRefreshList = new nsVoidArray();
00592       NS_ENSURE_TRUE(sPostRefreshList, NS_ERROR_OUT_OF_MEMORY);
00593     }
00594 
00595     if (sPostRefreshList->IndexOf(aControl) < 0) {
00596       sPostRefreshList->AppendElement(aControl);
00597     }
00598   } else {
00599     // We are not refreshing any models, so the control
00600     // can be refreshed immediately.
00601     aControl->Refresh();
00602   }
00603   return NS_OK;
00604 }
00605 
00606 PRBool
00607 nsXFormsModelElement::ContainerNeedsPostRefresh(nsIXFormsControl* aControl)
00608 {
00609 
00610   if (sRefreshing) {
00611     if (!sContainerPostRefreshList) {
00612       sContainerPostRefreshList = new nsVoidArray();
00613       if (!sContainerPostRefreshList) {
00614         return PR_FALSE;
00615       }
00616     }
00617 
00618     if (sContainerPostRefreshList->IndexOf(aControl) < 0) {
00619       sContainerPostRefreshList->AppendElement(aControl);
00620     }
00621 
00622     // return PR_TRUE to show that the control's refresh will be delayed,
00623     // whether as a result of this call or a previous call to this function.
00624     return PR_TRUE;
00625   }
00626 
00627   // Delaying the refresh doesn't make any sense.  But since this
00628   // function may be called from inside the control node's refresh already,
00629   // we shouldn't just assume that we can call the refresh here.  So
00630   // we'll just return PR_FALSE to signal that we couldn't delay the refresh.
00631 
00632   return PR_FALSE;
00633 }
00634 
00635 void
00636 nsXFormsModelElement::CancelPostRefresh(nsIXFormsControl* aControl)
00637 {
00638   if (sPostRefreshList)
00639     sPostRefreshList->RemoveElement(aControl);
00640 
00641   if (sContainerPostRefreshList)
00642     sContainerPostRefreshList->RemoveElement(aControl);
00643 }
00644 
00645 nsXFormsModelElement::nsXFormsModelElement()
00646   : mElement(nsnull),
00647     mFormControls(nsnull, &mControlListHash),
00648     mSchemaCount(0),
00649     mSchemaTotal(0),
00650     mPendingInstanceCount(0),
00651     mDocumentLoaded(PR_FALSE),
00652     mRebindAllControls(PR_FALSE),
00653     mInstancesInitialized(PR_FALSE),
00654     mReadyHandled(PR_FALSE),
00655     mLazyModel(PR_FALSE),
00656     mConstructDoneHandled(PR_FALSE),
00657     mProcessingUpdateEvent(PR_FALSE),
00658     mLoopMax(600),
00659     mInstanceDocuments(nsnull)
00660 {
00661   mControlListHash.Init();
00662 }
00663 
00664 NS_INTERFACE_MAP_BEGIN(nsXFormsModelElement)
00665   NS_INTERFACE_MAP_ENTRY(nsIXFormsModelElement)
00666   NS_INTERFACE_MAP_ENTRY(nsIXFormsNSModelElement)
00667   NS_INTERFACE_MAP_ENTRY(nsIModelElementPrivate)
00668   NS_INTERFACE_MAP_ENTRY(nsISchemaLoadListener)
00669   NS_INTERFACE_MAP_ENTRY(nsIWebServiceErrorHandler)
00670   NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
00671   NS_INTERFACE_MAP_ENTRY(nsIXFormsContextControl)
00672 NS_INTERFACE_MAP_END_INHERITING(nsXFormsStubElement)
00673 
00674 NS_IMPL_ADDREF_INHERITED(nsXFormsModelElement, nsXFormsStubElement)
00675 NS_IMPL_RELEASE_INHERITED(nsXFormsModelElement, nsXFormsStubElement)
00676 
00677 NS_IMETHODIMP
00678 nsXFormsModelElement::OnDestroyed()
00679 {
00680   mElement = nsnull;
00681   mSchemas = nsnull;
00682 
00683   if (mInstanceDocuments)
00684     mInstanceDocuments->DropReferences();
00685 
00686   mFormControls.Clear();
00687   mControlListHash.Clear();
00688 
00689   return NS_OK;
00690 }
00691 
00692 void
00693 nsXFormsModelElement::RemoveModelFromDocument()
00694 {
00695   mDocumentLoaded = PR_FALSE;
00696 
00697   nsCOMPtr<nsIDOMDocument> domDoc;
00698   mElement->GetOwnerDocument(getter_AddRefs(domDoc));
00699   if (!domDoc)
00700     return;
00701 
00702   RemoveFromModelList(domDoc, this);
00703 
00704   nsCOMPtr<nsIDOMEventTarget> targ = do_QueryInterface(domDoc);
00705   if (targ) {
00706     targ->RemoveEventListener(NS_LITERAL_STRING("DOMContentLoaded"), this, PR_TRUE);
00707 
00708     nsCOMPtr<nsIDOMWindowInternal> window;
00709     nsXFormsUtils::GetWindowFromDocument(domDoc, getter_AddRefs(window));
00710     targ = do_QueryInterface(window);
00711     if (targ) {
00712       targ->RemoveEventListener(NS_LITERAL_STRING("unload"), this, PR_TRUE);
00713     }
00714   }
00715 }
00716 
00717 NS_IMETHODIMP
00718 nsXFormsModelElement::GetScriptingInterfaces(PRUint32 *aCount, nsIID ***aArray)
00719 {
00720   return nsXFormsUtils::CloneScriptingInterfaces(sScriptingIIDs,
00721                                                  NS_ARRAY_LENGTH(sScriptingIIDs),
00722                                                  aCount, aArray);
00723 }
00724 
00725 NS_IMETHODIMP
00726 nsXFormsModelElement::WillChangeDocument(nsIDOMDocument* aNewDocument)
00727 {
00728   RemoveModelFromDocument();
00729   return NS_OK;
00730 }
00731 
00732 NS_IMETHODIMP
00733 nsXFormsModelElement::DocumentChanged(nsIDOMDocument* aNewDocument)
00734 {
00735   if (!aNewDocument)
00736     return NS_OK;
00737 
00738   AddToModelList(aNewDocument, this);
00739 
00740   nsCOMPtr<nsIDOMEventTarget> targ = do_QueryInterface(aNewDocument);
00741   if (targ) {
00742     targ->AddEventListener(NS_LITERAL_STRING("DOMContentLoaded"), this, PR_TRUE);
00743 
00744     nsCOMPtr<nsIDOMWindowInternal> window;
00745     nsXFormsUtils::GetWindowFromDocument(aNewDocument, getter_AddRefs(window));
00746     targ = do_QueryInterface(window);
00747     if (targ) {
00748       targ->AddEventListener(NS_LITERAL_STRING("unload"), this, PR_TRUE);
00749     }
00750   }
00751 
00752   return NS_OK;
00753 }
00754 
00755 NS_IMETHODIMP
00756 nsXFormsModelElement::DoneAddingChildren()
00757 {
00758   return InitializeInstances();
00759 }
00760 
00761 nsresult
00762 nsXFormsModelElement::InitializeInstances()
00763 {
00764   if (mInstancesInitialized || !mElement) {
00765     return NS_OK;
00766   }
00767 
00768   mInstancesInitialized = PR_TRUE;
00769 
00770   nsCOMPtr<nsIDOMNodeList> children;
00771   mElement->GetChildNodes(getter_AddRefs(children));
00772 
00773   PRUint32 childCount = 0;
00774   if (children) {
00775     children->GetLength(&childCount);
00776   }
00777 
00778   nsresult rv;
00779   for (PRUint32 i = 0; i < childCount; ++i) {
00780     nsCOMPtr<nsIDOMNode> child;
00781     children->Item(i, getter_AddRefs(child));
00782     if (nsXFormsUtils::IsXFormsElement(child, NS_LITERAL_STRING("instance"))) {
00783       nsCOMPtr<nsIInstanceElementPrivate> instance(do_QueryInterface(child));
00784       NS_ENSURE_STATE(instance);
00785       rv = instance->Initialize();
00786       NS_ENSURE_SUCCESS(rv, rv);
00787     }
00788   }
00789 
00790   // (XForms 4.2.1)
00791   // 1. load xml schemas
00792 
00793   nsAutoString schemaList;
00794   mElement->GetAttribute(NS_LITERAL_STRING("schema"), schemaList);
00795 
00796   if (!schemaList.IsEmpty()) {
00797     NS_ENSURE_TRUE(mSchemas, NS_ERROR_FAILURE);
00798     // Parse the whitespace-separated list.
00799     nsCOMPtr<nsIContent> content = do_QueryInterface(mElement);
00800     nsRefPtr<nsIURI> baseURI = content->GetBaseURI();
00801     nsRefPtr<nsIURI> docURI = content->GetOwnerDoc() ?
00802       content->GetOwnerDoc()->GetDocumentURI() : nsnull;
00803 
00804     nsCStringArray schemas;
00805     schemas.ParseString(NS_ConvertUTF16toUTF8(schemaList).get(), " \t\r\n");
00806 
00807     // Increase by 1 to prevent OnLoad from calling FinishConstruction
00808     mSchemaTotal = schemas.Count();
00809 
00810     for (PRInt32 i=0; i<mSchemaTotal; ++i) {
00811       rv = NS_OK;
00812       nsCAutoString uriSpec;
00813       nsCOMPtr<nsIURI> newURI;
00814       NS_NewURI(getter_AddRefs(newURI), *schemas[i], nsnull, baseURI);
00815       nsCOMPtr<nsIURL> newURL = do_QueryInterface(newURI);
00816       if (!newURL) {
00817         rv = NS_ERROR_UNEXPECTED;
00818       } else {
00819         // This code is copied from nsXMLEventsManager for extracting an
00820         // element ID from an xsd:anyURI link.
00821         nsCAutoString ref;
00822         newURL->GetRef(ref);
00823         newURL->SetRef(EmptyCString());
00824         PRBool equals = PR_FALSE;
00825         newURL->Equals(docURI, &equals);
00826         if (equals) {
00827           // We will not be able to locate the <xsd:schema> element using the
00828           // getElementById function defined on our document when <xsd:schema>
00829           // is treated as an ordinary XML data node.  So, we employ XPath to
00830           // locate it for us.
00831 
00832           NS_ConvertUTF8toUTF16 id(ref);
00833 
00834           nsCOMPtr<nsIDOMElement> el;
00835           GetSchemaElementById(mElement, id, getter_AddRefs(el));
00836           if (!el) {
00837             // Perhaps the <xsd:schema> element appears after the <xforms:model>
00838             // element in the document, so we'll defer loading it until the
00839             // document has finished loading.
00840             mPendingInlineSchemas.AppendString(id);
00841           } else {
00842             // We have an inline schema in the model element that was
00843             // referenced by the schema attribute. It will be processed
00844             // in FinishConstruction so we skip it now to avoid processing
00845             // it twice and giving invalid 'duplicate schema' errors.
00846             mSchemaTotal--;
00847             i--;
00848           }
00849         } else {
00850           newURI->GetSpec(uriSpec);
00851           rv = mSchemas->LoadAsync(NS_ConvertUTF8toUTF16(uriSpec), this);
00852         }
00853       }
00854       if (NS_FAILED(rv)) {
00855         // this is a fatal error
00856         nsXFormsUtils::ReportError(NS_LITERAL_STRING("schemaLoadError"), mElement);
00857         // Context Info: 'resource-uri'
00858         // The URI associated with the failed link.
00859         SetContextInfo("resource-uri", NS_ConvertUTF8toUTF16(uriSpec));
00860         nsXFormsUtils::DispatchEvent(mElement, eEvent_LinkException, nsnull,
00861                                      nsnull, &mContextInfo);
00862         return NS_OK;
00863       }
00864     }
00865   }
00866 
00867   // If all of the children are added and there aren't any instance elements,
00868   // yet, then we need to make sure that one is ready in case the form author
00869   // is using lazy authoring.
00870   // Lazy <xforms:intance> element is created in anonymous content using XBL.
00871   NS_ENSURE_STATE(mInstanceDocuments);
00872   PRUint32 instCount;
00873   mInstanceDocuments->GetLength(&instCount);
00874   if (!instCount) {
00875 #ifdef DEBUG
00876     printf("Creating lazy instance\n");
00877 #endif
00878     nsCOMPtr<nsIDOMDocument> domDoc;
00879     mElement->GetOwnerDocument(getter_AddRefs(domDoc));
00880     nsCOMPtr<nsIDOMDocumentXBL> xblDoc(do_QueryInterface(domDoc));
00881     if (xblDoc) {
00882       nsresult rv =
00883         xblDoc->AddBinding(mElement,
00884                            NS_LITERAL_STRING(XFORMS_LAZY_INSTANCE_BINDING));
00885       NS_ENSURE_SUCCESS(rv, rv);
00886 
00887       mInstanceDocuments->GetLength(&instCount);
00888 
00889       nsCOMPtr<nsIDOMNodeList> list;
00890       xblDoc->GetAnonymousNodes(mElement, getter_AddRefs(list));
00891       if (list) {
00892         PRUint32 childCount = 0;
00893         if (list) {
00894           list->GetLength(&childCount);
00895         }
00896 
00897         for (PRUint32 i = 0; i < childCount; ++i) {
00898           nsCOMPtr<nsIDOMNode> item;
00899           list->Item(i, getter_AddRefs(item));
00900           nsCOMPtr<nsIInstanceElementPrivate> instance =
00901             do_QueryInterface(item);
00902           if (instance) {
00903             rv = instance->Initialize();
00904             NS_ENSURE_SUCCESS(rv, rv);
00905 
00906             mLazyModel = PR_TRUE;
00907             break;
00908           }
00909         }
00910       }
00911     }
00912     NS_WARN_IF_FALSE(mLazyModel, "Installing lazy instance didn't succeed!");
00913   }
00914 
00915   // (XForms 4.2.1 - cont)
00916   // 2. construct an XPath data model from inline or external initial instance
00917   // data.  This is done by our child instance elements as they are inserted
00918   // into the document, and all of the instances will be processed by this
00919   // point.
00920 
00921   // schema and external instance data loads should delay document onload
00922 
00923   if (IsComplete()) {
00924     // No need to fire refresh event if we assume that all UI controls
00925     // appear later in the document.
00926     NS_ASSERTION(!mDocumentLoaded, "document should not be loaded yet");
00927     return FinishConstruction();
00928   }
00929 
00930   return NS_OK;
00931 }
00932 
00933 NS_IMETHODIMP
00934 nsXFormsModelElement::HandleDefault(nsIDOMEvent *aEvent, PRBool *aHandled)
00935 {
00936   if (!nsXFormsUtils::EventHandlingAllowed(aEvent, mElement))
00937     return NS_OK;
00938 
00939   *aHandled = PR_TRUE;
00940 
00941   nsAutoString type;
00942   aEvent->GetType(type);
00943   nsresult rv = NS_OK;
00944 
00945   if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Refresh].name)) {
00946     rv = Refresh();
00947   } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Revalidate].name)) {
00948     rv = Revalidate();
00949   } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Recalculate].name)) {
00950     rv = Recalculate();
00951   } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Rebuild].name)) {
00952     rv = Rebuild();
00953   } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_ModelConstructDone].name)) {
00954     rv = ConstructDone();
00955     mConstructDoneHandled = PR_TRUE;
00956   } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_Reset].name)) {
00957     Reset();
00958   } else if (type.EqualsASCII(sXFormsEventsEntries[eEvent_BindingException].name)) {
00959     // we threw up a popup during the nsXFormsUtils::DispatchEvent that sent
00960     // this error to the model
00961     *aHandled = PR_TRUE;
00962   } else {
00963     *aHandled = PR_FALSE;
00964   }
00965 
00966   NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
00967                    "nsXFormsModelElement::HandleDefault() failed!\n");
00968 
00969   return rv;
00970 }
00971 
00972 nsresult
00973 nsXFormsModelElement::ConstructDone()
00974 {
00975   nsresult rv = InitializeControls();
00976   NS_ENSURE_SUCCESS(rv, rv);
00977 
00978   return NS_OK;
00979 }
00980 
00981 NS_IMETHODIMP
00982 nsXFormsModelElement::OnCreated(nsIXTFGenericElementWrapper *aWrapper)
00983 {
00984   aWrapper->SetNotificationMask(nsIXTFElement::NOTIFY_WILL_CHANGE_DOCUMENT |
00985                                 nsIXTFElement::NOTIFY_DOCUMENT_CHANGED |
00986                                 nsIXTFElement::NOTIFY_DONE_ADDING_CHILDREN |
00987                                 nsIXTFElement::NOTIFY_HANDLE_DEFAULT);
00988 
00989   nsCOMPtr<nsIDOMElement> node;
00990   aWrapper->GetElementNode(getter_AddRefs(node));
00991 
00992   // It's ok to keep a weak pointer to mElement.  mElement will have an
00993   // owning reference to this object, so as long as we null out mElement in
00994   // OnDestroyed, it will always be valid.
00995 
00996   mElement = node;
00997   NS_ASSERTION(mElement, "Wrapper is not an nsIDOMElement, we'll crash soon");
00998 
00999   nsresult rv = mMDG.Init(this);
01000   NS_ENSURE_SUCCESS(rv, rv);
01001 
01002   mSchemas = do_CreateInstance(NS_SCHEMALOADER_CONTRACTID);
01003 
01004   mInstanceDocuments = new nsXFormsModelInstanceDocuments();
01005   NS_ASSERTION(mInstanceDocuments, "could not create mInstanceDocuments?!");
01006 
01007   // Initialize hash tables
01008   NS_ENSURE_TRUE(mNodeToType.Init(), NS_ERROR_OUT_OF_MEMORY);
01009   NS_ENSURE_TRUE(mNodeToP3PType.Init(), NS_ERROR_OUT_OF_MEMORY);
01010 
01011 
01012   // Get eventual user-set loop maximum. Used by RequestUpdateEvent().
01013   nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
01014   if (NS_SUCCEEDED(rv) && pref) {
01015     PRInt32 val;
01016     if (NS_SUCCEEDED(pref->GetIntPref("xforms.modelLoopMax", &val)))
01017       mLoopMax = val;
01018   }
01019 
01020   return NS_OK;
01021 }
01022 
01023 // nsIXFormsModelElement
01024 
01025 NS_IMETHODIMP
01026 nsXFormsModelElement::GetInstanceDocuments(nsIDOMNodeList **aDocuments)
01027 {
01028   NS_ENSURE_STATE(mInstanceDocuments);
01029   NS_ENSURE_ARG_POINTER(aDocuments);
01030   NS_ADDREF(*aDocuments = mInstanceDocuments);
01031   return NS_OK;
01032 }
01033 
01034 NS_IMETHODIMP
01035 nsXFormsModelElement::GetInstanceDocument(const nsAString& aInstanceID,
01036                                           nsIDOMDocument **aDocument)
01037 {
01038   NS_ENSURE_ARG_POINTER(aDocument);
01039 
01040   *aDocument = FindInstanceDocument(aInstanceID).get();  // transfer reference
01041 
01042   if (*aDocument) {
01043     return NS_OK;
01044   }
01045 
01046   const nsPromiseFlatString& flat = PromiseFlatString(aInstanceID);
01047   const PRUnichar *strings[] = { flat.get() };
01048   nsXFormsUtils::ReportError(aInstanceID.IsEmpty() ?
01049                                NS_LITERAL_STRING("defInstanceNotFound") :
01050                                NS_LITERAL_STRING("instanceNotFound"),
01051                              strings, 1, mElement, nsnull);
01052   return NS_ERROR_DOM_NOT_FOUND_ERR;
01053 }
01054 
01055 NS_IMETHODIMP
01056 nsXFormsModelElement::Rebuild()
01057 {
01058 #ifdef DEBUG
01059   printf("nsXFormsModelElement::Rebuild()\n");
01060 #endif
01061 
01062   // 1 . Clear graph
01063   nsresult rv;
01064   rv = mMDG.Clear();
01065   NS_ENSURE_SUCCESS(rv, rv);
01066 
01067   // Clear any type information
01068   NS_ENSURE_TRUE(mNodeToType.IsInitialized() && mNodeToP3PType.IsInitialized(),
01069                  NS_ERROR_FAILURE);
01070   mNodeToType.Clear();
01071   mNodeToP3PType.Clear();
01072 
01073   // 2. Process bind elements
01074   rv = ProcessBindElements();
01075   NS_ENSURE_SUCCESS(rv, rv);
01076 
01077   // 3. If this is not form load, re-attach all elements and validate
01078   //    instance documents
01079   if (mReadyHandled) {
01080     mRebindAllControls = PR_TRUE;
01081     ValidateInstanceDocuments();
01082   }
01083 
01084   // 4. Rebuild graph
01085   return mMDG.Rebuild();
01086 }
01087 
01088 NS_IMETHODIMP
01089 nsXFormsModelElement::Recalculate()
01090 {
01091 #ifdef DEBUG
01092   printf("nsXFormsModelElement::Recalculate()\n");
01093 #endif
01094 
01095   return mMDG.Recalculate(&mChangedNodes);
01096 }
01097 
01098 void
01099 nsXFormsModelElement::SetSingleState(nsIDOMElement *aElement,
01100                                      PRBool         aState,
01101                                      nsXFormsEvent  aOnEvent)
01102 {
01103   nsXFormsEvent event = aState ? aOnEvent : (nsXFormsEvent) (aOnEvent + 1);
01104 
01105   // Dispatch event
01106   nsXFormsUtils::DispatchEvent(aElement, event);
01107 }
01108 
01109 NS_IMETHODIMP
01110 nsXFormsModelElement::SetStates(nsIXFormsControl *aControl,
01111                                 nsIDOMNode       *aNode)
01112 {
01113   NS_ENSURE_ARG(aControl);
01114 
01115   nsCOMPtr<nsIDOMElement> element;
01116   aControl->GetElement(getter_AddRefs(element));
01117   NS_ENSURE_STATE(element);
01118 
01119   nsCOMPtr<nsIXTFElementWrapper> xtfWrap(do_QueryInterface(element));
01120   NS_ENSURE_STATE(xtfWrap);
01121 
01122   PRInt32 iState;
01123   const nsXFormsNodeState* ns = nsnull;
01124   if (aNode) {
01125     ns = mMDG.GetNodeState(aNode);
01126     NS_ENSURE_STATE(ns);
01127     iState = ns->GetIntrinsicState();
01128     nsCOMPtr<nsIContent> content(do_QueryInterface(element));
01129     NS_ENSURE_STATE(content);
01130     PRInt32 rangeState = content->IntrinsicState() &
01131                            (NS_EVENT_STATE_INRANGE | NS_EVENT_STATE_OUTOFRANGE);
01132     iState = ns->GetIntrinsicState() | rangeState;
01133   } else {
01134     aControl->GetDefaultIntrinsicState(&iState);
01135   }
01136 
01137   nsresult rv = xtfWrap->SetIntrinsicState(iState);
01138   NS_ENSURE_SUCCESS(rv, rv);
01139 
01140   // Event dispatching is defined by the bound node, so if there's no bound
01141   // node, there are no events to send. xforms-ready also needs to be handled,
01142   // because these events are not sent before that.
01143   if (!ns || !mReadyHandled)
01144     return NS_OK;
01145 
01146   if (ns->ShouldDispatchValid()) {
01147     SetSingleState(element, ns->IsValid(), eEvent_Valid);
01148   }
01149   if (ns->ShouldDispatchReadonly()) {
01150     SetSingleState(element, ns->IsReadonly(), eEvent_Readonly);
01151   }
01152   if (ns->ShouldDispatchRequired()) {
01153     SetSingleState(element, ns->IsRequired(), eEvent_Required);
01154   }
01155   if (ns->ShouldDispatchRelevant()) {
01156     SetSingleState(element, ns->IsRelevant(), eEvent_Enabled);
01157   }
01158 
01159   if (ns->ShouldDispatchValueChanged()) {
01160     nsXFormsUtils::DispatchEvent(element, eEvent_ValueChanged);
01161   }
01162 
01163   return NS_OK;
01164 }
01165 
01166 NS_IMETHODIMP
01167 nsXFormsModelElement::Revalidate()
01168 {
01169 #ifdef DEBUG
01170   printf("nsXFormsModelElement::Revalidate()\n");
01171 #endif
01172 
01173 #ifdef DEBUG_MODEL
01174   printf("[%s] Changed nodes:\n", __TIME__);
01175   for (PRInt32 j = 0; j < mChangedNodes.Count(); ++j) {
01176     nsCOMPtr<nsIDOMNode> node = mChangedNodes[j];
01177     nsAutoString name;
01178     node->GetNodeName(name);
01179     printf("\t%s [%p]\n",
01180            NS_ConvertUTF16toUTF8(name).get(),
01181            (void*) node);
01182   }
01183 #endif
01184 
01185   // Revalidate nodes
01186   mMDG.Revalidate(&mChangedNodes);
01187 
01188   return NS_OK;
01189 }
01190 
01191 nsresult
01192 nsXFormsModelElement::RefreshSubTree(nsXFormsControlListItem *aCurrent,
01193                                      PRBool                   aForceRebind)
01194 {
01195   nsresult rv;
01196   nsRefPtr<nsXFormsControlListItem> current = aCurrent;
01197   while (current) {
01198     nsCOMPtr<nsIXFormsControl> control(current->Control());
01199     NS_ASSERTION(control, "A tree node without a control?!");
01200 
01201     // Get bound node
01202     nsCOMPtr<nsIDOMNode> boundNode;
01203     control->GetBoundNode(getter_AddRefs(boundNode));
01204 
01205     PRBool rebind = aForceRebind;
01206     PRBool refresh = PR_FALSE;
01207     PRBool rebindChildren = PR_FALSE;
01208 
01209 #ifdef DEBUG_MODEL
01210       nsCOMPtr<nsIDOMElement> controlElement;
01211       control->GetElement(getter_AddRefs(controlElement));
01212       printf("rebind: %d, mRebindAllControls: %d, aForceRebind: %d\n",
01213              rebind, mRebindAllControls, aForceRebind);
01214       if (controlElement) {
01215         printf("Checking control: ");
01216         //DBG_TAGINFO(controlElement);
01217       }
01218 #endif
01219 
01220     if (mRebindAllControls || rebind) {
01221       refresh = rebind = PR_TRUE;
01222     } else {
01223       PRBool usesModelBinding = PR_FALSE;
01224       control->GetUsesModelBinding(&usesModelBinding);
01225 
01226 #ifdef DEBUG_MODEL
01227       printf("usesModelBinding: %d\n", usesModelBinding);
01228 #endif
01229 
01230       nsCOMArray<nsIDOMNode> *deps = nsnull;
01231       if (usesModelBinding) {
01232         if (!boundNode) {
01233           PRBool usesSNB = PR_TRUE;
01234           control->GetUsesSingleNodeBinding(&usesSNB);
01235 
01236           // If the control doesn't use single node binding (and can thus be
01237           // bound to many nodes), the above test for boundNode means nothing.
01238           // We'll need to continue on with the work this function does so that
01239           // any controls that this control contains can be tested for whether
01240           // they may need to refresh.
01241           if (usesSNB) {
01242             // If a control uses a model binding, but has no bound node a
01243             // rebuild is the only thing that'll (eventually) change it.  We
01244             // don't need to worry about contained controls (like a label)
01245             // since the fact that there is no bound node means that this
01246             // control (and contained controls) need to behave as if
01247             // irrelevant per spec.
01248             current = current->NextSibling();
01249             continue;
01250           }
01251         }
01252       } else {
01253         // Get dependencies
01254         control->GetDependencies(&deps);
01255       }
01256       PRUint32 depCount = deps ? deps->Count() : 0;
01257 
01258 #ifdef DEBUG_MODEL
01259       nsAutoString boundName;
01260       if (boundNode)
01261         boundNode->GetNodeName(boundName);
01262       printf("\tDependencies: %d, Bound to: '%s' [%p]\n",
01263              depCount,
01264              NS_ConvertUTF16toUTF8(boundName).get(),
01265              (void*) boundNode);
01266 
01267       nsAutoString depNodeName;
01268       for (PRUint32 t = 0; t < depCount; ++t) {
01269         nsCOMPtr<nsIDOMNode> tmpdep = deps->ObjectAt(t);
01270         if (tmpdep) {
01271           tmpdep->GetNodeName(depNodeName);
01272           printf("\t\t%s [%p]\n",
01273                  NS_ConvertUTF16toUTF8(depNodeName).get(),
01274                  (void*) tmpdep);
01275         }
01276       }
01277 #endif
01278 
01279       nsCOMPtr<nsIDOM3Node> curChanged;
01280 
01281       // Iterator over changed nodes. Checking for rebind, too.  If it ever
01282       // becomes true due to some condition below, we can stop this testing
01283       // since any control that needs to rebind will also refresh.
01284       for (PRInt32 j = 0; j < mChangedNodes.Count() && !rebind; ++j) {
01285         curChanged = do_QueryInterface(mChangedNodes[j]);
01286 
01287         // Check whether the bound node is dirty. If so, we need to refresh the
01288         // control (get updated node value from the bound node)
01289         if (!refresh && boundNode) {
01290           curChanged->IsSameNode(boundNode, &refresh);
01291 
01292           // Two ways to go here. Keep in mind that controls using model
01293           // binding expressions never needs to have dependencies checked as
01294           // they only rebind on xforms-rebuild
01295           if (refresh && usesModelBinding) {
01296             // 1) If the control needs a refresh, and uses model bindings,
01297             // we can stop checking here
01298             break;
01299           }
01300           if (refresh || usesModelBinding) {
01301             // 2) If either the control needs a refresh or it uses a model
01302             // binding we can continue to next changed node
01303             continue;
01304           }
01305         }
01306 
01307         // Check whether any dependencies are dirty. If so, we need to rebind
01308         // the control (re-evaluate it's binding expression)
01309         for (PRUint32 k = 0; k < depCount; ++k) {
01313           curChanged->IsSameNode(deps->ObjectAt(k), &rebind);
01314           if (rebind)
01315             // We need to rebind the control, no need to check any more
01316             break;
01317         }
01318       }
01319 #ifdef DEBUG_MODEL
01320       printf("\trebind: %d, refresh: %d\n", rebind, refresh);
01321 #endif
01322     }
01323 
01324     // Handle rebinding
01325     if (rebind) {
01326       rv = control->Bind(&rebindChildren);
01327       NS_ENSURE_SUCCESS(rv, rv);
01328     }
01329 
01330     // Handle refreshing
01331     if (rebind || refresh) {
01332       control->Refresh();
01333       // XXX: bug 336608: we should really check the return result, but
01334       // f.x. select1 returns error because of no widget...?  so we should
01335       // ensure that an error is only returned when there actually is an
01336       // error, and we should report that on the console... possibly we should
01337       // then continue, instead of bailing totally.
01338       // NS_ENSURE_SUCCESS(rv, rv);
01339     }
01340 
01341     // Refresh children
01342     rv = RefreshSubTree(current->FirstChild(), rebindChildren);
01343     NS_ENSURE_SUCCESS(rv, rv);
01344 
01345     current = current->NextSibling();
01346   }
01347 
01348   return NS_OK;
01349 }
01350 
01351 
01352 NS_IMETHODIMP
01353 nsXFormsModelElement::Refresh()
01354 {
01355 #ifdef DEBUG
01356   printf("nsXFormsModelElement::Refresh()\n");
01357 #endif
01358 
01359   // XXXbeaufour: Can we somehow suspend redraw / "screen update" while doing
01360   // the refresh? That should save a lot of time, and avoid flickering of
01361   // controls.
01362 
01363   // Using brackets here to provide a scope for the
01364   // nsPostRefresh.  We want to make sure that nsPostRefresh's destructor
01365   // runs (and thus processes the postrefresh and containerpostrefresh lists)
01366   // before we clear the dispatch flags
01367   {
01368     nsPostRefresh postRefresh = nsPostRefresh();
01369 
01370     if (!mDocumentLoaded) {
01371       return NS_OK;
01372     }
01373 
01374     // Kick off refreshing on root node
01375     nsresult rv = RefreshSubTree(mFormControls.FirstChild(), PR_FALSE);
01376     NS_ENSURE_SUCCESS(rv, rv);
01377   }
01378 
01379   // Clear refresh structures
01380   mChangedNodes.Clear();
01381   mRebindAllControls = PR_FALSE;
01382   mMDG.ClearDispatchFlags();
01383 
01384   return NS_OK;
01385 }
01386 
01387 // nsISchemaLoadListener
01388 
01389 NS_IMETHODIMP
01390 nsXFormsModelElement::OnLoad(nsISchema* aSchema)
01391 {
01392   mSchemaCount++;
01393 
01394   // If there is no model element, then schema loading finished after
01395   // main page failed to load.
01396   if (IsComplete() && mElement) {
01397     nsresult rv = FinishConstruction();
01398     NS_ENSURE_SUCCESS(rv, rv);
01399 
01400     MaybeNotifyCompletion();
01401   }
01402 
01403   return NS_OK;
01404 }
01405 
01406 // nsIWebServiceErrorHandler
01407 
01408 NS_IMETHODIMP
01409 nsXFormsModelElement::OnError(nsresult aStatus,
01410                               const nsAString &aStatusMessage)
01411 {
01412   nsXFormsUtils::ReportError(NS_LITERAL_STRING("schemaLoadError"), mElement);
01413   nsXFormsUtils::DispatchEvent(mElement, eEvent_LinkException);
01414   return NS_OK;
01415 }
01416 
01417 // nsIDOMEventListener
01418 
01419 NS_IMETHODIMP
01420 nsXFormsModelElement::HandleEvent(nsIDOMEvent* aEvent)
01421 {
01422   if (!nsXFormsUtils::EventHandlingAllowed(aEvent, mElement))
01423     return NS_OK;
01424 
01425   nsAutoString type;
01426   aEvent->GetType(type);
01427 
01428   if (type.EqualsLiteral("DOMContentLoaded")) {
01429     return HandleLoad(aEvent);
01430   }else if (type.EqualsLiteral("unload")) {
01431     return HandleUnload(aEvent);
01432   }
01433 
01434   return NS_OK;
01435 }
01436 
01437 // nsIModelElementPrivate
01438 
01439 NS_IMETHODIMP
01440 nsXFormsModelElement::AddFormControl(nsIXFormsControl *aControl,
01441                                      nsIXFormsControl *aParent)
01442 {
01443 #ifdef DEBUG_MODEL
01444   printf("nsXFormsModelElement::AddFormControl(con: %p, parent: %p)\n",
01445          (void*) aControl, (void*) aParent);
01446 #endif
01447 
01448   NS_ENSURE_ARG(aControl);
01449   return mFormControls.AddControl(aControl, aParent);
01450 }
01451 
01452 NS_IMETHODIMP
01453 nsXFormsModelElement::RemoveFormControl(nsIXFormsControl *aControl)
01454 {
01455 #ifdef DEBUG_MODEL
01456   printf("nsXFormsModelElement::RemoveFormControl(con: %p)\n",
01457          (void*) aControl);
01458 #endif
01459 
01460   NS_ENSURE_ARG(aControl);
01461   PRBool removed;
01462   nsresult rv = mFormControls.RemoveControl(aControl, removed);
01463   NS_WARN_IF_FALSE(removed,
01464                    "Tried to remove control that was not in the model");
01465   return rv;
01466 }
01467 
01468 NS_IMETHODIMP
01469 nsXFormsModelElement::GetTypeForControl(nsIXFormsControl  *aControl,
01470                                         nsISchemaType    **aType)
01471 {
01472   NS_ENSURE_ARG_POINTER(aType);
01473   *aType = nsnull;
01474 
01475   nsCOMPtr<nsIDOMNode> boundNode;
01476   aControl->GetBoundNode(getter_AddRefs(boundNode));
01477   if (!boundNode) {
01478     // if the control isn't bound to instance data, it doesn't make sense to
01479     // return a type.  It is perfectly valid for there to be no bound node,
01480     // so no need to use an NS_ENSURE_xxx macro, either.
01481     return NS_ERROR_FAILURE;
01482   }
01483 
01484   return GetTypeForNode(boundNode, aType);
01485 }
01486 
01487 NS_IMETHODIMP nsXFormsModelElement::GetTypeForNode(nsIDOMNode     *aBoundNode,
01488                                                    nsISchemaType **aType)
01489 {
01490   nsAutoString schemaTypeName, schemaTypeNamespace;
01491   nsresult rv = GetTypeFromNode(aBoundNode, schemaTypeName,
01492                                 schemaTypeNamespace);
01493 
01494   NS_ENSURE_SUCCESS(rv, rv);
01495 
01496   nsXFormsSchemaValidator validator;
01497 
01498   nsCOMPtr<nsISchemaCollection> schemaColl = do_QueryInterface(mSchemas);
01499   if (schemaColl) {
01500     nsCOMPtr<nsISchema> schema;
01501     schemaColl->GetSchema(schemaTypeNamespace, getter_AddRefs(schema));
01502     // if no schema found, then we will only handle built-in types.
01503     if (schema)
01504       validator.LoadSchema(schema);
01505   }
01506 
01507   if (validator.GetType(schemaTypeName, schemaTypeNamespace, aType))
01508     rv = NS_OK;
01509   else
01510     rv = NS_ERROR_FAILURE;
01511 
01512   return rv;
01513 }
01514 
01515 /* static */ nsresult
01516 nsXFormsModelElement::GetTypeAndNSFromNode(nsIDOMNode *aInstanceData,
01517                                            nsAString &aType, nsAString &aNSUri)
01518 {
01519   // 6.2.1 1. see if the instance data has a schema type.
01520   // if the control has a schema type then we will then
01521   // have to set a MIP node.
01522   nsCOMPtr<nsISchemaType> schemaType;
01523   nsresult rv = GetTypeForNode(aInstanceData, getter_AddRefs(schemaType));
01524 
01525   if (rv == NS_OK) {
01526     schemaType->GetTargetNamespace(aNSUri);
01527     schemaType->GetName(aType);
01528 
01529     return NS_OK;
01530   }
01531 
01532   // 6.2.1 2 & 3
01533   // see if the type is assigned as an xsi:type, or XForms:type
01534   nsAutoString schemaTypePrefix;
01535   rv = nsXFormsUtils::ParseTypeFromNode(aInstanceData, aType, schemaTypePrefix);
01536 
01537   // 6.2.1 4. Otherwise it is a string
01538   if (rv == NS_ERROR_NOT_AVAILABLE) {
01539     // if there is no type assigned, then assume that the type is 'string'
01540     aNSUri.Assign(NS_LITERAL_STRING(NS_NAMESPACE_XML_SCHEMA));
01541     aType.Assign(NS_LITERAL_STRING("string"));
01542     rv = NS_OK;
01543   } else {
01544     if (schemaTypePrefix.IsEmpty()) {
01545       aNSUri.AssignLiteral("");
01546     } else {
01547       // get the namespace url from the prefix
01548       nsCOMPtr<nsIDOM3Node> domNode3(do_QueryInterface(mElement, &rv));
01549       NS_ENSURE_SUCCESS(rv, rv);
01550 
01551       rv = domNode3->LookupNamespaceURI(schemaTypePrefix, aNSUri);
01552     }
01553   }
01554   return rv;
01555 }
01556 
01557 NS_IMETHODIMP
01558 nsXFormsModelElement::InstanceLoadStarted()
01559 {
01560   ++mPendingInstanceCount;
01561   return NS_OK;
01562 }
01563 
01564 NS_IMETHODIMP
01565 nsXFormsModelElement::InstanceLoadFinished(PRBool aSuccess,
01566                                            const nsAString& aURI)
01567 {
01568   if (!aSuccess) {
01569     // This will leave mPendingInstanceCount in an invalid state, which is
01570     // exactly what we want, because this is a fatal error, and processing
01571     // should stop. If we decrease mPendingInstanceCount, the model would
01572     // finish construction, which is wrong.
01573     nsXFormsUtils::ReportError(NS_LITERAL_STRING("instanceLoadError"), mElement);
01574     if (!aURI.IsEmpty()) {
01575       // Context Info: 'resource-uri'
01576       // The resource URI of the link that failed.
01577       nsCOMPtr<nsXFormsContextInfo> contextInfo =
01578         new nsXFormsContextInfo(mElement);
01579       NS_ENSURE_TRUE(contextInfo, NS_ERROR_OUT_OF_MEMORY);
01580       contextInfo->SetStringValue("resource-uri", aURI);
01581       mContextInfo.AppendObject(contextInfo);
01582     }
01583     nsXFormsUtils::DispatchEvent(mElement, eEvent_LinkException, nsnull,
01584                                  nsnull, &mContextInfo);
01585     return NS_OK;
01586   }
01587 
01588   --mPendingInstanceCount;
01589   if (IsComplete()) {
01590     nsresult rv = FinishConstruction();
01591     if (NS_SUCCEEDED(rv)) {
01592       MaybeNotifyCompletion();
01593     }
01594   }
01595 
01596   return NS_OK;
01597 }
01598 
01599 NS_IMETHODIMP
01600 nsXFormsModelElement::FindInstanceElement(const nsAString &aID,
01601                                           nsIInstanceElementPrivate **aElement)
01602 {
01603   NS_ENSURE_STATE(mInstanceDocuments);
01604   *aElement = nsnull;
01605 
01606   PRUint32 instCount;
01607   mInstanceDocuments->GetLength(&instCount);
01608   if (instCount) {
01609     nsCOMPtr<nsIDOMElement> element;
01610     nsAutoString id;
01611     for (PRUint32 i = 0; i < instCount; ++i) {
01612       nsIInstanceElementPrivate* instEle = mInstanceDocuments->GetInstanceAt(i);
01613       instEle->GetElement(getter_AddRefs(element));
01614 
01615       if (aID.IsEmpty()) {
01616         NS_ADDREF(instEle);
01617         *aElement = instEle;
01618         break;
01619       } else if (!element) {
01620         // this should only happen if the instance on the list is lazy authored
01621         // and as far as I can tell, a lazy authored instance should be the
01622         // first (and only) instance in the model and unable to have an ID.
01623         // But that isn't clear to me reading the spec, so for now
01624         // we'll play it safe in case the WG more clearly defines lazy authoring
01625         // in the future.
01626         continue;
01627       }
01628 
01629       element->GetAttribute(NS_LITERAL_STRING("id"), id);
01630       if (aID.Equals(id)) {
01631         NS_ADDREF(instEle);
01632         *aElement = instEle;
01633         break;
01634       }
01635     }
01636   }
01637 
01638   return NS_OK;
01639 }
01640 
01641 NS_IMETHODIMP
01642 nsXFormsModelElement::SetNodeValue(nsIDOMNode      *aNode,
01643                                    const nsAString &aNodeValue,
01644                                    PRBool           aDoRefresh,
01645                                    PRBool          *aNodeChanged)
01646 {
01647   NS_ENSURE_ARG_POINTER(aNodeChanged);
01648   nsresult rv = mMDG.SetNodeValue(aNode, aNodeValue, aNodeChanged);
01649   NS_ENSURE_SUCCESS(rv, rv);
01650   if (*aNodeChanged && aDoRefresh) {
01651     rv = RequestRecalculate();
01652     NS_ENSURE_SUCCESS(rv, rv);
01653     rv = RequestRevalidate();
01654     NS_ENSURE_SUCCESS(rv, rv);
01655     rv = RequestRefresh();
01656     NS_ENSURE_SUCCESS(rv, rv);
01657   }
01658 
01659   return NS_OK;
01660 }
01661 
01662 NS_IMETHODIMP
01663 nsXFormsModelElement::SetNodeContent(nsIDOMNode *aNode,
01664                                      nsIDOMNode *aNodeContent,
01665                                      PRBool      aDoRebuild)
01666 {
01667   nsresult rv = mMDG.SetNodeContent(aNode, aNodeContent);
01668   NS_ENSURE_SUCCESS(rv, rv);
01669 
01670   if (aDoRebuild) {
01671     rv = RequestRebuild();
01672     NS_ENSURE_SUCCESS(rv, rv);
01673     rv = RequestRecalculate();
01674     NS_ENSURE_SUCCESS(rv, rv);
01675     rv = RequestRevalidate();
01676     NS_ENSURE_SUCCESS(rv, rv);
01677     rv = RequestRefresh();
01678     NS_ENSURE_SUCCESS(rv, rv);
01679   }
01680 
01681   return NS_OK;
01682 }
01683 
01684 NS_IMETHODIMP
01685 nsXFormsModelElement::ValidateNode(nsIDOMNode *aInstanceNode, PRBool *aResult)
01686 {
01687   NS_ENSURE_ARG_POINTER(aResult);
01688 
01689   nsAutoString schemaTypeName, schemaTypeNamespace;
01690   nsresult rv = GetTypeAndNSFromNode(aInstanceNode, schemaTypeName,
01691                                      schemaTypeNamespace);
01692   NS_ENSURE_SUCCESS(rv, rv);
01693 
01694   nsXFormsSchemaValidator validator;
01695   nsCOMPtr<nsISchemaCollection> schemaColl = do_QueryInterface(mSchemas);
01696   if (schemaColl) {
01697     nsCOMPtr<nsISchema> schema;
01698     schemaColl->GetSchema(schemaTypeNamespace, getter_AddRefs(schema));
01699     // if no schema found, then we will only handle built-in types.
01700     if (schema)
01701       validator.LoadSchema(schema);
01702   }
01703 
01704   nsCOMPtr<nsISchemaType> type;
01705   rv = validator.GetType(schemaTypeName, schemaTypeNamespace,
01706                          getter_AddRefs(type));
01707   NS_ENSURE_SUCCESS(rv, rv);
01708 
01709   PRUint16 typevalue = nsISchemaType::SCHEMA_TYPE_SIMPLE;
01710   if (type) {
01711     rv = type->GetSchemaType(&typevalue);
01712     NS_ENSURE_SUCCESS(rv, rv);
01713   }
01714 
01715   PRBool isValid = PR_FALSE;
01716   if (typevalue == nsISchemaType::SCHEMA_TYPE_SIMPLE) {
01717     nsAutoString value;
01718     nsXFormsUtils::GetNodeValue(aInstanceNode, value);
01719     isValid = validator.ValidateString(value, schemaTypeName,
01720                                               schemaTypeNamespace);
01721   } else {
01722     isValid = validator.Validate(aInstanceNode);
01723   }
01724   *aResult = isValid;
01725   return NS_OK;
01726 }
01727 
01728 nsresult
01729 nsXFormsModelElement::ValidateDocument(nsIDOMDocument *aInstanceDocument,
01730                                        PRBool         *aResult)
01731 {
01732   NS_ENSURE_ARG_POINTER(aResult);
01733   NS_ENSURE_ARG(aInstanceDocument);
01734 
01735   /*
01736     This will process the instance document and check for schema validity.  It
01737     will mark nodes in the document with their schema types using nsIProperty
01738     until it hits a structural schema validation error.  So if the instance
01739     document's XML structure is invalid, don't expect type properties to be
01740     set.
01741 
01742     Note that if the structure is fine but some simple types nodes (nodes
01743     that contain text only) are invalid (say one has a empty nodeValue but
01744     should be a date), the schema validator will continue processing and add
01745     the type properties.  Schema validation will return false at the end.
01746   */
01747 
01748   nsCOMPtr<nsIDOMElement> element;
01749   nsresult rv = aInstanceDocument->GetDocumentElement(getter_AddRefs(element));
01750   NS_ENSURE_SUCCESS(rv, rv);
01751   NS_ENSURE_STATE(element);
01752 
01753   // get namespace from node
01754   nsAutoString nsuri;
01755   element->GetNamespaceURI(nsuri);
01756 
01757   nsCOMPtr<nsISchemaCollection> schemaColl = do_QueryInterface(mSchemas);
01758   NS_ENSURE_STATE(schemaColl);
01759 
01760   nsCOMPtr<nsISchema> schema;
01761   schemaColl->GetSchema(nsuri, getter_AddRefs(schema));
01762   if (!schema) {
01763     // No schema found, so nothing to validate
01764     *aResult = PR_TRUE;
01765     return NS_OK;
01766   }
01767 
01768   nsXFormsSchemaValidator validator;
01769   validator.LoadSchema(schema);
01770   // Validate will validate the node and its subtree, as per the schema
01771   // specification.
01772   *aResult = validator.Validate(element);
01773 
01774   return NS_OK;
01775 }
01776 
01777 /*
01778  *  SUBMIT_SERIALIZE_NODE   - node is to be serialized
01779  *  SUBMIT_SKIP_NODE        - node is not to be serialized
01780  *  SUBMIT_ABORT_SUBMISSION - abort submission (invalid node or empty required node)
01781  */
01782 NS_IMETHODIMP
01783 nsXFormsModelElement::HandleInstanceDataNode(nsIDOMNode     *aInstanceDataNode,
01784                                              unsigned short *aResult)
01785 {
01786   // abort by default
01787   *aResult = SUBMIT_ABORT_SUBMISSION;
01788 
01789   const nsXFormsNodeState* ns;
01790   ns = mMDG.GetNodeState(aInstanceDataNode);
01791   NS_ENSURE_STATE(ns);
01792 
01793   if (!ns->IsRelevant()) {
01794     // not relevant, thus skip
01795     *aResult = SUBMIT_SKIP_NODE;
01796   } else if (ns->IsRequired()) {
01797     // required and has a value, continue
01798     nsAutoString value;
01799     nsXFormsUtils::GetNodeValue(aInstanceDataNode, value);
01800     if (!value.IsEmpty() && ns->IsValid())
01801       *aResult = SUBMIT_SERIALIZE_NODE;
01802   } else if (ns->IsValid()) {
01803     // valid
01804     *aResult = SUBMIT_SERIALIZE_NODE;
01805   }
01806 
01807   return NS_OK;
01808 }
01809 
01810 NS_IMETHODIMP
01811 nsXFormsModelElement::GetLazyAuthored(PRBool *aLazyInstance)
01812 {
01813   *aLazyInstance = mLazyModel;
01814   return NS_OK;
01815 }
01816 
01817 NS_IMETHODIMP
01818 nsXFormsModelElement::GetIsReady(PRBool *aIsReady)
01819 {
01820   *aIsReady = mReadyHandled;
01821   return NS_OK;
01822 }
01823 
01824 NS_IMETHODIMP
01825 nsXFormsModelElement::GetTypeFromNode(nsIDOMNode *aInstanceData,
01826                                       nsAString  &aType,
01827                                       nsAString  &aNSUri)
01828 {
01829   // aInstanceData could be an instance data node or it could be an attribute
01830   // on an instance data node (basically the node that a control is bound to).
01831 
01832   nsString *typeVal = nsnull;
01833 
01834   // Get type stored directly on instance node
01835   nsAutoString typeAttribute;
01836   nsCOMPtr<nsIDOMElement> nodeElem(do_QueryInterface(aInstanceData));
01837   if (nodeElem) {
01838     nodeElem->GetAttributeNS(NS_LITERAL_STRING(NS_NAMESPACE_XML_SCHEMA_INSTANCE),
01839                              NS_LITERAL_STRING("type"), typeAttribute);
01840     if (!typeAttribute.IsEmpty()) {
01841       typeVal = &typeAttribute;
01842     }
01843   }
01844 
01845   // If there was no type information on the node itself, check for a type
01846   // bound to the node via <xforms:bind>
01847   if (!typeVal && !mNodeToType.Get(aInstanceData, &typeVal)) {
01848     // check if schema validation left us a nsISchemaType*
01849     nsCOMPtr<nsIAtom> key = do_GetAtom("xsdtype");
01850     NS_ENSURE_TRUE(key, NS_ERROR_OUT_OF_MEMORY);
01851 
01852     nsresult rv = NS_ERROR_FAILURE;
01853     nsCOMPtr<nsIVariant> xsdType;
01854     // this is stored on the DOM3Node as a property called xsdtype
01855     nsCOMPtr<nsIContent> pContent(do_QueryInterface(aInstanceData));
01856 
01857     if (pContent) {
01858        xsdType = static_cast<nsIVariant*>(pContent->GetProperty(key, &rv));
01859     } else {
01860       // see if this is stored on an attribute node
01861       nsCOMPtr<nsIAttribute> pAttribute(do_QueryInterface(aInstanceData));
01862 
01863       if (pAttribute) {
01864         xsdType = static_cast<nsIVariant*>(pAttribute->GetProperty(key, &rv));
01865       }
01866     }
01867 
01868     if (NS_SUCCEEDED(rv) && xsdType) {
01869       nsCOMPtr<nsISchemaType> type;
01870       nsIID *containedInterface;
01871 
01872       if (NS_SUCCEEDED(xsdType->GetAsInterface(&containedInterface,
01873                                                getter_AddRefs(type))) && type) {
01874         type->GetName(aType);
01875         type->GetTargetNamespace(aNSUri);
01876         return NS_OK;
01877       }
01878     }
01879 
01880     // No type information found
01881     return NS_ERROR_NOT_AVAILABLE;
01882   }
01883 
01884   // split type (ns:type) into namespace and type.
01885   nsAutoString prefix;
01886   PRInt32 separator = typeVal->FindChar(':');
01887   if ((PRUint32) separator == (typeVal->Length() - 1)) {
01888     const PRUnichar *strings[] = { typeVal->get() };
01889     nsXFormsUtils::ReportError(NS_LITERAL_STRING("missingTypeName"), strings, 1,
01890                                mElement, nsnull);
01891     return NS_ERROR_UNEXPECTED;
01892   }
01893 
01894   if (separator == kNotFound) {
01895     // no namespace prefix, which is valid.  In this case we should follow
01896     // http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/#src-qname and pick
01897     // up the default namespace.  Which will happen by passing an empty string
01898     // as first parameter to LookupNamespaceURI.
01899     prefix = EmptyString();
01900     aType.Assign(*typeVal);
01901   } else {
01902     prefix.Assign(Substring(*typeVal, 0, separator));
01903     aType.Assign(Substring(*typeVal, ++separator, typeVal->Length()));
01904 
01905     if (prefix.IsEmpty()) {
01906       aNSUri = EmptyString();
01907       return NS_OK;
01908     }
01909   }
01910 
01911   // get the namespace url from the prefix using instance data node
01912   nsresult rv;
01913   nsCOMPtr<nsIDOM3Node> domNode3 = do_QueryInterface(aInstanceData, &rv);
01914   NS_ENSURE_SUCCESS(rv, rv);
01915   rv = domNode3->LookupNamespaceURI(prefix, aNSUri);
01916 
01917   if (DOMStringIsNull(aNSUri)) {
01918     // if not found using instance data node, use <xf:instance> node
01919     nsCOMPtr<nsIDOMNode> instanceNode;
01920     rv = nsXFormsUtils::GetInstanceNodeForData(aInstanceData,
01921                                                getter_AddRefs(instanceNode));
01922     NS_ENSURE_SUCCESS(rv, rv);
01923 
01924     domNode3 = do_QueryInterface(instanceNode, &rv);
01925     NS_ENSURE_SUCCESS(rv, rv);
01926     rv = domNode3->LookupNamespaceURI(prefix, aNSUri);
01927   }
01928 
01929   return rv;
01930 }
01931 
01938 class Updating {
01939 private:
01940   nsXFormsModelElement* mModel;
01941 
01942 public:
01943   Updating(nsXFormsModelElement* aModel)
01944     : mModel(aModel) { mModel->mProcessingUpdateEvent = PR_TRUE; };
01945   ~Updating() { mModel->mProcessingUpdateEvent = PR_FALSE; };
01946 };
01947 
01948 nsresult
01949 nsXFormsModelElement::RequestUpdateEvent(nsXFormsEvent aEvent)
01950 {
01951   if (mProcessingUpdateEvent) {
01952     mUpdateEventQueue.AppendElement(NS_INT32_TO_PTR(aEvent));
01953     return NS_OK;
01954   }
01955 
01956   Updating upd(this);
01957 
01958   // Send the requested event
01959   nsresult rv = nsXFormsUtils::DispatchEvent(mElement, aEvent);
01960   NS_ENSURE_SUCCESS(rv, rv);
01961 
01962   // Process queued events
01963   PRInt32 loopCount = 0;
01964   while (mUpdateEventQueue.Count()) {
01965     nsXFormsEvent event =
01966       NS_STATIC_CAST(nsXFormsEvent, NS_PTR_TO_UINT32(mUpdateEventQueue[0]));
01967     NS_ENSURE_TRUE(mUpdateEventQueue.RemoveElementAt(0), NS_ERROR_FAILURE);
01968 
01969     rv = nsXFormsUtils::DispatchEvent(mElement, event);
01970     NS_ENSURE_SUCCESS(rv, rv);
01971     ++loopCount;
01972     if (mLoopMax && loopCount > mLoopMax) {
01973       // Note: we could also popup a dialog asking the user whether or not to
01974       // continue.
01975       nsXFormsUtils::ReportError(NS_LITERAL_STRING("modelLoopError"), mElement);
01976       nsXFormsUtils::HandleFatalError(mElement, NS_LITERAL_STRING("LoopError"));
01977       return NS_ERROR_FAILURE;
01978     }
01979   }
01980 
01981   return NS_OK;
01982 }
01983 
01984 
01985 NS_IMETHODIMP
01986 nsXFormsModelElement::RequestRebuild()
01987 {
01988   return RequestUpdateEvent(eEvent_Rebuild);
01989 }
01990 
01991 NS_IMETHODIMP
01992 nsXFormsModelElement::RequestRecalculate()
01993 {
01994   return RequestUpdateEvent(eEvent_Recalculate);
01995 }
01996 
01997 NS_IMETHODIMP
01998 nsXFormsModelElement::RequestRevalidate()
01999 {
02000   return RequestUpdateEvent(eEvent_Revalidate);
02001 }
02002 
02003 NS_IMETHODIMP
02004 nsXFormsModelElement::RequestRefresh()
02005 {
02006   return RequestUpdateEvent(eEvent_Refresh);
02007 }
02008 
02009 
02010 // nsIXFormsContextControl
02011 
02012 NS_IMETHODIMP
02013 nsXFormsModelElement::SetContext(nsIDOMNode *aContextNode,
02014                                  PRInt32     aContextPosition,
02015                                  PRInt32     aContextSize)
02016 {
02017   return NS_ERROR_NOT_IMPLEMENTED;
02018 }
02019 
02020 NS_IMETHODIMP
02021 nsXFormsModelElement::GetContext(nsAString      &aModelID,
02022                                  nsIDOMNode    **aContextNode,
02023                                  PRInt32        *aContextPosition,
02024                                  PRInt32        *aContextSize)
02025 {
02026   // Adding the nsIXFormsContextControl interface to model to allow
02027   // submission elements to call our binding evaluation methods, like
02028   // EvaluateNodeBinding.  If GetContext can get called outside of the binding
02029   // codepath, then this MIGHT lead to problems.
02030 
02031   NS_ENSURE_ARG(aContextSize);
02032   NS_ENSURE_ARG(aContextPosition);
02033   *aContextNode = nsnull;
02034 
02035   // better get the stuff most likely to fail out of the way first.  No sense
02036   // changing the other values that we are returning unless this is successful.
02037   nsresult rv = NS_ERROR_FAILURE;
02038 
02039   // Anybody (like a submission element) asking a model element for its context
02040   // for XPath expressions will want the root node of the default instance
02041   // document
02042   nsCOMPtr<nsIDOMDocument> firstInstanceDoc =
02043     FindInstanceDocument(EmptyString());
02044   NS_ENSURE_TRUE(firstInstanceDoc, rv);
02045 
02046   nsCOMPtr<nsIDOMElement> firstInstanceRoot;
02047   rv = firstInstanceDoc->GetDocumentElement(getter_AddRefs(firstInstanceRoot));
02048   NS_ENSURE_TRUE(firstInstanceRoot, rv);
02049 
02050   nsCOMPtr<nsIDOMNode>rootNode = do_QueryInterface(firstInstanceRoot);
02051   rootNode.swap(*aContextNode);
02052 
02053   // found the context, so can finish up assinging the rest of the values that
02054   // we are returning
02055   *aContextPosition = 1;
02056   *aContextSize = 1;
02057 
02058   nsAutoString id;
02059   mElement->GetAttribute(NS_LITERAL_STRING("id"), id);
02060   aModelID.Assign(id);
02061 
02062   return NS_OK;
02063 }
02064 
02065 NS_IMETHODIMP
02066 nsXFormsModelElement::AddRemoveAbortedControl(nsIXFormsControl *aControl,
02067                                               PRBool            aAdd)
02068 {
02069   return NS_ERROR_NOT_IMPLEMENTED;
02070 }
02071 
02072 // internal methods
02073 
02074 already_AddRefed<nsIDOMDocument>
02075 nsXFormsModelElement::FindInstanceDocument(const nsAString &aID)
02076 {
02077   nsCOMPtr<nsIInstanceElementPrivate> instance;
02078   nsXFormsModelElement::FindInstanceElement(aID, getter_AddRefs(instance));
02079 
02080   nsIDOMDocument *doc = nsnull;
02081   if (instance) {
02082     instance->GetInstanceDocument(&doc); // addrefs
02083   }
02084 
02085   return doc;
02086 }
02087 
02088 nsresult
02089 nsXFormsModelElement::ProcessBindElements()
02090 {
02091   // ProcessBindElements() will go through each xforms:bind element in
02092   // document order and apply all of the Model Item Properties to the
02093   // instance items in the nodeset. This information will also be entered
02094   // in the Master Dependency Graph.  Most of this work is done in the
02095   // ProcessBind() method.
02096 
02097   nsCOMPtr<nsIDOMDocument> firstInstanceDoc =
02098     FindInstanceDocument(EmptyString());
02099   if (!firstInstanceDoc)
02100     return NS_OK;
02101 
02102   nsCOMPtr<nsIDOMElement> firstInstanceRoot;
02103   firstInstanceDoc->GetDocumentElement(getter_AddRefs(firstInstanceRoot));
02104 
02105   nsresult rv;
02106   nsCOMPtr<nsIXFormsXPathEvaluator> xpath = 
02107            do_CreateInstance("@mozilla.org/dom/xforms-xpath-evaluator;1", &rv);
02108   NS_ENSURE_TRUE(xpath, rv);
02109   
02110   nsCOMPtr<nsIDOMNodeList> children;
02111   mElement->GetChildNodes(getter_AddRefs(children));
02112 
02113   PRUint32 childCount = 0;
02114   if (children)
02115     children->GetLength(&childCount);
02116 
02117   nsAutoString namespaceURI, localName;
02118   for (PRUint32 i = 0; i < childCount; ++i) {
02119     nsCOMPtr<nsIDOMNode> child;
02120     children->Item(i, getter_AddRefs(child));
02121     NS_ASSERTION(child, "there can't be null items in the NodeList!");
02122 
02123     child->GetLocalName(localName);
02124     if (localName.EqualsLiteral("bind")) {
02125       child->GetNamespaceURI(namespaceURI);
02126       if (namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS)) {
02127         rv = ProcessBind(xpath, firstInstanceRoot, 1, 1,
02128                          nsCOMPtr<nsIDOMElement>(do_QueryInterface(child)),
02129                          PR_TRUE);
02130         if (NS_FAILED(rv)) {
02131           return NS_OK;
02132         }
02133       }
02134     }
02135   }
02136 
02137   return NS_OK;
02138 }
02139 
02140 void
02141 nsXFormsModelElement::Reset()
02142 {
02143   BackupOrRestoreInstanceData(PR_TRUE);
02144   nsXFormsUtils::DispatchEvent(mElement, eEvent_Rebuild);
02145   nsXFormsUtils::DispatchEvent(mElement, eEvent_Recalculate);
02146   nsXFormsUtils::DispatchEvent(mElement, eEvent_Revalidate);
02147   nsXFormsUtils::DispatchEvent(mElement, eEvent_Refresh);
02148 }
02149 
02150 // This function will restore all of the model's instance data to it's original
02151 // state if the supplied boolean is PR_TRUE.  If it is PR_FALSE, this function
02152 // will cause this model's instance data to be backed up.
02153 void
02154 nsXFormsModelElement::BackupOrRestoreInstanceData(PRBool restore)
02155 {
02156   if (!mInstanceDocuments)
02157     return;
02158 
02159   PRUint32 instCount;
02160   mInstanceDocuments->GetLength(&instCount);
02161   if (instCount) {
02162     for (PRUint32 i = 0; i < instCount; ++i) {
02163       nsIInstanceElementPrivate *instance =
02164         mInstanceDocuments->GetInstanceAt(i);
02165 
02166       // Don't know what to do with error if we get one.
02167       // Restore/BackupOriginalDocument will already output warnings.
02168       if (restore) {
02169         instance->RestoreOriginalDocument();
02170       }
02171       else {
02172         instance->BackupOriginalDocument();
02173       }
02174     }
02175   }
02176 
02177 }
02178 
02179 
02180 nsresult
02181 nsXFormsModelElement::FinishConstruction()
02182 {
02183   // Ensure that FinishConstruction isn't called due to some callback
02184   // or event handler after the model has started going through its
02185   // destruction phase
02186   NS_ENSURE_STATE(mElement);
02187 
02188   // process inline schemas that aren't referenced via the schema attribute
02189   nsCOMPtr<nsIDOMNodeList> children;
02190   mElement->GetChildNodes(getter_AddRefs(children));
02191 
02192   if (children) {
02193     PRUint32 childCount = 0;
02194     children->GetLength(&childCount);
02195 
02196     nsCOMPtr<nsIDOMNode> node;
02197     nsCOMPtr<nsIDOMElement> element;
02198     nsAutoString nsURI, localName, targetNamespace;
02199 
02200     for (PRUint32 i = 0; i < childCount; ++i) {
02201       children->Item(i, getter_AddRefs(node));
02202 
02203       element = do_QueryInterface(node);
02204       if (!element)
02205         continue;
02206 
02207       node->GetNamespaceURI(nsURI);
02208       node->GetLocalName(localName);
02209       if (nsURI.EqualsLiteral(NS_NAMESPACE_XML_SCHEMA) &&
02210           localName.EqualsLiteral("schema")) {
02211         if (!IsDuplicateSchema(element)) {
02212           nsCOMPtr<nsISchema> schema;
02213           nsresult rv = mSchemas->ProcessSchemaElement(element, nsnull,
02214                                                        getter_AddRefs(schema));
02215           if (!NS_SUCCEEDED(rv)) {
02216             nsXFormsUtils::ReportError(NS_LITERAL_STRING("schemaProcessError"),
02217                                        node);
02218           }
02219         }
02220       }
02221     }
02222   }
02223 
02224   // (XForms 4.2.1 - cont)
02225   // 3. if applicable, initialize P3P
02226 
02227   // 4. construct instance data from initial instance data.  apply all
02228   // <bind> elements in document order.
02229 
02230   // we get the instance data from our instance child nodes
02231 
02232   // We're done initializing this model.
02233   // 5. Perform an xforms-rebuild, xforms-recalculate, and xforms-revalidate in
02234   // sequence, for this model element. (The xforms-refresh is not performed
02235   // since the user interface has not yet been initialized).
02236   nsXFormsUtils::DispatchEvent(mElement, eEvent_Rebuild);
02237   nsXFormsUtils::DispatchEvent(mElement, eEvent_Recalculate);
02238   nsXFormsUtils::DispatchEvent(mElement, eEvent_Revalidate);
02239 
02240   return NS_OK;
02241 }
02242 
02243 nsresult
02244 nsXFormsModelElement::InitializeControls()
02245 {
02246 #ifdef DEBUG
02247   printf("nsXFormsModelElement::InitializeControls()\n");
02248 #endif
02249   nsPostRefresh postRefresh = nsPostRefresh();
02250 
02251   nsXFormsControlListItem::iterator it;
02252   nsresult rv;
02253   PRBool dummy;
02254   for (it = mFormControls.begin(); it != mFormControls.end(); ++it) {
02255     // Get control
02256     nsCOMPtr<nsIXFormsControl> control = (*it)->Control();
02257     NS_ASSERTION(control, "mFormControls has null control?!");
02258 
02259 #ifdef DEBUG_MODEL
02260     printf("\tControl (%p): ", (void*) control);
02261     nsCOMPtr<nsIDOMElement> controlElement;
02262     control->GetElement(getter_AddRefs(controlElement));
02263     // DBG_TAGINFO(controlElement);
02264 #endif
02265     // Rebind
02266     rv = control->Bind(&dummy);
02267     NS_ENSURE_SUCCESS(rv, rv);
02268 
02269     // Refresh controls
02270     rv = control->Refresh();
02271     // XXX: Bug 336608, refresh still fails for some controls, for some
02272     // reason.
02273     // NS_ENSURE_SUCCESS(rv, rv);
02274   }
02275 
02276   mChangedNodes.Clear();
02277 
02278   return NS_OK;
02279 }
02280 
02281 void
02282 nsXFormsModelElement::ValidateInstanceDocuments()
02283 {
02284   if (mInstanceDocuments) {
02285     PRUint32 instCount;
02286     mInstanceDocuments->GetLength(&instCount);
02287     if (instCount) {
02288       nsCOMPtr<nsIDOMDocument> document;
02289 
02290       for (PRUint32 i = 0; i < instCount; ++i) {
02291         nsIInstanceElementPrivate* instEle =
02292           mInstanceDocuments->GetInstanceAt(i);
02293         nsCOMPtr<nsIXFormsNSInstanceElement> NSInstEle(instEle);
02294         NSInstEle->GetInstanceDocument(getter_AddRefs(document));
02295         NS_ASSERTION(document,
02296                      "nsIXFormsNSInstanceElement::GetInstanceDocument returned null?!");
02297 
02298         if (document) {
02299           PRBool isValid = PR_FALSE;
02300           ValidateDocument(document, &isValid);
02301 
02302           if (!isValid) {
02303             nsCOMPtr<nsIDOMElement> instanceElement;
02304             instEle->GetElement(getter_AddRefs(instanceElement));
02305 
02306             nsXFormsUtils::ReportError(NS_LITERAL_STRING("instDocumentInvalid"),
02307                                        instanceElement);
02308           }
02309         }
02310       }
02311     }
02312   }
02313 }
02314 
02315 // NOTE: This function only runs to completion for _one_ of the models in the
02316 // document.
02317 void
02318 nsXFormsModelElement::MaybeNotifyCompletion()
02319 {
02320   nsCOMPtr<nsIDOMDocument> domDoc;
02321   mElement->GetOwnerDocument(getter_AddRefs(domDoc));
02322 
02323   const nsVoidArray *models = GetModelList(domDoc);
02324   if (!models) {
02325     NS_NOTREACHED("no model list property");
02326     return;
02327   }
02328 
02329   PRInt32 i;
02330 
02331   // Nothing to be done if any model is incomplete or hasn't seen
02332   // DOMContentLoaded.
02333   for (i = 0; i < models->Count(); ++i) {
02334     nsXFormsModelElement *model =
02335         NS_STATIC_CAST(nsXFormsModelElement *, models->ElementAt(i));
02336     if (!model->mDocumentLoaded || !model->IsComplete())
02337       return;
02338 
02339     // Check validity of |functions=| attribute, if it exists.  Since we
02340     // don't support ANY extension functions currently, the existance of
02341     // |functions=| with a non-empty value is an error.
02342     nsCOMPtr<nsIDOMElement> tElement = model->mElement;
02343     nsAutoString extFunctionAtt;
02344     tElement->GetAttribute(NS_LITERAL_STRING("functions"), extFunctionAtt);
02345     if (!extFunctionAtt.IsEmpty()) {
02346       nsXFormsUtils::ReportError(NS_LITERAL_STRING("invalidExtFunction"),
02347                                  tElement);
02348 
02349       // Context Info: 'error-message'
02350       // Error message containing the expression being processed.
02351       nsAutoString errorMsg;
02352       errorMsg.AssignLiteral("Non-existent extension functions: ");
02353       errorMsg.Append(extFunctionAtt);
02354       SetContextInfo("error-message", errorMsg);
02355       nsXFormsUtils::DispatchEvent(tElement, eEvent_ComputeException, nsnull,
02356                                    nsnull, &mContextInfo);
02357       return;
02358     }
02359   }
02360 
02361   // validate the instance documents because we want schemaValidation to add
02362   // schema type properties from the schema file unto our instance document
02363   // elements.
02364   // XXX: wrong location of this call, @see bug 339674
02365   ValidateInstanceDocuments();
02366 
02367   // Register deferred binds with the model. It does not bind the controls,
02368   // only bind them to the model they belong to.
02369   nsXFormsModelElement::ProcessDeferredBinds(domDoc);
02370 
02371   // Okay, dispatch xforms-model-construct-done
02372   for (i = 0; i < models->Count(); ++i) {
02373     nsXFormsModelElement *model =
02374         NS_STATIC_CAST(nsXFormsModelElement *, models->ElementAt(i));
02375     nsXFormsUtils::DispatchEvent(model->mElement, eEvent_ModelConstructDone);
02376   }
02377 
02378   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
02379   if (doc) {
02380     PRUint32 loadingMessages = NS_PTR_TO_UINT32(
02381       doc->GetProperty(nsXFormsAtoms::externalMessagesProperty));
02382     if (loadingMessages) {
02383       // if we are still waiting for external messages to load, then put off
02384       // the xforms-ready until a model in the document is notified that they
02385       // are finished loading
02386 
02387       return;
02388     }
02389   }
02390 
02391   // Backup instances and fire xforms-ready
02392   for (i = 0; i < models->Count(); ++i) {
02393     nsXFormsModelElement *model =
02394         NS_STATIC_CAST(nsXFormsModelElement *, models->ElementAt(i));
02395     model->BackupOrRestoreInstanceData(PR_FALSE);
02396     model->mReadyHandled = PR_TRUE;
02397     nsXFormsUtils::DispatchEvent(model->mElement, eEvent_Ready);
02398   }
02399 }
02400 
02401 nsresult
02402 nsXFormsModelElement::ProcessBind(nsIXFormsXPathEvaluator *aEvaluator,
02403                                   nsIDOMNode              *aContextNode,
02404                                   PRInt32                 aContextPosition,
02405                                   PRInt32                 aContextSize,
02406                                   nsIDOMElement           *aBindElement,
02407                                   PRBool                  aIsOuter)
02408 {
02409   // Get the model item properties specified by this <bind>.
02410   nsCOMPtr<nsIDOMNSXPathExpression> props[eModel__count];
02411   nsAutoString propStrings[eModel__count];
02412   nsresult rv;
02413   nsAutoString attrStr;
02414 
02415   for (PRUint32 i = 0; i < eModel__count; ++i) {
02416     sModelPropsList[i]->ToString(attrStr);
02417 
02418     aBindElement->GetAttribute(attrStr, propStrings[i]);
02419   }
02420 
02421   // Find the nodeset that this bind applies to.
02422   nsCOMPtr<nsIDOMXPathResult> result;
02423 
02424   nsAutoString expr;
02425   aBindElement->GetAttribute(NS_LITERAL_STRING("nodeset"), expr);
02426   if (expr.IsEmpty()) {
02427     expr = NS_LITERAL_STRING(".");
02428   }
02429 
02430   rv = aEvaluator->Evaluate(expr, aContextNode, aContextPosition, aContextSize,
02431                             aBindElement, aContextNode,
02432                             nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE,
02433                             nsnull, getter_AddRefs(result));
02434   if (NS_FAILED(rv)) {
02435     if (rv == nsIDOMXPathException::INVALID_EXPRESSION_ERR) {
02436       // the xpath expression isn't valid xpath
02437 
02438       const nsPromiseFlatString& flat = PromiseFlatString(expr);
02439       const PRUnichar *strings[] = { flat.get() };
02440       nsXFormsUtils::ReportError(NS_LITERAL_STRING("exprParseError"),
02441                                  strings, 1, aBindElement, nsnull);
02442 
02443       // Context Info: 'error-message'
02444       // Error message containing the expression being processed.
02445       nsAutoString errorMsg;
02446       errorMsg.AssignLiteral("Error parsing XPath expression: ");
02447       errorMsg.Append(expr);
02448       SetContextInfo("error-message", errorMsg);
02449       nsXFormsUtils::DispatchEvent(mElement, eEvent_ComputeException, nsnull,
02450                                    nsnull, &mContextInfo);
02451     } else {
02452 #ifdef DEBUG
02453       printf("xforms-binding-exception: XPath Evaluation failed\n");
02454 #endif
02455       const PRUnichar *strings[] = { expr.get() };
02456       nsXFormsUtils::ReportError(NS_LITERAL_STRING("nodesetEvaluateError"),
02457                                  strings, 1, aBindElement, aBindElement);
02458       nsXFormsUtils::DispatchEvent(mElement, eEvent_BindingException);
02459     }
02460     return rv;
02461   }
02462 
02463   NS_ENSURE_STATE(result);
02464 
02465   // If this is an outer bind, store the nodeset, as controls binding to this
02466   // bind will need this.
02467   if (aIsOuter) {
02468     nsCOMPtr<nsIContent> content(do_QueryInterface(aBindElement));
02469     NS_ASSERTION(content, "nsIDOMElement not implementing nsIContent?!");
02470     rv = content->SetProperty(nsXFormsAtoms::bind, result,
02471                               SupportsDtorFunc);
02472     NS_ENSURE_SUCCESS(rv, rv);
02473 
02474     // addref, circumventing nsDerivedSave
02475     NS_ADDREF(NS_STATIC_CAST(nsIDOMXPathResult*, result));
02476   }
02477 
02478   PRUint32 snapLen;
02479   rv = result->GetSnapshotLength(&snapLen);
02480   NS_ENSURE_SUCCESS(rv, rv);
02481 
02482 
02483   // Iterate over resultset
02484   nsCOMArray<nsIDOMNode> deps;
02485   nsCOMPtr<nsIDOMNode> node;
02486   PRUint32 snapItem;
02487   for (snapItem = 0; snapItem < snapLen; ++snapItem) {
02488     rv = result->SnapshotItem(snapItem, getter_AddRefs(node));
02489     NS_ENSURE_SUCCESS(rv, rv);
02490     
02491     if (!node) {
02492       NS_WARNING("nsXFormsModelElement::ProcessBind(): Empty node in result set.");
02493       continue;
02494     }
02495     
02496     // Apply MIPs
02497     nsXFormsXPathParser parser;
02498     nsXFormsXPathAnalyzer analyzer(aEvaluator, aBindElement, node);
02499     PRBool multiMIP = PR_FALSE;
02500     for (PRUint32 j = 0; j < eModel__count; ++j) {
02501       if (propStrings[j].IsEmpty())
02502         continue;
02503 
02504       // type and p3ptype are stored as properties on the instance node
02505       if (j == eModel_type || j == eModel_p3ptype) {
02506         nsClassHashtable<nsISupportsHashKey, nsString> *table;
02507         table = j == eModel_type ? &mNodeToType : &mNodeToP3PType;
02508         NS_ENSURE_TRUE(table->IsInitialized(), NS_ERROR_FAILURE);
02509 
02510         // Check for existing value
02511         if (table->Get(node, nsnull)) {
02512           multiMIP = PR_TRUE;
02513           break;
02514         }
02515 
02516         // Insert value
02517         nsAutoPtr<nsString> newString(new nsString(propStrings[j]));
02518         NS_ENSURE_TRUE(newString, NS_ERROR_OUT_OF_MEMORY);
02519         NS_ENSURE_TRUE(table->Put(node, newString), NS_ERROR_OUT_OF_MEMORY);
02520 
02521         // string is succesfully stored in the table, we should not dealloc it
02522         newString.forget();
02523 
02524         if (j == eModel_type) {
02525           // Inform MDG that it needs to check type. The only arguments
02526           // actually used are |eModel_constraint| and |node|.
02527           rv = mMDG.AddMIP(eModel_constraint, nsnull, nsnull, PR_FALSE, node, 1,
02528                            1);
02529           NS_ENSURE_SUCCESS(rv, rv);
02530         }
02531       } else {
02532         rv = aEvaluator->CreateExpression(propStrings[j], aBindElement, node,
02533                                           getter_AddRefs(props[j]));
02534         if (NS_FAILED(rv)) {
02535           const PRUnichar *strings[] = { propStrings[j].get() };
02536           nsXFormsUtils::ReportError(NS_LITERAL_STRING("mipParseError"),
02537                                      strings, 1, aBindElement, aBindElement);
02538 
02539           // Context Info: 'error-message'
02540           // Error message containing the expression being processed.
02541           nsAutoString errorMsg;
02542           errorMsg.AssignLiteral("Error while parsing model item property: ");
02543           errorMsg.Append(propStrings[j]);
02544           SetContextInfo("error-message", errorMsg);
02545           nsXFormsUtils::DispatchEvent(mElement, eEvent_ComputeException,
02546                                        nsnull, nsnull, &mContextInfo);
02547           return rv;
02548         }
02549 
02550         // the rest of the MIPs are given to the MDG
02551         nsCOMPtr<nsIDOMNSXPathExpression> expr = props[j];
02552 
02553         // Get node dependencies
02554         nsAutoPtr<nsXFormsXPathNode> xNode(parser.Parse(propStrings[j]));
02555         deps.Clear();
02556         rv = analyzer.Analyze(node, xNode, expr, &propStrings[j], &deps,
02557                               snapItem + 1, snapLen, PR_FALSE);
02558         NS_ENSURE_SUCCESS(rv, rv);
02559 
02560         // Insert into MDG
02561         rv = mMDG.AddMIP((ModelItemPropName) j,
02562                          expr,
02563                          &deps,
02564                          parser.UsesDynamicFunc(),
02565                          node,
02566                          snapItem + 1,
02567                          snapLen);
02568 
02569         // if the call results in NS_ERROR_ABORT the page has tried to set a
02570         // MIP twice, break and emit an exception.
02571         if (rv == NS_ERROR_ABORT) {
02572           multiMIP = PR_TRUE;
02573           break;
02574         }
02575         NS_ENSURE_SUCCESS(rv, rv);
02576       }
02577     }
02578 
02579     // If the attribute is already there, the page sets a MIP twice
02580     // which is illegal, and should result in an xforms-binding-exception.
02581     // @see http://www.w3.org/TR/xforms/slice4.html#evt-modelConstruct
02582     // (item 4, c)
02583     if (multiMIP) {
02584 #ifdef DEBUG
02585       printf("xforms-binding-exception: Multiple MIPs on same node!");
02586 #endif
02587       nsXFormsUtils::ReportError(NS_LITERAL_STRING("multiMIPError"),
02588                                  aBindElement);
02589       nsXFormsUtils::DispatchEvent(aBindElement,
02590                                    eEvent_BindingException);
02591       return NS_ERROR_FAILURE;
02592     }
02593 
02594     // Now evaluate any child <bind> elements.
02595     nsCOMPtr<nsIDOMNodeList> children;
02596     aBindElement->GetChildNodes(getter_AddRefs(children));
02597     if (children) {
02598       PRUint32 childCount = 0;
02599       children->GetLength(&childCount);
02600 
02601       nsCOMPtr<nsIDOMNode> child;
02602       nsAutoString value;
02603 
02604       for (PRUint32 k = 0; k < childCount; ++k) {
02605         children->Item(k, getter_AddRefs(child));
02606         if (child) {
02607           child->GetLocalName(value);
02608           if (!value.EqualsLiteral("bind"))
02609             continue;
02610 
02611           child->GetNamespaceURI(value);
02612           if (!value.EqualsLiteral(NS_NAMESPACE_XFORMS))
02613             continue;
02614 
02615           rv = ProcessBind(aEvaluator, node,
02616                            snapItem + 1, snapLen,
02617                            nsCOMPtr<nsIDOMElement>(do_QueryInterface(child)));
02618           NS_ENSURE_SUCCESS(rv, rv);
02619         }
02620       }
02621     }
02622   }
02623 
02624   return NS_OK;
02625 }
02626 
02627 NS_IMETHODIMP
02628 nsXFormsModelElement::AddInstanceElement(nsIInstanceElementPrivate *aInstEle)
02629 {
02630   NS_ENSURE_STATE(mInstanceDocuments);
02631   mInstanceDocuments->AddInstance(aInstEle);
02632 
02633   return NS_OK;
02634 }
02635 
02636 NS_IMETHODIMP
02637 nsXFormsModelElement::RemoveInstanceElement(nsIInstanceElementPrivate *aInstEle)
02638 {
02639   NS_ENSURE_STATE(mInstanceDocuments);
02640   mInstanceDocuments->RemoveInstance(aInstEle);
02641 
02642   return NS_OK;
02643 }
02644 
02645 NS_IMETHODIMP
02646 nsXFormsModelElement::MessageLoadFinished()
02647 {
02648   // This is our signal that all external message links have been tested.  If
02649   // we were waiting for this to send out xforms-ready, then now is the time.
02650 
02651   // if this document hasn't processed xforms-model-construct-done, yet (which
02652   // must precede xforms-ready), then we'll send out the xforms-ready later
02653   // as part of our normal handling.  If we've already become ready, then this
02654   // event was probably generated by a change in the src attribute on the
02655   // message element.  Ignore it in that case.
02656   if (!mConstructDoneHandled || mReadyHandled) {
02657     return NS_OK;
02658   }
02659 
02660   nsCOMPtr<nsIDOMDocument> domDoc;
02661   mElement->GetOwnerDocument(getter_AddRefs(domDoc));
02662   const nsVoidArray *models = GetModelList(domDoc);
02663   nsCOMPtr<nsIDocument>doc = do_QueryInterface(domDoc);
02664   nsCOMArray<nsIXFormsControl> *deferredBindList =
02665     NS_STATIC_CAST(nsCOMArray<nsIXFormsControl> *,
02666                    doc->GetProperty(nsXFormsAtoms::deferredBindListProperty));
02667 
02668   // if we've already gotten the xforms-model-construct-done event and not
02669   // yet the xforms-ready, we've hit a window where we may still be
02670   // processing the deferred control binding.  If so, we'll leave now and
02671   // leave it to MaybeNotifyCompletion to generate the xforms-ready event.
02672   if (deferredBindList) {
02673     return NS_OK;
02674   }
02675 
02676 
02677   // if we reached here, then we had to wait on sending out the xforms-ready
02678   // events until the external messages were tested.  Now we are finally
02679   // ready to send out xforms-ready to all of the models.
02680   for (int i = 0; i < models->Count(); ++i) {
02681     nsXFormsModelElement *model =
02682         NS_STATIC_CAST(nsXFormsModelElement *, models->ElementAt(i));
02683     model->mReadyHandled = PR_TRUE;
02684     nsXFormsUtils::DispatchEvent(model->mElement, eEvent_Ready);
02685   }
02686 
02687   return NS_OK;
02688 }
02689 
02690 NS_IMETHODIMP
02691 nsXFormsModelElement::GetHasDOMContentFired(PRBool *aLoaded)
02692 {
02693   NS_ENSURE_ARG_POINTER(aLoaded);
02694 
02695   *aLoaded = mDocumentLoaded;
02696   return NS_OK;
02697 }
02698 
02699 NS_IMETHODIMP
02700 nsXFormsModelElement::ForceRebind(nsIXFormsControl* aControl)
02701 {
02702   if (!aControl) {
02703     return NS_OK;
02704   }
02705 
02706   nsXFormsControlListItem* controlItem = mFormControls.FindControl(aControl);
02707   NS_ENSURE_STATE(controlItem);
02708 
02709   PRBool rebindChildren;
02710   nsresult rv = aControl->Bind(&rebindChildren);
02711   NS_ENSURE_SUCCESS(rv, rv);
02712 
02713   rv = aControl->Refresh();
02714   // XXX: no rv-check, see bug 336608
02715 
02716   // Refresh children
02717   return RefreshSubTree(controlItem->FirstChild(), rebindChildren);
02718 }
02719 
02720 nsresult
02721 nsXFormsModelElement::GetBuiltinTypeName(PRUint16   aType,
02722                                          nsAString& aName)
02723 {
02724   switch (aType) {
02725     case nsISchemaBuiltinType::BUILTIN_TYPE_STRING:
02726       aName.AssignLiteral("string");
02727       break;
02728     case nsISchemaBuiltinType::BUILTIN_TYPE_BOOLEAN:
02729       aName.AssignLiteral("boolean");
02730       break;
02731     case nsISchemaBuiltinType::BUILTIN_TYPE_DECIMAL:
02732       aName.AssignLiteral("decimal");
02733       break;
02734     case nsISchemaBuiltinType::BUILTIN_TYPE_FLOAT:
02735       aName.AssignLiteral("float");
02736       break;
02737     case nsISchemaBuiltinType::BUILTIN_TYPE_DOUBLE:
02738       aName.AssignLiteral("double");
02739       break;
02740     case nsISchemaBuiltinType::BUILTIN_TYPE_DURATION:
02741       aName.AssignLiteral("duration");
02742       break;
02743     case nsISchemaBuiltinType::BUILTIN_TYPE_DATETIME:
02744       aName.AssignLiteral("dateTime");
02745       break;
02746     case nsISchemaBuiltinType::BUILTIN_TYPE_TIME:
02747       aName.AssignLiteral("time");
02748       break;
02749     case nsISchemaBuiltinType::BUILTIN_TYPE_DATE:
02750       aName.AssignLiteral("date");
02751       break;
02752     case nsISchemaBuiltinType::BUILTIN_TYPE_GYEARMONTH:
02753       aName.AssignLiteral("gYearMonth");
02754       break;
02755     case nsISchemaBuiltinType::BUILTIN_TYPE_GYEAR:
02756       aName.AssignLiteral("gYear");
02757       break;
02758     case nsISchemaBuiltinType::BUILTIN_TYPE_GMONTHDAY:
02759       aName.AssignLiteral("gMonthDay");
02760       break;
02761     case nsISchemaBuiltinType::BUILTIN_TYPE_GDAY:
02762       aName.AssignLiteral("gDay");
02763       break;
02764     case nsISchemaBuiltinType::BUILTIN_TYPE_GMONTH:
02765       aName.AssignLiteral("gMonth");
02766       break;
02767     case nsISchemaBuiltinType::BUILTIN_TYPE_HEXBINARY:
02768       aName.AssignLiteral("hexBinary");
02769       break;
02770     case nsISchemaBuiltinType::BUILTIN_TYPE_BASE64BINARY:
02771       aName.AssignLiteral("base64Binary");
02772       break;
02773     case nsISchemaBuiltinType::BUILTIN_TYPE_ANYURI:
02774       aName.AssignLiteral("anyURI");
02775       break;
02776     case nsISchemaBuiltinType::BUILTIN_TYPE_QNAME:
02777       aName.AssignLiteral("QName");
02778       break;
02779     case nsISchemaBuiltinType::BUILTIN_TYPE_NOTATION:
02780       aName.AssignLiteral("NOTATION");
02781       break;
02782     case nsISchemaBuiltinType::BUILTIN_TYPE_NORMALIZED_STRING:
02783       aName.AssignLiteral("normalizedString");
02784       break;
02785     case nsISchemaBuiltinType::BUILTIN_TYPE_TOKEN:
02786       aName.AssignLiteral("token");
02787       break;
02788     case nsISchemaBuiltinType::BUILTIN_TYPE_BYTE:
02789       aName.AssignLiteral("byte");
02790       break;
02791     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDBYTE:
02792       aName.AssignLiteral("unsignedByte");
02793       break;
02794     case nsISchemaBuiltinType::BUILTIN_TYPE_INTEGER:
02795       aName.AssignLiteral("integer");
02796       break;
02797     case nsISchemaBuiltinType::BUILTIN_TYPE_NEGATIVEINTEGER:
02798       aName.AssignLiteral("negativeInteger");
02799       break;
02800     case nsISchemaBuiltinType::BUILTIN_TYPE_NONPOSITIVEINTEGER:
02801       aName.AssignLiteral("nonPositiveInteger");
02802       break;
02803     case nsISchemaBuiltinType::BUILTIN_TYPE_LONG:
02804       aName.AssignLiteral("long");
02805       break;
02806     case nsISchemaBuiltinType::BUILTIN_TYPE_NONNEGATIVEINTEGER:
02807       aName.AssignLiteral("nonNegativeInteger");
02808       break;
02809     case nsISchemaBuiltinType::BUILTIN_TYPE_INT:
02810       aName.AssignLiteral("int");
02811       break;
02812     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDINT:
02813       aName.AssignLiteral("unsignedInt");
02814       break;
02815     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDLONG:
02816       aName.AssignLiteral("unsignedLong");
02817       break;
02818     case nsISchemaBuiltinType::BUILTIN_TYPE_POSITIVEINTEGER:
02819       aName.AssignLiteral("positiveInteger");
02820       break;
02821     case nsISchemaBuiltinType::BUILTIN_TYPE_SHORT:
02822       aName.AssignLiteral("short");
02823       break;
02824     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDSHORT:
02825       aName.AssignLiteral("unsignedShort");
02826       break;
02827     case nsISchemaBuiltinType::BUILTIN_TYPE_LANGUAGE:
02828       aName.AssignLiteral("language");
02829       break;
02830     case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKEN:
02831       aName.AssignLiteral("NMTOKEN");
02832       break;
02833     case nsISchemaBuiltinType::BUILTIN_TYPE_NAME:
02834       aName.AssignLiteral("Name");
02835       break;
02836     case nsISchemaBuiltinType::BUILTIN_TYPE_NCNAME:
02837       aName.AssignLiteral("NCName");
02838       break;
02839     case nsISchemaBuiltinType::BUILTIN_TYPE_ID:
02840       aName.AssignLiteral("ID");
02841       break;
02842     case nsISchemaBuiltinType::BUILTIN_TYPE_IDREF:
02843       aName.AssignLiteral("IDREF");
02844       break;
02845     case nsISchemaBuiltinType::BUILTIN_TYPE_ENTITY:
02846       aName.AssignLiteral("ENTITY");
02847       break;
02848     case nsISchemaBuiltinType::BUILTIN_TYPE_IDREFS:
02849       aName.AssignLiteral("IDREFS");
02850       break;
02851     case nsISchemaBuiltinType::BUILTIN_TYPE_ENTITIES:
02852       aName.AssignLiteral("ENTITIES");
02853       break;
02854     case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKENS:
02855       aName.AssignLiteral("NMTOKENS");
02856       break;
02857     default:
02858       // should never hit here
02859       NS_WARNING("nsXFormsModelElement::GetBuiltinTypeName: Unknown builtin type encountered.");
02860       return NS_ERROR_FAILURE;
02861   }
02862 
02863   return NS_OK;
02864 }
02865 
02866 nsresult
02867 nsXFormsModelElement::GetBuiltinTypesNames(PRUint16       aType,
02868                                            nsStringArray *aNameArray)
02869 {
02870   // This function recursively appends aType (and its base types) to
02871   // aNameArray.  So it assumes aType isn't in the array already.
02872   nsAutoString typeString, builtString;
02873   PRUint16 parentType = 0;
02874 
02875   // We won't append xsd:anyType as the base of every type since that is kinda
02876   // redundant.
02877 
02878   nsresult rv = GetBuiltinTypeName(aType, typeString);
02879   NS_ENSURE_SUCCESS(rv, rv);
02880 
02881   switch (aType) {
02882     case nsISchemaBuiltinType::BUILTIN_TYPE_NORMALIZED_STRING:
02883       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_STRING;
02884       break;
02885     case nsISchemaBuiltinType::BUILTIN_TYPE_TOKEN:
02886       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_NORMALIZED_STRING;
02887       break;
02888     case nsISchemaBuiltinType::BUILTIN_TYPE_BYTE:
02889       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_SHORT;
02890       break;
02891     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDBYTE:
02892       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDSHORT;
02893       break;
02894     case nsISchemaBuiltinType::BUILTIN_TYPE_INTEGER:
02895       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_DECIMAL;
02896       break;
02897     case nsISchemaBuiltinType::BUILTIN_TYPE_NEGATIVEINTEGER:
02898       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_NONPOSITIVEINTEGER;
02899       break;
02900     case nsISchemaBuiltinType::BUILTIN_TYPE_NONPOSITIVEINTEGER:
02901       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_INTEGER;
02902       break;
02903     case nsISchemaBuiltinType::BUILTIN_TYPE_LONG:
02904       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_INTEGER;
02905       break;
02906     case nsISchemaBuiltinType::BUILTIN_TYPE_NONNEGATIVEINTEGER:
02907       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_INTEGER;
02908       break;
02909     case nsISchemaBuiltinType::BUILTIN_TYPE_INT:
02910       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_LONG;
02911       break;
02912     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDINT:
02913       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDLONG;
02914       break;
02915     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDLONG:
02916       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_NONNEGATIVEINTEGER;
02917       break;
02918     case nsISchemaBuiltinType::BUILTIN_TYPE_POSITIVEINTEGER:
02919       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_NONNEGATIVEINTEGER;
02920       break;
02921     case nsISchemaBuiltinType::BUILTIN_TYPE_SHORT:
02922       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_INT;
02923       break;
02924     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDSHORT:
02925       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDINT;
02926       break;
02927     case nsISchemaBuiltinType::BUILTIN_TYPE_LANGUAGE:
02928       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_TOKEN;
02929       break;
02930     case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKEN:
02931       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_TOKEN;
02932       break;
02933     case nsISchemaBuiltinType::BUILTIN_TYPE_NAME:
02934       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_TOKEN;
02935       break;
02936     case nsISchemaBuiltinType::BUILTIN_TYPE_NCNAME:
02937       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_NAME;
02938       break;
02939     case nsISchemaBuiltinType::BUILTIN_TYPE_ID:
02940       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_NCNAME;
02941       break;
02942     case nsISchemaBuiltinType::BUILTIN_TYPE_IDREF:
02943       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_NCNAME;
02944       break;
02945     case nsISchemaBuiltinType::BUILTIN_TYPE_ENTITY:
02946       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_NCNAME;
02947       break;
02948     case nsISchemaBuiltinType::BUILTIN_TYPE_IDREFS:
02949       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_IDREF;
02950       break;
02951     case nsISchemaBuiltinType::BUILTIN_TYPE_ENTITIES:
02952       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_ENTITY;
02953       break;
02954     case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKENS:
02955       parentType = nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKEN;
02956       break;
02957   }
02958 
02959   builtString.AppendLiteral(NS_NAMESPACE_XML_SCHEMA);
02960   builtString.AppendLiteral("#");
02961   builtString.Append(typeString);
02962   aNameArray->AppendString(builtString);
02963 
02964   if (parentType)
02965     return GetBuiltinTypesNames(parentType, aNameArray);
02966 
02967   return NS_OK;
02968 }
02969 
02970 nsresult
02971 nsXFormsModelElement::WalkTypeChainInternal(nsISchemaType *aType,
02972                                             PRBool         aFindRootBuiltin,
02973                                             PRUint16      *aBuiltinType,
02974                                             nsStringArray *aTypeArray)
02975 {
02976   PRUint16 schemaTypeValue = 0;
02977   aType->GetSchemaType(&schemaTypeValue);
02978   NS_ENSURE_STATE(schemaTypeValue);
02979   nsresult rv = NS_OK;
02980   nsCOMPtr<nsISchemaSimpleType> simpleType;
02981 
02982   if (schemaTypeValue == nsISchemaType::SCHEMA_TYPE_SIMPLE) {
02983     simpleType = do_QueryInterface(aType);
02984     NS_ENSURE_STATE(simpleType);
02985     PRUint16 simpleTypeValue;
02986     simpleType->GetSimpleType(&simpleTypeValue);
02987     NS_ENSURE_STATE(simpleTypeValue);
02988 
02989     switch (simpleTypeValue) {
02990       case nsISchemaSimpleType::SIMPLE_TYPE_BUILTIN:
02991       {
02992         nsCOMPtr<nsISchemaBuiltinType> builtinType(do_QueryInterface(aType));
02993         NS_ENSURE_STATE(builtinType);
02994 
02995         if (aFindRootBuiltin)
02996           return BuiltinTypeToPrimative(builtinType, aBuiltinType);
02997 
02998         PRUint16 builtinTypeVal;
02999         rv = builtinType->GetBuiltinType(&builtinTypeVal);
03000         NS_ENSURE_SUCCESS(rv, rv);
03001 
03002         if (aBuiltinType)
03003           *aBuiltinType = builtinTypeVal;
03004 
03005         if (aTypeArray)
03006           return GetBuiltinTypesNames(builtinTypeVal, aTypeArray);
03007 
03008         return NS_OK;
03009       }
03010       case nsISchemaSimpleType::SIMPLE_TYPE_RESTRICTION:
03011       {
03012         nsCOMPtr<nsISchemaRestrictionType> restType(do_QueryInterface(aType));
03013         NS_ENSURE_STATE(restType);
03014         restType->GetBaseType(getter_AddRefs(simpleType));
03015 
03016         break;
03017       }
03018       case nsISchemaSimpleType::SIMPLE_TYPE_LIST:
03019       {
03020         nsCOMPtr<nsISchemaListType> listType(do_QueryInterface(aType));
03021         NS_ENSURE_STATE(listType);
03022         listType->GetListType(getter_AddRefs(simpleType));
03023 
03024         break;
03025       }
03026       case nsISchemaSimpleType::SIMPLE_TYPE_UNION:
03027       {
03028         // For now union types aren't supported.  A union means that the type
03029         // could be of any type listed in the union and still be valid.  But we
03030         // don't know which path it will take since we'd basically have to
03031         // validate the node value to know.  Someday we may have to figure out
03032         // how to properly handle this, though we may never need to if no other
03033         // processor supports it.  Strictly interpreting the spec, we don't
03034         // need to handle unions as far as determining whether a control can
03035         // bind to data of a given type.  Just the types defined in the spec
03036         // and restrictions of those types.
03037         return NS_ERROR_XFORMS_UNION_TYPE;
03038       }
03039       default:
03040         // We only anticipate the 4 types listed above.  Definitely an error
03041         // if we get something else.
03042         return NS_ERROR_FAILURE;
03043     }
03044 
03045   } else if (schemaTypeValue == nsISchemaType::SCHEMA_TYPE_COMPLEX) {
03046     nsCOMPtr<nsISchemaComplexType> complexType(do_QueryInterface(aType));
03047     NS_ENSURE_STATE(complexType);
03048     PRUint16 complexTypeValue = 0;
03049     complexType->GetDerivation(&complexTypeValue);
03050     NS_ENSURE_STATE(complexTypeValue);
03051     if ((complexTypeValue ==
03052          nsISchemaComplexType::DERIVATION_RESTRICTION_SIMPLE) ||
03053         (complexTypeValue ==
03054          nsISchemaComplexType::DERIVATION_EXTENSION_SIMPLE)) {
03055       complexType->GetSimpleBaseType(getter_AddRefs(simpleType));
03056     } else {
03057       return NS_ERROR_FAILURE;
03058     }
03059   } else {
03060     return NS_ERROR_FAILURE;
03061   }
03062 
03063   // For SIMPLE_TYPE_LIST and SIMPLE_TYPE_RESTRICTION we need to go around
03064   // the horn again with the next simpleType.  Same with
03065   // DERIVATION_RESTRICTION_SIMPLE and DERIVATION_EXTENSION_SIMPLE.  All other
03066   // types should not reach here.
03067 
03068   NS_ENSURE_STATE(simpleType);
03069 
03070   if (aTypeArray) {
03071     nsAutoString builtString;
03072     rv = aType->GetTargetNamespace(builtString);
03073     NS_ENSURE_SUCCESS(rv, rv);
03074     nsAutoString typeName;
03075     rv = aType->GetName(typeName);
03076     NS_ENSURE_SUCCESS(rv, rv);
03077     builtString.AppendLiteral("#");
03078     builtString.Append(typeName);
03079     aTypeArray->AppendString(builtString);
03080   }
03081 
03082   return WalkTypeChainInternal(simpleType, aFindRootBuiltin, aBuiltinType,
03083                                aTypeArray);
03084 
03085 }
03086 
03087 nsresult
03088 nsXFormsModelElement::BuiltinTypeToPrimative(nsISchemaBuiltinType *aSchemaType,
03089                                              PRUint16             *aPrimType)
03090 {
03091   NS_ENSURE_ARG(aSchemaType);
03092   NS_ENSURE_ARG_POINTER(aPrimType);
03093 
03094   PRUint16 builtinType = 0;
03095   nsresult rv = aSchemaType->GetBuiltinType(&builtinType);
03096   NS_ENSURE_SUCCESS(rv, rv);
03097 
03098   // Note: this won't return BUILTIN_TYPE_ANY since that is the root of all
03099   // types.
03100 
03101   switch (builtinType) {
03102     case nsISchemaBuiltinType::BUILTIN_TYPE_STRING:
03103     case nsISchemaBuiltinType::BUILTIN_TYPE_BOOLEAN:
03104     case nsISchemaBuiltinType::BUILTIN_TYPE_DECIMAL:
03105     case nsISchemaBuiltinType::BUILTIN_TYPE_FLOAT:
03106     case nsISchemaBuiltinType::BUILTIN_TYPE_DOUBLE:
03107     case nsISchemaBuiltinType::BUILTIN_TYPE_DURATION:
03108     case nsISchemaBuiltinType::BUILTIN_TYPE_DATETIME:
03109     case nsISchemaBuiltinType::BUILTIN_TYPE_TIME:
03110     case nsISchemaBuiltinType::BUILTIN_TYPE_DATE:
03111     case nsISchemaBuiltinType::BUILTIN_TYPE_GYEARMONTH:
03112     case nsISchemaBuiltinType::BUILTIN_TYPE_GYEAR:
03113     case nsISchemaBuiltinType::BUILTIN_TYPE_GMONTHDAY:
03114     case nsISchemaBuiltinType::BUILTIN_TYPE_GDAY:
03115     case nsISchemaBuiltinType::BUILTIN_TYPE_GMONTH:
03116     case nsISchemaBuiltinType::BUILTIN_TYPE_HEXBINARY:
03117     case nsISchemaBuiltinType::BUILTIN_TYPE_BASE64BINARY:
03118     case nsISchemaBuiltinType::BUILTIN_TYPE_ANYURI:
03119     case nsISchemaBuiltinType::BUILTIN_TYPE_QNAME:
03120     case nsISchemaBuiltinType::BUILTIN_TYPE_NOTATION:
03121       *aPrimType = builtinType;
03122       break;
03123 
03124     case nsISchemaBuiltinType::BUILTIN_TYPE_NORMALIZED_STRING:
03125     case nsISchemaBuiltinType::BUILTIN_TYPE_TOKEN:
03126     case nsISchemaBuiltinType::BUILTIN_TYPE_LANGUAGE:
03127     case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKEN:
03128     case nsISchemaBuiltinType::BUILTIN_TYPE_NAME:
03129     case nsISchemaBuiltinType::BUILTIN_TYPE_NCNAME:
03130     case nsISchemaBuiltinType::BUILTIN_TYPE_ID:
03131     case nsISchemaBuiltinType::BUILTIN_TYPE_IDREF:
03132     case nsISchemaBuiltinType::BUILTIN_TYPE_ENTITY:
03133     case nsISchemaBuiltinType::BUILTIN_TYPE_IDREFS:
03134     case nsISchemaBuiltinType::BUILTIN_TYPE_ENTITIES:
03135     case nsISchemaBuiltinType::BUILTIN_TYPE_NMTOKENS:
03136       *aPrimType = nsISchemaBuiltinType::BUILTIN_TYPE_STRING;
03137       break;
03138     case nsISchemaBuiltinType::BUILTIN_TYPE_BYTE:
03139     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDBYTE:
03140     case nsISchemaBuiltinType::BUILTIN_TYPE_INTEGER:
03141     case nsISchemaBuiltinType::BUILTIN_TYPE_NEGATIVEINTEGER:
03142     case nsISchemaBuiltinType::BUILTIN_TYPE_NONPOSITIVEINTEGER:
03143     case nsISchemaBuiltinType::BUILTIN_TYPE_LONG:
03144     case nsISchemaBuiltinType::BUILTIN_TYPE_NONNEGATIVEINTEGER:
03145     case nsISchemaBuiltinType::BUILTIN_TYPE_INT:
03146     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDINT:
03147     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDLONG:
03148     case nsISchemaBuiltinType::BUILTIN_TYPE_POSITIVEINTEGER:
03149     case nsISchemaBuiltinType::BUILTIN_TYPE_SHORT:
03150     case nsISchemaBuiltinType::BUILTIN_TYPE_UNSIGNEDSHORT:
03151       *aPrimType = nsISchemaBuiltinType::BUILTIN_TYPE_DECIMAL;
03152       break;
03153     default:
03154       // should never hit here
03155       NS_WARNING("nsXFormsModelElement::BuiltinTypeToPrimative: Unknown builtin type encountered.");
03156       return NS_ERROR_FAILURE;
03157   }
03158 
03159   return NS_OK;
03160 }
03161 
03162 NS_IMETHODIMP
03163 nsXFormsModelElement::GetDerivedTypeList(const nsAString &aType,
03164                                          const nsAString &aNamespace,
03165                                          nsAString       &aTypeList)
03166 {
03167   nsCOMPtr<nsISchemaCollection> schemaColl = do_QueryInterface(mSchemas);
03168   NS_ENSURE_STATE(schemaColl);
03169 
03170   nsCOMPtr<nsISchemaType> schemaType;
03171   schemaColl->GetType(aType, aNamespace, getter_AddRefs(schemaType));
03172   NS_ENSURE_STATE(schemaType);
03173 
03174   nsStringArray typeArray;
03175   nsresult rv = WalkTypeChainInternal(schemaType, PR_FALSE, nsnull, &typeArray);
03176   if (NS_SUCCEEDED(rv)) {
03177     nsCOMPtr<nsIStringEnumerator> stringEnum;
03178     rv = NS_NewStringEnumerator(getter_AddRefs(stringEnum), &typeArray);
03179     if (NS_SUCCEEDED(rv)) {
03180       nsAutoString constructorString;
03181       PRBool hasMore = PR_FALSE;
03182       rv = stringEnum->HasMore(&hasMore);
03183       while (NS_SUCCEEDED(rv) && hasMore) {
03184         nsAutoString tempString;
03185         rv = stringEnum->GetNext(tempString);
03186         if (NS_SUCCEEDED(rv)) {
03187           constructorString.Append(tempString);
03188           stringEnum->HasMore(&hasMore);
03189           if (hasMore) {
03190             constructorString.AppendLiteral(" ");
03191           }
03192         }
03193       }
03194 
03195       if (NS_SUCCEEDED(rv)) {
03196         aTypeList.Assign(constructorString);
03197       }
03198     }
03199   }
03200 
03201   if (NS_FAILED(rv)) {
03202     aTypeList.Assign(EmptyString());
03203   }
03204 
03205   typeArray.Clear();
03206 
03207   return rv;
03208 }
03209 
03210 NS_IMETHODIMP
03211 nsXFormsModelElement::GetBuiltinTypeNameForControl(nsIXFormsControl  *aControl,
03212                                                    nsAString&         aTypeName)
03213 {
03214   NS_ENSURE_ARG(aControl);
03215 
03216   nsCOMPtr<nsISchemaType> schemaType;
03217   nsresult rv = GetTypeForControl(aControl, getter_AddRefs(schemaType));
03218   NS_ENSURE_SUCCESS(rv, rv);
03219 
03220   PRUint16 builtinType;
03221   rv = WalkTypeChainInternal(schemaType, PR_FALSE, &builtinType);
03222   NS_ENSURE_SUCCESS(rv, rv);
03223 
03224   return GetBuiltinTypeName(builtinType, aTypeName);
03225 }
03226 
03227 NS_IMETHODIMP
03228 nsXFormsModelElement::GetRootBuiltinType(nsISchemaType *aType,
03229                                          PRUint16      *aBuiltinType)
03230 {
03231   NS_ENSURE_ARG(aType);
03232   NS_ENSURE_ARG_POINTER(aBuiltinType);
03233 
03234   return WalkTypeChainInternal(aType, PR_TRUE, aBuiltinType);
03235 }
03236 
03237 /* static */ void
03238 nsXFormsModelElement::Startup()
03239 {
03240   sModelPropsList[eModel_type] = nsXFormsAtoms::type;
03241   sModelPropsList[eModel_readonly] = nsXFormsAtoms::readonly;
03242   sModelPropsList[eModel_required] = nsXFormsAtoms::required;
03243   sModelPropsList[eModel_relevant] = nsXFormsAtoms::relevant;
03244   sModelPropsList[eModel_calculate] = nsXFormsAtoms::calculate;
03245   sModelPropsList[eModel_constraint] = nsXFormsAtoms::constraint;
03246   sModelPropsList[eModel_p3ptype] = nsXFormsAtoms::p3ptype;
03247 }
03248 
03249 already_AddRefed<nsIDOMElement>
03250 nsXFormsModelElement::GetDOMElement()
03251 {
03252   nsIDOMElement* element = nsnull;
03253   NS_IF_ADDREF(element = mElement);
03254   return element;
03255 }
03256 
03257 static void
03258 DeleteBindList(void    *aObject,
03259                nsIAtom *aPropertyName,
03260                void    *aPropertyValue,
03261                void    *aData)
03262 {
03263   delete NS_STATIC_CAST(nsCOMArray<nsIXFormsControl> *, aPropertyValue);
03264 }
03265 
03266 /* static */ nsresult
03267 nsXFormsModelElement::DeferElementBind(nsIXFormsControl *aControl)
03268 {
03269   NS_ENSURE_ARG_POINTER(aControl);
03270   nsCOMPtr<nsIDOMElement> element;
03271   nsresult rv = aControl->GetElement(getter_AddRefs(element));
03272   NS_ENSURE_SUCCESS(rv, rv);
03273 
03274   nsCOMPtr<nsIContent> content(do_QueryInterface(element));
03275   NS_ASSERTION(content, "nsIDOMElement not implementing nsIContent?!");
03276 
03277   nsCOMPtr<nsIDocument> doc = content->GetCurrentDoc();
03278   if (!doc) {
03279     // We do not care about elements without a document. If they get added to
03280     // a document at some point in time, they'll try to bind again.
03281     return NS_OK;
03282   }
03283 
03284   // We are using a PRBool on each control to mark whether the control is on the
03285   // deferredBindList.  We are running into too many scenarios where a control
03286   // could be added more than once which will lead to inefficiencies because
03287   // calling bind and refresh on some controls is getting pretty expensive.
03288   // We need to keep the document order of the controls AND don't want
03289   // to walk the deferredBindList every time we want to check about adding a
03290   // control.
03291   PRBool onList = PR_FALSE;
03292   aControl->GetOnDeferredBindList(&onList);
03293   if (onList) {
03294     return NS_OK;
03295   }
03296 
03297   nsCOMArray<nsIXFormsControl> *deferredBindList =
03298     NS_STATIC_CAST(nsCOMArray<nsIXFormsControl> *,
03299                    doc->GetProperty(nsXFormsAtoms::deferredBindListProperty));
03300 
03301   if (!deferredBindList) {
03302     deferredBindList = new nsCOMArray<nsIXFormsControl>(16);
03303     NS_ENSURE_TRUE(deferredBindList, NS_ERROR_OUT_OF_MEMORY);
03304 
03305     doc->SetProperty(nsXFormsAtoms::deferredBindListProperty, deferredBindList,
03306                      DeleteBindList);
03307   }
03308 
03309   // always append to the end of the list.  We need to keep the elements in
03310   // document order when we process the binds later.  Otherwise we have trouble
03311   // when an element is trying to bind and should use its parent as a context
03312   // for the xpath evaluation but the parent isn't bound yet.
03313   deferredBindList->AppendObject(aControl);
03314   aControl->SetOnDeferredBindList(PR_TRUE);
03315 
03316   return NS_OK;
03317 }
03318 
03319 /* static */ void
03320 nsXFormsModelElement::ProcessDeferredBinds(nsIDOMDocument *aDoc)
03321 {
03322 #ifdef DEBUG_MODEL
03323   printf("nsXFormsModelElement::ProcessDeferredBinds()\n");
03324 #endif
03325 
03326   nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
03327 
03328   if (!doc) {
03329     return;
03330   }
03331 
03332   nsPostRefresh postRefresh = nsPostRefresh();
03333 
03334   doc->SetProperty(nsXFormsAtoms::readyForBindProperty, doc);
03335 
03336   nsCOMArray<nsIXFormsControl> *deferredBindList =
03337       NS_STATIC_CAST(nsCOMArray<nsIXFormsControl> *,
03338                      doc->GetProperty(nsXFormsAtoms::deferredBindListProperty));
03339 
03340   if (deferredBindList) {
03341     for (PRInt32 i = 0; i < deferredBindList->Count(); ++i) {
03342       nsIXFormsControl *control = deferredBindList->ObjectAt(i);
03343       if (control) {
03344         control->BindToModel(PR_FALSE);
03345         control->SetOnDeferredBindList(PR_FALSE);
03346       }
03347     }
03348 
03349     doc->DeleteProperty(nsXFormsAtoms::deferredBindListProperty);
03350   }
03351 }
03352 
03353 nsresult
03354 nsXFormsModelElement::HandleLoad(nsIDOMEvent* aEvent)
03355 {
03356   if (!mInstancesInitialized) {
03357     // XXX This is for Bug 308106. In Gecko 1.8 DoneAddingChildren is not
03358     //     called in XUL if the element doesn't have any child nodes.
03359     InitializeInstances();
03360   }
03361 
03362   mDocumentLoaded = PR_TRUE;
03363 
03364   nsCOMPtr<nsIDOMDocument> document;
03365   mElement->GetOwnerDocument(getter_AddRefs(document));
03366   NS_ENSURE_STATE(document);
03367   nsXFormsUtils::DispatchDeferredEvents(document);
03368 
03369   // dispatch xforms-model-construct, xforms-rebuild, xforms-recalculate,
03370   // xforms-revalidate
03371 
03372   // We wait until DOMContentLoaded to dispatch xforms-model-construct,
03373   // since the model may have an action handler for this event and Mozilla
03374   // doesn't register XML Event listeners until the document is loaded.
03375 
03376   // xforms-model-construct is not cancellable, so always proceed.
03377 
03378   nsXFormsUtils::DispatchEvent(mElement, eEvent_ModelConstruct);
03379 
03380   if (mPendingInlineSchemas.Count() > 0) {
03381     nsCOMPtr<nsIDOMElement> el;
03382     nsresult rv = NS_OK;
03383     for (PRInt32 i=0; i<mPendingInlineSchemas.Count(); ++i) {
03384       GetSchemaElementById(mElement, *mPendingInlineSchemas[i],
03385                            getter_AddRefs(el));
03386       if (!el) {
03387         rv = NS_ERROR_UNEXPECTED;
03388       } else {
03389         // According to section 3.3.1 of the spec, more than one schema per
03390         // namespace isn't allowed, but it also doesn't spell out very well
03391         // what this means a processor should do about it.  Since most
03392         // processors ignore this rule and it isn't specifically a fatal error,
03393         // we won't make this a failure here.
03394         if (!IsDuplicateSchema(el)) {
03395           nsCOMPtr<nsISchema> schema;
03396           // no need to observe errors via the callback.  instead, rely on
03397           // this method returning a failure code when it encounters errors.
03398           rv = mSchemas->ProcessSchemaElement(el, nsnull,
03399                                               getter_AddRefs(schema));
03400           if (NS_SUCCEEDED(rv))
03401             mSchemaCount++;
03402         }
03403       }
03404       if (NS_FAILED(rv)) {
03405         // this is a fatal error
03406         nsXFormsUtils::ReportError(NS_LITERAL_STRING("schemaLoadError"), mElement);
03407         nsXFormsUtils::DispatchEvent(mElement, eEvent_LinkException);
03408         return NS_OK;
03409       }
03410     }
03411     if (IsComplete()) {
03412       rv = FinishConstruction();
03413       NS_ENSURE_SUCCESS(rv, rv);
03414     }
03415     mPendingInlineSchemas.Clear();
03416   }
03417 
03418   // We may still be waiting on external documents to load.
03419   MaybeNotifyCompletion();
03420 
03421   return NS_OK;
03422 }
03423 
03424 nsresult
03425 nsXFormsModelElement::HandleUnload(nsIDOMEvent* aEvent)
03426 {
03427   // due to fastback changes, had to move this notification out from under
03428   // model's WillChangeDocument override.
03429   nsXFormsUtils::DispatchEvent(mElement, eEvent_ModelDestruct);
03430 
03431   mSchemas = nsnull;
03432 
03433   if (mInstanceDocuments)
03434     mInstanceDocuments->DropReferences();
03435 
03436   mFormControls.Clear();
03437   mControlListHash.Clear();
03438   return NS_OK;
03439 }
03440 
03441 PRBool
03442 nsXFormsModelElement::IsDuplicateSchema(nsIDOMElement *aSchemaElement)
03443 {
03444   nsCOMPtr<nsISchemaCollection> schemaColl = do_QueryInterface(mSchemas);
03445   if (!schemaColl)
03446     return PR_FALSE;
03447 
03448   const nsAFlatString& empty = EmptyString();
03449   nsAutoString targetNamespace;
03450   aSchemaElement->GetAttributeNS(empty,
03451                                  NS_LITERAL_STRING("targetNamespace"),
03452                                  targetNamespace);
03453   targetNamespace.Trim(" \r\n\t");
03454 
03455   nsCOMPtr<nsISchema> schema;
03456   schemaColl->GetSchema(targetNamespace, getter_AddRefs(schema));
03457   if (!schema)
03458     return PR_FALSE;
03459 
03460   // A schema with the same target namespace already exists in the
03461   // schema collection and the first instance has already been processed.
03462   // Report an error to the JS console and dispatch the LinkError event,
03463   // but do not consider it a fatal error.
03464   const nsPromiseFlatString& flat = PromiseFlatString(targetNamespace);
03465   const PRUnichar *strings[] = { flat.get() };
03466   nsXFormsUtils::ReportError(NS_LITERAL_STRING("duplicateSchema"),
03467                              strings, 1, aSchemaElement, aSchemaElement,
03468                              nsnull);
03469   nsXFormsUtils::DispatchEvent(mElement, eEvent_LinkError);
03470   return PR_TRUE;
03471 }
03472 
03473 nsresult
03474 nsXFormsModelElement::SetContextInfo(const char *aName, const nsAString &aValue)
03475 {
03476   nsCOMPtr<nsXFormsContextInfo> contextInfo = new nsXFormsContextInfo(mElement);
03477   NS_ENSURE_TRUE(contextInfo, NS_ERROR_OUT_OF_MEMORY);
03478   contextInfo->SetStringValue(aName, aValue);
03479   mContextInfo.AppendObject(contextInfo);
03480 
03481   return NS_OK;
03482 }
03483 
03484 nsresult
03485 NS_NewXFormsModelElement(nsIXTFElement **aResult)
03486 {
03487   *aResult = new nsXFormsModelElement();
03488   if (!*aResult)
03489     return NS_ERROR_OUT_OF_MEMORY;
03490 
03491   NS_ADDREF(*aResult);
03492   return NS_OK;
03493 }
03494 
03495 
03496 // ---------------------------- //
03497 
03498 // nsXFormsModelInstanceDocuments
03499 
03500 NS_IMPL_ISUPPORTS2(nsXFormsModelInstanceDocuments, nsIDOMNodeList, nsIClassInfo)
03501 
03502 nsXFormsModelInstanceDocuments::nsXFormsModelInstanceDocuments()
03503   : mInstanceList(16)
03504 {
03505 }
03506 
03507 NS_IMETHODIMP
03508 nsXFormsModelInstanceDocuments::GetLength(PRUint32* aLength)
03509 {
03510   *aLength = mInstanceList.Count();
03511 
03512   return NS_OK;
03513 }
03514 
03515 NS_IMETHODIMP
03516 nsXFormsModelInstanceDocuments::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
03517 {
03518   *aReturn = nsnull;
03519   nsIInstanceElementPrivate* instance = mInstanceList.SafeObjectAt(aIndex);
03520   if (instance) {
03521     nsCOMPtr<nsIDOMDocument> doc;
03522     if (NS_SUCCEEDED(instance->GetInstanceDocument(getter_AddRefs(doc))) && doc) {
03523       NS_ADDREF(*aReturn = doc);
03524     }
03525   }
03526 
03527   return NS_OK;
03528 }
03529 
03530 nsIInstanceElementPrivate*
03531 nsXFormsModelInstanceDocuments::GetInstanceAt(PRUint32 aIndex)
03532 {
03533   return mInstanceList.ObjectAt(aIndex);
03534 }
03535 
03536 void
03537 nsXFormsModelInstanceDocuments::AddInstance(nsIInstanceElementPrivate *aInst)
03538 {
03539   // always append to the end of the list.  We need to keep the elements in
03540   // document order since the first instance element is the default instance
03541   // document for the model.
03542   mInstanceList.AppendObject(aInst);
03543 }
03544 
03545 void
03546 nsXFormsModelInstanceDocuments::RemoveInstance(nsIInstanceElementPrivate *aInst)
03547 {
03548   mInstanceList.RemoveObject(aInst);
03549 }
03550 
03551 void
03552 nsXFormsModelInstanceDocuments::DropReferences()
03553 {
03554   mInstanceList.Clear();
03555 }
03556 
03557 // nsIClassInfo implementation
03558 
03559 static const nsIID sInstScriptingIIDs[] = {
03560   NS_IDOMNODELIST_IID
03561 };
03562 
03563 NS_IMETHODIMP
03564 nsXFormsModelInstanceDocuments::GetInterfaces(PRUint32   *aCount,
03565                                               nsIID   * **aArray)
03566 {
03567   return
03568     nsXFormsUtils::CloneScriptingInterfaces(sInstScriptingIIDs,
03569                                             NS_ARRAY_LENGTH(sInstScriptingIIDs),
03570                                             aCount, aArray);
03571 }
03572 
03573 NS_IMETHODIMP
03574 nsXFormsModelInstanceDocuments::GetHelperForLanguage(PRUint32 language,
03575                                                      nsISupports **_retval)
03576 {
03577   *_retval = nsnull;
03578   return NS_OK;
03579 }
03580 
03581 NS_IMETHODIMP
03582 nsXFormsModelInstanceDocuments::GetContractID(char * *aContractID)
03583 {
03584   *aContractID = nsnull;
03585   return NS_OK;
03586 }
03587 
03588 NS_IMETHODIMP
03589 nsXFormsModelInstanceDocuments::GetClassDescription(char * *aClassDescription)
03590 {
03591   *aClassDescription = nsnull;
03592   return NS_OK;
03593 }
03594 
03595 NS_IMETHODIMP
03596 nsXFormsModelInstanceDocuments::GetClassID(nsCID * *aClassID)
03597 {
03598   *aClassID = nsnull;
03599   return NS_OK;
03600 }
03601 
03602 NS_IMETHODIMP
03603 nsXFormsModelInstanceDocuments::GetImplementationLanguage(PRUint32 *aLang)
03604 {
03605   *aLang = nsIProgrammingLanguage::CPLUSPLUS;
03606   return NS_OK;
03607 }
03608 
03609 NS_IMETHODIMP
03610 nsXFormsModelInstanceDocuments::GetFlags(PRUint32 *aFlags)
03611 {
03612   *aFlags = nsIClassInfo::DOM_OBJECT;
03613   return NS_OK;
03614 }
03615 
03616 NS_IMETHODIMP
03617 nsXFormsModelInstanceDocuments::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
03618 {
03619   return NS_ERROR_NOT_AVAILABLE;
03620 }