Back to index

lightning-sunbird  0.9+nobinonly
nsXBLWindowHandler.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 Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   - David W. Hyatt (hyatt@netscape.com)
00024  *   - Mike Pinkerton (pinkerton@netscape.com)
00025  *   - Akkana Peck (akkana@netscape.com)
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 
00042 #include "nsXBLWindowHandler.h"
00043 
00044 #include "nsCOMPtr.h"
00045 #include "nsPIWindowRoot.h"
00046 #include "nsIDOMWindowInternal.h"
00047 #include "nsIFocusController.h"
00048 #include "nsIScriptGlobalObject.h"
00049 #include "nsIDocShell.h"
00050 #include "nsIPresShell.h"
00051 #include "nsIDOMElement.h"
00052 #include "nsIDOMEventReceiver.h"
00053 #include "nsXBLPrototypeHandler.h"
00054 #include "nsXBLPrototypeBinding.h"
00055 #include "nsIPrivateDOMEvent.h"
00056 #include "nsIDOMEvent.h"
00057 #include "nsIContent.h"
00058 #include "nsHTMLAtoms.h"
00059 #include "nsXULAtoms.h"
00060 #include "nsINameSpaceManager.h"
00061 #include "nsIXBLDocumentInfo.h"
00062 #include "nsIDocument.h"
00063 #include "nsIXBLService.h"
00064 #include "nsIServiceManager.h"
00065 #include "nsIDOMDocument.h"
00066 #include "nsIDOMNSDocument.h"
00067 #include "nsISelectionController.h"
00068 #include "nsXULAtoms.h"
00069 #include "nsIURI.h"
00070 #include "nsNetUtil.h"
00071 #include "nsContentUtils.h"
00072 
00073 class nsXBLSpecialDocInfo
00074 {
00075 public:
00076   nsCOMPtr<nsIXBLDocumentInfo> mHTMLBindings;
00077   nsCOMPtr<nsIXBLDocumentInfo> mUserHTMLBindings;
00078 
00079   static const char sHTMLBindingStr[];
00080   static const char sUserHTMLBindingStr[];
00081 
00082   PRBool mInitialized;
00083 
00084 public:
00085   void LoadDocInfo();
00086   void GetAllHandlers(const char* aType,
00087                       nsXBLPrototypeHandler** handler,
00088                       nsXBLPrototypeHandler** userHandler);
00089   void GetHandlers(nsIXBLDocumentInfo* aInfo,
00090                    const nsACString& aRef,
00091                    nsXBLPrototypeHandler** aResult);
00092 
00093   nsXBLSpecialDocInfo() : mInitialized(PR_FALSE) {};
00094 };
00095 
00096 const char nsXBLSpecialDocInfo::sHTMLBindingStr[] = "chrome://global/content/platformHTMLBindings.xml";
00097 
00098 void nsXBLSpecialDocInfo::LoadDocInfo()
00099 {
00100   if (mInitialized)
00101     return;
00102   mInitialized = PR_TRUE;
00103 
00104   nsresult rv;
00105   nsCOMPtr<nsIXBLService> xblService = 
00106            do_GetService("@mozilla.org/xbl;1", &rv);
00107   if (NS_FAILED(rv) || !xblService)
00108     return;
00109 
00110   // Obtain the platform doc info
00111   nsCOMPtr<nsIURI> bindingURI;
00112   NS_NewURI(getter_AddRefs(bindingURI), sHTMLBindingStr);
00113   if (!bindingURI) {
00114     return;
00115   }
00116   xblService->LoadBindingDocumentInfo(nsnull, nsnull,
00117                                       bindingURI,
00118                                       PR_TRUE, 
00119                                       getter_AddRefs(mHTMLBindings));
00120 
00121   const nsAdoptingCString& userHTMLBindingStr =
00122     nsContentUtils::GetCharPref("dom.userHTMLBindings.uri");
00123   if (!userHTMLBindingStr.IsEmpty()) {
00124     NS_NewURI(getter_AddRefs(bindingURI), userHTMLBindingStr);
00125     if (!bindingURI) {
00126       return;
00127     }
00128 
00129     xblService->LoadBindingDocumentInfo(nsnull, nsnull,
00130                                         bindingURI,
00131                                         PR_TRUE, 
00132                                         getter_AddRefs(mUserHTMLBindings));
00133   }
00134 }
00135 
00136 //
00137 // GetHandlers
00138 //
00139 // 
00140 void
00141 nsXBLSpecialDocInfo::GetHandlers(nsIXBLDocumentInfo* aInfo,
00142                                  const nsACString& aRef,
00143                                  nsXBLPrototypeHandler** aResult)
00144 {
00145   nsXBLPrototypeBinding* binding;
00146   aInfo->GetPrototypeBinding(aRef, &binding);
00147   
00148   NS_ASSERTION(binding, "No binding found for the XBL window key handler.");
00149   if (!binding)
00150     return;
00151 
00152   *aResult = binding->GetPrototypeHandlers();
00153 } // GetHandlers
00154 
00155 void
00156 nsXBLSpecialDocInfo::GetAllHandlers(const char* aType,
00157                                     nsXBLPrototypeHandler** aHandler,
00158                                     nsXBLPrototypeHandler** aUserHandler)
00159 {
00160   if (mUserHTMLBindings) {
00161     nsCAutoString type(aType);
00162     type.Append("User");
00163     GetHandlers(mUserHTMLBindings, type, aUserHandler);
00164   }
00165   if (mHTMLBindings) {
00166     GetHandlers(mHTMLBindings, nsDependentCString(aType), aHandler);
00167   }
00168 }
00169 
00170 // Init statics
00171 nsXBLSpecialDocInfo* nsXBLWindowHandler::sXBLSpecialDocInfo = nsnull;
00172 PRUint32 nsXBLWindowHandler::sRefCnt = 0;
00173 
00174 
00175 //
00176 // nsXBLWindowHandler ctor
00177 //
00178 // Increment the refcount
00179 //
00180 nsXBLWindowHandler::nsXBLWindowHandler(nsIDOMElement* aElement,
00181                                        nsIDOMEventReceiver* aReceiver)
00182   : mReceiver(aReceiver),
00183     mHandler(nsnull),
00184     mUserHandler(nsnull)
00185 {
00186   if (aElement) {
00187     nsCOMPtr<nsIDOMDocument> domDoc;
00188     aElement->GetOwnerDocument(getter_AddRefs(domDoc));
00189     nsCOMPtr<nsIDOMNSDocument> nsDomDoc = do_QueryInterface(domDoc);
00190     if (nsDomDoc) {
00191       nsDomDoc->GetBoxObjectFor(aElement, getter_AddRefs(mBoxObjectForElement));
00192     }
00193   }
00194   ++sRefCnt;
00195 }
00196 
00197 
00198 //
00199 // nsXBLWindowHandler dtor
00200 //
00201 // Decrement the refcount. If we get to zero, get rid of the static XBL doc
00202 // info.
00203 //
00204 nsXBLWindowHandler::~nsXBLWindowHandler()
00205 {
00206   --sRefCnt;
00207   if ( !sRefCnt ) {
00208     delete sXBLSpecialDocInfo;
00209     sXBLSpecialDocInfo = nsnull;
00210   }
00211 }
00212 
00213 
00214 already_AddRefed<nsIDOMElement>
00215 nsXBLWindowHandler::GetElement()
00216 {
00217   if (!mBoxObjectForElement) {
00218     return nsnull;
00219   }
00220   nsCOMPtr<nsIDOMElement> element;
00221   mBoxObjectForElement->GetElement(getter_AddRefs(element));
00222   nsIDOMElement* el = nsnull;
00223   element.swap(el);
00224   return el;
00225 }
00226 
00227 //
00228 // IsEditor
00229 //
00230 // Determine if the document we're working with is Editor or Browser
00231 //
00232 PRBool
00233 nsXBLWindowHandler :: IsEditor()
00234 {
00235   nsCOMPtr<nsPIWindowRoot> windowRoot(do_QueryInterface(mReceiver));
00236   NS_ENSURE_TRUE(windowRoot, PR_FALSE);
00237   nsCOMPtr<nsIFocusController> focusController;
00238   windowRoot->GetFocusController(getter_AddRefs(focusController));
00239   if (!focusController) {
00240     NS_WARNING("********* Something went wrong! No focus controller on the root!!!\n");
00241     return PR_FALSE;
00242   }
00243 
00244   nsCOMPtr<nsIDOMWindowInternal> focusedWindow;
00245   focusController->GetFocusedWindow(getter_AddRefs(focusedWindow));
00246   if (!focusedWindow)
00247     return PR_FALSE;
00248   
00249   nsCOMPtr<nsIScriptGlobalObject> obj(do_QueryInterface(focusedWindow));
00250   nsIDocShell *docShell = obj->GetDocShell();
00251   nsCOMPtr<nsIPresShell> presShell;
00252   if (docShell)
00253     docShell->GetPresShell(getter_AddRefs(presShell));
00254 
00255   if (presShell) {
00256     PRInt16 isEditor;
00257     presShell->GetSelectionFlags(&isEditor);
00258     return isEditor == nsISelectionDisplay::DISPLAY_ALL;
00259   }
00260 
00261   return PR_FALSE;
00262 } // IsEditor
00263 
00264 
00265 //
00266 // WalkHandlersInternal
00267 //
00268 // Given a particular DOM event and a pointer to the first handler in the list,
00269 // scan through the list to find something to handle the event and then make it
00270 // so.
00271 //
00272 nsresult
00273 nsXBLWindowHandler::WalkHandlersInternal(nsIDOMEvent* aEvent,
00274                                          nsIAtom* aEventType, 
00275                                          nsXBLPrototypeHandler* aHandler)
00276 {
00277   nsresult rv;
00278   nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aEvent));
00279   
00280   // Try all of the handlers until we find one that matches the event.
00281   for (nsXBLPrototypeHandler *currHandler = aHandler; currHandler;
00282        currHandler = currHandler->GetNextHandler()) {
00283     PRBool stopped;
00284     privateEvent->IsDispatchStopped(&stopped);
00285     if (stopped) {
00286       // The event is finished, don't execute any more handlers
00287       return NS_OK;
00288     }
00289 
00290     if (!EventMatched(currHandler, aEventType, aEvent))
00291       continue;  // try the next one
00292 
00293     // Before executing this handler, check that it's not disabled,
00294     // and that it has something to do (oncommand of the <key> or its
00295     // <command> is non-empty).
00296     nsCOMPtr<nsIContent> elt = currHandler->GetHandlerElement();
00297     nsCOMPtr<nsIDOMElement> commandElt;
00298 
00299     // See if we're in a XUL doc.
00300     nsCOMPtr<nsIDOMElement> el = GetElement();
00301     if (el && elt) {
00302       // We are.  Obtain our command attribute.
00303       nsAutoString command;
00304       elt->GetAttr(kNameSpaceID_None, nsXULAtoms::command, command);
00305       if (!command.IsEmpty()) {
00306         // Locate the command element in question.  Note that we
00307         // know "elt" is in a doc if we're dealing with it here.
00308         NS_ASSERTION(elt->IsInDoc(), "elt must be in document");
00309         nsCOMPtr<nsIDOMDocument> domDoc(
00310            do_QueryInterface(elt->GetCurrentDoc()));
00311         if (domDoc)
00312           domDoc->GetElementById(command, getter_AddRefs(commandElt));
00313 
00314         if (!commandElt) {
00315           NS_ERROR("A XUL <key> is observing a command that doesn't exist. Unable to execute key binding!\n");
00316           continue;
00317         }
00318       }
00319     }
00320 
00321     if (!commandElt) {
00322       commandElt = do_QueryInterface(elt);
00323     }
00324 
00325     if (commandElt) {
00326       nsAutoString value;
00327       commandElt->GetAttribute(NS_LITERAL_STRING("disabled"), value);
00328       if (value.EqualsLiteral("true")) {
00329         continue;  // this handler is disabled, try the next one
00330       }
00331 
00332       // Check that there is an oncommand handler
00333       commandElt->GetAttribute(NS_LITERAL_STRING("oncommand"), value);
00334       if (value.IsEmpty()) {
00335         continue;  // nothing to do
00336       }
00337     }
00338 
00339     nsCOMPtr<nsIDOMEventReceiver> rec;
00340     nsCOMPtr<nsIDOMElement> element = GetElement();
00341     if (element) {
00342       rec = do_QueryInterface(commandElt);
00343     } else {
00344       rec = mReceiver;
00345     }
00346 
00347     rv = currHandler->ExecuteHandler(rec, aEvent);
00348     if (NS_SUCCEEDED(rv)) {
00349       return NS_OK;
00350     }
00351   }
00352 
00353   return NS_OK;
00354 } // WalkHandlersInternal
00355 
00356 
00357 
00358 //
00359 // EnsureHandlers
00360 //
00361 // Lazily load the platform and user bindings
00362 //
00363 nsresult
00364 nsXBLWindowHandler::EnsureHandlers(PRBool *aIsEditor)
00365 {
00366   if (!sXBLSpecialDocInfo)
00367     sXBLSpecialDocInfo = new nsXBLSpecialDocInfo();    
00368   if (!sXBLSpecialDocInfo) {
00369     if (aIsEditor) {
00370       *aIsEditor = PR_FALSE;
00371     }
00372     return NS_ERROR_OUT_OF_MEMORY;
00373   }
00374   sXBLSpecialDocInfo->LoadDocInfo();
00375 
00376   // Now determine which handlers we should be using.
00377   PRBool isEditor = IsEditor();
00378   if (isEditor) {
00379     sXBLSpecialDocInfo->GetAllHandlers("editor", &mHandler, &mUserHandler);
00380   }
00381   else {
00382     sXBLSpecialDocInfo->GetAllHandlers("browser", &mHandler, &mUserHandler);
00383   }
00384 
00385   if (aIsEditor)
00386     *aIsEditor = isEditor;
00387 
00388   return NS_OK;
00389   
00390 } // EnsureHandlers
00391