diff options
author | jcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-09 20:40:06 +0000 |
---|---|---|
committer | jcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-09 20:40:06 +0000 |
commit | 69444cc086ef3ddf9aaecb4d6bebcb24687c6977 (patch) | |
tree | edf46ca873f1a736095f86614dbb4abff316f14c | |
parent | edd32342189ef6329e894ff08456a2c565606355 (diff) | |
download | chromium_src-69444cc086ef3ddf9aaecb4d6bebcb24687c6977.zip chromium_src-69444cc086ef3ddf9aaecb4d6bebcb24687c6977.tar.gz chromium_src-69444cc086ef3ddf9aaecb4d6bebcb24687c6977.tar.bz2 |
This CL adds a confirmation box when closing the browser with in-progress downloads.
BUG=1028
TEST=Start several bug downloads, close the browser. A dialog shows up to warn you are about to lose the downloads. Try the wait and continue button. Try again with several windows, and in Incognito mode.
Review URL: http://codereview.chromium.org/62131
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13453 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/app/generated_resources.grd | 11 | ||||
-rw-r--r-- | chrome/browser/browser.cc | 76 | ||||
-rw-r--r-- | chrome/browser/browser.h | 28 | ||||
-rw-r--r-- | chrome/browser/browser_window.h | 6 | ||||
-rw-r--r-- | chrome/browser/cocoa/browser_window_cocoa.h | 1 | ||||
-rw-r--r-- | chrome/browser/cocoa/browser_window_cocoa.mm | 5 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_window_gtk.cc | 5 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_window_gtk.h | 1 | ||||
-rw-r--r-- | chrome/browser/views/frame/browser_view.cc | 76 | ||||
-rw-r--r-- | chrome/browser/views/frame/browser_view.h | 1 | ||||
-rw-r--r-- | chrome/test/test_browser_window.h | 1 |
11 files changed, 208 insertions, 3 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 3a69196..c28c691 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -1349,6 +1349,17 @@ each locale. --> &Remove </message> + <!-- Remove in-progress downloads confirmation dialog --> + <message name="IDS_DOWNLOAD_REMOVE_CONFIRM_TITLE" desc="Title of the dialog asking for user confirmation to close the browser when downloads are in-progress."> + You have <ph name="DOWNLOAD_COUNT">$1<ex>3</ex></ph> download(s) in progress. If you close Google Chrome, uncompleted downloads will be canceled and removed. + </message> + <message name="IDS_DOWNLOAD_REMOVE_CONFIRM_OK_BUTTON_LABEL" desc="Button text for OKing to close the browser when downloads are in-progress."> + Close and remove downloads + </message> + <message name="IDS_DOWNLOAD_REMOVE_CONFIRM_CANCEL_BUTTON_LABEL" desc="Button text for canceling the closing of the browser when downloads are in-progress."> + Wait for downloads to finish + </message> + <!-- Gears shortcut strings --> <message name="IDS_CREATE_SHORTCUTS" desc="Default installation menu label"> Create application &shortcuts... diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 3923936..35e4e22 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -16,6 +16,7 @@ #include "chrome/browser/browser_window.h" #include "chrome/browser/character_encoding.h" #include "chrome/browser/debugger/devtools_manager.h" +#include "chrome/browser/download/download_manager.h" #include "chrome/browser/find_bar.h" #include "chrome/browser/find_bar_controller.h" #include "chrome/browser/location_bar.h" @@ -176,6 +177,7 @@ Browser::Browser(Type type, Profile* profile) toolbar_model_(this), chrome_updater_factory_(this), is_attempting_to_close_browser_(false), + cancel_download_confirmation_state_(NOT_PROMPTED), maximized_state_(MAXIMIZED_STATE_DEFAULT), method_factory_(this), idle_task_(new BrowserIdleTimer) { @@ -442,9 +444,12 @@ bool Browser::ShouldShowDistributorLogo() const { // Browser, OnBeforeUnload handling: bool Browser::ShouldCloseWindow() { - if (HasCompletedUnloadProcessing()) { + if (!CanCloseWithInProgressDownloads()) + return false; + + if (HasCompletedUnloadProcessing()) return true; - } + is_attempting_to_close_browser_ = true; for (int i = 0; i < tab_count(); ++i) { @@ -484,7 +489,27 @@ void Browser::OnWindowClosing() { CloseAllTabs(); } -/////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// In-progress download termination handling: + +void Browser::InProgressDownloadResponse(bool cancel_downloads) { + if (cancel_downloads) { + cancel_download_confirmation_state_ = RESPONSE_RECEIVED; + CloseWindow(); + return; + } + + // Sets the confirmation state to NOT_PROMPTED so that if the user tries to + // close again we'll show the warning again. + cancel_download_confirmation_state_ = NOT_PROMPTED; + + // Show the download page so the user can figure-out what downloads are still + // in-progress. + ShowDownloadsTab(); +} + + +//////////////////////////////////////////////////////////////////////////////// // Browser, Tab adding/showing functions: TabContents* Browser::AddTabWithURL( @@ -2483,6 +2508,51 @@ void Browser::ClearUnloadState(TabContents* tab) { /////////////////////////////////////////////////////////////////////////////// +// Browser, In-progress download termination handling (private): + +bool Browser::CanCloseWithInProgressDownloads() { + if (cancel_download_confirmation_state_ != NOT_PROMPTED) { + // This should probably not happen. + DCHECK(cancel_download_confirmation_state_ != WAITING_FOR_RESPONSE); + return true; + } + + // If there are no download in-progress, our job is done. + DownloadManager* download_manager = profile_->GetDownloadManager(); + if (!download_manager || download_manager->in_progress_count() == 0) + return true; + + // Let's figure out if we are the last window for our profile. + // Note that we cannot just use BrowserList::GetBrowserCount as browser + // windows closing is delayed and the returned count might include windows + // that are being closed. + int count = 0; + for (BrowserList::const_iterator iter = BrowserList::begin(); + iter != BrowserList::end(); ++iter) { + // Don't count this browser window or any other in the process of closing. + if (*iter == this || (*iter)->is_attempting_to_close_browser_) + continue; + + // We test the original profile, because an incognito browser window keeps + // the original profile alive (and its DownloadManager). + // We also need to test explicitly the profile directly so that 2 incognito + // profiles count as a match. + if ((*iter)->profile() == profile() || + (*iter)->profile()->GetOriginalProfile() == profile()) + count++; + } + if (count > 0) + return true; + + cancel_download_confirmation_state_ = WAITING_FOR_RESPONSE; + window_->ConfirmBrowserCloseWithPendingDownloads(); + + // Return false so the browser does not close. We'll close if the user + // confirms in the dialog. + return false; +} + +/////////////////////////////////////////////////////////////////////////////// // Browser, Assorted utility functions (private): Browser* Browser::GetOrCreateTabbedBrowser() { diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h index 63b28d5..9db95d5 100644 --- a/chrome/browser/browser.h +++ b/chrome/browser/browser.h @@ -187,6 +187,14 @@ class Browser : public TabStripModelDelegate, // cleanup. void OnWindowClosing(); + // In-progress download termination handling ///////////////////////////////// + + // Called when the user has decided whether to proceed or not with the browser + // closure. |cancel_downloads| is true if the downloads should be canceled + // and the browser closed, false if the browser should stay open and the + // downloads running. + void InProgressDownloadResponse(bool cancel_downloads); + // TabStripModel pass-thrus ///////////////////////////////////////////////// TabStripModel* tabstrip_model() const { @@ -551,6 +559,13 @@ class Browser : public TabStripModelDelegate, // successfully fired. void ClearUnloadState(TabContents* tab); + // In-progress download termination handling ///////////////////////////////// + + // Called when the window is closing to check if potential in-progress + // downloads should prevent it from closing. + // Returns true if the window can close, false otherwise. + bool CanCloseWithInProgressDownloads(); + // Assorted utility functions /////////////////////////////////////////////// // Retrieve the last active tabbed browser with the same profile as the @@ -667,6 +682,19 @@ class Browser : public TabStripModelDelegate, // in preparation for closing the browser. bool is_attempting_to_close_browser_; + // In-progress download termination handling ///////////////////////////////// + + enum CancelDownloadConfirmationState { + NOT_PROMPTED, // We have not asked the user. + WAITING_FOR_RESPONSE, // We have asked the user and have not received a + // reponse yet. + RESPONSE_RECEIVED // The user was prompted and made a decision already. + }; + + // State used to figure-out whether we should prompt the user for confirmation + // when the browser is closed with in-progress downloads. + CancelDownloadConfirmationState cancel_download_confirmation_state_; + ///////////////////////////////////////////////////////////////////////////// // Override values for the bounds of the window and its maximized state. diff --git a/chrome/browser/browser_window.h b/chrome/browser/browser_window.h index 50d3dda..e7e8e4f 100644 --- a/chrome/browser/browser_window.h +++ b/chrome/browser/browser_window.h @@ -164,6 +164,12 @@ class BrowserWindow { // Shows the New Profile dialog box. virtual void ShowNewProfileDialog() = 0; + // Shows the confirmation dialog box warning that the browser is closing with + // in-progress downloads. + // This method should call Browser::InProgressDownloadResponse once the user + // has confirmed. + virtual void ConfirmBrowserCloseWithPendingDownloads() = 0; + // Shows a dialog box with HTML content, e.g. for Gears. |parent_window| is // the window the dialog should be opened modal to and is a native window // handle. diff --git a/chrome/browser/cocoa/browser_window_cocoa.h b/chrome/browser/cocoa/browser_window_cocoa.h index c13d779..d673a8d 100644 --- a/chrome/browser/cocoa/browser_window_cocoa.h +++ b/chrome/browser/cocoa/browser_window_cocoa.h @@ -65,6 +65,7 @@ class BrowserWindowCocoa : public BrowserWindow { virtual void ShowPasswordManager(); virtual void ShowSelectProfileDialog(); virtual void ShowNewProfileDialog(); + virtual void ConfirmBrowserCloseWithPendingDownloads(); virtual void ShowHTMLDialog(HtmlDialogUIDelegate* delegate, void* parent_window); diff --git a/chrome/browser/cocoa/browser_window_cocoa.mm b/chrome/browser/cocoa/browser_window_cocoa.mm index 792c2b3..da387cd 100644 --- a/chrome/browser/cocoa/browser_window_cocoa.mm +++ b/chrome/browser/cocoa/browser_window_cocoa.mm @@ -194,6 +194,11 @@ void BrowserWindowCocoa::ShowNewProfileDialog() { NOTIMPLEMENTED(); } +void BrowserWindowCocoa::ConfirmBrowserCloseWithPendingDownloads() { + NOTIMPLEMENTED(); + browser_->InProgressDownloadResponse(false); +} + void BrowserWindowCocoa::ShowHTMLDialog(HtmlDialogUIDelegate* delegate, void* parent_window) { NOTIMPLEMENTED(); diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc index d8417ab..70ed15d 100644 --- a/chrome/browser/gtk/browser_window_gtk.cc +++ b/chrome/browser/gtk/browser_window_gtk.cc @@ -486,6 +486,11 @@ void BrowserWindowGtk::ShowHTMLDialog(HtmlDialogUIDelegate* delegate, NOTIMPLEMENTED(); } +void BrowserWindowGtk::ConfirmBrowserCloseWithPendingDownloads() { + NOTIMPLEMENTED(); + browser_->InProgressDownloadResponse(false); +} + void BrowserWindowGtk::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { diff --git a/chrome/browser/gtk/browser_window_gtk.h b/chrome/browser/gtk/browser_window_gtk.h index 2629fb1..e7d87cf 100644 --- a/chrome/browser/gtk/browser_window_gtk.h +++ b/chrome/browser/gtk/browser_window_gtk.h @@ -76,6 +76,7 @@ class BrowserWindowGtk : public BrowserWindow, virtual void ShowPasswordManager(); virtual void ShowSelectProfileDialog(); virtual void ShowNewProfileDialog(); + virtual void ConfirmBrowserCloseWithPendingDownloads(); virtual void ShowHTMLDialog(HtmlDialogUIDelegate* delegate, void* parent_window); diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index b746436..260b891 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -12,6 +12,7 @@ #include "chrome/browser/bookmarks/bookmark_utils.h" #include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" +#include "chrome/browser/download/download_manager.h" #include "chrome/browser/encoding_menu_controller_delegate.h" #include "chrome/browser/find_bar_controller.h" #include "chrome/browser/view_ids.h" @@ -53,6 +54,7 @@ #include "chrome/common/resource_bundle.h" #include "chrome/common/win_util.h" #include "chrome/views/controls/scrollbar/native_scroll_bar.h" +#include "chrome/views/fill_layout.h" #include "chrome/views/view.h" #include "chrome/views/widget/hwnd_notification_source.h" #include "chrome/views/widget/root_view.h" @@ -191,6 +193,73 @@ class ResizeCorner : public views::View { DISALLOW_COPY_AND_ASSIGN(ResizeCorner); }; +//////////////////////////////////////////////////////////////////////////////// +// DownloadInProgressConfirmDialogDelegate + +class DownloadInProgressConfirmDialogDelegate : public views::DialogDelegate, + public views::View { + public: + explicit DownloadInProgressConfirmDialogDelegate(Browser* browser) + : browser_(browser) { + int download_count = browser->profile()->GetDownloadManager()-> + in_progress_count(); + label_ = new views::Label(l10n_util::GetStringF( + IDS_DOWNLOAD_REMOVE_CONFIRM_TITLE, download_count)); + label_->SetMultiLine(true); + label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + label_->set_border(views::Border::CreateEmptyBorder(10, 10, 10, 10)); + AddChildView(label_); + SetParentOwned(false); + SetLayoutManager(new views::FillLayout()); + } + + // View implementation: + virtual gfx::Size GetPreferredSize() { + const int kContentWidth = 400; + return gfx::Size(kContentWidth, label_->GetHeightForWidth(kContentWidth)); + } + + // DialogDelegate implementation: + virtual int GetDefaultDialogButton() const { + return DIALOGBUTTON_CANCEL; + } + + virtual std::wstring GetDialogButtonLabel(DialogButton button) const { + if (button == DIALOGBUTTON_OK) + return l10n_util::GetString(IDS_DOWNLOAD_REMOVE_CONFIRM_OK_BUTTON_LABEL); + + DCHECK_EQ(DIALOGBUTTON_CANCEL, button); + return l10n_util::GetString( + IDS_DOWNLOAD_REMOVE_CONFIRM_CANCEL_BUTTON_LABEL); + } + + virtual bool Accept() { + browser_->InProgressDownloadResponse(true); + return true; + } + + virtual bool Cancel() { + browser_->InProgressDownloadResponse(false); + return true; + } + + virtual void DeleteDelegate() { + delete this; + } + + // WindowDelegate implementation: + virtual bool IsModal() const { return true; } + + virtual views::View* GetContentsView() { + return this; + } + + private: + Browser* browser_; + views::Label* label_; + + DISALLOW_COPY_AND_ASSIGN(DownloadInProgressConfirmDialogDelegate); +}; /////////////////////////////////////////////////////////////////////////////// // BrowserView, public: @@ -822,6 +891,13 @@ void BrowserView::ShowNewProfileDialog() { NewProfileDialog::RunDialog(); } +void BrowserView::ConfirmBrowserCloseWithPendingDownloads() { + DownloadInProgressConfirmDialogDelegate* delegate = + new DownloadInProgressConfirmDialogDelegate(browser_.get()); + views::Window::CreateChromeWindow(GetWidget()->GetNativeView(), gfx::Rect(), + delegate)->Show(); +} + void BrowserView::ShowHTMLDialog(HtmlDialogUIDelegate* delegate, void* parent_window) { HWND parent_hwnd = reinterpret_cast<HWND>(parent_window); diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h index f95c0fa..5479cdc 100644 --- a/chrome/browser/views/frame/browser_view.h +++ b/chrome/browser/views/frame/browser_view.h @@ -205,6 +205,7 @@ class BrowserView : public BrowserWindow, virtual void ShowPasswordManager(); virtual void ShowSelectProfileDialog(); virtual void ShowNewProfileDialog(); + virtual void ConfirmBrowserCloseWithPendingDownloads(); virtual void ShowHTMLDialog(HtmlDialogUIDelegate* delegate, void* parent_window); diff --git a/chrome/test/test_browser_window.h b/chrome/test/test_browser_window.h index 2be1bd7..7a8ad17 100644 --- a/chrome/test/test_browser_window.h +++ b/chrome/test/test_browser_window.h @@ -59,6 +59,7 @@ class TestBrowserWindow : public BrowserWindow { virtual void ShowPasswordManager() {} virtual void ShowSelectProfileDialog() {} virtual void ShowNewProfileDialog() {} + virtual void ConfirmBrowserCloseWithPendingDownloads() {} virtual void ShowHTMLDialog(HtmlDialogUIDelegate* delegate, void* parent_window) {} protected: |