Back to index

lightning-sunbird  0.9+nobinonly
nsXFormsActionElement.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  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsXFormsActionElement.h"
00040 #include "nsIXFormsModelElement.h"
00041 #include "nsIDOMNodeList.h"
00042 #include "nsIDOMDocument.h"
00043 #include "nsIDOMEvent.h"
00044 #include "nsIDOMElement.h"
00045 #include "nsIXTFBindableElementWrapper.h"
00046 
00047 #define DEFERRED_REBUILD     0x01
00048 #define DEFERRED_RECALCULATE 0x02
00049 #define DEFERRED_REVALIDATE  0x04
00050 #define DEFERRED_REFRESH     0x08
00051 
00052 NS_IMPL_ADDREF_INHERITED(nsXFormsActionElement, nsXFormsBindableControlStub)
00053 NS_IMPL_RELEASE_INHERITED(nsXFormsActionElement, nsXFormsBindableControlStub)
00054 
00055 NS_INTERFACE_MAP_BEGIN(nsXFormsActionElement)
00056   NS_INTERFACE_MAP_ENTRY(nsIXFormsActionModuleElement)
00057   NS_INTERFACE_MAP_ENTRY(nsIXFormsActionElement)
00058   NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
00059 NS_INTERFACE_MAP_END_INHERITING(nsXFormsBindableControlStub)
00060 
00061 NS_IMETHODIMP
00062 nsXFormsActionElement::OnCreated(nsIXTFBindableElementWrapper* aWrapper)
00063 {
00064   nsresult rv = nsXFormsBindableControlStub::OnCreated(aWrapper);
00065   NS_ENSURE_SUCCESS(rv, rv);
00066 
00067   aWrapper->SetNotificationMask(nsIXTFElement::NOTIFY_WILL_CHANGE_DOCUMENT |
00068                                 nsIXTFElement::NOTIFY_WILL_CHANGE_PARENT |
00069                                 nsIXTFElement::NOTIFY_DOCUMENT_CHANGED |
00070                                 nsIXTFElement::NOTIFY_PARENT_CHANGED);
00071 
00072   return NS_OK;
00073 }
00074 
00075 NS_IMETHODIMP
00076 nsXFormsActionElement::OnDestroyed() {
00077   mParentAction = nsnull;
00078   mElement = nsnull;
00079   return NS_OK;
00080 }
00081 
00082 NS_IMETHODIMP
00083 nsXFormsActionElement::WillChangeParent(nsIDOMElement *aNewParent)
00084 {
00085   SetRepeatState(eType_Unknown);
00086   return NS_OK;
00087 }
00088 
00089 NS_IMETHODIMP
00090 nsXFormsActionElement::ParentChanged(nsIDOMElement *aNewParent)
00091 {
00092   mHasParent = aNewParent != nsnull;
00093   UpdateRepeatState(aNewParent);
00094   return NS_OK;
00095 }
00096 
00097 NS_IMETHODIMP
00098 nsXFormsActionElement::WillChangeDocument(nsIDOMDocument *aNewDocument)
00099 {
00100   SetRepeatState(eType_Unknown);
00101   return NS_OK;
00102 }
00103 
00104 NS_IMETHODIMP
00105 nsXFormsActionElement::DocumentChanged(nsIDOMDocument *aNewDocument)
00106 {
00107   mHasDoc = aNewDocument != nsnull;
00108 
00109   nsCOMPtr<nsIDOMNode> parent;
00110   mElement->GetParentNode(getter_AddRefs(parent));
00111   UpdateRepeatState(parent);
00112   return NS_OK;
00113 }
00114 
00115 NS_IMETHODIMP
00116 nsXFormsActionElement::HandleEvent(nsIDOMEvent* aEvent)
00117 {
00118   if (GetRepeatState() == eType_Template) {
00119     return NS_OK;
00120   }
00121 
00122   return nsXFormsUtils::EventHandlingAllowed(aEvent, mElement) ?
00123            HandleAction(aEvent, nsnull) : NS_OK;
00124 }
00125 
00126 PR_STATIC_CALLBACK(PLDHashOperator) DoDeferredActions(nsISupports * aModel, 
00127                                                       PRUint32 aDeferred,
00128                                                       void * data)
00129 {
00130   if (aModel && aDeferred) {
00131     nsCOMPtr<nsIModelElementPrivate> model(do_QueryInterface(aModel));
00132 
00133     if (aDeferred & DEFERRED_REBUILD)
00134       model->RequestRebuild();
00135     if (aDeferred & DEFERRED_RECALCULATE)
00136       model->RequestRecalculate();
00137     if (aDeferred & DEFERRED_REVALIDATE)
00138       model->RequestRevalidate();
00139     if (aDeferred & DEFERRED_REFRESH)
00140       model->RequestRefresh();
00141   }
00142   return PL_DHASH_NEXT;
00143 }
00144 
00145 NS_IMETHODIMP
00146 nsXFormsActionElement::HandleAction(nsIDOMEvent* aEvent,
00147                                     nsIXFormsActionElement* aParentAction)
00148 {
00149   return nsXFormsActionModuleBase::DoHandleAction(this, aEvent, aParentAction);
00150 }
00151 
00152 nsresult
00153 nsXFormsActionElement::HandleSingleAction(nsIDOMEvent* aEvent,
00154                                           nsIXFormsActionElement* aParentAction)
00155 {
00156   if (!mDeferredUpdates.IsInitialized()) {
00157     NS_ENSURE_TRUE(mDeferredUpdates.Init(), NS_ERROR_OUT_OF_MEMORY);
00158   } else {
00159     mDeferredUpdates.Clear();
00160   }
00161 
00162   mParentAction = aParentAction;
00163   nsCOMPtr<nsIDOMNodeList> childNodes;
00164   mElement->GetChildNodes(getter_AddRefs(childNodes));
00165   if (!childNodes) {
00166     return NS_OK;
00167   }
00168 
00169   PRUint32 count;
00170   childNodes->GetLength(&count);
00171   nsCOMPtr<nsIXFormsActionModuleElement> actionChild;
00172   nsCOMPtr<nsIDOMEvent> event(aEvent);
00173   for (PRUint32 i = 0; i < count; ++i) {
00174     nsCOMPtr<nsIDOMNode> child;
00175     childNodes->Item(i, getter_AddRefs(child));
00176     actionChild = do_QueryInterface(child);
00177     if (actionChild) {
00178       actionChild->HandleAction(event, this);
00179     }
00180   }
00181   if (!aParentAction) { //Otherwise parent will handle deferred updates
00182     mDeferredUpdates.EnumerateRead(DoDeferredActions, nsnull);
00183   }
00184   return NS_OK;
00185 }
00186 
00187 NS_IMETHODIMP
00188 nsXFormsActionElement::SetRebuild(nsIModelElementPrivate* aModel,
00189                                   PRBool aEnable)
00190 {
00191   if (mParentAction) {
00192     return mParentAction->SetRebuild(aModel, aEnable);
00193   }
00194 
00195   PRUint32 deferred = 0;
00196 
00197   // It is possible that QI's to an interface that isn't nsISupports (like
00198   // nsIModelElementPrivate) could produce different values even from the same
00199   // model element.  So we'll convert the model to nsISupports before querying
00200   // it or storing it via hashtable.
00201   nsCOMPtr<nsISupports> temp(do_QueryInterface(aModel));
00202   mDeferredUpdates.Get(temp, &deferred);
00203   if (aEnable) {
00204     deferred |= DEFERRED_REBUILD;
00205   } else {
00206     deferred &= ~DEFERRED_REBUILD;
00207   }
00208   
00209   mDeferredUpdates.Put(temp, deferred);
00210   return NS_OK;
00211 }
00212 
00213 NS_IMETHODIMP
00214 nsXFormsActionElement::SetRecalculate(nsIModelElementPrivate* aModel,
00215                                       PRBool aEnable)
00216 {
00217   if (mParentAction) {
00218     return mParentAction->SetRecalculate(aModel, aEnable);
00219   }
00220 
00221   PRUint32 deferred = 0;
00222 
00223   // It is possible that QI's to an interface that isn't nsISupports (like
00224   // nsIModelElementPrivate) could produce different values even from the same
00225   // model element.  So we'll convert the model to nsISupports before querying
00226   // it or storing it via hashtable.
00227   nsCOMPtr<nsISupports> temp(do_QueryInterface(aModel));
00228   mDeferredUpdates.Get(temp, &deferred);
00229   if (aEnable) {
00230     deferred |= DEFERRED_RECALCULATE;
00231   } else {
00232     deferred &= ~DEFERRED_RECALCULATE;
00233   }
00234   mDeferredUpdates.Put(temp, deferred);
00235   return NS_OK;
00236 }
00237 
00238 NS_IMETHODIMP
00239 nsXFormsActionElement::SetRevalidate(nsIModelElementPrivate* aModel,
00240                                      PRBool aEnable)
00241 {
00242   if (mParentAction) {
00243     return mParentAction->SetRevalidate(aModel, aEnable);
00244   }
00245 
00246   PRUint32 deferred = 0;
00247 
00248   // It is possible that QI's to an interface that isn't nsISupports (like
00249   // nsIModelElementPrivate) could produce different values even from the same
00250   // model element.  So we'll convert the model to nsISupports before querying
00251   // it or storing it via hashtable.
00252   nsCOMPtr<nsISupports> temp(do_QueryInterface(aModel));
00253   mDeferredUpdates.Get(temp, &deferred);
00254   if (aEnable) {
00255     deferred |= DEFERRED_REVALIDATE;
00256   } else {
00257     deferred &= ~DEFERRED_REVALIDATE;
00258   }
00259   mDeferredUpdates.Put(temp, deferred);
00260   return NS_OK;
00261 }
00262 
00263 NS_IMETHODIMP
00264 nsXFormsActionElement::SetRefresh(nsIModelElementPrivate* aModel,
00265                                   PRBool aEnable)
00266 {
00267   if (mParentAction) {
00268     return mParentAction->SetRefresh(aModel, aEnable);
00269   }
00270 
00271   PRUint32 deferred = 0;
00272 
00273   // It is possible that QI's to an interface that isn't nsISupports (like
00274   // nsIModelElementPrivate) could produce different values even from the same
00275   // model element.  So we'll convert the model to nsISupports before querying
00276   // it or storing it via hashtable.
00277   nsCOMPtr<nsISupports> temp(do_QueryInterface(aModel));
00278   mDeferredUpdates.Get(temp, &deferred);
00279   if (aEnable) {
00280     deferred |= DEFERRED_REFRESH;
00281   } else {
00282     deferred &= ~DEFERRED_REFRESH;
00283   }
00284   mDeferredUpdates.Put(temp, deferred);
00285   return NS_OK;
00286 }
00287 
00288 NS_IMETHODIMP
00289 nsXFormsActionElement::GetCurrentEvent(nsIDOMEvent** aEvent)
00290 {
00291   NS_IF_ADDREF(*aEvent = mCurrentEvent);
00292   return NS_OK;
00293 }
00294 
00295 NS_HIDDEN_(nsresult)
00296 NS_NewXFormsActionElement(nsIXTFElement **aResult)
00297 {
00298   *aResult = new nsXFormsActionElement();
00299   if (!*aResult) {
00300     return NS_ERROR_OUT_OF_MEMORY;
00301   }
00302 
00303   NS_ADDREF(*aResult);
00304   return NS_OK;
00305 }
00306