Bug 598144 - Make personas plus compatible with Firefox 4 client-1.6.2
authorJose E. Bolanos <jose@appcoast.com>
Mon, 14 Feb 2011 12:02:04 -0600
branchclient-1.6.2
changeset 1353 94b21d77ef12cfcc0c0dd8e8a4cd5a996bb8f447
parent 1351 4365e50f9444b01138e784c36d86f98ff6f6a86b
child 1354 607df82c4f922ec09bc442ce109fb4fc11f021b0
push id871
push userjose@glaxstar.com
push dateMon, 14 Feb 2011 18:05:25 +0000
bugs598144
Bug 598144 - Make personas plus compatible with Firefox 4
client/chrome.manifest.in
client/content/personas.css
client/content/personas.js
client/content/personas.xul
client/defaults/preferences/prefs.js.in
client/modules/service.js
--- a/client/chrome.manifest.in
+++ b/client/chrome.manifest.in
@@ -27,16 +27,18 @@ skin  personas  classic/1.0  @chrome_pat
 skin  personas  classic/1.0  @chrome_path@skin/winxp/thunderbird/ application={3550f703-e582-4d05-9a08-453d09bdfdc6}                      os=WINNT   osversion<6
 skin  personas  classic/1.0  @chrome_path@skin/vista/thunderbird/ application={3550f703-e582-4d05-9a08-453d09bdfdc6}                      os=WINNT   osversion>=6
 skin  personas  classic/1.0  @chrome_path@skin/mac/thunderbird/   application={3550f703-e582-4d05-9a08-453d09bdfdc6}                      os=Darwin
 
 # Choose default stylesheet for customPersonaEditor.xul according to application (Firefox, Thunderbird).
 style chrome://personas/content/customPersonaEditor.xul chrome://browser/skin/    application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
 style chrome://personas/content/customPersonaEditor.xul chrome://messenger/skin/  application={3550f703-e582-4d05-9a08-453d09bdfdc6}
 
+style chrome://global/content/customizeToolbar.xul  chrome://personas/content/personas.css  application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+
 # localizations in alphabetical order
 #
 # Note: localizations sometimes become out of date, and we haven't quite
 # figured out what to do in that situation.  The current strategy is to ship
 # all localizations in their pristine state with development builds,
 # even though they may be out of date (and thus break users who use them)
 # and ship all localizations with missing strings replaced by their English
 # equivalents for release builds, even though it means English strings will
--- a/client/content/personas.css
+++ b/client/content/personas.css
@@ -15,16 +15,17 @@
  *
  * The Initial Developer of the Original Code is Mozilla.
  * Portions created by the Initial Developer are Copyright (C) 2007
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Chris Beard <cbeard@mozilla.org>
  *   Myk Melez <myk@mozilla.org>
+ *   Jose E. Bolanos <jose@appcoast.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -37,38 +38,56 @@
 
 
 /* Note: OS-specific styles live in the stylesheets in the skin/ directory. */
 
 
 /******************************************************************************/
 /* Personas Menu/Toolbarbutton */
 
-#personas-selector-button {
+#personas-selector-button,
+#personas-toolbar-button {
   list-style-image: url("chrome://personas/content/personas_16x16.png");
   -moz-image-region: rect(0, 16px, 16px, 0px);
 }
 
+#personas-toolbar-button {
+  -moz-box-orient: horizontal;
+}
+
+#personas-toolbar-button > .toolbarbutton-icon {
+  margin: 0px !important;
+  width: auto !important;
+  height: auto !important;
+}
+
 #personas-selector-button[buttonover="true"],
-#personas-selector-button:hover {
+#personas-selector-button:hover,
+#personas-toolbar-button[buttonover="true"],
+#personas-toolbar-button:hover {
   -moz-image-region: rect(16px, 16px, 32px, 0px);
 }
 
 #personas-selector-button[buttondown="true"],
 #personas-selector-button[open="true"],
-#personas-selector-button:hover:active  {
+#personas-selector-button:hover:active,
+#personas-toolbar-button[buttondown="true"],
+#personas-toolbar-button[open="true"],
+#personas-toolbar-button:hover:active {
   -moz-image-region: rect(48px, 16px, 64px, 0px);
 }
 
-#personas-selector-menu menuitem[header] {
+#personas-selector-menu menuitem[header],
+#personas-toolbar-menu menuitem[header] {
   font-weight: bold;
   color: black;
 }
 
-#personas-selector-menu menuitem[recent="true"] {
+#personas-selector-menu menuitem[recent="true"],
+#personas-toolbar-menu menuitem[recent="true"] {
   list-style-image: url("chrome://personas/content/new.png");
 }
 
 #personas-current menu {
   font-weight: bold !important;
 }
 
 /**
--- a/client/content/personas.js
+++ b/client/content/personas.js
@@ -18,16 +18,17 @@
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Chris Beard <cbeard@mozilla.org>
  *   Myk Melez <myk@mozilla.org>
  *   Chris <kidkog@gmail.com>
  *   Byron Jones (glob) <bugzilla@glob.com.au>
  *   Anant Narayanan <anant@kix.in>
+ *   Jose E. Bolanos <jose@appcoast.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -101,16 +102,21 @@ let PersonaController = {
     return this._menuButton = document.getElementById("personas-selector-button");
   },
 
   get _menuPopup() {
     delete this._menuPopup;
     return this._menuPopup = document.getElementById("personas-selector-menu");
   },
 
+  get _toolbarButton() {
+    delete this._toolbarButton;
+    return this._toolbarButton = document.getElementById("personas-toolbar-button");
+  },
+
   get _sessionStore() {
     delete this._sessionStore;
     return this._sessionStore = Cc["@mozilla.org/browser/sessionstore;1"]
                                 .getService(Ci.nsISessionStore);
   },
 
   get _header() {
     delete this._header;
@@ -331,50 +337,86 @@ let PersonaController = {
       }
     }
     // Listen for various persona-related events that can bubble up from content,
     // not handled by the LightweightThemeManager.
     document.addEventListener("CheckPersonas", this, false, true);
     document.addEventListener("AddFavoritePersona", this, false, true);
     document.addEventListener("RemoveFavoritePersona", this, false, true);
 
-    // Check for a first-run or updated extension and display some additional
+
+    // Check for a first-run or updated version and display some additional
     // information to users.
     let lastVersion = this._prefs.get("lastversion");
-    let thisVersion = Cc["@mozilla.org/extensions/manager;1"].
-                      getService(Ci.nsIExtensionManager).
-                      getItemForID(PERSONAS_EXTENSION_ID).version;
-    if (lastVersion == "firstrun") {
-      // Show the first run page.
-      let firstRunURL = this._siteURL + "firstrun?version=" + thisVersion;
-      let t = this;
-      setTimeout(function() t.openURLInTab(firstRunURL), 500);
-      this._prefs.set("lastversion", thisVersion);
+    let thisVersion = null;
+    let t = this;
+
+    let displayVersionInfo = function() {
+      if (lastVersion == "firstrun") {
+        // Show the first run page.
+        let firstRunURL = t._siteURL + "firstrun?version=" + thisVersion;
+        setTimeout(function() t.openURLInTab(firstRunURL), 500);
+        t._prefs.set("lastversion", thisVersion);
+      }
+      else if (lastVersion != thisVersion) {
+        let updatedURL = t._siteURL + "updated?version=" + thisVersion;
+        setTimeout(function() t.openURLInTab(updatedURL), 500);
+        t._prefs.set("lastversion", thisVersion);
+      }
+    };
+
+    if ("@mozilla.org/extensions/manager;1" in Cc) {  // removed in FF 4.*
+      thisVersion = Cc["@mozilla.org/extensions/manager;1"].
+                        getService(Ci.nsIExtensionManager).
+                        getItemForID(PERSONAS_EXTENSION_ID).version
+      displayVersionInfo();
     }
-    else if (lastVersion != thisVersion) {
-      let updatedURL = this._siteURL + "updated?version=" + thisVersion;
-      let t = this;
-      setTimeout(function() t.openURLInTab(updatedURL), 500);
-      this._prefs.set("lastversion", thisVersion);
+    else {
+      try {
+        Cu.import("resource://gre/modules/AddonManager.jsm", this);
+        this.AddonManager.getAddonByID(PERSONAS_EXTENSION_ID,
+          function(aAddon) {
+            thisVersion = aAddon.version;
+            displayVersionInfo();
+          });
+      }
+      catch (e) {
+        // AddonManager module not available.
+      }
     }
 
     // Apply the current persona to the window if the LightweightThemeManager
     // is not available.
     // Also, we don't apply the default persona because Firefox starts with that.
     // Check for per-window personas and restore the persona from session store.
     if (!this.LightweightThemeManager) {
       if (this._prefs.get("perwindow") &&
           this._sessionStore.getWindowValue(window, "persona")) {
         this._applyPersona(this.JSON.parse(
           this._sessionStore.getWindowValue(window, "persona")
         ));
       } else if (PersonaService.selected != "default") {
         this._applyPersona(PersonaService.currentPersona);
       }
     }
+
+    // Perform special operations for Firefox 4 compatibility:
+    // * Hide the status bar button
+    // * Install the toolbar button in the Add-on bar (first time only).
+    if (PersonaService.appInfo.ID == PersonaService.FIREFOX_ID) {
+      let addonBar = window.document.getElementById("addon-bar");
+      if (addonBar) {
+        this._menuButton.setAttribute("hidden", true);
+
+        if (!this._prefs.get("toolbarButtonInstalled")) {
+          this._installToolbarButton(addonBar);
+          this._prefs.set("toolbarButtonInstalled", true);
+        }
+      }
+    }
   },
 
   shutDown: function() {
     if (!this.LightweightThemeManager) {
       this.Observers.remove("personas:persona:changed", this);
       this.Observers.remove("domwindowopened", this);
       document.removeEventListener("SelectPersona", this, false);
       document.removeEventListener("PreviewPersona", this, false);
@@ -389,16 +431,42 @@ let PersonaController = {
           break;
       }
     }
     document.removeEventListener("CheckPersonas", this, false);
     document.removeEventListener("AddFavoritePersona", this, false);
     document.removeEventListener("RemoveFavoritePersona", this, false);
   },
 
+  _installToolbarButton : function(aToolbar) {
+    const PERSONAS_BUTTON_ID = "personas-toolbar-button";
+
+    let curSet = aToolbar.currentSet;
+
+    // Add the button if it's not in the toolbar's current set
+    if (-1 == curSet.indexOf(PERSONAS_BUTTON_ID)) {
+
+      // Insert the button at the end.
+      let newSet = curSet + "," + PERSONAS_BUTTON_ID;
+
+      aToolbar.currentSet = newSet;
+      aToolbar.setAttribute("currentset", newSet);
+      document.persist(aToolbar.id, "currentset");
+
+      try {
+        BrowserToolboxCustomizeDone(true);
+      }
+      catch(e){}
+
+      // Make sure the toolbar is visible
+      if (aToolbar.getAttribute("collapsed") == "true")
+        aToolbar.setAttribute("collapsed", "false");
+      document.persist(aToolbar.id, "collapsed");
+    }
+  },
 
   //**************************************************************************//
   // Appearance Updates
 
   _applyPersona: function(persona) {
 
     // Style header and footer
     this._header.setAttribute("persona", persona.id);
@@ -909,31 +977,43 @@ let PersonaController = {
     // onto the button so the popup appears when the user clicks it.
     // We'll move the popup back onto the Personas menu in the Tools menu
     // when the popup hides.
     // FIXME: remove this workaround once bug 461899 is fixed.
     if (this._menuPopup.parentNode != this._menuButton)
       this._menuButton.appendChild(this._menuPopup);
   },
 
+  onToolbarButtonMouseDown: function(event) {
+    // If the menu popup isn't on the toolbar button, then move the popup
+    // onto the button so the popup appears when the user clicks it.
+    // We'll move the popup back onto the Personas menu in the Tools menu
+    // when the popup hides.
+    // FIXME: remove this workaround once bug 461899 is fixed.
+    if (this._menuPopup.parentNode != this._toolbarButton)
+      this._toolbarButton.appendChild(this._menuPopup);
+  },
+
   onPopupShowing: function(event) {
     if (event.target == this._menuPopup)
       this._rebuildMenu();
 
     return true;
   },
 
   onPopupHiding: function(event) {
     if (event.target == this._menuPopup) {
       // If the menu popup isn't on the Personas menu in the Tools menu,
       // then move the popup back onto that menu so the popup appears when
       // the user selects it.  We'll move the popup back onto the menu button
       // in onMenuButtonMouseDown when the user clicks on the menu button.
-      if (this._menuPopup.parentNode != this._menu)
+      if (this._menuPopup.parentNode != this._menu) {
+        this._menuPopup.parentNode.removeAttribute("open");
         this._menu.appendChild(this._menuPopup);
+      }
     }
   },
 
   _rebuildMenu: function() {
     // If we don't have personas data, we won't be able to fully build the menu,
     // and we'll display a message to that effect in tooltips over the parts
     // of the menu that are data-dependent (the Most Popular, New, and
     // By Category submenus).  The message also suggests that the user try again
--- a/client/content/personas.xul
+++ b/client/content/personas.xul
@@ -17,16 +17,17 @@
    -
    - The Initial Developer of the Original Code is Mozilla.
    - Portions created by the Initial Developer are Copyright (C) 2007
    - the Initial Developer. All Rights Reserved.
    -
    - Contributor(s):
    -   Chris Beard <cbeard@mozilla.org>
    -   Myk Melez <myk@mozilla.org>
+   -   Jose E. Bolanos <jose@appcoast.com>
    -
    - Alternatively, the contents of this file may be used under the terms of
    - either the GNU General Public License Version 2 or later (the "GPL"), or
    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    - in which case the provisions of the GPL or the LGPL are applicable instead
    - of those above. If you wish to allow use of your version of this file only
    - under the terms of either the GPL or the LGPL, and not to allow others to
    - use your version of this file under the terms of the MPL, indicate your
@@ -47,17 +48,17 @@
 
   <script type="application/javascript" src="chrome://personas/content/personas.js"/>
 
   <popupset id="mainPopupSet">
     <tooltip id="personasDataUnavailableTooltip"/>
   </popupset>
 
   <menupopup id="menu_ToolsPopup">
-    <menu id="personas-menu" class="menu-iconic" label="&personas_app_title;" 
+    <menu id="personas-menu" class="menu-iconic" label="&personas_app_title;"
                 insertafter="menu_openAddons">
        <menupopup id="personas-selector-menu"
                   onpopupshowing="return PersonaController.onPopupShowing(event)"
                   onpopuphiding="PersonaController.onPopupHiding(event)">
         <menu id="persona-current" class="menu-iconic">
           <menupopup id="persona-current-context-menu">
             <menuitem id="persona-current-view-detail"/>
             <menuitem id="persona-current-view-designer"/>
@@ -87,9 +88,15 @@
 
   <statusbar id="status-bar">
     <statusbarpanel id="personas-selector-button" class="statusbarpanel-menu-iconic"
                     insertbefore="statusbar-display"
                     onmousedown="PersonaController.onMenuButtonMouseDown()">
     </statusbarpanel>
   </statusbar>
 
+  <toolbarpalette id="BrowserToolbarPalette">
+    <toolbarbutton id="personas-toolbar-button" type="menu"
+      label="&personas_app_title;"
+      onmousedown="PersonaController.onToolbarButtonMouseDown();"/>
+  </toolbarpalette>
+
 </overlay>
--- a/client/defaults/preferences/prefs.js.in
+++ b/client/defaults/preferences/prefs.js.in
@@ -109,8 +109,11 @@ pref("extensions.personas.revisionID", "
 // old fast since they come out so often).
 pref("extensions.personas.channel", "@channel@");
 
 // Preference to switch per-window personas mode on
 pref("extensions.personas.perwindow", false);
 
 pref("PersonaService.logging.console", "@console_log_level@");
 pref("PersonaService.logging.dump", "@dump_log_level@");
+
+// Whether or not the toolbar button has been installed once (Firefox 4 support)
+pref("extensions.personas.toolbarButtonInstalled", false);
--- a/client/modules/service.js
+++ b/client/modules/service.js
@@ -87,19 +87,25 @@ let PersonaService = {
                            getService(Ci.nsIXULAppInfo).
                            QueryInterface(Ci.nsIXULRuntime);
   },
 
   get extension() {
     delete this.extension;
 
     if (this.appInfo.ID == this.FIREFOX_ID) {
-      return this.extension = Cc["@mozilla.org/fuel/application;1"].
-                              getService(Ci.fuelIApplication).
-                              extensions.get(PERSONAS_EXTENSION_ID);
+      let fuelApplication =
+        Cc["@mozilla.org/fuel/application;1"].getService(Ci.fuelIApplication);
+      // Fuel Application extensions is no longer available (synchronously) in
+      // Firefox 4. However, it is only used to detect the extension's first run
+      // and load the initial_persona cookie in old versions of Firefox which have no
+      // integrated support for Personas; it does not need to be adjusted since there
+      // will never exist a initial_persona cookie for Firefox 4.
+      if (fuelApplication.extensions)
+        return this.extension = fuelApplication.extensions.get(PERSONAS_EXTENSION_ID);
     }
 
     // If STEEL provides a FUEL-compatible extIExtension interface
     // in Thunderbird, return it here.
 
     return this.extension = null;
   },
 
@@ -583,17 +589,17 @@ let PersonaService = {
 
   /**
    * extensions.personas.selected: the type of persona that the user selected;
    * possible values are default (the default Firefox theme), random (a random
    * persona from a category), current (the value of this.currentPersona), and
    * randomFavorite (a random persona from the favorite list).
    */
   get selected()        { return this._prefs.get("selected") },
-  set selected(newVal)  {        this._prefs.set("selected", newVal) },
+  set selected(newVal)  {        this._prefs.set("selected", newVal); },
 
   /**
    * extensions.personas.current: the current persona
    */
   get currentPersona() {
     let current = this._prefs.get("current");
     if (current) {
       try       { return JSON.parse(current) }
@@ -1010,17 +1016,19 @@ let PersonaService = {
 
   /**
    * Updates the add-on to reflect the changes from the Tools - Add-ons - Themes
    * dialog. If a lightweight theme is set, it is also set as the add-on's current
    * persona. If a regular theme is set, the current persona is set to "default".
    */
   onLightweightThemeChanged: function() {
     let currentTheme = LightweightThemeManager.currentTheme;
-    if (currentTheme && currentTheme.id != this.currentPersona.id)
+
+    if (currentTheme &&
+        (currentTheme.id != this.currentPersona.id || this.selected == "default"))
       this.changeToPersona(currentTheme);
     else if (!currentTheme && this.selected != "default")
       this.changeToDefaultPersona();
   },
 
   //**************************************************************************//
   // Random Rotation