Bug 624847 - 'Undo Close Tab' closes current group when only one blank tab is left [r=ian, a=sdwilsh]
authorTim Taubert <tim.taubert@gmx.de>
Thu, 03 Feb 2011 02:43:32 +0100
changeset 61861 3c87074d5f50d069edf461fe21d86a5b558cfd98
parent 61860 be4f8b47377e4c75398fdf56507469a9c163f967
child 61862 f00b81064d570e372b70ac673ca4b00c40556f2e
push id18522
push usereakhgari@mozilla.com
push dateThu, 03 Feb 2011 17:29:54 +0000
treeherdermozilla-central@3c87074d5f50 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersian, sdwilsh
bugs624847
milestone2.0b12pre
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 624847 - 'Undo Close Tab' closes current group when only one blank tab is left [r=ian, a=sdwilsh]
browser/base/content/browser-tabview.js
browser/base/content/browser.js
browser/base/content/tabview/groupitems.js
browser/base/content/tabview/ui.js
browser/base/content/test/tabview/Makefile.in
browser/base/content/test/tabview/browser_tabview_bug624847.js
--- a/browser/base/content/browser-tabview.js
+++ b/browser/base/content/browser-tabview.js
@@ -15,16 +15,17 @@
 #
 # 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>
 #   Ian Gilman <ian@iangilman.com>
+#   Tim Taubert <tim.taubert@gmx.de>
 #
 # 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
@@ -241,22 +242,26 @@ let TabView = {
           // Switch to the new tab, and close the old group if it's now empty.
           let oldGroupItem = groupItems.getActiveGroupItem();
           window.gBrowser.selectedTab = tabItem.tab;
           oldGroupItem.closeIfEmpty();
         });
       }
     }, true);
   },
-  
+
   // ----------
   // Prepares the tab view for undo close tab.
-  prepareUndoCloseTab: function() {
-    if (this._window)
+  prepareUndoCloseTab: function(blankTabToRemove) {
+    if (this._window) {
       this._window.UI.restoredClosedTab = true;
+
+      if (blankTabToRemove)
+        blankTabToRemove._tabViewTabIsRemovedAfterRestore = true;
+    }
   },
 
   // ----------
   // Cleans up the tab view after undo close tab.
   afterUndoCloseTab: function () {
     if (this._window)
       this._window.UI.restoredClosedTab = false;
   }
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -7178,17 +7178,17 @@ function undoCloseTab(aIndex) {
       !gPrefService.getBoolPref("browser.tabs.autoHide") &&
       isTabEmpty(gBrowser.selectedTab))
     blankTabToRemove = gBrowser.selectedTab;
 
   var tab = null;
   var ss = Cc["@mozilla.org/browser/sessionstore;1"].
            getService(Ci.nsISessionStore);
   if (ss.getClosedTabCount(window) > (aIndex || 0)) {
-    TabView.prepareUndoCloseTab();
+    TabView.prepareUndoCloseTab(blankTabToRemove);
     tab = ss.undoCloseTab(window, aIndex || 0);
     TabView.afterUndoCloseTab();
 
     if (blankTabToRemove)
       gBrowser.removeTab(blankTabToRemove);
   }
 
   return tab;
--- a/browser/base/content/tabview/groupitems.js
+++ b/browser/base/content/tabview/groupitems.js
@@ -981,16 +981,21 @@ GroupItem.prototype = Utils.extend(new I
       item.setRotation(0);
 
       item.droppable(true);
       item.removeSubscriber(this, "close");
 
       if (typeof item.setResizable == 'function')
         item.setResizable(true, options.immediately);
 
+      // if a blank tab is selected while restoring a tab the blank tab gets
+      // removed. we need to keep the group alive for the restored tab.
+      if (item.tab._tabViewTabIsRemovedAfterRestore)
+        options.dontClose = true;
+
       let closed = options.dontClose ? false : this.closeIfEmpty();
       if (closed)
         this._makeClosestTabActive();
       else if (!options.dontArrage)
         this.arrange({animate: !options.immediately});
 
       this._sendToSubscribers("childRemoved",{ groupItemId: this.id, item: item });
     } catch(e) {
--- a/browser/base/content/tabview/ui.js
+++ b/browser/base/content/tabview/ui.js
@@ -726,24 +726,31 @@ let UI = {
 
           var groupItem = GroupItems.getActiveGroupItem();
 
           // 1) Only go back to the TabView tab when there you close the last
           // tab of a groupItem.
           let closingLastOfGroup = (groupItem && 
               groupItem._children.length == 1 && 
               groupItem._children[0].tab == tab);
-          
+
           // 2) Take care of the case where you've closed the last tab in
           // an un-named groupItem, which means that the groupItem is gone (null) and
           // there are no visible tabs. 
           let closingUnnamedGroup = (groupItem == null &&
               gBrowser.visibleTabs.length <= 1); 
-              
-          if (closingLastOfGroup || closingUnnamedGroup) {
+
+          // 3) When a blank tab is active while restoring a closed tab the
+          // blank tab gets removed. The active group is not closed as this is
+          // where the restored tab goes. So do not show the TabView.
+          let closingBlankTabAfterRestore =
+            (tab && tab._tabViewTabIsRemovedAfterRestore);
+
+          if ((closingLastOfGroup || closingUnnamedGroup) &&
+              !closingBlankTabAfterRestore) {
             // for the tab focus event to pick up.
             self._closedLastVisibleTab = true;
             self.showTabView();
           }
         }
       }
     };
 
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -89,16 +89,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug618816.js \
                  browser_tabview_bug618828.js \
                  browser_tabview_bug619937.js \
                  browser_tabview_bug622835.js \
                  browser_tabview_bug622872.js \
                  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_bug627288.js \
                  browser_tabview_bug627736.js \
                  browser_tabview_bug628165.js \
                  browser_tabview_bug628270.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug624847.js
@@ -0,0 +1,127 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  let cw;
+  let groupItemId;
+  let prefix = 'start';
+
+  let assertTabViewIsHidden = function () {
+    ok(!TabView.isVisible(), prefix + ': tabview is hidden');
+  }
+
+  let assertNumberOfGroups = function (num) {
+    is(cw.GroupItems.groupItems.length, num, prefix + ': there should be ' + num + ' groups');
+  }
+
+  let assertNumberOfTabs = function (num) {
+    is(gBrowser.visibleTabs.length, num, prefix + ': there should be ' + num + ' tabs');
+  }
+
+  let assertNumberOfPinnedTabs = function (num) {
+    is(gBrowser._numPinnedTabs, num, prefix + ': there should be ' + num + ' pinned tabs');
+  }
+
+  let assertGroupItemPreserved = function () {
+    is(cw.GroupItems.groupItems[0].id, groupItemId, prefix + ': groupItem was preserved');
+  }
+
+  let assertValidPrerequisites = function () {
+    assertNumberOfTabs(1);
+    assertNumberOfGroups(1);
+    assertNumberOfPinnedTabs(0);
+    assertTabViewIsHidden();
+  }
+
+  let createTab = function (url) {
+    return gBrowser.loadOneTab(url || 'http://mochi.test:8888/', {inBackground: true});
+  }
+
+  let createBlankTab = function () {
+    return createTab('about:blank');
+  }
+
+  let restoreTab = function (callback) {
+    let tab = undoCloseTab(0);
+
+    if (tab._tabViewTabItem._reconnected) {
+      afterAllTabsLoaded(callback);
+      return;
+    }
+
+    tab._tabViewTabItem.addSubscriber(tab, 'reconnected', function () {
+      tab._tabViewTabItem.removeSubscriber(tab, 'reconnected');
+      afterAllTabsLoaded(callback);
+    });
+  }
+
+  let finishTest = function () {
+    prefix = 'finish';
+    assertValidPrerequisites();
+    finish();
+  }
+
+  let testUndoCloseWithSelectedBlankTab = function () {
+    prefix = 'unpinned';
+    let tab = createTab();
+    assertNumberOfTabs(2);
+
+    afterAllTabsLoaded(function () {
+      gBrowser.removeTab(tab);
+      assertNumberOfTabs(1);
+      assertNumberOfPinnedTabs(0);
+
+      restoreTab(function () {
+        prefix = 'unpinned-restored';
+        assertValidPrerequisites();
+        assertGroupItemPreserved();
+
+        createBlankTab();
+        afterAllTabsLoaded(testUndoCloseWithSelectedBlankPinnedTab);
+      });
+    });
+  }
+
+  let testUndoCloseWithSelectedBlankPinnedTab = function () {
+    prefix = 'pinned';
+    assertNumberOfTabs(2);
+
+    afterAllTabsLoaded(function () {
+      gBrowser.removeTab(gBrowser.tabs[0]);
+      gBrowser.pinTab(gBrowser.tabs[0]);
+
+      registerCleanupFunction(function () {
+        let tab = gBrowser.tabs[0];
+        if (tab.pinned)
+          gBrowser.unpinTab(tab);
+      });
+
+      assertNumberOfTabs(1);
+      assertNumberOfPinnedTabs(1);
+
+      restoreTab(function () {
+        prefix = 'pinned-restored';
+        assertValidPrerequisites();
+        assertGroupItemPreserved();
+
+        createBlankTab();
+        gBrowser.removeTab(gBrowser.tabs[0]);
+
+        afterAllTabsLoaded(finishTest);
+      });
+    });
+  }
+
+  waitForExplicitFinish();
+  registerCleanupFunction(function () TabView.hide());
+
+  showTabView(function () {
+    hideTabView(function () {
+      cw = TabView.getContentWindow();
+      groupItemId = cw.GroupItems.groupItems[0].id;
+
+      assertValidPrerequisites();
+      testUndoCloseWithSelectedBlankTab();
+    });
+  });
+}