Back to index

lightning-sunbird  0.9+nobinonly
nsXFormsActionModuleBase.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  * Olli Pettay.
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Olli Pettay <Olli.Pettay@helsinki.fi> (original author)
00024  *   John L. Clark <jlc6@po.cwru.edu>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsXFormsActionModuleBase.h"
00041 #include "nsXFormsActionElement.h"
00042 #include "nsIDOM3Node.h"
00043 #include "nsMemory.h"
00044 #include "nsIDOMNodeList.h"
00045 #include "nsXFormsModelElement.h"
00046 #include "nsString.h"
00047 #include "nsIDOMElement.h"
00048 #include "nsIDOMNodeList.h"
00049 #include "nsIXTFGenericElementWrapper.h"
00050 #include "nsIDOMDocumentEvent.h"
00051 #include "nsIDOMEventTarget.h"
00052 
00053 #include "nsXFormsUtils.h"
00054 #include "nsIDOMAttr.h"
00055 #include "nsIXFormsControl.h"
00056 
00057 #include "nsIPrefBranch.h"
00058 #include "nsIPrefService.h"
00059 #include "nsServiceManagerUtils.h"
00060 
00061 nsXFormsActionModuleBase::nsXFormsActionModuleBase() : mElement(nsnull)
00062 {
00063 }
00064 
00065 nsXFormsActionModuleBase::~nsXFormsActionModuleBase()
00066 {
00067 }
00068 
00069 NS_IMPL_ISUPPORTS_INHERITED2(nsXFormsActionModuleBase,
00070                              nsXFormsStubElement,
00071                              nsIXFormsActionModuleElement,
00072                              nsIDOMEventListener)
00073 
00074 NS_IMETHODIMP
00075 nsXFormsActionModuleBase::OnCreated(nsIXTFGenericElementWrapper *aWrapper)
00076 {
00077   // It's ok to keep a weak pointer to mElement.  mElement will have an
00078   // owning reference to this object, so as long as we null out mElement in
00079   // OnDestroyed, it will always be valid.
00080   nsCOMPtr<nsIDOMElement> node;
00081   aWrapper->GetElementNode(getter_AddRefs(node));
00082   mElement = node;
00083   NS_ASSERTION(mElement, "Wrapper is not an nsIDOMElement, we'll crash soon");
00084 
00085   aWrapper->SetNotificationMask(nsIXTFElement::NOTIFY_WILL_CHANGE_DOCUMENT |
00086                                 nsIXTFElement::NOTIFY_WILL_CHANGE_PARENT |
00087                                 nsIXTFElement::NOTIFY_DOCUMENT_CHANGED |
00088                                 nsIXTFElement::NOTIFY_PARENT_CHANGED);
00089 
00090   return NS_OK;
00091 }
00092 
00093 NS_IMETHODIMP nsXFormsActionModuleBase::OnDestroyed()
00094 {
00095   mElement = nsnull;
00096   return NS_OK;
00097 }
00098 
00099 NS_IMETHODIMP
00100 nsXFormsActionModuleBase::WillChangeParent(nsIDOMElement *aNewParent)
00101 {
00102   SetRepeatState(eType_Unknown);
00103   return NS_OK;
00104 }
00105 
00106 NS_IMETHODIMP
00107 nsXFormsActionModuleBase::ParentChanged(nsIDOMElement *aNewParent)
00108 {
00109   nsXFormsStubElement::ParentChanged(aNewParent);
00110   UpdateRepeatState(aNewParent);
00111   return NS_OK;
00112 }
00113 
00114 NS_IMETHODIMP
00115 nsXFormsActionModuleBase::WillChangeDocument(nsIDOMDocument *aNewDocument)
00116 {
00117   SetRepeatState(eType_Unknown);
00118   return NS_OK;
00119 }
00120 
00121 NS_IMETHODIMP
00122 nsXFormsActionModuleBase::DocumentChanged(nsIDOMDocument *aNewDocument)
00123 {
00124   nsXFormsStubElement::DocumentChanged(aNewDocument);
00125 
00126   nsCOMPtr<nsIDOMNode> parent;
00127   mElement->GetParentNode(getter_AddRefs(parent));
00128   UpdateRepeatState(parent);
00129   return NS_OK;
00130 }
00131 
00132 NS_IMETHODIMP
00133 nsXFormsActionModuleBase::HandleEvent(nsIDOMEvent* aEvent)
00134 {
00135   if (GetRepeatState() == eType_Template) {
00136     return NS_OK;
00137   }
00138 
00139   return nsXFormsUtils::EventHandlingAllowed(aEvent, mElement) ?
00140            HandleAction(aEvent, nsnull) : NS_OK;
00141 }
00142 
00143 NS_IMETHODIMP
00144 nsXFormsActionModuleBase::HandleAction(nsIDOMEvent            *aEvent,
00145                                        nsIXFormsActionElement *aParentAction)
00146 {
00147   return nsXFormsActionModuleBase::DoHandleAction(this, aEvent, aParentAction);
00148 }
00149 
00150 /* static */ nsresult
00151 nsXFormsActionModuleBase::DoHandleAction(nsXFormsActionModuleHelper *aXFormsAction,
00152                                          nsIDOMEvent                *aEvent,
00153                                          nsIXFormsActionElement     *aParentAction)
00154 {
00155   nsCOMPtr<nsIDOMElement> element = aXFormsAction->GetElement();
00156   if (!element) {
00157     return NS_OK;
00158   }
00159   aXFormsAction->SetCurrentEvent(aEvent);
00160 
00161   // Set the maximum run time for the loop (in microseconds).
00162   PRTime microseconds = nsXFormsUtils::waitLimit * PR_USEC_PER_SEC;
00163 
00164   PRTime runTime = 0, start = PR_Now();
00165 
00166   while (PR_TRUE) {
00167     // Test the `if` and `while` attributes to determine whether this action
00168     // can be performed and should be repeated.
00169     PRBool usesWhile;
00170     if (!nsXFormsActionModuleBase::CanPerformAction(element, &usesWhile)) {
00171       return NS_OK;
00172     }
00173 
00174     nsresult rv = aXFormsAction->HandleSingleAction(aEvent, aParentAction);
00175     NS_ENSURE_SUCCESS(rv, rv);
00176 
00177     // Repeat this action if it can iterate and if it uses the `while`
00178     // attribute (the expression of which must have evaluated to true to
00179     // arrive here).
00180     if (!aXFormsAction->CanIterate() || !usesWhile) {
00181       return NS_OK;
00182     }
00183 
00184     // See if we've exceeded our time limit, and if so, prompt the user to
00185     // determine if she wants to cancel the loop.
00186     LL_SUB(runTime, PR_Now(), start);
00187     if (microseconds <= 0 || runTime < microseconds) {
00188       continue;
00189     }
00190 
00191     // The remaining part of the loop prompts the user about cancelling the
00192     // loop, and is only executed if we've gone over the time limit.
00193     PRBool stopWaiting = nsXFormsUtils::AskStopWaiting(element);
00194 
00195     if (stopWaiting) {
00196       // Stop the loop
00197       return NS_OK;
00198     } else {
00199       start = PR_Now();
00200     }
00201   }
00202 }
00203 
00204 /* static */
00205 PRBool
00206 nsXFormsActionModuleBase::CanPerformAction(nsIDOMElement *aElement,
00207                                            PRBool        *aUsesWhile,
00208                                            nsIDOMNode    *aContext,
00209                                            PRInt32        aContextSize,
00210                                            PRInt32        aContextPosition)
00211 {
00212   *aUsesWhile = PR_FALSE;
00213 
00214   nsAutoString ifExpr;
00215   nsAutoString whileExpr;
00216   aElement->GetAttribute(NS_LITERAL_STRING("if"), ifExpr);
00217   aElement->GetAttribute(NS_LITERAL_STRING("while"), whileExpr);
00218 
00219   if (whileExpr.IsEmpty() && ifExpr.IsEmpty()) {
00220     return PR_TRUE;
00221   }
00222 
00223   nsresult rv;
00224   nsCOMPtr<nsIDOMXPathResult> res;
00225   PRBool condTrue;
00226 
00227   nsCOMPtr<nsIDOMNode> contextNode;
00228 
00229   if (aContext) {
00230     contextNode = aContext;
00231   } else {
00232     // Determine evaluation context.
00233     nsCOMPtr<nsIModelElementPrivate> model;
00234     nsCOMPtr<nsIDOMElement> bindElement;
00235     nsCOMPtr<nsIXFormsControl> parentControl;
00236     PRBool outerBind;
00237     rv = nsXFormsUtils::GetNodeContext(aElement, 0,
00238                                        getter_AddRefs(model),
00239                                        getter_AddRefs(bindElement),
00240                                        &outerBind,
00241                                        getter_AddRefs(parentControl),
00242                                        getter_AddRefs(contextNode),
00243                                        &aContextPosition, &aContextSize, PR_FALSE);
00244     NS_ENSURE_SUCCESS(rv, PR_FALSE);
00245   }
00246 
00247   if (!whileExpr.IsEmpty()) {
00248     *aUsesWhile = PR_TRUE;
00249 
00250     rv = nsXFormsUtils::EvaluateXPath(whileExpr, contextNode, aElement,
00251                                       nsIDOMXPathResult::BOOLEAN_TYPE,
00252                                       getter_AddRefs(res),
00253                                       aContextPosition, aContextSize);
00254     NS_ENSURE_SUCCESS(rv, PR_FALSE);
00255     
00256     rv = res->GetBooleanValue(&condTrue);
00257     if (NS_FAILED(rv) || !condTrue) {
00258       return PR_FALSE;
00259     }
00260   }
00261 
00262   if (!ifExpr.IsEmpty()) {
00263     rv = nsXFormsUtils::EvaluateXPath(ifExpr, contextNode, aElement,
00264                                       nsIDOMXPathResult::BOOLEAN_TYPE,
00265                                       getter_AddRefs(res),
00266                                       aContextPosition, aContextSize);
00267     NS_ENSURE_SUCCESS(rv, PR_FALSE);
00268     
00269     rv = res->GetBooleanValue(&condTrue);
00270     if (NS_FAILED(rv) || !condTrue) {
00271       return PR_FALSE;
00272     }
00273   }
00274 
00275   return PR_TRUE;
00276 }
00277 
00278 NS_IMETHODIMP
00279 nsXFormsActionModuleBase::GetCurrentEvent(nsIDOMEvent **aEvent)
00280 {
00281   NS_IF_ADDREF(*aEvent = mCurrentEvent);
00282   return NS_OK;
00283 }