Bug 473045 - Update to nsIHandlerApp for win7 jump lists (plus tests). r=bz
authorJim Mathies <jmathies@mozilla.com>
Thu, 24 Sep 2009 21:45:16 -0500
changeset 33033 8bf0e12c6652adfd20e5c075dde4c31a6a9f8c75
parent 33032 d39a7c261f9d294c8ef7aea765a3f3d7ad6cd4d3
child 33035 42ccb2cdeac0adb1eec0dd03b486f952e91f1c5a
push idunknown
push userunknown
push dateunknown
reviewersbz
bugs473045
milestone1.9.3a1pre
Bug 473045 - Update to nsIHandlerApp for win7 jump lists (plus tests). r=bz
netwerk/mime/public/nsIMIMEInfo.idl
uriloader/exthandler/nsDBusHandlerApp.cpp
uriloader/exthandler/nsDBusHandlerApp.h
uriloader/exthandler/nsLocalHandlerApp.cpp
uriloader/exthandler/nsLocalHandlerApp.h
uriloader/exthandler/nsWebHandlerApp.js
uriloader/exthandler/tests/unit/test_handlerService.js
--- a/netwerk/mime/public/nsIMIMEInfo.idl
+++ b/netwerk/mime/public/nsIMIMEInfo.idl
@@ -237,30 +237,37 @@ interface nsIMIMEInfo : nsIHandlerInfo {
 /**
  * nsIHandlerApp represents an external application that can handle content
  * of some sort (either a MIME type or a protocol).
  *
  * FIXME: now that we've made nsIWebHandlerApp inherit from nsIHandlerApp,
  * we should also try to make nsIWebContentHandlerInfo inherit from or possibly
  * be replaced by nsIWebHandlerApp (bug 394710).
  */
-[scriptable, uuid(8d298761-0963-4c90-99e2-6ea498825e82)]
+[scriptable, uuid(8BDF20A4-9170-4548-AF52-78311A44F920)]
 interface nsIHandlerApp : nsISupports {
 
     /**
      * Human readable name for the handler
      */
     attribute AString name;
 
     /**
+     * Detailed description for this handler. Suitable for
+     * a tooltip or short informative sentence.
+     */
+    attribute AString detailedDescription;
+
+    /**
      * Whether or not the given handler app is logically equivalent to the
      * invokant (i.e. they represent the same app).
      * 
      * Two apps are the same if they are both either local or web handlers
-     * and their executables/URI templates are the same in a string comparison.
+     * and their executables/URI templates and command line parameters are
+     * the same.
      *
      * @param aHandlerApp the handler app to compare to the invokant
      *
      * @returns true if the two are logically equivalent, false otherwise
      */
     boolean equals(in nsIHandlerApp aHandlerApp);
 
     /**
@@ -284,23 +291,62 @@ interface nsIHandlerApp : nsISupports {
     void launchWithURI(in nsIURI aURI, 
                        [optional] in nsIInterfaceRequestor aWindowContext);
 
 };
 
 /**
  * nsILocalHandlerApp is a local OS-level executable
  */
-[scriptable, uuid(9812be73-273c-478c-8170-c3e0db08ae7c)]
+[scriptable, uuid(D36B6329-52AE-4f45-80F4-B2536AE5F8B2)]
 interface nsILocalHandlerApp : nsIHandlerApp {
 
     /**
      * Pointer to the executable file used to handle content
      */
     attribute nsIFile executable;
+
+    /**
+     * Returns the current number of command line parameters.
+     */
+    readonly attribute unsigned long parameterCount;
+
+    /**
+     * Clears the current list of command line parameters.
+     */
+    void clearParameters();
+
+    /**
+     * Appends a command line parameter to the command line
+     * parameter list.
+     *
+     * @param param the parameter to add.
+     */
+    void appendParameter(in AString param);
+
+    /**
+     * Retrieves a specific command line parameter.
+     *
+     * @param param the index of the parameter to return.
+     *
+     * @return the parameter string.
+     *
+     * @throw NS_ERROR_INVALID_ARG if the index is out of range.
+     */
+    AString getParameter(in unsigned long parameterIndex);
+
+    /**
+     * Checks to see if a parameter exists in the command line
+     * parameter list.
+     *
+     * @param param the parameter to search for.
+     *
+     * @return TRUE if the parameter exists in the current list. 
+     */
+    boolean parameterExists(in AString param);
 };
 
 /**
  * nsIWebHandlerApp is a web-based handler, as speced by the WhatWG HTML5
  * draft.  Currently, only GET-based handlers are supported.  At some point, 
  * we probably want to work with WhatWG to spec out and implement POST-based
  * handlers as well.
  */
--- a/uriloader/exthandler/nsDBusHandlerApp.cpp
+++ b/uriloader/exthandler/nsDBusHandlerApp.cpp
@@ -68,16 +68,30 @@ NS_IMETHODIMP nsDBusHandlerApp::GetName(
 }
 
 NS_IMETHODIMP nsDBusHandlerApp::SetName(const nsAString & aName)
 {
   mName.Assign(aName);
   return NS_OK;
 }
 
+NS_IMETHODIMP nsDBusHandlerApp::SetDetailedDescription(const nsAString & aDescription)
+{
+  mDetailedDescription.Assign(aDescription);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsDBusHandlerApp::GetDetailedDescription(nsAString& aDescription)
+{
+  aDescription.Assign(mDetailedDescription);
+  
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 nsDBusHandlerApp::Equals(nsIHandlerApp *aHandlerApp, PRBool *_retval)
 {
   NS_ENSURE_ARG_POINTER(aHandlerApp);
   
   // If the handler app isn't a dbus handler app, then it's not the same app.
   nsCOMPtr<nsIDBusHandlerApp> dbusHandlerApp = do_QueryInterface(aHandlerApp);
   if (!dbusHandlerApp) {
--- a/uriloader/exthandler/nsDBusHandlerApp.h
+++ b/uriloader/exthandler/nsDBusHandlerApp.h
@@ -51,15 +51,16 @@ public:
   NS_DECL_NSIDBUSHANDLERAPP
 
   nsDBusHandlerApp() { }
 
   virtual ~nsDBusHandlerApp() { }
 
 protected:
   nsString mName;
+  nsString mDetailedDescription;
   nsCString mService;
   nsCString mMethod;
   nsCString mInterface;
   nsCString mObjpath;
 
 };
 #endif
--- a/uriloader/exthandler/nsLocalHandlerApp.cpp
+++ b/uriloader/exthandler/nsLocalHandlerApp.cpp
@@ -65,34 +65,72 @@ NS_IMETHODIMP nsLocalHandlerApp::GetName
 NS_IMETHODIMP nsLocalHandlerApp::SetName(const nsAString & aName)
 {
   mName.Assign(aName);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsLocalHandlerApp::SetDetailedDescription(const nsAString & aDescription)
+{
+  mDetailedDescription.Assign(aDescription);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsLocalHandlerApp::GetDetailedDescription(nsAString& aDescription)
+{
+  aDescription.Assign(mDetailedDescription);
+  
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsLocalHandlerApp::Equals(nsIHandlerApp *aHandlerApp, PRBool *_retval)
 {
   NS_ENSURE_ARG_POINTER(aHandlerApp);
 
+  *_retval = PR_FALSE;
+
   // If the handler app isn't a local handler app, then it's not the same app.
   nsCOMPtr <nsILocalHandlerApp> localHandlerApp = do_QueryInterface(aHandlerApp);
-  if (!localHandlerApp) {
-    *_retval = PR_FALSE;
+  if (!localHandlerApp)
     return NS_OK;
-  }
 
   // If either handler app doesn't have an executable, then they aren't
   // the same app.
   nsCOMPtr<nsIFile> executable;
   nsresult rv = localHandlerApp->GetExecutable(getter_AddRefs(executable));
-  if (NS_FAILED(rv) || !executable || !mExecutable) {
-    *_retval = PR_FALSE;
+  if (NS_FAILED(rv))
+    return rv;
+
+  // Equality for two empty nsIHandlerApp
+  if (!executable && !mExecutable) {
+    *_retval = PR_TRUE;
+    return NS_OK;
+  }
+
+  // At least one is set so they are not equal
+  if (!mExecutable || !executable)
     return NS_OK;
+
+  // Check the command line parameter list lengths
+  PRUint32 len;
+  localHandlerApp->GetParameterCount(&len);
+  if (mParameters.Length() != len)
+    return NS_OK;
+
+  // Check the command line params lists
+  for (PRUint32 idx = 0; idx < mParameters.Length(); idx++) {
+    nsAutoString param;
+    if (NS_FAILED(localHandlerApp->GetParameter(idx, param)) ||
+        !param.Equals(mParameters[idx]))
+      return NS_OK;
   }
 
   return executable->Equals(mExecutable, _retval);
 }
 
 NS_IMETHODIMP
 nsLocalHandlerApp::LaunchWithURI(nsIURI *aURI,
                                  nsIInterfaceRequestor *aWindowContext)
@@ -117,20 +155,65 @@ nsLocalHandlerApp::LaunchWithIProcess(co
   const char *string = aArg.get();
 
   return process->Run(PR_FALSE, &string, 1);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// nsILocalHandlerApp
 
-NS_IMETHODIMP nsLocalHandlerApp::GetExecutable(nsIFile **aExecutable)
+/* attribute nsIFile executable; */
+NS_IMETHODIMP
+nsLocalHandlerApp::GetExecutable(nsIFile **aExecutable)
 {
   NS_IF_ADDREF(*aExecutable = mExecutable);
   return NS_OK;
 }
 
-NS_IMETHODIMP nsLocalHandlerApp::SetExecutable(nsIFile *aExecutable)
+NS_IMETHODIMP
+nsLocalHandlerApp::SetExecutable(nsIFile *aExecutable)
 {
   mExecutable = aExecutable;
   return NS_OK;
 }
 
+/* readonly attribute unsigned long parameterCount; */
+NS_IMETHODIMP
+nsLocalHandlerApp::GetParameterCount(PRUint32 *aParameterCount)
+{
+  *aParameterCount = mParameters.Length();
+  return NS_OK;
+}
+
+/* void clearParameters (); */
+NS_IMETHODIMP
+nsLocalHandlerApp::ClearParameters()
+{
+  mParameters.Clear();
+  return NS_OK;
+}
+
+/* void appendParameter (in AString param); */
+NS_IMETHODIMP
+nsLocalHandlerApp::AppendParameter(const nsAString & aParam)
+{
+  mParameters.AppendElement(aParam);
+  return NS_OK;
+}
+
+/* AString getParameter (in unsigned long parameterIndex); */
+NS_IMETHODIMP
+nsLocalHandlerApp::GetParameter(PRUint32 parameterIndex, nsAString & _retval)
+{
+  if (mParameters.Length() <= parameterIndex)
+    return NS_ERROR_INVALID_ARG;
+
+  _retval.Assign(mParameters[parameterIndex]);
+  return NS_OK;
+}
+
+/* boolean parameterExists (in AString param); */
+NS_IMETHODIMP
+nsLocalHandlerApp::ParameterExists(const nsAString & aParam, PRBool *_retval)
+{
+  *_retval = mParameters.Contains(aParam);
+  return NS_OK;
+}
--- a/uriloader/exthandler/nsLocalHandlerApp.h
+++ b/uriloader/exthandler/nsLocalHandlerApp.h
@@ -38,16 +38,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef __nsLocalHandlerAppImpl_h__
 #define __nsLocalHandlerAppImpl_h__
 
 #include "nsString.h"
 #include "nsIMIMEInfo.h"
 #include "nsIFile.h"
+#include "nsTArray.h"
 
 class nsLocalHandlerApp : public nsILocalHandlerApp
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIHANDLERAPP
   NS_DECL_NSILOCALHANDLERAPP
 
@@ -57,28 +58,29 @@ public:
     : mName(aName), mExecutable(aExecutable) { }
 
   nsLocalHandlerApp(const nsAString & aName, nsIFile *aExecutable) 
     : mName(aName), mExecutable(aExecutable) { }
   virtual ~nsLocalHandlerApp() { }
 
 protected:
   nsString mName;
+  nsString mDetailedDescription;
+  nsTArray<nsString> mParameters;
   nsCOMPtr<nsIFile> mExecutable;
   
   /**
    * Launches this application with a single argument (typically either
    * a file path or a URI spec).  This is meant as a helper method for
    * implementations of (e.g.) LaunchWithURI.
    *
    * @param aApp The application to launch (may not be null)
    * @param aArg The argument to pass on the command line
    */
-   NS_HIDDEN_(nsresult) LaunchWithIProcess(const nsCString &aArg);
-
+  NS_HIDDEN_(nsresult) LaunchWithIProcess(const nsCString &aArg);
 };
 
 // any platforms that need a platform-specific class instead of just 
 // using nsLocalHandlerApp need to add an include and a typedef here.
 #ifdef XP_MACOSX
 # ifndef NSLOCALHANDLERAPPMAC_H_  
 # include "mac/nsLocalHandlerAppMac.h"
 typedef nsLocalHandlerAppMac PlatformLocalHandlerApp_t;
--- a/uriloader/exthandler/nsWebHandlerApp.js
+++ b/uriloader/exthandler/nsWebHandlerApp.js
@@ -55,29 +55,38 @@ nsWebHandlerApp.prototype = {
   //////////////////////////////////////////////////////////////////////////////
   //// nsWebHandler
 
   classDescription: "A web handler for protocols and content",
   classID: Components.ID("8b1ae382-51a9-4972-b930-56977a57919d"),
   contractID: "@mozilla.org/uriloader/web-handler-app;1",
 
   _name: null,
+  _detailedDescription: null,
   _uriTemplate: null,
 
   //////////////////////////////////////////////////////////////////////////////
   //// nsIHandlerApp
 
   get name() {
     return this._name;
   },
 
   set name(aName) {
     this._name = aName;
   },
 
+  get detailedDescription() {
+    return this._detailedDescription;
+  },
+
+  set detailedDescription(aDesc) {
+    this._detailedDescription = aDesc;
+  },
+
   equals: function(aHandlerApp) {
     if (!aHandlerApp)
       throw Cr.NS_ERROR_NULL_POINTER;
 
     if (aHandlerApp instanceof Ci.nsIWebHandlerApp &&
         aHandlerApp.uriTemplate &&
         this.uriTemplate &&
         aHandlerApp.uriTemplate == this.uriTemplate)
--- a/uriloader/exthandler/tests/unit/test_handlerService.js
+++ b/uriloader/exthandler/tests/unit/test_handlerService.js
@@ -337,16 +337,80 @@ function run_test() {
   do_check_eq(possibleHandlersInfo.possibleApplicationHandlers.length, 1);
 
   // Make sure the handler is the one we didn't remove.
   webPossibleHandler = possibleHandlersInfo.possibleApplicationHandlers.
                        queryElementAt(0, Ci.nsIWebHandlerApp);
   do_check_eq(webPossibleHandler.name, webHandler.name);
   do_check_true(webPossibleHandler.equals(webHandler));
 
+  //////////////////////////////////////////////////////
+  // handler info command line parameters and equality
+  var localApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
+                 createInstance(Ci.nsILocalHandlerApp);
+  var handlerApp = localApp.QueryInterface(Ci.nsIHandlerApp);
+
+  do_check_true(handlerApp.equals(localApp));
+
+  localApp.executable = executable;
+
+  do_check_eq(0, localApp.parameterCount);
+  localApp.appendParameter("-test1");
+  do_check_eq(1, localApp.parameterCount);
+  localApp.appendParameter("-test2");
+  do_check_eq(2, localApp.parameterCount);
+  do_check_true(localApp.parameterExists("-test1"));
+  do_check_true(localApp.parameterExists("-test2"));
+  do_check_false(localApp.parameterExists("-false"));
+  localApp.clearParameters();
+  do_check_eq(0, localApp.parameterCount);
+
+  var localApp2 = Cc["@mozilla.org/uriloader/local-handler-app;1"].
+                  createInstance(Ci.nsILocalHandlerApp);
+  
+  localApp2.executable = executable;
+
+  localApp.clearParameters();
+  do_check_true(localApp.equals(localApp2));
+
+  // equal:
+  // cut -d 1 -f 2
+  // cut -d 1 -f 2
+
+  localApp.appendParameter("-test1");
+  localApp.appendParameter("-test2");
+  localApp.appendParameter("-test3");
+  localApp2.appendParameter("-test1");
+  localApp2.appendParameter("-test2");
+  localApp2.appendParameter("-test3");
+  do_check_true(localApp.equals(localApp2));
+
+  // not equal:
+  // cut -d 1 -f 2
+  // cut -f 1 -d 2
+
+  localApp.clearParameters();
+  localApp2.clearParameters();
+
+  localApp.appendParameter("-test1");
+  localApp.appendParameter("-test2");
+  localApp.appendParameter("-test3");
+  localApp2.appendParameter("-test2");
+  localApp2.appendParameter("-test1");
+  localApp2.appendParameter("-test3");
+  do_check_false(localApp2.equals(localApp));
+
+  var str;
+  str = localApp.getParameter(0)
+  do_check_eq(str, "-test1");
+  str = localApp.getParameter(1)
+  do_check_eq(str, "-test2");
+  str = localApp.getParameter(2)
+  do_check_eq(str, "-test3");
+
   // FIXME: test round trip integrity for a protocol.
   // FIXME: test round trip integrity for a handler info with a web handler.
 
   //**************************************************************************//
   // getTypeFromExtension tests
 
   // test non-existent extension
   var lolType = handlerSvc.getTypeFromExtension("lolcat");