Bug 626525 - Disable "move to group" and "next group" if Panorama hasn't been run. r=dao a=b
authorRaymond Lee <raymond@appcoast.com>
Fri, 04 Feb 2011 10:16:23 +0100
changeset 61927 f2a6a78478dc6692fc06cb85a97d130650676018
parent 61926 847a825087f209993654ab1ff726998b9cb91a04
child 61928 fa442c0d6d2939b18d5068312659c9702d2023fd
push id18542
push userdgottwald@mozilla.com
push dateFri, 04 Feb 2011 09:16:59 +0000
treeherdermozilla-central@f2a6a78478dc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdao, b
bugs626525
milestone2.0b12pre
first release with
nightly win64
f2a6a78478dc / 4.0b12pre / 20110204030202 / files
nightly linux32
nightly linux64
nightly mac
nightly win32
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly win64
Bug 626525 - Disable "move to group" and "next group" if Panorama hasn't been run. r=dao a=b
browser/base/content/browser-tabview.js
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/test/tabview/Makefile.in
browser/base/content/test/tabview/browser_tabview_bug626525.js
--- a/browser/base/content/browser-tabview.js
+++ b/browser/base/content/browser-tabview.js
@@ -34,53 +34,89 @@
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
 let TabView = {
   _deck: null,
   _window: null,
-  _sessionstore: null,
+  _firstRunExperienced: false,
+  _browserKeyHandlerInitialized: false,
   VISIBILITY_IDENTIFIER: "tabview-visibility",
 
   // ----------
   get windowTitle() {
     delete this.windowTitle;
     let brandBundle = document.getElementById("bundle_brand");
     let brandShortName = brandBundle.getString("brandShortName");
     let title = gNavigatorBundle.getFormattedString("tabView2.title", [brandShortName]);
     return this.windowTitle = title;
   },
+  
+  // ----------
+  get firstRunExperienced() {
+    return this._firstRunExperienced;
+  },
 
   // ----------
   init: function TabView_init() {
-    // ___ keys    
-    this._setBrowserKeyHandlers();
+    if (!Services.prefs.prefHasUserValue("browser.panorama.experienced_first_run") ||
+        !Services.prefs.getBoolPref("browser.panorama.experienced_first_run")) {
+      Services.prefs.addObserver(
+        "browser.panorama.experienced_first_run", this, false);
+    } else {
+      this._firstRunExperienced = true;
+
+      if ((gBrowser.tabs.length - gBrowser.visibleTabs.length) > 0)
+        this._setBrowserKeyHandlers();
 
-    // ___ visibility
-    this._sessionstore =
-      Cc["@mozilla.org/browser/sessionstore;1"].
-        getService(Ci.nsISessionStore);
+      // ___ visibility
+      let sessionstore =
+        Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
+      let data = sessionstore.getWindowValue(window, this.VISIBILITY_IDENTIFIER);
 
-    let data = this._sessionstore.getWindowValue(window, this.VISIBILITY_IDENTIFIER);
+      if (data && data == "true") {
+        this.show();
+      } else {
+        let self = this;
 
-    if (data && data == "true") {
-      this.show();
-    } else {
-      let self = this;
-      // if a tab is changed from hidden to unhidden and the iframe is not 
-      // initialized, load the iframe and setup the tab.
-      this._tabShowEventListener = function (event) {
-        if (!self._window)
-          self._initFrame(function() {
-            self._window.UI.onTabSelect(gBrowser.selectedTab);
-          });
-      };
-      gBrowser.tabContainer.addEventListener(
+        // if a tab is changed from hidden to unhidden and the iframe is not 
+        // initialized, load the iframe and setup the tab.
+        this._tabShowEventListener = function (event) {
+          if (!self._window)
+            self._initFrame(function() {
+              self._window.UI.onTabSelect(gBrowser.selectedTab);
+            });
+        };
+        gBrowser.tabContainer.addEventListener(
+          "TabShow", this._tabShowEventListener, true);
+      }
+    }
+  },
+
+  // ----------
+  // Observes topic changes.
+  observe: function TabView_observe(subject, topic, data) {
+    if (topic == "nsPref:changed") {
+      Services.prefs.removeObserver(
+        "browser.panorama.experienced_first_run", this);
+      this._firstRunExperienced = true;
+    }
+  },
+
+  // ----------
+  // Uninitializes TabView.
+  uninit: function TabView_uninit() {
+    if (!this._firstRunExperienced) {
+      Services.prefs.removeObserver(
+        "browser.panorama.experienced_first_run", this);
+    }
+    if (this._tabShowEventListener) {
+      gBrowser.tabContainer.removeEventListener(
         "TabShow", this._tabShowEventListener, true);
     }
   },
 
   // ----------
   // Creates the frame and calls the callback once it's loaded. 
   // If the frame already exists, calls the callback immediately. 
   _initFrame: function TabView__initFrame(callback) {
@@ -102,17 +138,20 @@ let TabView = {
 
       iframe.setAttribute("src", "chrome://browser/content/tabview.html");
       this._deck.appendChild(iframe);
       this._window = iframe.contentWindow;
 
       if (this._tabShowEventListener) {
         gBrowser.tabContainer.removeEventListener(
           "TabShow", this._tabShowEventListener, true);
+        this._tabShowEventListener = null;
       }
+
+      this._setBrowserKeyHandlers();
     }
   },
 
   // ----------
   getContentWindow: function TabView_getContentWindow() {
     return this._window;
   },
 
@@ -146,17 +185,17 @@ let TabView = {
   // ----------
   toggle: function() {
     if (this.isVisible())
       this.hide();
     else 
       this.show();
   },
   
-  getActiveGroupName: function Tabview_getActiveGroupName() {
+  getActiveGroupName: function TabView_getActiveGroupName() {
     // We get the active group this way, instead of querying
     // GroupItems.getActiveGroupItem() because the tabSelect event
     // will not have happened by the time the browser tries to
     // update the title.
     let activeTab = window.gBrowser.selectedTab;
     if (activeTab._tabViewTabItem && activeTab._tabViewTabItem.parent){
       let groupName = activeTab._tabViewTabItem.parent.getTitle();
       if (groupName)
@@ -189,46 +228,57 @@ let TabView = {
           isEmpty = false;
         }
       });
       separator.hidden = isEmpty;
     });
   },
 
   // ----------
-  _createGroupMenuItem : function(groupItem) {
+  _createGroupMenuItem: function TabView__createGroupMenuItem(groupItem) {
     let menuItem = document.createElement("menuitem")
     menuItem.setAttribute("label", groupItem.getTitle());
     menuItem.setAttribute(
       "oncommand", 
       "TabView.moveTabTo(TabContextMenu.contextTab,'" + groupItem.id + "')");
 
     return menuItem;
   },
 
   // ----------
-  moveTabTo: function(tab, groupItemId) {
-    if (this._window)
+  moveTabTo: function TabView_moveTabTo(tab, groupItemId) {
+    if (this._window) {
       this._window.GroupItems.moveTabToGroupItem(tab, groupItemId);
+    } else {
+      let self = this;
+      this._initFrame(function() {
+        self._window.GroupItems.moveTabToGroupItem(tab, groupItemId);
+      });
+    }
   },
 
   // ----------
-  enableSearch: function Tabview_enableSearch(event) {
+  enableSearch: function TabView_enableSearch(event) {
     if (this._window)
       this._window.UI.enableSearch(event);
   },
 
   // ----------
   // Adds new key commands to the browser, for invoking the Tab Candy UI
   // and for switching between groups of tabs when outside of the Tab Candy UI.
-  _setBrowserKeyHandlers : function() {
-    let self = this;
+  _setBrowserKeyHandlers: function TabView__setBrowserKeyHandlers() {
+    if (this._browserKeyHandlerInitialized)
+      return;
 
+    this._browserKeyHandlerInitialized = true;
+
+    let self = this;
     window.addEventListener("keypress", function(event) {
-      if (self.isVisible())
+      if (self.isVisible() ||
+          (gBrowser.tabs.length - gBrowser.visibleTabs.length) == 0)
         return;
 
       let charCode = event.charCode;
       // Control (+ Shift) + `
       if (event.ctrlKey && !event.metaKey && !event.altKey &&
           (charCode == 96 || charCode == 126)) {
         event.stopPropagation();
         event.preventDefault();
@@ -259,10 +309,18 @@ let TabView = {
     }
   },
 
   // ----------
   // Cleans up the tab view after undo close tab.
   afterUndoCloseTab: function () {
     if (this._window)
       this._window.UI.restoredClosedTab = false;
+  },
+
+  // ----------
+  // On move to group pop showing.
+  moveToGroupPopupShowing: function TabView_moveToGroupPopupShowing(event) {
+    // there are hidden tabs so initialize the iframe and update the context menu
+    if ((gBrowser.tabs.length - gBrowser.visibleTabs.length) > 0)
+      this.updateContextMenu(TabContextMenu.contextTab, event.target);
   }
 };
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1669,16 +1669,17 @@ function BrowserShutdown()
 {
   if (Win7Features)
     Win7Features.onCloseWindow();
 
   gPrefService.removeObserver(ctrlTab.prefName, ctrlTab);
   gPrefService.removeObserver(allTabs.prefName, allTabs);
   ctrlTab.uninit();
   allTabs.uninit();
+  TabView.uninit();
 
   CombinedStopReload.uninit();
 
   gGestureSupport.init(false);
 
   FullScreen.cleanup();
 
   try {
@@ -8403,17 +8404,18 @@ var TabContextMenu = {
 
     // Hide "Bookmark All Tabs" for a pinned tab.  Update its state if visible.
     let bookmarkAllTabs = document.getElementById("context_bookmarkAllTabs");
     bookmarkAllTabs.hidden = this.contextTab.pinned;
     if (!bookmarkAllTabs.hidden)
       PlacesCommandHook.updateBookmarkAllTabsCommand();
 
     // Hide "Move to Group" if it's a pinned tab.
-    document.getElementById("context_tabViewMenu").hidden = this.contextTab.pinned;
+    document.getElementById("context_tabViewMenu").hidden =
+      (this.contextTab.pinned || !TabView.firstRunExperienced);
   }
 };
 
 XPCOMUtils.defineLazyGetter(this, "HUDConsoleUI", function () {
   Cu.import("resource:///modules/HUDService.jsm");
   try {
     return HUDService.consoleUI;
   }
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -120,17 +120,17 @@
                 accesskey="&pinAppTab.accesskey;"
                 oncommand="gBrowser.pinTab(TabContextMenu.contextTab);"/>
       <menuitem id="context_unpinTab" label="&unpinAppTab.label;" hidden="true"
                 accesskey="&unpinAppTab.accesskey;"
                 oncommand="gBrowser.unpinTab(TabContextMenu.contextTab);"/>
       <menu id="context_tabViewMenu" label="&moveToGroup.label;"
             accesskey="&moveToGroup.accesskey;">
         <menupopup id="context_tabViewMenuPopup"
-                   onpopupshowing="if (event.target == this) TabView.updateContextMenu(TabContextMenu.contextTab, this);">
+                   onpopupshowing="if (event.target == this) TabView.moveToGroupPopupShowing(event);">
           <menuseparator id="context_tabViewNamedGroups" hidden="true"/>
           <menuitem id="context_tabViewNewGroup" label="&moveToNewGroup.label;"
                     oncommand="TabView.moveTabTo(TabContextMenu.contextTab, null);"/>
         </menupopup>
       </menu>
       <menuitem id="context_openTabInWindow" label="&moveToNewWindow.label;"
                 accesskey="&moveToNewWindow.accesskey;"
                 tbattr="tabbrowser-multiple"
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -94,16 +94,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug624265.js \
                  browser_tabview_bug624931.js \
                  browser_tabview_bug624727.js \
                  browser_tabview_bug624847.js \
                  browser_tabview_bug624953.js \
                  browser_tabview_bug625269.js \
                  browser_tabview_bug625424.js \
                  browser_tabview_bug626368.js \
+                 browser_tabview_bug626525.js \
                  browser_tabview_bug627288.js \
                  browser_tabview_bug627736.js \
                  browser_tabview_bug628165.js \
                  browser_tabview_bug628270.js \
                  browser_tabview_bug629195.js \
                  browser_tabview_bug630102.js \
                  browser_tabview_dragdrop.js \
                  browser_tabview_exit_button.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug626525.js
@@ -0,0 +1,160 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let prefsBranch;
+let currentActiveGroupItemId;
+
+function test() {
+  waitForExplicitFinish();
+
+  // disable the first run pref
+  prefsBranch = Services.prefs.getBranch("browser.panorama.");
+  prefsBranch.setBoolPref("experienced_first_run", false);
+
+  let win =
+    window.openDialog(getBrowserURL(), "_blank", "all,dialog=no", "about:blank");
+
+  let onLoad = function() {
+    win.removeEventListener("load", onLoad, false);
+
+    let theObserver = function(subject, topic, data) {
+      Services.obs.removeObserver(
+        theObserver, "browser-delayed-startup-finished");
+      test1(win);
+    }
+    Services.obs.addObserver(
+      theObserver, "browser-delayed-startup-finished", false);
+  };
+
+  win.addEventListener("load", onLoad, false);
+}
+
+// check whether tha menu is hidden when the "experienced_first_run" pref is
+// false
+function test1(win) {
+  is(win.gBrowser.tabs.length - win.gBrowser.visibleTabs.length, 0,
+     "There are no hidden tabs")
+
+  let originalTab = win.gBrowser.visibleTabs[0];
+
+  openTabContextPopup(win, originalTab);
+
+  ok(win.document.getElementById("context_tabViewMenu").hidden,
+     "The menu should be hidden");
+
+  closeTabContextPopup(win);
+
+  executeSoon(function() { 
+    ok(!win.TabView.getContentWindow(), "The tab view iframe is not loaded");
+    test2(win);
+  });
+}
+
+// press the next group key combination and check whether the iframe has loaded or not
+function test2(win) {
+  goToNextGroup(win);
+
+  // give it a delay so we can ensure the iframe has not been loaded
+  executeSoon(function() {
+    ok(!win.TabView.getContentWindow(),
+       "The tab view iframe is not loaded after pressing the next group key combination");
+
+    test3(win);
+  });
+}
+
+// first run has happened, open the tab context menupopup and the tabview menu,
+// move a tab to another group including iframe initialization.  Then,
+// use the key combination to change to the next group.
+function test3(win) {
+  prefsBranch.setBoolPref("experienced_first_run", true);
+
+  let newTab = win.gBrowser.addTab("about:blank");
+
+  // open the tab context menupopup and the tabview menupopup
+  openTabContextPopup(win, newTab);
+  win.document.getElementById("context_tabViewMenuPopup").openPopup(
+    win.document.getElementById("context_tabViewMenu"), "end_after", 0, 0,
+    true, false);
+
+  ok(!win.document.getElementById("context_tabViewMenu").hidden,
+     "The menu should be visible now");
+  is(win.gBrowser.tabs.length - win.gBrowser.visibleTabs.length, 0,
+     "There are no hidden tabs")
+  ok(!win.TabView.getContentWindow(),
+     "The tab view iframe is not loaded after opening tab context menu");
+
+  let onTabViewFrameInitialized = function() {
+     win.removeEventListener(
+       "tabviewframeinitialized", onTabViewFrameInitialized, false);
+
+     let contentWindow = win.document.getElementById("tab-view").contentWindow;
+
+     // show the tab view to ensure groups are created before checking.
+     let onTabViewShown = function() {
+       win.removeEventListener("tabviewshown", onTabViewShown, false);
+
+       ok(win.TabView.isVisible(), "Tab View is visible");
+
+       is(contentWindow.GroupItems.groupItems.length, 2,
+          "There are two group items");
+       is(contentWindow.GroupItems.groupItems[0].getChildren().length, 1,
+          "There should be one tab item in the first group");
+       is(contentWindow.GroupItems.groupItems[1].getChildren().length, 1,
+          "There should be one tab item in the second group");
+
+       // simulate the next group key combination
+       currentActiveGroupItemId =
+         contentWindow.GroupItems.getActiveGroupItem().id;
+
+       win.addEventListener("tabviewhidden", onTabViewHidden, false);
+
+       win.TabView.toggle();
+     };
+     let onTabViewHidden = function() {
+       win.removeEventListener("tabviewhidden", onTabViewHidden, false);
+
+       goToNextGroup(win);
+
+       isnot(contentWindow.GroupItems.getActiveGroupItem().id,
+             currentActiveGroupItemId, "Just switched to another group");
+
+       // close the window and finish it
+       win.close();
+       finish();
+     };
+     win.addEventListener("tabviewshown", onTabViewShown, false);
+     // give it a delay to ensure everything is loaded.
+     executeSoon(function() { win.TabView.toggle(); });
+  };
+  win.addEventListener(
+    "tabviewframeinitialized", onTabViewFrameInitialized, false);
+  // move the tab to another group using the menu item
+  win.document.getElementById("context_tabViewNewGroup").doCommand();
+
+  // close popups
+  win.document.getElementById("context_tabViewMenuPopup").hidePopup();
+  closeTabContextPopup(win);
+}
+
+function openTabContextPopup(win, tab) {
+  win.document.popupNode = tab;
+  win.document.getElementById("tabContextMenu").openPopup(
+    tab, "end_after", 0, 0, true, false);
+}
+
+function closeTabContextPopup(win) {
+  win.document.getElementById("tabContextMenu").hidePopup();
+}
+
+function goToNextGroup(win) {
+  let utils =
+    win.QueryInterface(Ci.nsIInterfaceRequestor).
+      getInterface(Ci.nsIDOMWindowUtils);
+
+  const masks = Ci.nsIDOMNSEvent;
+  let mval = 0;
+  mval |= masks.CONTROL_MASK;
+
+  utils.sendKeyEvent("keypress", 0, 96, mval);
+}