Bug 1082108 - Add a button to disable the devedition theme from Customize Mode. r=Gijs, a=sledru
authorBrian Grinstead <bgrinstead@mozilla.com>
Tue, 14 Oct 2014 13:29:30 -0500
changeset 234673 c35d9f79f1ff35799cb0ef6dabc82a4a3c3bd59e
parent 234672 5feb6e3234e5bc3ccea1a91840a18baef2ce81ac
child 234674 1f3d0612bdba38c0e7aa2b3c5cd4f234bafd7d9b
push id611
push userraliiev@mozilla.com
push dateMon, 05 Jan 2015 23:23:16 +0000
treeherdermozilla-release@345cd3b9c445 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs, sledru
bugs1082108
milestone35.0a2
Bug 1082108 - Add a button to disable the devedition theme from Customize Mode. r=Gijs, a=sledru
browser/app/profile/firefox.js
browser/components/customizableui/CustomizableUI.jsm
browser/components/customizableui/CustomizeMode.jsm
browser/components/customizableui/content/customizeMode.inc.xul
browser/components/customizableui/test/browser_970511_undo_restore_default.js
browser/themes/shared/customizableui/customizeMode.inc.css
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1287,16 +1287,17 @@ pref("services.sync.prefs.sync.security.
 pref("services.sync.prefs.sync.security.tls.version.max", true);
 pref("services.sync.prefs.sync.signon.rememberSignons", true);
 pref("services.sync.prefs.sync.spellchecker.dictionary", true);
 pref("services.sync.prefs.sync.xpinstall.whitelist.required", true);
 #endif
 
 // Developer edition preferences
 pref("browser.devedition.theme.enabled", false);
+pref("browser.devedition.theme.showCustomizeButton", false);
 
 // Disable the error console
 pref("devtools.errorconsole.enabled", false);
 
 // Developer toolbar and GCLI preferences
 pref("devtools.toolbar.enabled", true);
 pref("devtools.toolbar.visible", false);
 pref("devtools.commands.dir", "");
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -32,16 +32,17 @@ XPCOMUtils.defineLazyServiceGetter(this,
 const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 const kSpecialWidgetPfx = "customizableui-special-";
 
 const kPrefCustomizationState        = "browser.uiCustomization.state";
 const kPrefCustomizationAutoAdd      = "browser.uiCustomization.autoAdd";
 const kPrefCustomizationDebug        = "browser.uiCustomization.debug";
 const kPrefDrawInTitlebar            = "browser.tabs.drawInTitlebar";
+const kPrefDeveditionTheme           = "browser.devedition.theme.enabled";
 
 /**
  * The keys are the handlers that are fired when the event type (the value)
  * is fired on the subview. A widget that provides a subview has the option
  * of providing onViewShowing and onViewHiding event handlers.
  */
 const kSubviewEvents = [
   "ViewShowing",
@@ -134,16 +135,17 @@ let gBuildWindows = new Map();
 let gNewElementCount = 0;
 let gGroupWrapperCache = new Map();
 let gSingleWrapperCache = new WeakMap();
 let gListeners = new Set();
 
 let gUIStateBeforeReset = {
   uiCustomizationState: null,
   drawInTitlebar: null,
+  gUIStateBeforeReset: null,
 };
 
 let gModuleName = "[CustomizableUI]";
 #include logging.js
 
 let CustomizableUIInternal = {
   initialize: function() {
     LOG("Initializing");
@@ -2294,23 +2296,25 @@ let CustomizableUIInternal = {
     this._rebuildRegisteredAreas();
 
     gResetting = false;
   },
 
   _resetUIState: function() {
     try {
       gUIStateBeforeReset.drawInTitlebar = Services.prefs.getBoolPref(kPrefDrawInTitlebar);
+      gUIStateBeforeReset.deveditionTheme = Services.prefs.getBoolPref(kPrefDeveditionTheme);
       gUIStateBeforeReset.uiCustomizationState = Services.prefs.getCharPref(kPrefCustomizationState);
     } catch(e) { }
 
     this._resetExtraToolbars();
 
     Services.prefs.clearUserPref(kPrefCustomizationState);
     Services.prefs.clearUserPref(kPrefDrawInTitlebar);
+    Services.prefs.clearUserPref(kPrefDeveditionTheme);
     LOG("State reset");
 
     // Reset placements to make restoring default placements possible.
     gPlacements = new Map();
     gDirtyAreaCache = new Set();
     gSeenWidgets = new Set();
     // Clear the saved state to ensure that defaults will be used.
     gSavedState = null;
@@ -2362,30 +2366,33 @@ let CustomizableUIInternal = {
     }
   },
 
   /**
    * Undoes a previous reset, restoring the state of the UI to the state prior to the reset.
    */
   undoReset: function() {
     if (gUIStateBeforeReset.uiCustomizationState == null ||
-        gUIStateBeforeReset.drawInTitlebar == null) {
+        gUIStateBeforeReset.drawInTitlebar == null ||
+        gUIStateBeforeReset.deveditionTheme == null) {
       return;
     }
     gUndoResetting = true;
 
     let uiCustomizationState = gUIStateBeforeReset.uiCustomizationState;
     let drawInTitlebar = gUIStateBeforeReset.drawInTitlebar;
+    let deveditionTheme = gUIStateBeforeReset.deveditionTheme;
 
     // Need to clear the previous state before setting the prefs
     // because pref observers may check if there is a previous UI state.
     this._clearPreviousUIState();
 
     Services.prefs.setCharPref(kPrefCustomizationState, uiCustomizationState);
     Services.prefs.setBoolPref(kPrefDrawInTitlebar, drawInTitlebar);
+    Services.prefs.setBoolPref(kPrefDeveditionTheme, deveditionTheme);
     this.loadSavedState();
     // If the user just customizes toolbar/titlebar visibility, gSavedState will be null
     // and we don't need to do anything else here:
     if (gSavedState) {
       for (let areaId of Object.keys(gSavedState.placements)) {
         let placements = gSavedState.placements[areaId];
         gPlacements.set(areaId, placements);
       }
@@ -2553,16 +2560,20 @@ let CustomizableUIInternal = {
         }
       }
     }
 
     if (Services.prefs.prefHasUserValue(kPrefDrawInTitlebar)) {
       LOG(kPrefDrawInTitlebar + " pref is non-default");
       return false;
     }
+    if (Services.prefs.prefHasUserValue(kPrefDeveditionTheme)) {
+      LOG(kPrefDeveditionTheme + " pref is non-default");
+      return false;
+    }
 
     return true;
   },
 
   setToolbarVisibility: function(aToolbarId, aIsVisible) {
     // We only persist the attribute the first time.
     let isFirstChangedToolbar = true;
     for (let window of CustomizableUI.windows) {
@@ -3253,17 +3264,18 @@ this.CustomizableUI = {
   /**
    * Can the last Restore Defaults operation be undone.
    *
    * @return A boolean stating whether an undo of the
    *         Restore Defaults can be performed.
    */
   get canUndoReset() {
     return gUIStateBeforeReset.uiCustomizationState != null ||
-           gUIStateBeforeReset.drawInTitlebar != null;
+           gUIStateBeforeReset.drawInTitlebar != null ||
+           gUIStateBeforeReset.deveditionTheme != null;
   },
 
   /**
    * Get the placement of a widget. This is by far the best way to obtain
    * information about what the state of your widget is. The internals of
    * this call are cheap (no DOM necessary) and you will know where the user
    * has put your widget.
    *
--- a/browser/components/customizableui/CustomizeMode.jsm
+++ b/browser/components/customizableui/CustomizeMode.jsm
@@ -12,16 +12,18 @@ const kPrefCustomizationDebug = "browser
 const kPrefCustomizationAnimation = "browser.uiCustomization.disableAnimation";
 const kPaletteId = "customization-palette";
 const kAboutURI = "about:customizing";
 const kDragDataTypePrefix = "text/toolbarwrapper-id/";
 const kPlaceholderClass = "panel-customization-placeholder";
 const kSkipSourceNodePref = "browser.uiCustomization.skipSourceNodeCheck";
 const kToolbarVisibilityBtn = "customization-toolbar-visibility-button";
 const kDrawInTitlebarPref = "browser.tabs.drawInTitlebar";
+const kDeveditionThemePref = "browser.devedition.theme.enabled";
+const kDeveditionButtonPref = "browser.devedition.theme.showCustomizeButton";
 const kMaxTransitionDurationMs = 2000;
 
 const kPanelItemContextMenu = "customizationPanelItemContextMenu";
 const kPaletteItemContextMenu = "customizationPaletteItemContextMenu";
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/CustomizableUI.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@@ -64,18 +66,21 @@ function CustomizeMode(aWindow) {
   this.tipPanel = this.document.getElementById("customization-tipPanel");
   let lwthemeButton = this.document.getElementById("customization-lwtheme-button");
   if (Services.prefs.getCharPref("general.skins.selectedSkin") != "classic/1.0") {
     lwthemeButton.setAttribute("hidden", "true");
   }
 #ifdef CAN_DRAW_IN_TITLEBAR
   this._updateTitlebarButton();
   Services.prefs.addObserver(kDrawInTitlebarPref, this, false);
+#endif
+  this._updateDevEditionThemeButton();
+  Services.prefs.addObserver(kDeveditionButtonPref, this, false);
+  Services.prefs.addObserver(kDeveditionThemePref, this, false);
   this.window.addEventListener("unload", this);
-#endif
 };
 
 CustomizeMode.prototype = {
   _changed: false,
   _transitioning: false,
   window: null,
   document: null,
   // areas is used to cache the customizable areas when in customization mode.
@@ -100,16 +105,18 @@ CustomizeMode.prototype = {
   get _handler() {
     return this.window.CustomizationHandler;
   },
 
   uninit: function() {
 #ifdef CAN_DRAW_IN_TITLEBAR
     Services.prefs.removeObserver(kDrawInTitlebarPref, this);
 #endif
+    Services.prefs.removeObserver(kDeveditionButtonPref, this);
+    Services.prefs.removeObserver(kDeveditionThemePref, this);
   },
 
   toggle: function() {
     if (this._handler.isEnteringCustomizeMode || this._handler.isExitingCustomizeMode) {
       this._wantToBeInCustomizeMode = !this._wantToBeInCustomizeMode;
       return;
     }
     if (this._customizing) {
@@ -1442,32 +1449,31 @@ CustomizeMode.prototype = {
       case "mouseup":
         this._onMouseUp(aEvent);
         break;
       case "keypress":
         if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) {
           this.exit();
         }
         break;
-#ifdef CAN_DRAW_IN_TITLEBAR
       case "unload":
         this.uninit();
         break;
-#endif
     }
   },
 
   observe: function(aSubject, aTopic, aData) {
     switch (aTopic) {
       case "nsPref:changed":
         this._updateResetButton();
         this._updateUndoResetButton();
 #ifdef CAN_DRAW_IN_TITLEBAR
         this._updateTitlebarButton();
 #endif
+        this._updateDevEditionThemeButton();
         break;
       case "lightweight-theme-window-updated":
         if (aSubject == this.window) {
           aData = JSON.parse(aData);
           if (!aData) {
             this.removeLWTStyling();
           } else {
             this.updateLWTStyling(aData);
@@ -1493,16 +1499,39 @@ CustomizeMode.prototype = {
   },
 
   toggleTitlebar: function(aShouldShowTitlebar) {
     // Drawing in the titlebar means not showing the titlebar, hence the negation:
     Services.prefs.setBoolPref(kDrawInTitlebarPref, !aShouldShowTitlebar);
   },
 #endif
 
+  _updateDevEditionThemeButton: function() {
+    let button = this.document.getElementById("customization-devedition-theme-button");
+
+    let themeEnabled = Services.prefs.getBoolPref(kDeveditionThemePref);
+    if (themeEnabled) {
+      button.setAttribute("checked", "true");
+    } else {
+      button.removeAttribute("checked");
+    }
+
+    let buttonVisible = Services.prefs.getBoolPref(kDeveditionButtonPref);
+    if (buttonVisible) {
+      button.removeAttribute("hidden");
+    } else {
+      button.setAttribute("hidden", "true");
+    }
+  },
+  toggleDevEditionTheme: function() {
+    let button = this.document.getElementById("customization-devedition-theme-button");
+    let preferenceValue = button.hasAttribute("checked");
+    Services.prefs.setBoolPref(kDeveditionThemePref, preferenceValue);
+  },
+
   _onDragStart: function(aEvent) {
     __dumpDragData(aEvent);
     let item = aEvent.target;
     while (item && item.localName != "toolbarpaletteitem") {
       if (item.localName == "toolbar") {
         return;
       }
       item = item.parentNode;
--- a/browser/components/customizableui/content/customizeMode.inc.xul
+++ b/browser/components/customizableui/content/customizeMode.inc.xul
@@ -47,16 +47,24 @@
             <toolbarbutton class="customization-lwtheme-menu-footeritem"
                            label="&customizeMode.lwthemes.menuGetMore;"
                            accesskey="&customizeMode.lwthemes.menuGetMore.accessKey;"
                            tabindex="0"
                            oncommand="gCustomizeMode.getMoreThemes(event);"/>
           </hbox>
         </panel>
       </button>
+
+      <button id="customization-devedition-theme-button"
+              class="customizationmode-button"
+              hidden="true"
+              label="&customizeMode.deveditionTheme.label;"
+              oncommand="gCustomizeMode.toggleDevEditionTheme()"
+              type="checkbox" />
+
       <spacer id="customization-footer-spacer"/>
       <button id="customization-undo-reset-button"
               class="customizationmode-button"
               hidden="true"
               oncommand="gCustomizeMode.undoReset();"
               label="&undoCmd.label;"/>
       <button id="customization-reset-button"
               oncommand="gCustomizeMode.reset();"
--- a/browser/components/customizableui/test/browser_970511_undo_restore_default.js
+++ b/browser/components/customizableui/test/browser_970511_undo_restore_default.js
@@ -96,12 +96,50 @@ add_task(function() {
   is(Services.prefs.getBoolPref(prefName), !defaultValue, "Undo-reset goes back to previous pref value");
   is(undoResetButton.hidden, true, "Undo reset button should be hidden after undo-reset clicked");
 
   Services.prefs.clearUserPref(prefName);
   ok(CustomizableUI.inDefaultState, "In default state after pref cleared");
   is(undoResetButton.hidden, true, "Undo reset button should be hidden at end of test");
 });
 
+// Bug 1082108 - Restore Defaults should clear user pref for devedition theme
+add_task(function() {
+  let prefName = "browser.devedition.theme.enabled";
+  Services.prefs.setBoolPref("browser.devedition.theme.showCustomizeButton", true);
+  let defaultValue = Services.prefs.getBoolPref(prefName);
+  let restoreDefaultsButton = document.getElementById("customization-reset-button");
+  let deveditionThemeButton = document.getElementById("customization-devedition-theme-button");
+  let undoResetButton = document.getElementById("customization-undo-reset-button");
+  ok(CustomizableUI.inDefaultState, "Should be in default state at start of test");
+  ok(restoreDefaultsButton.disabled, "Restore defaults button should be disabled when in default state");
+  is(deveditionThemeButton.hasAttribute("checked"), defaultValue, "Devedition theme button should reflect pref value");
+  is(undoResetButton.hidden, true, "Undo reset button should be hidden at start of test");
+  Services.prefs.setBoolPref(prefName, !defaultValue);
+  ok(!restoreDefaultsButton.disabled, "Restore defaults button should be enabled when pref changed");
+  is(deveditionThemeButton.hasAttribute("checked"), !defaultValue, "Devedition theme button should reflect changed pref value");
+  ok(!CustomizableUI.inDefaultState, "With devedition theme flipped, no longer default");
+  is(undoResetButton.hidden, true, "Undo reset button should be hidden after pref change");
+
+  yield gCustomizeMode.reset();
+  ok(restoreDefaultsButton.disabled, "Restore defaults button should be disabled after reset");
+  is(deveditionThemeButton.hasAttribute("checked"), defaultValue, "devedition theme button should reflect default value after reset");
+  is(Services.prefs.getBoolPref(prefName), defaultValue, "Reset should reset devedition.theme.enabled");
+  ok(CustomizableUI.inDefaultState, "In default state after devedition theme reset");
+  is(undoResetButton.hidden, false, "Undo reset button should be visible after reset");
+  ok(!undoResetButton.disabled, "Undo reset button should be enabled after reset");
+
+  yield gCustomizeMode.undoReset();
+  ok(!restoreDefaultsButton.disabled, "Restore defaults button should be enabled after undo-reset");
+  is(deveditionThemeButton.hasAttribute("checked"), !defaultValue, "devedition theme button should reflect undo-reset value");
+  ok(!CustomizableUI.inDefaultState, "No longer in default state after undo");
+  is(Services.prefs.getBoolPref(prefName), !defaultValue, "Undo-reset goes back to previous pref value");
+  is(undoResetButton.hidden, true, "Undo reset button should be hidden after undo-reset clicked");
+
+  Services.prefs.clearUserPref(prefName);
+  ok(CustomizableUI.inDefaultState, "In default state after pref cleared");
+  is(undoResetButton.hidden, true, "Undo reset button should be hidden at end of test");
+});
+
 add_task(function asyncCleanup() {
   yield gCustomizeMode.reset();
   yield endCustomizing();
 });
--- a/browser/themes/shared/customizableui/customizeMode.inc.css
+++ b/browser/themes/shared/customizableui/customizeMode.inc.css
@@ -125,16 +125,25 @@
   padding: 2px 12px;
   background-color: rgb(251,251,251);
   color: rgb(71,71,71);
   box-shadow: 0 1px rgba(255, 255, 255, 0.5),
               inset 0 1px rgba(255, 255, 255, 0.5);
   -moz-appearance: none;
 }
 
+#customization-titlebar-visibility-button[checked],
+#customization-devedition-theme-button[checked] {
+  background-color: rgb(218, 218, 218);
+  border-color: rgb(168, 168, 168);
+  text-shadow: 0 1px rgb(236, 236, 236);
+  box-shadow: 0 1px rgba(255, 255, 255, 0.5),
+              inset 0 1px rgb(196, 196, 196);
+}
+
 .customizationmode-button[disabled="true"] {
   opacity: .5;
 }
 
 .customizationmode-button > .box-inherit > .box-inherit > .button-icon,
 .customizationmode-button > .button-box > .button-icon {
   height: 24px;
 }
@@ -151,21 +160,16 @@
 }
 
 #customization-titlebar-visibility-button > .button-box > .button-icon {
   vertical-align: middle;
 }
 
 #customization-titlebar-visibility-button[checked] {
   -moz-image-region: rect(0, 48px, 24px, 24px);
-  background-color: rgb(218, 218, 218);
-  border-color: rgb(168, 168, 168);
-  text-shadow: 0 1px rgb(236, 236, 236);
-  box-shadow: 0 1px rgba(255, 255, 255, 0.5),
-              inset 0 1px rgb(196, 196, 196);
 }
 
 #main-window[customize-entered] #customization-panel-container {
   background-image: url("chrome://browser/skin/customizableui/customizeMode-separatorHorizontal.png"),
                     url("chrome://browser/skin/customizableui/customizeMode-separatorVertical.png"),
                     url("chrome://browser/skin/customizableui/customizeMode-gridTexture.png"),
                     url("chrome://browser/skin/customizableui/background-noise-toolbar.png"),
                     linear-gradient(to bottom, #3e86ce, #3878ba);