Bug 1460392 - Port bug 1457027 to TB: Part 7 - Move action icon getters to HandlerInfoWrapper. r=aceman
authorRichard Marti <richard.marti@gmail.com>
Fri, 28 Sep 2018 08:52:49 +0200
changeset 33266 eca38904a853f703807ce93917e6704492f476e8
parent 33265 cc895db45e990bb2d1dada0f87b708a4310045aa
child 33267 2131ecd0173c88f2a080af5c8ce46ecbb36dd272
push id387
push userclokep@gmail.com
push dateMon, 10 Dec 2018 21:30:47 +0000
reviewersaceman
bugs1460392, 1457027
Bug 1460392 - Port bug 1457027 to TB: Part 7 - Move action icon getters to HandlerInfoWrapper. r=aceman
mail/components/preferences/applications.js
--- a/mail/components/preferences/applications.js
+++ b/mail/components/preferences/applications.js
@@ -200,16 +200,76 @@ class HandlerInfoWrapper {
         return gApplicationsPane._prefsBundle.getFormattedString("usePluginIn",
           [this.pluginName,
           gApplicationsPane._brandShortName]);
       default:
         throw new Error(`Unexpected preferredAction: ${this.preferredAction}`);
     }
   }
 
+  get actionIconClass() {
+    if (this.alwaysAskBeforeHandling) {
+      return "ask";
+    }
+
+    switch (this.preferredAction) {
+      case Ci.nsIHandlerInfo.saveToDisk:
+        return "save";
+
+      case Ci.nsIHandlerInfo.handleInternally:
+        if (this instanceof InternalHandlerInfoWrapper) {
+          return "ask";
+        }
+
+      case kActionUsePlugin:
+        return "plugin";
+    }
+
+    return "";
+  }
+
+  get actionIcon() {
+    switch (this.preferredAction) {
+      case Ci.nsIHandlerInfo.useSystemDefault:
+        return this.iconURLForSystemDefault;
+
+      case Ci.nsIHandlerInfo.useHelperApp:
+        let preferredApp = this.preferredApplicationHandler;
+        if (gApplicationsPane.isValidHandlerApp(preferredApp)) {
+          return gApplicationsPane._getIconURLForHandlerApp(preferredApp);
+        }
+      // Explicit fall-through
+
+      // This should never happen, but if preferredAction is set to some weird
+      // value, then fall back to the generic application icon.
+      default:
+        return ICON_URL_APP;
+    }
+  }
+
+  get iconURLForSystemDefault() {
+    // Handler info objects for MIME types on some OSes implement a property bag
+    // interface from which we can get an icon for the default app, so if we're
+    // dealing with a MIME type on one of those OSes, then try to get the icon.
+    if (this.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo &&
+        this.wrappedHandlerInfo instanceof Ci.nsIPropertyBag) {
+      try {
+        let url = this.wrappedHandlerInfo.getProperty("defaultApplicationIconURL");
+        if (url) {
+          return url + "?size=16";
+        }
+      } catch (ex) { }
+    }
+
+    // If this isn't a MIME type object on an OS that supports retrieving
+    // the icon, or if we couldn't retrieve the icon for some other reason,
+    // then use a generic icon.
+    return ICON_URL_APP;
+  }
+
   get preferredApplicationHandler() {
     return this.wrappedHandlerInfo.preferredApplicationHandler;
   }
 
   set preferredApplicationHandler(aNewValue) {
     this.wrappedHandlerInfo.preferredApplicationHandler = aNewValue;
 
     // Make sure the preferred handler is in the set of possible handlers.
@@ -1100,18 +1160,17 @@ var gApplicationsPane = {
       item.setAttribute("typeDescription", visibleType.typeDescription);
       item.setAttribute("shortTypeDescription", visibleType.description);
       item.setAttribute("shortTypeDetails", this._typeDetails(visibleType));
       if (visibleType.smallIcon)
         item.setAttribute("typeIcon", visibleType.smallIcon);
       item.setAttribute("actionDescription", visibleType.actionDescription);
 
       if (!this._setIconClassForPreferredAction(visibleType, item)) {
-        item.setAttribute("actionIcon",
-                          this._getIconURLForPreferredAction(visibleType));
+        item.setAttribute("actionIcon", visibleType.actionIcon);
       }
 
       this._list.appendChild(item);
 
       if (visibleType.type === lastSelectedType) {
         this._list.selectedItem = item;
       }
     }
@@ -1243,17 +1302,17 @@ var gApplicationsPane = {
     // Create a menu item for the OS default application, if any.
     if (handlerInfo.hasDefaultHandler) {
       var defaultMenuItem = document.createElement("menuitem");
       defaultMenuItem.setAttribute("action", Ci.nsIHandlerInfo.useSystemDefault);
       let label = this._prefsBundle.getFormattedString("useDefault",
                                                        [handlerInfo.defaultDescription]);
       defaultMenuItem.setAttribute("label", label);
       defaultMenuItem.setAttribute("tooltiptext", handlerInfo.defaultDescription);
-      defaultMenuItem.setAttribute("image", this._getIconURLForSystemDefault(handlerInfo));
+      defaultMenuItem.setAttribute("image", handlerInfo.iconURLForSystemDefault);
 
       menuPopup.appendChild(defaultMenuItem);
     }
 
     // Create menu items for possible handlers.
     let preferredApp = handlerInfo.preferredApplicationHandler;
     let possibleApps = handlerInfo.possibleApplicationHandlers.enumerate();
     var possibleAppMenuItems = [];
@@ -1267,17 +1326,18 @@ var gApplicationsPane = {
       let label;
       if (possibleApp instanceof Ci.nsILocalHandlerApp)
         label = getDisplayNameForFile(possibleApp.executable);
       else
         label = possibleApp.name;
       label = this._prefsBundle.getFormattedString("useApp", [label]);
       menuItem.setAttribute("label", label);
       menuItem.setAttribute("tooltiptext", label);
-      menuItem.setAttribute("image", this._getIconURLForHandlerApp(possibleApp));
+      menuItem.setAttribute("image", gApplicationsPane
+                            ._getIconURLForHandlerApp(possibleApp));
 
       // Attach the handler app object to the menu item so we can use it
       // to make changes to the datastore when the user selects the item.
       menuItem.handlerApp = possibleApp;
 
       menuPopup.appendChild(menuItem);
       possibleAppMenuItems.push(menuItem);
     }
@@ -1484,18 +1544,17 @@ var gApplicationsPane = {
 
     // Make sure the handler info object is flagged to indicate that there is
     // now some user configuration for the type.
     handlerInfo.handledOnlyByPlugin = false;
 
     // Update the action label and image to reflect the new preferred action.
     typeItem.setAttribute("actionDescription", handlerInfo.actionDescription);
     if (!this._setIconClassForPreferredAction(handlerInfo, typeItem)) {
-      typeItem.setAttribute("actionIcon",
-                            this._getIconURLForPreferredAction(handlerInfo));
+      typeItem.setAttribute("actionIcon", handlerInfo.actionIcon);
     }
   },
 
   manageApp(aEvent) {
     // Don't let the normal "on select action" handler get this event,
     // as we handle it specially ourselves.
     aEvent.stopPropagation();
 
@@ -1505,18 +1564,17 @@ var gApplicationsPane = {
     let closingCallback = () => {
       // Rebuild the actions menu so that we revert to the previous selection,
       // or "Always ask" if the previous default application has been removed.
       this.rebuildActionsMenu();
 
       // Update the richlistitem too. Will be visible when selecting another row.
       typeItem.setAttribute("actionDescription", handlerInfo.actionDescription);
       if (!this._setIconClassForPreferredAction(handlerInfo, typeItem)) {
-        typeItem.setAttribute("actionIcon",
-                              this._getIconURLForPreferredAction(handlerInfo));
+        typeItem.setAttribute("actionIcon", handlerInfo.actionIcon);
       }
     };
 
     gSubDialog.open(
       "chrome://messenger/content/preferences/applicationManager.xul",
       "resizable=no", handlerInfo, closingCallback);
   },
 
@@ -1633,52 +1691,25 @@ var gApplicationsPane = {
   },
 
   _setIconClassForPreferredAction(aHandlerInfo, aElement) {
     // If this returns true, the attribute that CSS sniffs for was set to something
     // so you shouldn't manually set an icon URI.
     // This removes the existing actionIcon attribute if any, even if returning false.
     aElement.removeAttribute("actionIcon");
 
-    if (aHandlerInfo.alwaysAskBeforeHandling) {
-      aElement.setAttribute(APP_ICON_ATTR_NAME, "ask");
+    if (aHandlerInfo.actionIconClass) {
+      aElement.setAttribute(APP_ICON_ATTR_NAME, aHandlerInfo.actionIconClass);
       return true;
     }
 
-    switch (aHandlerInfo.preferredAction) {
-      case Ci.nsIHandlerInfo.saveToDisk:
-        aElement.setAttribute(APP_ICON_ATTR_NAME, "save");
-        return true;
-
-      case Ci.nsIHandlerInfo.handleInternally:
-        break;
-
-      case kActionUsePlugin:
-        aElement.setAttribute(APP_ICON_ATTR_NAME, "plugin");
-        return true;
-    }
     aElement.removeAttribute(APP_ICON_ATTR_NAME);
     return false;
   },
 
-  _getIconURLForPreferredAction(aHandlerInfo) {
-    switch (aHandlerInfo.preferredAction) {
-      case Ci.nsIHandlerInfo.useSystemDefault:
-        return this._getIconURLForSystemDefault(aHandlerInfo);
-
-      case Ci.nsIHandlerInfo.useHelperApp:
-        let preferredApp = aHandlerInfo.preferredApplicationHandler;
-        if (gApplicationsPane.isValidHandlerApp(preferredApp))
-          return this._getIconURLForHandlerApp(preferredApp);
-    }
-    // This should never happen, but if preferredAction is set to some weird
-    // value, then fall back to the generic application icon.
-    return ICON_URL_APP;
-  },
-
   _getIconURLForHandlerApp(aHandlerApp) {
     if (aHandlerApp instanceof Ci.nsILocalHandlerApp)
       return this._getIconURLForFile(aHandlerApp.executable);
 
     if (aHandlerApp instanceof Ci.nsIWebHandlerApp)
       return this._getIconURLForWebApp(aHandlerApp.uriTemplate);
 
     if (aHandlerApp instanceof Ci.nsIWebContentHandlerInfo)
@@ -1706,32 +1737,35 @@ var gApplicationsPane = {
     // they'll only visit URLs derived from that template (i.e. with %s
     // in the template replaced by the URL of the content being handled).
 
     if (/^https?/.test(uri.scheme))
       return uri.prePath + "/favicon.ico";
 
     return /^https?/.test(uri.scheme) ? uri.resolve("/favicon.ico") : "";
   },
+};
 
-  _getIconURLForSystemDefault(aHandlerInfo) {
-    // Handler info objects for MIME types on some OSes implement a property bag
-    // interface from which we can get an icon for the default app, so if we're
-    // dealing with a MIME type on one of those OSes, then try to get the icon.
-    if ("wrappedHandlerInfo" in aHandlerInfo) {
-      let wrappedHandlerInfo = aHandlerInfo.wrappedHandlerInfo;
+/**
+ * InternalHandlerInfoWrapper provides a basic mechanism to create an internal
+ * mime type handler that can be enabled/disabled in the applications preference
+ * menu.
+ */
+class InternalHandlerInfoWrapper extends HandlerInfoWrapper {
+  constructor(mimeType) {
+    super(mimeType, gMIMEService.getFromTypeAndExtension(mimeType, null));
+  }
 
-      if (wrappedHandlerInfo instanceof Ci.nsIMIMEInfo &&
-          wrappedHandlerInfo instanceof Ci.nsIPropertyBag) {
-        try {
-          let url = wrappedHandlerInfo.getProperty("defaultApplicationIconURL");
-          if (url)
-            return url + "?size=16";
-        } catch (ex) { }
-      }
-    }
+  // Override store so we so we can notify any code listening for registration
+  // or unregistration of this handler.
+  store() {
+    super.store();
+    Services.obs.notifyObservers(null, this._handlerChanged);
+  }
 
-    // If this isn't a MIME type object on an OS that supports retrieving
-    // the icon, or if we couldn't retrieve the icon for some other reason,
-    // then use a generic icon.
-    return ICON_URL_APP;
-  },
-};
+  get enabled() {
+    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+  }
+
+  get description() {
+    return gApplicationsPane._prefsBundle.getString(this._appPrefLabel);
+  }
+}