Bug 589324 - Switch-to-Tab after Session Restore does not respect Tab Candy grouping [r=dietrich, a=blocking2.0]
authorRaymond Lee <raymond@raysquare.com>
Sat, 13 Nov 2010 02:37:34 +0800
changeset 57554 9b8ee895f234a4a7226f2b8a75e8e399d8ce7777
parent 57553 ba45d6b7fce254287f3b5fe0c6e01b1145d25b64
child 57555 91465c3b341b6697b248bb28c6a4276953e59c80
push idunknown
push userunknown
push dateunknown
reviewersdietrich, blocking2
bugs589324
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 589324 - Switch-to-Tab after Session Restore does not respect Tab Candy grouping [r=dietrich, a=blocking2.0]
browser/base/content/browser-tabview.js
browser/base/content/test/browser_visibleTabs.js
browser/base/content/test/tabview/Makefile.in
browser/base/content/test/tabview/browser_tabview_bug580412.js
browser/base/content/test/tabview/browser_tabview_bug589324.js
browser/base/content/test/tabview/dummy_page.html
--- a/browser/base/content/browser-tabview.js
+++ b/browser/base/content/browser-tabview.js
@@ -35,78 +35,95 @@
 #
 # ***** END LICENSE BLOCK *****
 
 let TabView = {
   _deck: null,
   _window: null,
   _sessionstore: null,
   _visibilityID: "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;
   },
 
   // ----------
-  init: function TabView_init() {    
+  init: function TabView_init() {
     // ___ keys    
     this._setBrowserKeyHandlers();
 
     // ___ visibility
     this._sessionstore =
       Cc["@mozilla.org/browser/sessionstore;1"].
         getService(Ci.nsISessionStore);
 
     let data = this._sessionstore.getWindowValue(window, this._visibilityID);
-    if (data && data == "true")
+    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(
+        "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) {
     if (this._window) {
       if (typeof callback == "function")
         callback();
     } else {
       // ___ find the deck
       this._deck = document.getElementById("tab-view-deck");
-      
+
       // ___ create the frame
       let iframe = document.createElement("iframe");
       iframe.id = "tab-view";
       iframe.setAttribute("transparent", "true");
       iframe.flex = 1;
-              
+
       if (typeof callback == "function")
         iframe.addEventListener("DOMContentLoaded", callback, false);
-      
+
       iframe.setAttribute("src", "chrome://browser/content/tabview.html");
       this._deck.appendChild(iframe);
       this._window = iframe.contentWindow;
 
       // ___ visibility storage handler
       let self = this;
       function observer(subject, topic, data) {
         if (topic == "quit-application-requested") {
           let data = (self.isVisible() ? "true" : "false");
           self._sessionstore.setWindowValue(window, self._visibilityID, data);
         }
       }
-      
       Services.obs.addObserver(observer, "quit-application-requested", false);
+
+      if (this._tabShowEventListener) {
+        gBrowser.tabContainer.removeEventListener(
+          "TabShow", this._tabShowEventListener, true);
+      }
     }
   },
-  
+
   // ----------
   getContentWindow: function TabView_getContentWindow() {
     return this._window;
   },
 
   // ----------
   isVisible: function() {
     return (this._deck ? this._deck.selectedIndex == 1 : false);
--- a/browser/base/content/test/browser_visibleTabs.js
+++ b/browser/base/content/test/browser_visibleTabs.js
@@ -55,16 +55,23 @@ function test() {
   is(gBrowser.selectedTab, origTab, "sanity check that we're on the original tab");
   gBrowser.showOnlyTheseTabs([testTab]);
   is(gBrowser.visibleTabs.length, 3, "all 3 tabs are still visible");
 
   // Select the test tab and only show that (and pinned)
   gBrowser.selectedTab = testTab;
   gBrowser.showOnlyTheseTabs([testTab]);
 
+  // if the tabview frame is initialized, we need to move the orignal tab to
+  // another group; otherwise, selecting a tab would make all three tabs in 
+  // the same group to display.
+  let tabViewWindow = TabView.getContentWindow();
+  if (tabViewWindow)
+    tabViewWindow.GroupItems.moveTabToGroupItem(origTab, null);
+
   visible = gBrowser.visibleTabs;
   is(visible.length, 2, "2 tabs should be visible including the pinned");
   is(visible[0], pinned, "first is pinned");
   is(visible[1], testTab, "next is the test tab");
   is(gBrowser.tabs.length, 3, "3 tabs should still be open");
 
   gBrowser.selectTabAtIndex(0);
   is(gBrowser.selectedTab, pinned, "first tab is pinned");
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -43,16 +43,17 @@ relativesrcdir  = browser/base/content/t
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _BROWSER_FILES = \
                  browser_tabview_apptabs.js \
                  browser_tabview_bug580412.js \
                  browser_tabview_bug587043.js \
                  browser_tabview_bug587990.js \
+                 browser_tabview_bug589324.js \
                  browser_tabview_bug590606.js \
                  browser_tabview_bug591706.js \
                  browser_tabview_bug594176.js \
                  browser_tabview_bug595191.js \
                  browser_tabview_bug595518.js \
                  browser_tabview_bug595521.js \
                  browser_tabview_bug595804.js \
                  browser_tabview_bug595930.js \
@@ -65,16 +66,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_orphaned_tabs.js \
                  browser_tabview_privatebrowsing.js \
                  browser_tabview_rtl.js \
                  browser_tabview_search.js \
                  browser_tabview_snapping.js \
                  browser_tabview_startup_transitions.js \
                  browser_tabview_undo_group.js \
                  browser_tabview_firstrun_pref.js \
+                 dummy_page.html \
                  head.js \
                  search1.html \
                  search2.html \
                  $(NULL)
 
 # compartments: test disabled
 #                 browser_tabview_multiwindow_search.js \
 
--- a/browser/base/content/test/tabview/browser_tabview_bug580412.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug580412.js
@@ -54,31 +54,31 @@ function onTabViewWindowLoaded() {
   ok(TabView.isVisible(), "Tab View is visible");
   is(contentWindow.GroupItems.groupItems.length, 1, "There is only one group");
   let currentActiveGroup = contentWindow.GroupItems.getActiveGroupItem();
 
 //  is(currentActiveGroup.getBounds.bottom(), 40,
 //    "There's currently 40 px between the first group and second group");
 
   let endGame = function() {
+    contentWindow.UI.reset();
     let onTabViewHidden = function() {
       window.removeEventListener("tabviewhidden", onTabViewHidden, false);
       ok(!TabView.isVisible(), "TabView is shown");
       finish();
     };
     window.addEventListener("tabviewhidden", onTabViewHidden, false);
 
     ok(TabView.isVisible(), "TabView is shown");
     
     gBrowser.selectedTab = originalTab;
     TabView.hide();
   }
   
   let part1 = function() {
-//    contentWindow.UI.reset();
     // move down 20 so we're far enough away from the top.
     checkSnap(currentActiveGroup, 0, 20, contentWindow, function(snapped){
       ok(!snapped,"Move away from the edge");
 
       // Just pick it up and drop it.
       checkSnap(currentActiveGroup, 0, 0, contentWindow, function(snapped){
         ok(!snapped,"Just pick it up and drop it");
         
@@ -88,17 +88,19 @@ function onTabViewWindowLoaded() {
           checkSnap(currentActiveGroup, 0, 5, contentWindow, function(snapped){
             ok(!snapped,"Moving five pixels: shouldn't snap");
             endGame();
           });
         });
       });
     });
   }
-  
+
+  currentActiveGroup.setPosition(40, 40, true);
+  currentActiveGroup.arrange({animate: false});
   part1();
 }
 
 function simulateDragDrop(tabItem, offsetX, offsetY, contentWindow) {
   // enter drag mode
   let dataTransfer;
 
   EventUtils.synthesizeMouse(
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug589324.js
@@ -0,0 +1,127 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is bug 589324 test.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Raymond Lee <raymond@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
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * 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 ***** */
+
+function test() {
+  const DUMMY_PAGE_URL = "http://mochi.test:8888/browser/browser/base/content/test/tabview/dummy_page.html";
+  const DUMMY_PAGE_URL_2 = "http://mochi.test:8888/";
+
+  let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
+  waitForExplicitFinish();
+
+  // open a new window and setup the window state.
+  let newWin = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no");
+  newWin.addEventListener("load", function(event) {
+    this.removeEventListener("load", arguments.callee, false);
+
+    let newState = {
+      windows: [{
+        tabs: [{
+          entries: [{ url: DUMMY_PAGE_URL }],
+          hidden: true,
+          attributes: {},
+          extData: {
+            "tabview-tab":
+              '{"bounds":{"left":21,"top":29,"width":204,"height":153},' +
+              '"userSize":null,"url":"' + DUMMY_PAGE_URL + '","groupID":1,' + 
+              '"imageData":null,"title":null}'
+          }
+        },{
+          entries: [{ url: DUMMY_PAGE_URL_2 }],
+          hidden: false,
+          attributes: {},
+          extData: {
+            "tabview-tab": 
+              '{"bounds":{"left":315,"top":29,"width":111,"height":84},' + 
+              '"userSize":null,"url":"' + DUMMY_PAGE_URL_2 + '","groupID":2,' + 
+              '"imageData":null,"title":null}'
+          },
+        }],
+        selected:2,
+        _closedTabs: [],
+        extData: {
+          "tabview-groups": '{"nextID":3,"activeGroupId":2}',
+          "tabview-group": 
+            '{"1":{"bounds":{"left":15,"top":5,"width":280,"height":232},' + 
+            '"userSize":null,"locked":{},"title":"","id":1},' + 
+            '"2":{"bounds":{"left":309,"top":5,"width":267,"height":226},' + 
+            '"userSize":null,"locked":{},"title":"","id":2}}',
+          "tabview-ui": '{"pageBounds":{"left":0,"top":0,"width":788,"height":548}}'
+        }, sizemode:"normal"
+      }]
+    };
+    ss.setWindowState(newWin, JSON.stringify(newState), true);
+
+    let firstTab = newWin.gBrowser.tabs[0];
+    let secondTab = newWin.gBrowser.tabs[1];
+
+    // wait until the first tab is fully loaded
+    let browser = newWin.gBrowser.getBrowserForTab(firstTab);
+    let onLoad = function() {
+      browser.removeEventListener("load", onLoad, true);
+
+      is(browser.currentURI.spec, DUMMY_PAGE_URL, 
+         "The url of first tab url is dummy_page.html");
+
+      // check the hidden state of both tabs.
+      ok(firstTab.hidden, "The first tab is hidden");
+      ok(!secondTab.hidden, "The second tab is not hidden");
+      is(secondTab, newWin.gBrowser.selectedTab, "The second tab is selected");
+
+      // when the second tab is hidden, the iframe should be initialized and 
+      // the first tab should be visible.
+      let onTabHide = function() {
+        newWin.gBrowser.tabContainer.addEventListener("TabHide", onTabHide, true);
+
+        ok(newWin.TabView.getContentWindow(), "");
+
+        ok(!firstTab.hidden, "The first tab is not hidden");
+        is(firstTab, newWin.gBrowser.selectedTab, "The first tab is selected");
+        ok(secondTab.hidden, "The second tab is hidden");
+
+        // clean up and finish
+        newWin.close();
+
+        finish();
+      };
+      newWin.gBrowser.tabContainer.addEventListener("TabHide", onTabHide, true);
+
+      // switch to another tab
+      newWin.switchToTabHavingURI(DUMMY_PAGE_URL);
+    }
+    browser.addEventListener("load", onLoad, true);
+  }, false);
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/dummy_page.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>This is a dummy test page</title>
+</head>
+<body>
+<p>This is a dummy test page</p>
+</body>
+</html>