Back to index

lightning-sunbird  0.9+nobinonly
nsXFormsDelegateStub.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) 2005
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Allan Beaufour <abeaufour@novell.com>
00024  *  Olli Pettay <Olli.Pettay@helsinki.fi>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * 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 
00041 #include "nsIDOMDocument.h"
00042 #include "nsIDOM3Node.h"
00043 #include "nsIDOMEventTarget.h"
00044 #include "nsIDOMEvent.h"
00045 #include "nsIDOMUIEvent.h"
00046 #include "nsIDOMDocumentView.h"
00047 #include "nsIDOMAbstractView.h"
00048 #include "nsIDOMDocumentEvent.h"
00049 #include "nsDOMString.h"
00050 #include "nsIModelElementPrivate.h"
00051 #include "nsIXFormsUIWidget.h"
00052 #include "nsXFormsAtoms.h"
00053 #include "nsXFormsDelegateStub.h"
00054 #include "nsXFormsUtils.h"
00055 #include "nsIServiceManager.h"
00056 #include "nsXFormsModelElement.h"
00057 
00058 NS_IMPL_ISUPPORTS_INHERITED2(nsXFormsDelegateStub,
00059                              nsXFormsBindableControlStub,
00060                              nsIDelegateInternal,
00061                              nsIXFormsDelegate)
00062 
00063 
00064 NS_IMETHODIMP
00065 nsXFormsDelegateStub::OnCreated(nsIXTFBindableElementWrapper *aWrapper)
00066 {
00067   nsresult rv = nsXFormsBindableControlStub::OnCreated(aWrapper);
00068   NS_ENSURE_SUCCESS(rv, rv);
00069   aWrapper->SetNotificationMask(kStandardNotificationMask);
00070   return rv;
00071 }
00072 
00073 NS_IMETHODIMP
00074 nsXFormsDelegateStub::OnDestroyed()
00075 {
00076   nsXFormsModelElement::CancelPostRefresh(this);
00077   if (mAccessor) {
00078     mAccessor->Destroy();
00079   }
00080   return nsXFormsBindableControlStub::OnDestroyed();
00081 }
00082 
00083 // nsIXFormsControl
00084 
00085 NS_IMETHODIMP
00086 nsXFormsDelegateStub::Refresh()
00087 {
00088   if (GetRepeatState() == eType_Template)
00089     return NS_OK_XFORMS_NOREFRESH;
00090 
00091   const nsVoidArray* list = nsPostRefresh::PostRefreshList();
00092   if (list && list->IndexOf(this) >= 0) {
00093     // This control will be refreshed later.
00094     return NS_OK_XFORMS_NOREFRESH;
00095   }
00096 
00097   nsresult rv = nsXFormsBindableControlStub::Refresh();
00098   NS_ENSURE_SUCCESS(rv, rv);
00099 
00100   SetMozTypeAttribute();
00101 
00102   nsCOMPtr<nsIXFormsUIWidget> widget = do_QueryInterface(mElement);
00103 
00104   return widget ? widget->Refresh() : NS_OK;
00105 }
00106 
00107 NS_IMETHODIMP
00108 nsXFormsDelegateStub::TryFocus(PRBool* aOK)
00109 {
00110   *aOK = PR_FALSE;
00111   if (GetRelevantState()) {
00112     nsCOMPtr<nsIXFormsUIWidget> widget = do_QueryInterface(mElement);
00113     if (widget) {
00114       widget->Focus(aOK);
00115     }
00116   }
00117 
00118   return NS_OK;
00119 }
00120 
00121 // nsIXFormsDelegate
00122 
00123 NS_IMETHODIMP
00124 nsXFormsDelegateStub::GetValue(nsAString& aValue)
00125 {
00126   SetDOMStringToNull(aValue);
00127   if (mBoundNode) {
00128     nsXFormsUtils::GetNodeValue(mBoundNode, aValue);
00129   }
00130 
00131   return NS_OK;
00132 }
00133 
00134 NS_IMETHODIMP
00135 nsXFormsDelegateStub::SetValue(const nsAString& aValue)
00136 {
00137   if (!mBoundNode || !mModel)
00138     return NS_OK;
00139 
00140   PRBool changed;
00141   nsresult rv = mModel->SetNodeValue(mBoundNode, aValue, PR_TRUE, &changed);
00142   NS_ENSURE_SUCCESS(rv, rv);
00143 
00144   return NS_OK;
00145 }
00146 
00147 NS_IMETHODIMP
00148 nsXFormsDelegateStub::GetHasBoundNode(PRBool *aHasBoundNode)
00149 {
00150   NS_ENSURE_ARG_POINTER(aHasBoundNode);
00151   *aHasBoundNode = mBoundNode ? PR_TRUE : PR_FALSE;
00152   return NS_OK;
00153 }
00154 
00155 NS_IMETHODIMP
00156 nsXFormsDelegateStub::ReportError(const nsAString& aErrorMsg)
00157 {
00158   const nsPromiseFlatString& flat = PromiseFlatString(aErrorMsg);
00159   nsXFormsUtils::ReportError(flat, mElement);
00160   return NS_OK;
00161 }
00162 
00163 NS_IMETHODIMP
00164 nsXFormsDelegateStub::ReportErrorMessage(const nsAString& aErrorMsg)
00165 {
00166   const nsPromiseFlatString& flat = PromiseFlatString(aErrorMsg);
00167   nsXFormsUtils::ReportErrorMessage(flat, mElement);
00168   return NS_OK;
00169 }
00170 
00171 NS_IMETHODIMP
00172 nsXFormsDelegateStub::WidgetAttached()
00173 {
00174   if (GetRepeatState() == eType_Template)
00175     return NS_OK;
00176 
00177   if (HasBindingAttribute()) {
00178     // If control is bounded to instance data then we should ask for refresh
00179     // only when model is loaded entirely. The reason is control is refreshed
00180     // by model when it get loaded.
00181     if (!nsXFormsUtils::IsDocumentReadyForBind(mElement))
00182       return NS_OK;
00183   }
00184 
00185   nsXFormsModelElement::NeedsPostRefresh(this);
00186   return NS_OK;
00187 }
00188 
00189 // nsXFormsDelegateStub
00190 
00191 NS_IMETHODIMP
00192 nsXFormsDelegateStub::IsTypeAllowed(PRUint16 aType, PRBool *aIsAllowed,
00193                                     nsRestrictionFlag *aRestriction,
00194                                     nsAString &aTypes)
00195 {
00196   NS_ENSURE_ARG_POINTER(aRestriction);
00197   NS_ENSURE_ARG_POINTER(aIsAllowed);
00198   *aIsAllowed = PR_TRUE;
00199   *aRestriction = eTypes_NoRestriction;
00200   aTypes.Truncate();
00201   return NS_OK;
00202 }
00203 
00204 void
00205 nsXFormsDelegateStub::SetMozTypeAttribute()
00206 {
00207   NS_NAMED_LITERAL_STRING(mozTypeNs, NS_NAMESPACE_MOZ_XFORMS_TYPE);
00208   NS_NAMED_LITERAL_STRING(mozType, "type");
00209   NS_NAMED_LITERAL_STRING(mozTypeList, "typelist");
00210   NS_NAMED_LITERAL_STRING(mozRejectedType, "rejectedtype");
00211 
00212   // can't use mBoundNode here since mBoundNode can exist for xf:output, for
00213   // example, even if there is no binding attribute.
00214   nsCOMPtr<nsIDOMNode> boundNode;
00215   GetBoundNode(getter_AddRefs(boundNode));
00216   if (mModel && boundNode) {
00217     nsAutoString type, nsOrig;
00218     if (NS_FAILED(mModel->GetTypeAndNSFromNode(boundNode, type, nsOrig))) {
00219       mElement->RemoveAttributeNS(mozTypeNs, mozType);
00220       mElement->RemoveAttributeNS(mozTypeNs, mozTypeList);
00221       mElement->RemoveAttributeNS(mozTypeNs, mozRejectedType);
00222       return;
00223     }
00224 
00225     nsAutoString attrValue(nsOrig);
00226     attrValue.AppendLiteral("#");
00227     attrValue.Append(type);
00228     mElement->SetAttributeNS(mozTypeNs, mozType, attrValue);
00229 
00230     // Get the list of types that this type derives from and set it as the
00231     // value of the basetype attribute
00232     nsresult rv = mModel->GetDerivedTypeList(type, nsOrig, attrValue);
00233     if (NS_SUCCEEDED(rv)) {
00234       mElement->SetAttributeNS(mozTypeNs, mozTypeList, attrValue);
00235     } else {
00236       // Note: even if we can't build the derived type list, we should leave on
00237       // mozType attribute.  We can still use the attr for validation, etc.  But
00238       // the type-restricted controls like range and upload won't display since
00239       // they are bound to their anonymous content by @typeList.  Make sure that
00240       // we don't leave around mozTypeList if it isn't accurate.
00241       mElement->RemoveAttributeNS(mozTypeNs, mozTypeList);
00242     }
00243 
00244     // Get the builtin type that the bound type is derived from.  Then determine
00245     // if this control is allowed to bind to this type.  Some controls like
00246     // input, secret, textarea, upload and range can only bind to some types
00247     // and not to others.
00248     PRUint16 builtinType = 0;
00249     rv = GetBoundBuiltinType(&builtinType);
00250     if (NS_SUCCEEDED(rv)) {
00251       PRBool isAllowed = PR_TRUE;
00252       nsAutoString restrictedTypeList;
00253       nsRestrictionFlag restriction;
00254       IsTypeAllowed(builtinType, &isAllowed, &restriction, restrictedTypeList);
00255       if (!isAllowed) {
00256         // if this control isn't allowed to bind to this type, we'll set the
00257         // 'mozType:rejectedtype' attr to true so that our default CSS will
00258         // not display the control
00259         mElement->SetAttributeNS(mozTypeNs, mozRejectedType,
00260                                  NS_LITERAL_STRING("true"));
00261 
00262         // build the error string that we want output to the ErrorConsole
00263         nsAutoString localName;
00264         mElement->GetLocalName(localName);
00265         const PRUnichar *strings[] = { localName.get(), restrictedTypeList.get() };
00266 
00267         nsXFormsUtils::ReportError(
00268           restriction == eTypes_Inclusive ?
00269             NS_LITERAL_STRING("boundTypeErrorInclusive") :
00270             NS_LITERAL_STRING("boundTypeErrorExclusive"),
00271           strings, 2, mElement, mElement);
00272         return;
00273       }
00274     }
00275     // We reached here for one of two reasons:
00276     // 1) The control can handle this type
00277     // 2) We don't have enough information to make a judgement.
00278     //
00279     // Either way, we'll remove the attribute so that the control is useable
00280     mElement->RemoveAttributeNS(mozTypeNs, mozRejectedType);
00281 
00282     return;
00283   }
00284 
00285   mElement->RemoveAttributeNS(mozTypeNs, mozType);
00286   mElement->RemoveAttributeNS(mozTypeNs, mozTypeList);
00287   mElement->RemoveAttributeNS(mozTypeNs, mozRejectedType);
00288   return;
00289 }
00290 
00291 NS_IMETHODIMP
00292 nsXFormsDelegateStub::GetXFormsAccessors(nsIXFormsAccessors **aAccessor)
00293 {
00294   if (!mAccessor) {
00295     mAccessor = new nsXFormsAccessors(this, mElement);
00296     if (!mAccessor) {
00297       return NS_ERROR_OUT_OF_MEMORY;
00298     }
00299   }
00300   NS_ADDREF(*aAccessor = mAccessor);
00301   return NS_OK;
00302 }