Commit 940ccb2c authored by jcampan@chromium.org's avatar jcampan@chromium.org

Relanding this, it was missing the Mac unit-test change, that was breaking the build.

TBR=ben

Closing the last tab with a download in-progress would cause the tab to be
closed and become unusable if the user decides not to proceed with the browser
shutdown.
This is because we check for in-progress downloads when the browser is closed,
and the tab is closed before that, leaving the tab-strip in a bad state.

This CL ensures we also bring-up the confirmation dialog when the last tab is
closed.

BUG=10680
TEST=Start downloading a big file. While the file is downloading, close all
tabs. When closing the last tab, the in-progress download dialog should be
shown. Select the 'Wait for downloads', the download tab should be shown and
the previous tab should still be displayed and functional.
Close all tabs again, this time select the 'Close and cancel downloads'
option, the browser should be closed.
Review URL: http://codereview.chromium.org/100210

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14952 0039d316-1c4b-4281-b951-d872f2087c98
parent 7f74a4ee
...@@ -1525,6 +1525,15 @@ bool Browser::RunUnloadListenerBeforeClosing(TabContents* contents) { ...@@ -1525,6 +1525,15 @@ bool Browser::RunUnloadListenerBeforeClosing(TabContents* contents) {
return false; return false;
} }
bool Browser::CanCloseContentsAt(int index) {
if (tabstrip_model_.count() > 1)
return true;
// We are closing the last tab for this browser. Make sure to check for
// in-progress downloads.
// Note that the next call when it returns false will ask the user for
// confirmation before closing the browser if the user decides so.
return CanCloseWithInProgressDownloads();
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Browser, TabStripModelObserver implementation: // Browser, TabStripModelObserver implementation:
......
...@@ -432,6 +432,7 @@ class Browser : public TabStripModelDelegate, ...@@ -432,6 +432,7 @@ class Browser : public TabStripModelDelegate,
virtual void CloseFrameAfterDragSession(); virtual void CloseFrameAfterDragSession();
virtual void CreateHistoricalTab(TabContents* contents); virtual void CreateHistoricalTab(TabContents* contents);
virtual bool RunUnloadListenerBeforeClosing(TabContents* contents); virtual bool RunUnloadListenerBeforeClosing(TabContents* contents);
virtual bool CanCloseContentsAt(int index);
// Overridden from TabStripModelObserver: // Overridden from TabStripModelObserver:
virtual void TabInsertedAt(TabContents* contents, virtual void TabInsertedAt(TabContents* contents,
......
...@@ -49,6 +49,8 @@ class TestTabStripDelegate : public TabStripModelDelegate { ...@@ -49,6 +49,8 @@ class TestTabStripDelegate : public TabStripModelDelegate {
return true; return true;
} }
virtual void RestoreTab() { } virtual void RestoreTab() { }
virtual bool CanCloseContentsAt(int index) { return true; }
}; };
class TabStripControllerTest : public testing::Test { class TabStripControllerTest : public testing::Test {
......
...@@ -515,6 +515,9 @@ bool TabStripModel::IsNewTabAtEndOfTabStrip(TabContents* contents) const { ...@@ -515,6 +515,9 @@ bool TabStripModel::IsNewTabAtEndOfTabStrip(TabContents* contents) const {
bool TabStripModel::InternalCloseTabContentsAt(int index, bool TabStripModel::InternalCloseTabContentsAt(int index,
bool create_historical_tab) { bool create_historical_tab) {
if (!delegate_->CanCloseContentsAt(index))
return false;
TabContents* detached_contents = GetContentsAt(index); TabContents* detached_contents = GetContentsAt(index);
if (delegate_->RunUnloadListenerBeforeClosing(detached_contents)) if (delegate_->RunUnloadListenerBeforeClosing(detached_contents))
......
...@@ -109,7 +109,7 @@ class TabStripModelDelegate { ...@@ -109,7 +109,7 @@ class TabStripModelDelegate {
virtual TabContents* AddBlankTab(bool foreground) = 0; virtual TabContents* AddBlankTab(bool foreground) = 0;
virtual TabContents* AddBlankTabAt(int index, bool foreground) = 0; virtual TabContents* AddBlankTabAt(int index, bool foreground) = 0;
// Ask for a new TabStripModel to be created and the given tab contents to // Asks for a new TabStripModel to be created and the given tab contents to
// be added to it. Its size and position are reflected in |window_bounds|. // be added to it. Its size and position are reflected in |window_bounds|.
// If |dock_info|'s type is other than NONE, the newly created window should // If |dock_info|'s type is other than NONE, the newly created window should
// be docked as identified by |dock_info|. Returns the Browser object // be docked as identified by |dock_info|. Returns the Browser object
...@@ -128,7 +128,7 @@ class TabStripModelDelegate { ...@@ -128,7 +128,7 @@ class TabStripModelDelegate {
TAB_TEAROFF_ACTION = 2 TAB_TEAROFF_ACTION = 2
}; };
// Determine what drag actions are possible for the specified strip. // Determines what drag actions are possible for the specified strip.
virtual int GetDragActions() const = 0; virtual int GetDragActions() const = 0;
// Creates an appropriate TabContents for the given URL. This is handled by // Creates an appropriate TabContents for the given URL. This is handled by
...@@ -144,10 +144,10 @@ class TabStripModelDelegate { ...@@ -144,10 +144,10 @@ class TabStripModelDelegate {
bool defer_load, bool defer_load,
SiteInstance* instance) const = 0; SiteInstance* instance) const = 0;
// Return whether some contents can be duplicated. // Returns whether some contents can be duplicated.
virtual bool CanDuplicateContentsAt(int index) = 0; virtual bool CanDuplicateContentsAt(int index) = 0;
// Duplicate the contents at the provided index and places it into its own // Duplicates the contents at the provided index and places it into its own
// window. // window.
virtual void DuplicateContentsAt(int index) = 0; virtual void DuplicateContentsAt(int index) = 0;
...@@ -171,6 +171,9 @@ class TabStripModelDelegate { ...@@ -171,6 +171,9 @@ class TabStripModelDelegate {
// Restores the last closed tab if CanRestoreTab would return true. // Restores the last closed tab if CanRestoreTab would return true.
virtual void RestoreTab() = 0; virtual void RestoreTab() = 0;
// Returns whether some contents can be closed.
virtual bool CanCloseContentsAt(int index) = 0;
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
...@@ -254,8 +257,9 @@ class TabStripModel : public NotificationObserver { ...@@ -254,8 +257,9 @@ class TabStripModel : public NotificationObserver {
// Closes the TabContents at the specified index. This causes the TabContents // Closes the TabContents at the specified index. This causes the TabContents
// to be destroyed, but it may not happen immediately (e.g. if it's a // to be destroyed, but it may not happen immediately (e.g. if it's a
// WebContents). // WebContents).
// Returns true if the TabContents was closed immediately, false if we are // Returns true if the TabContents was closed immediately, false if it was not
// waiting for a response from an onunload handler. // closed (we may be waiting for a response from an onunload handler, or
// waiting for the user to confirm closure).
bool CloseTabContentsAt(int index) { bool CloseTabContentsAt(int index) {
return InternalCloseTabContentsAt(index, true); return InternalCloseTabContentsAt(index, true);
} }
......
...@@ -22,9 +22,11 @@ ...@@ -22,9 +22,11 @@
class TabStripDummyDelegate : public TabStripModelDelegate { class TabStripDummyDelegate : public TabStripModelDelegate {
public: public:
explicit TabStripDummyDelegate(TabContents* dummy) explicit TabStripDummyDelegate(TabContents* dummy)
: dummy_contents_(dummy) {} : dummy_contents_(dummy), can_close_(true) {}
virtual ~TabStripDummyDelegate() {} virtual ~TabStripDummyDelegate() {}
void set_can_close(bool value) { can_close_ = value; }
// Overridden from TabStripModelDelegate: // Overridden from TabStripModelDelegate:
virtual TabContents* AddBlankTab(bool foreground) { return NULL; } virtual TabContents* AddBlankTab(bool foreground) { return NULL; }
virtual TabContents* AddBlankTabAt(int index, bool foreground) { virtual TabContents* AddBlankTabAt(int index, bool foreground) {
...@@ -56,12 +58,16 @@ class TabStripDummyDelegate : public TabStripModelDelegate { ...@@ -56,12 +58,16 @@ class TabStripDummyDelegate : public TabStripModelDelegate {
} }
virtual bool CanRestoreTab() { return false; } virtual bool CanRestoreTab() { return false; }
virtual void RestoreTab() {} virtual void RestoreTab() {}
virtual bool CanCloseContentsAt(int index) { return can_close_ ; }
private: private:
// A dummy TabContents we give to callers that expect us to actually build a // A dummy TabContents we give to callers that expect us to actually build a
// Destinations tab for them. // Destinations tab for them.
TabContents* dummy_contents_; TabContents* dummy_contents_;
// Whether tabs can be closed.
bool can_close_;
DISALLOW_EVIL_CONSTRUCTORS(TabStripDummyDelegate); DISALLOW_EVIL_CONSTRUCTORS(TabStripDummyDelegate);
}; };
...@@ -311,7 +317,15 @@ TEST_F(TabStripModelTest, TestBasicAPI) { ...@@ -311,7 +317,15 @@ TEST_F(TabStripModelTest, TestBasicAPI) {
// Test CloseTabContentsAt // Test CloseTabContentsAt
{ {
tabstrip.CloseTabContentsAt(2); // Let's test nothing happens when the delegate veto the close.
delegate.set_can_close(false);
EXPECT_FALSE(tabstrip.CloseTabContentsAt(2));
EXPECT_EQ(3, tabstrip.count());
EXPECT_EQ(0, observer.GetStateCount());
// Now let's close for real.
delegate.set_can_close(true);
EXPECT_TRUE(tabstrip.CloseTabContentsAt(2));
EXPECT_EQ(2, tabstrip.count()); EXPECT_EQ(2, tabstrip.count());
EXPECT_EQ(3, observer.GetStateCount()); EXPECT_EQ(3, observer.GetStateCount());
......
...@@ -904,6 +904,8 @@ void TabStrip::CloseTab(Tab* tab) { ...@@ -904,6 +904,8 @@ void TabStrip::CloseTab(Tab* tab) {
available_width_for_tabs_ = GetAvailableWidthForTabs(last_tab); available_width_for_tabs_ = GetAvailableWidthForTabs(last_tab);
resize_layout_scheduled_ = true; resize_layout_scheduled_ = true;
AddMessageLoopObserver(); AddMessageLoopObserver();
// Note that the next call might not close the tab (because of unload
// hanlders or if the delegate veto the close).
model_->CloseTabContentsAt(tab_index); model_->CloseTabContentsAt(tab_index);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment