Back to index

lightning-sunbird  0.9+nobinonly
nsXFormsContextContainer.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  * Novell, Inc.
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Allan Beaufour <abeaufour@novell.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * 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 "nsXFormsContextContainer.h"
00040 #include "nsIDOMDocument.h"
00041 #include "nsIDOMElement.h"
00042 #include "nsIDOMNSEvent.h"
00043 #include "nsIDOMEventTarget.h"
00044 #include "nsIDOMSerializer.h"
00045 #include "nsIDOMXPathResult.h"
00046 
00047 #include "nsIModelElementPrivate.h"
00048 #include "nsIXFormsContextControl.h"
00049 #include "nsIXFormsRepeatElement.h"
00050 #include "nsXFormsUtils.h"
00051 
00052 #ifdef DEBUG
00053 //#define DEBUG_XF_CONTEXTCONTAINER
00054 #endif
00055 
00056 NS_IMPL_ISUPPORTS1(nsXFormsFocusListener, nsIDOMEventListener)
00057 
00058 NS_IMETHODIMP
00059 nsXFormsFocusListener::HandleEvent(nsIDOMEvent* aEvent)
00060 {
00061   return mContainer ? mContainer->HandleFocus(aEvent) : NS_OK;
00062 }
00063 
00064 NS_IMPL_ISUPPORTS_INHERITED1(nsXFormsContextContainer,
00065                              nsXFormsBindableControlStub,
00066                              nsIXFormsRepeatItemElement)
00067 
00068 nsresult
00069 nsXFormsContextContainer::HandleFocus(nsIDOMEvent *aEvent)
00070 {
00071   if (!aEvent || !mElement)
00072     return NS_OK;
00073 
00074   if (!nsXFormsUtils::EventHandlingAllowed(aEvent, mElement))
00075     return NS_OK;
00076 
00077   // Need to explicitly create the parent chain. This ensures that this code
00078   // works both in 1.8, which has the old event dispatching code, and also in
00079   // the later versions of Gecko with the new event dispatching.
00080   // See also Bug 331081.
00081   nsCOMPtr<nsIDOMNSEvent> event = do_QueryInterface(aEvent);
00082   NS_ENSURE_STATE(event);
00083   nsCOMPtr<nsIDOMEventTarget> target;
00084   event->GetOriginalTarget(getter_AddRefs(target));
00085   nsCOMPtr<nsIDOMNode> currentNode = do_QueryInterface(target);
00086 
00087   nsCOMArray<nsIDOMNode> containerStack(4);
00088   while (currentNode) {
00089     nsCOMPtr<nsIXFormsRepeatItemElement> repeatItem =
00090       do_QueryInterface(currentNode);
00091     if (repeatItem) {
00092       containerStack.AppendObject(currentNode);
00093     }
00094     nsCOMPtr<nsIDOMNode> parent;
00095     currentNode->GetParentNode(getter_AddRefs(parent));
00096     currentNode.swap(parent);
00097   }
00098 
00099   for (PRInt32 i = containerStack.Count() - 1; i >= 0; --i) {
00100     nsCOMPtr<nsIDOMNode> node = containerStack[i];
00101     if (node) {
00102       // Either we, or an element we contain, has gotten focus, so we need to
00103       // set the repeat index. This is done through the <repeat> the
00104       // nsXFormsContextContainer belongs to.
00105       //
00106       // Start by finding the <repeat> (our grandparent):
00107       // <repeat> <-- gParent
00108       //   <div>
00109       //     <contextcontainer> <-- this
00110       //   </div>
00111       // </repeat>
00112       nsCOMPtr<nsIDOMNode> parent;
00113       node->GetParentNode(getter_AddRefs(parent));
00114       if (parent) {
00115         nsCOMPtr<nsIDOMNode> grandParent;
00116         parent->GetParentNode(getter_AddRefs(grandParent));
00117         nsCOMPtr<nsIXFormsRepeatElement> repeat =
00118           do_QueryInterface(grandParent);
00119         nsCOMPtr<nsIXFormsRepeatItemElement> repeatItem =
00120           do_QueryInterface(node);
00121         if (repeat && repeatItem) {
00122           PRInt32 position = 1;
00123           repeatItem->GetContextPosition(&position);
00124           // Tell <repeat> about the new index position
00125           PRUint32 tmp = position;
00126           repeat->SetIndex(&tmp, PR_FALSE);
00127         }
00128       }
00129     }
00130   }
00131 
00132   return NS_OK;
00133 }
00134 
00135 NS_IMETHODIMP
00136 nsXFormsContextContainer::DocumentChanged(nsIDOMDocument *aNewDocument)
00137 {
00138   if (mFocusListener) {
00139     mFocusListener->Detach();
00140     nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mElement);
00141     if (target) {
00142       target->RemoveEventListener(NS_LITERAL_STRING("focus"), mFocusListener,
00143                                   PR_TRUE);
00144     }
00145     mFocusListener = nsnull;
00146   }
00147 
00148   if (aNewDocument) {
00149     nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mElement);
00150     if (target) {
00151       mFocusListener = new nsXFormsFocusListener(this);
00152       NS_ENSURE_TRUE(mFocusListener, NS_ERROR_OUT_OF_MEMORY);
00153       target->AddEventListener(NS_LITERAL_STRING("focus"), mFocusListener,
00154                                PR_TRUE);
00155     }
00156   }
00157   return NS_OK;
00158 }
00159 
00160 NS_IMETHODIMP
00161 nsXFormsContextContainer::CloneState(nsIDOMElement *aElement)
00162 {
00163   nsCOMPtr<nsIXFormsContextControl> other = do_QueryInterface(aElement);
00164   if (!other) {
00165     NS_WARNING("CloneState called with a different type source node");
00166     return NS_ERROR_FAILURE;
00167   }
00168 
00169   nsAutoString modelID;
00170   PRInt32 position, size;
00171   other->GetContext(modelID, getter_AddRefs(mBoundNode), &position, &size);
00172 
00173   return NS_OK;
00174 }
00175 
00176 // nsIXFormsContextControl
00177 
00178 NS_IMETHODIMP
00179 nsXFormsContextContainer::SetContext(nsIDOMNode *aContextNode,
00180                                      PRInt32     aContextPosition,
00181                                      PRInt32     aContextSize)
00182 {
00183   mContextIsDirty = (mContextIsDirty ||
00184                      mBoundNode != aContextNode ||
00185                      mContextPosition != aContextPosition ||
00186                      mContextSize != aContextSize);
00187 
00188   if (mContextIsDirty) {
00189     mBoundNode = aContextNode;
00190     mContextPosition = aContextPosition;
00191     mContextSize = aContextSize;
00192   }
00193 
00194   return BindToModel();
00195 }
00196 
00197 NS_IMETHODIMP
00198 nsXFormsContextContainer::GetContext(nsAString      &aModelID,
00199                                      nsIDOMNode    **aContextNode,
00200                                      PRInt32        *aContextPosition,
00201                                      PRInt32        *aContextSize)
00202 {
00203   nsresult rv = nsXFormsBindableControlStub::GetContext(aModelID,
00204                                                         aContextNode,
00205                                                         aContextPosition,
00206                                                         aContextSize);
00207   NS_ENSURE_SUCCESS(rv, rv);
00208 
00209   *aContextPosition = mContextPosition;
00210   *aContextSize = mContextSize;
00211 
00212   return NS_OK;
00213 }
00214 
00215 // nsIXFormsControl
00216 
00217 NS_IMETHODIMP
00218 nsXFormsContextContainer::Bind(PRBool *aContextChanged)
00219 {
00220   NS_ENSURE_ARG(aContextChanged);
00221   *aContextChanged = mContextIsDirty;
00222   mContextIsDirty = PR_FALSE;
00223   return NS_OK;
00224 }
00225 
00226 NS_IMETHODIMP
00227 nsXFormsContextContainer::IsEventTarget(PRBool* aOK)
00228 {
00229   *aOK = PR_FALSE;
00230   return NS_OK;
00231 }
00232 
00233 // nsIXFormsRepeatItemElement
00238 NS_IMETHODIMP
00239 nsXFormsContextContainer::SetIndexState(PRBool aHasIndex)
00240 {
00241   if (mElement) {
00242     mHasIndex = aHasIndex;
00243     NS_NAMED_LITERAL_STRING(classStr, "class");
00244     if (aHasIndex) {
00245       mElement->SetAttribute(classStr,
00246                              NS_LITERAL_STRING("xf-repeat-item xf-repeat-index"));
00247     } else {
00248       mElement->SetAttribute(classStr, NS_LITERAL_STRING("xf-repeat-item"));
00249     }
00250   }
00251   return NS_OK;
00252 }
00253 
00254 NS_IMETHODIMP
00255 nsXFormsContextContainer::GetIndexState(PRBool *aHasIndex)
00256 {
00257   NS_ENSURE_ARG(aHasIndex);
00258   *aHasIndex = mHasIndex;
00259   return NS_OK;
00260 }
00261 
00262 NS_IMETHODIMP
00263 nsXFormsContextContainer::GetContextPosition(PRInt32 *aContextPosition)
00264 {
00265   *aContextPosition = mContextPosition;
00266   return NS_OK;
00267 }
00268 
00269 void
00270 nsXFormsContextContainer::SetRepeatState(nsRepeatState aState)
00271 {
00272   // A context container can have one of two states...eType_Unknown
00273   // (uninitialized) and eType_GeneratedContent.  This assumes
00274   // that one cannot be generated outside of the repeat or itemset code.
00275 
00276   nsRepeatState state = aState;
00277   if (state != eType_Unknown) {
00278     state = eType_GeneratedContent;
00279   }
00280 
00281   nsXFormsBindableControlStub::SetRepeatState(state);
00282   return;
00283 }
00284 
00285 // Factory
00286 NS_HIDDEN_(nsresult)
00287 NS_NewXFormsContextContainer(nsIXTFElement **aResult)
00288 {
00289   *aResult = new nsXFormsContextContainer();
00290   if (!*aResult)
00291     return NS_ERROR_OUT_OF_MEMORY;
00292 
00293   NS_ADDREF(*aResult);
00294   return NS_OK;
00295 }