diff options
author | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-20 17:12:56 +0000 |
---|---|---|
committer | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-20 17:12:56 +0000 |
commit | 029ad376f9f1c5d8e04ac49d6c86f84cfed4cc37 (patch) | |
tree | e1e5d0c4f72384450c8c646a04b04b7730a1ca33 /chrome | |
parent | 63e6f83268772fd27144a82470d552967b1ca244 (diff) | |
download | chromium_src-029ad376f9f1c5d8e04ac49d6c86f84cfed4cc37.zip chromium_src-029ad376f9f1c5d8e04ac49d6c86f84cfed4cc37.tar.gz chromium_src-029ad376f9f1c5d8e04ac49d6c86f84cfed4cc37.tar.bz2 |
CrOS - Change file browser to use new ExtensionDialog window.
The CrOS file browser was initially built to use HtmlDialogView, which does not really understand extensions. This CL implements an ExtensionDialog similar to an ExtensionPopup, and uses it for the file browser. This allows us to return to using window.close() in the file manager extension JavaScript and hopefully will make the file browser less brittle going forward.
BUG=chromium-os:15415
TEST=Hit control-O to open files. Try opening a file, canceling with the cancel button, and canceling with escape. Do the same with "save as" for images. Automated tests to follow.
Review URL: http://codereview.chromium.org/7034046
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@86099 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
18 files changed, 398 insertions, 235 deletions
diff --git a/chrome/browser/extensions/extension_file_browser_private_api.cc b/chrome/browser/extensions/extension_file_browser_private_api.cc index b8552ef..0be5fa8 100644 --- a/chrome/browser/extensions/extension_file_browser_private_api.cc +++ b/chrome/browser/extensions/extension_file_browser_private_api.cc @@ -24,7 +24,6 @@ #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/prefs/scoped_user_pref_update.h" #include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/views/html_dialog_view.h" #include "chrome/browser/ui/webui/extension_icon_source.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" @@ -765,7 +764,7 @@ FileDialogFunction::~FileDialogFunction() { // static FileDialogFunction::Callback -FileDialogFunction::Callback::null_(NULL, NULL, NULL); +FileDialogFunction::Callback::null_(NULL, NULL); // static FileDialogFunction::Callback::Map FileDialogFunction::Callback::map_; @@ -773,10 +772,9 @@ FileDialogFunction::Callback::Map FileDialogFunction::Callback::map_; // static void FileDialogFunction::Callback::Add(int32 tab_id, SelectFileDialog::Listener* listener, - HtmlDialogView* dialog, void* params) { if (map_.find(tab_id) == map_.end()) { - map_.insert(std::make_pair(tab_id, Callback(listener, dialog, params))); + map_.insert(std::make_pair(tab_id, Callback(listener, params))); } else { DLOG_ASSERT("FileDialogFunction::AddCallback tab_id already present"); } @@ -796,25 +794,23 @@ FileDialogFunction::Callback::Find(int32 tab_id) { int32 FileDialogFunction::GetTabId() const { - return dispatcher()->delegate()->GetAssociatedTabContents()-> - controller().session_id().id(); + int32 tab_id = 0; + // TODO(jamescook): This is going to fail when we switch to tab-modal + // dialogs. Figure out a way to find which SelectFileDialog::Listener + // to call from inside these extension FileDialogFunctions. + Browser* browser = const_cast<FileDialogFunction*>(this)->GetCurrentBrowser(); + if (browser) { + TabContents* contents = browser->GetSelectedTabContents(); + if (contents) + tab_id = ExtensionTabUtil::GetTabId(contents); + } + return tab_id; } const FileDialogFunction::Callback& FileDialogFunction::GetCallback() const { - if (!dispatcher() || !dispatcher()->delegate() || - !dispatcher()->delegate()->GetAssociatedTabContents()) { - return Callback::null(); - } return Callback::Find(GetTabId()); } -void FileDialogFunction::CloseDialog(HtmlDialogView* dialog) { - DCHECK(dialog); - TabContents* contents = dispatcher()->delegate()->GetAssociatedTabContents(); - if (contents) - dialog->CloseContents(contents); -} - // GetFileSystemRootPathOnFileThread can only be called from the file thread, // so here we are. This function takes a vector of virtual paths, converts // them to local paths and calls GetLocalPathsResponseOnUIThread with the @@ -898,9 +894,6 @@ void SelectFileFunction::GetLocalPathsResponseOnUIThread( const Callback& callback = GetCallback(); DCHECK(!callback.IsNull()); if (!callback.IsNull()) { - // Must do this before callback, as the callback may delete listeners - // waiting for window close. - CloseDialog(callback.dialog()); callback.listener()->FileSelected(files[0], index, callback.params()); @@ -997,9 +990,6 @@ void SelectFilesFunction::GetLocalPathsResponseOnUIThread( const Callback& callback = GetCallback(); DCHECK(!callback.IsNull()); if (!callback.IsNull()) { - // Must do this before callback, as the callback may delete listeners - // waiting for window close. - CloseDialog(callback.dialog()); callback.listener()->MultiFilesSelected(files, callback.params()); } SendResponse(true); @@ -1009,9 +999,6 @@ bool CancelFileDialogFunction::RunImpl() { const Callback& callback = GetCallback(); DCHECK(!callback.IsNull()); if (!callback.IsNull()) { - // Must do this before callback, as the callback may delete listeners - // waiting for window close. - CloseDialog(callback.dialog()); callback.listener()->FileSelectionCanceled(callback.params()); } SendResponse(true); diff --git a/chrome/browser/extensions/extension_file_browser_private_api.h b/chrome/browser/extensions/extension_file_browser_private_api.h index 463d51e..207d281 100644 --- a/chrome/browser/extensions/extension_file_browser_private_api.h +++ b/chrome/browser/extensions/extension_file_browser_private_api.h @@ -17,7 +17,6 @@ #include "webkit/fileapi/file_system_callback_dispatcher.h" class GURL; -class HtmlDialogView; // Implements the chrome.fileBrowserPrivate.requestLocalFileSystem method. class RequestLocalFileSystemFunction : public AsyncExtensionFunction { @@ -85,29 +84,23 @@ class FileDialogFunction class Callback { public: Callback(SelectFileDialog::Listener* listener, - HtmlDialogView* dialog, void* params) : listener_(listener), - dialog_(dialog), params_(params) { } SelectFileDialog::Listener* listener() const { return listener_; } - HtmlDialogView* dialog() const { return dialog_; } void* params() const { return params_; } bool IsNull() const { return listener_ == NULL; } static void Add(int32 tab_id, SelectFileDialog::Listener* listener, - HtmlDialogView* dialog, void* params); static void Remove(int32 tab_id); static const Callback& Find(int32 tab_id); static const Callback& null() { return null_; } private: - SelectFileDialog::Listener* listener_; - HtmlDialogView* dialog_; void* params_; // statics. @@ -133,9 +126,6 @@ class FileDialogFunction // Get the callback for the hosting tab. const Callback& GetCallback() const; - // Closes the dialog window containing the file dialog HtmlDialogView. - void CloseDialog(HtmlDialogView* dialog); - private: // Figure out the tab_id of the hosting tab. int32 GetTabId() const; diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index 0a8c7e2..2870cd6 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -351,6 +351,7 @@ void ExtensionHost::DidStopLoading() { bool notify = !did_stop_loading_; did_stop_loading_ = true; if (extension_host_type_ == ViewType::EXTENSION_POPUP || + extension_host_type_ == ViewType::EXTENSION_DIALOG || extension_host_type_ == ViewType::EXTENSION_INFOBAR) { #if defined(TOOLKIT_VIEWS) if (view_.get()) @@ -365,6 +366,9 @@ void ExtensionHost::DidStopLoading() { if (extension_host_type_ == ViewType::EXTENSION_BACKGROUND_PAGE) { UMA_HISTOGRAM_TIMES("Extensions.BackgroundPageLoadTime", since_created_.Elapsed()); + } else if (extension_host_type_ == ViewType::EXTENSION_DIALOG) { + UMA_HISTOGRAM_TIMES("Extensions.DialogLoadTime", + since_created_.Elapsed()); } else if (extension_host_type_ == ViewType::EXTENSION_POPUP) { UMA_HISTOGRAM_TIMES("Extensions.PopupLoadTime", since_created_.Elapsed()); @@ -476,6 +480,7 @@ void ExtensionHost::SetSuppressMessageBoxes(bool suppress_message_boxes) { void ExtensionHost::Close(RenderViewHost* render_view_host) { if (extension_host_type_ == ViewType::EXTENSION_POPUP || + extension_host_type_ == ViewType::EXTENSION_DIALOG || extension_host_type_ == ViewType::EXTENSION_INFOBAR) { NotificationService::current()->Notify( NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, @@ -508,6 +513,7 @@ WebPreferences ExtensionHost::GetWebkitPrefs() { webkit_prefs.javascript_enabled = true; if (extension_host_type_ == ViewType::EXTENSION_POPUP || + extension_host_type_ == ViewType::EXTENSION_DIALOG || extension_host_type_ == ViewType::EXTENSION_INFOBAR) webkit_prefs.allow_scripts_to_close_windows = true; @@ -790,6 +796,7 @@ int ExtensionHost::GetBrowserWindowID() const { // those mentioned below, and background pages. int window_id = extension_misc::kUnknownWindowId; if (extension_host_type_ == ViewType::EXTENSION_POPUP || + extension_host_type_ == ViewType::EXTENSION_DIALOG || extension_host_type_ == ViewType::EXTENSION_INFOBAR) { // If the host is bound to a browser, then extract its window id. // Extensions hosted in ExternalTabContainer objects may not have diff --git a/chrome/browser/extensions/extension_infobar_delegate.cc b/chrome/browser/extensions/extension_infobar_delegate.cc index c9fdca2..25d7152 100644 --- a/chrome/browser/extensions/extension_infobar_delegate.cc +++ b/chrome/browser/extensions/extension_infobar_delegate.cc @@ -25,7 +25,7 @@ ExtensionInfoBarDelegate::ExtensionInfoBarDelegate(Browser* browser, closing_(false) { ExtensionProcessManager* manager = browser->profile()->GetExtensionProcessManager(); - extension_host_.reset(manager->CreateInfobar(url, browser)); + extension_host_.reset(manager->CreateInfobarHost(url, browser)); extension_host_->set_associated_tab_contents(tab_contents); registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc index 8a37287..4be0f74 100644 --- a/chrome/browser/extensions/extension_process_manager.cc +++ b/chrome/browser/extensions/extension_process_manager.cc @@ -29,10 +29,10 @@ class IncognitoExtensionProcessManager : public ExtensionProcessManager { public: explicit IncognitoExtensionProcessManager(Profile* profile); virtual ~IncognitoExtensionProcessManager() {} - virtual ExtensionHost* CreateView(const Extension* extension, - const GURL& url, - Browser* browser, - ViewType::Type view_type); + virtual ExtensionHost* CreateViewHost(const Extension* extension, + const GURL& url, + Browser* browser, + ViewType::Type view_type) OVERRIDE; virtual void CreateBackgroundHost(const Extension* extension, const GURL& url); virtual SiteInstance* GetSiteInstanceForURL(const GURL& url); @@ -109,10 +109,11 @@ ExtensionProcessManager::~ExtensionProcessManager() { DCHECK(background_hosts_.empty()); } -ExtensionHost* ExtensionProcessManager::CreateView(const Extension* extension, - const GURL& url, - Browser* browser, - ViewType::Type view_type) { +ExtensionHost* ExtensionProcessManager::CreateViewHost( + const Extension* extension, + const GURL& url, + Browser* browser, + ViewType::Type view_type) { DCHECK(extension); // A NULL browser may only be given for pop-up views. DCHECK(browser || (!browser && view_type == ViewType::EXTENSION_POPUP)); @@ -128,9 +129,8 @@ ExtensionHost* ExtensionProcessManager::CreateView(const Extension* extension, return host; } -ExtensionHost* ExtensionProcessManager::CreateView(const GURL& url, - Browser* browser, - ViewType::Type view_type) { +ExtensionHost* ExtensionProcessManager::CreateViewHost( + const GURL& url, Browser* browser, ViewType::Type view_type) { // A NULL browser may only be given for pop-up views. DCHECK(browser || (!browser && view_type == ViewType::EXTENSION_POPUP)); ExtensionService* service = @@ -138,30 +138,34 @@ ExtensionHost* ExtensionProcessManager::CreateView(const GURL& url, if (service) { const Extension* extension = service->GetExtensionByURL(url); if (extension) - return CreateView(extension, url, browser, view_type); + return CreateViewHost(extension, url, browser, view_type); } return NULL; } -ExtensionHost* ExtensionProcessManager::CreatePopup(const Extension* extension, - const GURL& url, - Browser* browser) { - return CreateView(extension, url, browser, ViewType::EXTENSION_POPUP); +ExtensionHost* ExtensionProcessManager::CreatePopupHost( + const Extension* extension, const GURL& url, Browser* browser) { + return CreateViewHost(extension, url, browser, ViewType::EXTENSION_POPUP); +} + +ExtensionHost* ExtensionProcessManager::CreatePopupHost( + const GURL& url, Browser* browser) { + return CreateViewHost(url, browser, ViewType::EXTENSION_POPUP); } -ExtensionHost* ExtensionProcessManager::CreatePopup(const GURL& url, - Browser* browser) { - return CreateView(url, browser, ViewType::EXTENSION_POPUP); +ExtensionHost* ExtensionProcessManager::CreateDialogHost( + const GURL& url, Browser* browser) { + return CreateViewHost(url, browser, ViewType::EXTENSION_DIALOG); } -ExtensionHost* ExtensionProcessManager::CreateInfobar( +ExtensionHost* ExtensionProcessManager::CreateInfobarHost( const Extension* extension, const GURL& url, Browser* browser) { - return CreateView(extension, url, browser, ViewType::EXTENSION_INFOBAR); + return CreateViewHost(extension, url, browser, ViewType::EXTENSION_INFOBAR); } -ExtensionHost* ExtensionProcessManager::CreateInfobar(const GURL& url, - Browser* browser) { - return CreateView(url, browser, ViewType::EXTENSION_INFOBAR); +ExtensionHost* ExtensionProcessManager::CreateInfobarHost( + const GURL& url, Browser* browser) { + return CreateViewHost(url, browser, ViewType::EXTENSION_INFOBAR); } void ExtensionProcessManager::CreateBackgroundHost( @@ -365,15 +369,15 @@ IncognitoExtensionProcessManager::IncognitoExtensionProcessManager( NotificationService::AllSources()); } -ExtensionHost* IncognitoExtensionProcessManager::CreateView( +ExtensionHost* IncognitoExtensionProcessManager::CreateViewHost( const Extension* extension, const GURL& url, Browser* browser, ViewType::Type view_type) { if (extension->incognito_split_mode()) { if (IsIncognitoEnabled(extension)) { - return ExtensionProcessManager::CreateView(extension, url, - browser, view_type); + return ExtensionProcessManager::CreateViewHost(extension, url, + browser, view_type); } else { NOTREACHED() << "We shouldn't be trying to create an incognito extension view unless " @@ -381,7 +385,8 @@ ExtensionHost* IncognitoExtensionProcessManager::CreateView( return NULL; } } else { - return original_manager_->CreateView(extension, url, browser, view_type); + return original_manager_->CreateViewHost(extension, url, + browser, view_type); } } diff --git a/chrome/browser/extensions/extension_process_manager.h b/chrome/browser/extensions/extension_process_manager.h index 1fc1bb5..8bf5e77 100644 --- a/chrome/browser/extensions/extension_process_manager.h +++ b/chrome/browser/extensions/extension_process_manager.h @@ -35,27 +35,28 @@ class ExtensionProcessManager : public NotificationObserver { // Creates a new ExtensionHost with its associated view, grouping it in the // appropriate SiteInstance (and therefore process) based on the URL and // profile. - virtual ExtensionHost* CreateView(const Extension* extension, - const GURL& url, - Browser* browser, - ViewType::Type view_type); - ExtensionHost* CreateView(const GURL& url, - Browser* browser, - ViewType::Type view_type); - ExtensionHost* CreatePopup(const Extension* extension, - const GURL& url, - Browser* browser); - ExtensionHost* CreatePopup(const GURL& url, Browser* browser); - ExtensionHost* CreateInfobar(const Extension* extension, - const GURL& url, - Browser* browser); - ExtensionHost* CreateInfobar(const GURL& url, - Browser* browser); + virtual ExtensionHost* CreateViewHost(const Extension* extension, + const GURL& url, + Browser* browser, + ViewType::Type view_type); + ExtensionHost* CreateViewHost(const GURL& url, + Browser* browser, + ViewType::Type view_type); + ExtensionHost* CreatePopupHost(const Extension* extension, + const GURL& url, + Browser* browser); + ExtensionHost* CreatePopupHost(const GURL& url, Browser* browser); + ExtensionHost* CreateDialogHost(const GURL& url, Browser* browser); + ExtensionHost* CreateInfobarHost(const Extension* extension, + const GURL& url, + Browser* browser); + ExtensionHost* CreateInfobarHost(const GURL& url, + Browser* browser); // Open the extension's options page. void OpenOptionsPage(const Extension* extension, Browser* browser); - // Creates a new UI-less extension instance. Like CreateView, but not + // Creates a new UI-less extension instance. Like CreateViewHost, but not // displayed anywhere. virtual void CreateBackgroundHost(const Extension* extension, const GURL& url); diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc index 813461a..bd936a0 100644 --- a/chrome/browser/extensions/extensions_ui.cc +++ b/chrome/browser/extensions/extensions_ui.cc @@ -785,7 +785,8 @@ void ExtensionsDOMHandler::GetActivePagesForExtensionProcess( continue; const RenderViewHost* host = static_cast<const RenderViewHost*>(widget); if (host == deleting_rvh_ || - ViewType::EXTENSION_POPUP == host->delegate()->GetRenderViewType()) + ViewType::EXTENSION_POPUP == host->delegate()->GetRenderViewType() || + ViewType::EXTENSION_DIALOG == host->delegate()->GetRenderViewType()) continue; GURL url = host->delegate()->GetURL(); diff --git a/chrome/browser/resources/file_manager/js/file_manager.js b/chrome/browser/resources/file_manager/js/file_manager.js index 2da4679..b96ecd9 100644 --- a/chrome/browser/resources/file_manager/js/file_manager.js +++ b/chrome/browser/resources/file_manager/js/file_manager.js @@ -1871,6 +1871,11 @@ FileManager.prototype = { } break; + case 27: // Escape => Cancel dialog. + event.preventDefault(); + this.onCancel_(); + break; + case 32: // Ctrl-Space => New Folder. if (this.newFolderButton_.style.display != 'none' && event.ctrlKey) { event.preventDefault(); @@ -1902,6 +1907,7 @@ FileManager.prototype = { */ FileManager.prototype.onCancel_ = function(event) { chrome.fileBrowserPrivate.cancelDialog(); + window.close(); }; /** @@ -1927,7 +1933,7 @@ FileManager.prototype = { chrome.fileBrowserPrivate.selectFile(currentDirUrl + encodeURI(filename), 0); - // Window closed by above call. + window.close(); return; } @@ -1953,7 +1959,7 @@ FileManager.prototype = { // Multi-file selection has no other restrictions. if (this.dialogType_ == FileManager.DialogType.SELECT_OPEN_MULTI_FILE) { chrome.fileBrowserPrivate.selectFiles(ary); - // Window closed by above call. + window.close(); return; } @@ -1977,7 +1983,7 @@ FileManager.prototype = { } chrome.fileBrowserPrivate.selectFile(ary[0], 0); - // Window closed by above call. + window.close(); }; })(); diff --git a/chrome/browser/ui/gtk/extensions/extension_popup_gtk.cc b/chrome/browser/ui/gtk/extensions/extension_popup_gtk.cc index ccd4979..995e619 100644 --- a/chrome/browser/ui/gtk/extensions/extension_popup_gtk.cc +++ b/chrome/browser/ui/gtk/extensions/extension_popup_gtk.cc @@ -163,7 +163,7 @@ void ExtensionPopupGtk::Show(const GURL& url, Browser* browser, if (!manager) return; - ExtensionHost* host = manager->CreatePopup(url, browser); + ExtensionHost* host = manager->CreatePopupHost(url, browser); // This object will delete itself when the bubble is closed. new ExtensionPopupGtk(browser, host, anchor, inspect); } diff --git a/chrome/browser/ui/shell_dialogs.h b/chrome/browser/ui/shell_dialogs.h index c016f6f..eecaf0b 100644 --- a/chrome/browser/ui/shell_dialogs.h +++ b/chrome/browser/ui/shell_dialogs.h @@ -139,9 +139,6 @@ class SelectFileDialog gfx::NativeWindow owning_window, void* params); - // browser_mode is true when running inside the browser. - virtual void set_browser_mode(bool value) {} - protected: friend class base::RefCountedThreadSafe<SelectFileDialog>; explicit SelectFileDialog(Listener* listener); diff --git a/chrome/browser/ui/views/extensions/extension_dialog.cc b/chrome/browser/ui/views/extensions/extension_dialog.cc new file mode 100644 index 0000000..a2989e9 --- /dev/null +++ b/chrome/browser/ui/views/extensions/extension_dialog.cc @@ -0,0 +1,154 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/extensions/extension_dialog.h" + +#include "chrome/browser/extensions/extension_host.h" +#include "chrome/browser/extensions/extension_process_manager.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/views/bubble/bubble_border.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/common/extensions/extension.h" +#include "content/browser/renderer_host/render_view_host.h" +#include "content/browser/renderer_host/render_widget_host_view.h" +#include "content/common/notification_details.h" +#include "content/common/notification_source.h" +#include "content/common/notification_type.h" +#include "googleurl/src/gurl.h" +#include "views/widget/root_view.h" +#include "views/window/window.h" + +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/wm_ipc.h" +#include "third_party/cros/chromeos_wm_ipc_enums.h" +#endif + +ExtensionDialog::ExtensionDialog(ExtensionHost* host, views::Widget* frame, + const gfx::Rect& relative_to, int width, + int height, Observer* observer) + : BrowserBubble(host->view(), + frame, + relative_to, + BubbleBorder::FLOAT), // Centered over rectangle. + extension_host_(host), + width_(width), + height_(height), + closing_(false), + observer_(observer) { + AddRef(); // Balanced in Close(); + set_delegate(this); + host->view()->SetContainer(this); + + // Listen for the containing view calling window.close(); + registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, + Source<Profile>(host->profile())); + + // Use a fixed-size view. + host->view()->SetBounds(host->view()->x(), host->view()->y(), + width, height); + ResizeToView(); +} + +ExtensionDialog::~ExtensionDialog() { +} + +// static +ExtensionDialog* ExtensionDialog::Show( + const GURL& url, + Browser* browser, + int width, + int height, + Observer* observer) { + CHECK(browser); + ExtensionProcessManager* manager = + browser->profile()->GetExtensionProcessManager(); + DCHECK(manager); + if (!manager) + return NULL; + ExtensionHost* host = manager->CreateDialogHost(url, browser); + views::Widget* frame = BrowserView::GetBrowserViewForNativeWindow( + browser->window()->GetNativeHandle())->GetWidget(); + gfx::Rect relative_to = browser->window()->GetBounds(); + ExtensionDialog* popup = new ExtensionDialog(host, frame, relative_to, width, + height, observer); + popup->Show(true); + + return popup; +} + +void ExtensionDialog::Close() { + if (closing_) + return; + closing_ = true; + DetachFromBrowser(); + + if (observer_) + observer_->ExtensionDialogIsClosing(this); + + Release(); // Balanced in ctor. +} + +void ExtensionDialog::Show(bool activate) { + if (popup_->IsVisible()) + return; + +#if defined(OS_WIN) + frame_->GetContainingWindow()->DisableInactiveRendering(); +#endif + + BrowserBubble::Show(activate); +} + +///////////////////////////////////////////////////////////////////////////// +// BrowserBubble::Delegate methods. + +void ExtensionDialog::BubbleBrowserWindowMoved(BrowserBubble* bubble) { +} + +void ExtensionDialog::BubbleBrowserWindowClosing(BrowserBubble* bubble) { + if (!closing_) + Close(); +} + +void ExtensionDialog::BubbleGotFocus(BrowserBubble* bubble) { + // Forward the focus to the renderer. + host()->render_view_host()->view()->Focus(); +} + +void ExtensionDialog::BubbleLostFocus(BrowserBubble* bubble, + bool lost_focus_to_child) { +} + +///////////////////////////////////////////////////////////////////////////// +// ExtensionView::Container overrides. + +void ExtensionDialog::OnExtensionMouseMove(ExtensionView* view) { +} + +void ExtensionDialog::OnExtensionMouseLeave(ExtensionView* view) { +} + +void ExtensionDialog::OnExtensionPreferredSizeChanged(ExtensionView* view) { +} + +///////////////////////////////////////////////////////////////////////////// +// NotificationObserver overrides. + +void ExtensionDialog::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + switch (type.value) { + case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: + // If we aren't the host of the popup, then disregard the notification. + if (Details<ExtensionHost>(host()) != details) + return; + Close(); + break; + default: + NOTREACHED() << L"Received unexpected notification"; + break; + } +} diff --git a/chrome/browser/ui/views/extensions/extension_dialog.h b/chrome/browser/ui/views/extensions/extension_dialog.h new file mode 100644 index 0000000..8a545ee --- /dev/null +++ b/chrome/browser/ui/views/extensions/extension_dialog.h @@ -0,0 +1,102 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSION_DIALOG_H_ +#define CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSION_DIALOG_H_ +#pragma once + +#include "base/memory/ref_counted.h" +#include "chrome/browser/extensions/extension_host.h" +#include "chrome/browser/ui/views/browser_bubble.h" +#include "chrome/browser/ui/views/extensions/extension_view.h" +#include "content/common/notification_observer.h" + +class Browser; +class ExtensionHost; +class GURL; +class Profile; + +namespace views { +class Widget; +} + +// Modal dialog containing contents provided by an extension. +// Dialog is automatically centered in the browser window and has fixed size. +// For example, used by the Chrome OS file browser. +// TODO(jamescook): This feels odd as a BrowserBubble. Factor out a common +// base class for ExtensionDialog and BrowserBubble. +class ExtensionDialog : public BrowserBubble, + public BrowserBubble::Delegate, + public ExtensionView::Container, + public NotificationObserver, + public base::RefCounted<ExtensionDialog> { + public: + // Observer to ExtensionDialog events. + class Observer { + public: + // Called when the ExtensionDialog is closing. Note that it + // is ref-counted, and thus will be released shortly after + // making this delegate call. + virtual void ExtensionDialogIsClosing(ExtensionDialog* popup) = 0; + }; + + virtual ~ExtensionDialog(); + + // Create and show a dialog with |url| centered over the browser window. + // |browser| is the browser to which the pop-up will be attached. + // |width| and |height| are the size of the dialog in pixels. + static ExtensionDialog* Show(const GURL& url, Browser* browser, + int width, + int height, + Observer* observer); + + // Closes the ExtensionDialog. + void Close(); + + ExtensionHost* host() const { return extension_host_.get(); } + + // BrowserBubble overrides. + virtual void Show(bool activate); + + // BrowserBubble::Delegate methods. + virtual void BubbleBrowserWindowMoved(BrowserBubble* bubble); + virtual void BubbleBrowserWindowClosing(BrowserBubble* bubble); + virtual void BubbleGotFocus(BrowserBubble* bubble); + virtual void BubbleLostFocus(BrowserBubble* bubble, + bool lost_focus_to_child); + + // ExtensionView::Container overrides. + virtual void OnExtensionMouseMove(ExtensionView* view); + virtual void OnExtensionMouseLeave(ExtensionView* view); + virtual void OnExtensionPreferredSizeChanged(ExtensionView* view); + + // NotificationObserver overrides. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + private: + ExtensionDialog(ExtensionHost* host, views::Widget* frame, + const gfx::Rect& relative_to, int width, int height, + Observer* observer); + + // The contained host for the view. + scoped_ptr<ExtensionHost> extension_host_; + + // Dialog size in pixels. + int width_; + int height_; + + // Whether the ExtensionDialog is current going about closing itself. + bool closing_; + + NotificationRegistrar registrar_; + + // The observer of this popup. + Observer* observer_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionDialog); +}; + +#endif // CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSION_DIALOG_H_ diff --git a/chrome/browser/ui/views/extensions/extension_popup.cc b/chrome/browser/ui/views/extensions/extension_popup.cc index 12f65fe..121f0b7 100644 --- a/chrome/browser/ui/views/extensions/extension_popup.cc +++ b/chrome/browser/ui/views/extensions/extension_popup.cc @@ -186,7 +186,7 @@ ExtensionPopup* ExtensionPopup::Show( if (!manager) return NULL; - ExtensionHost* host = manager->CreatePopup(url, browser); + ExtensionHost* host = manager->CreatePopupHost(url, browser); views::Widget* frame = BrowserView::GetBrowserViewForNativeWindow( browser->window()->GetNativeHandle())->GetWidget(); ExtensionPopup* popup = new ExtensionPopup(host, frame, relative_to, diff --git a/chrome/browser/ui/views/file_manager_dialogs.cc b/chrome/browser/ui/views/file_manager_dialogs.cc index a966fb2..926ffc2 100644 --- a/chrome/browser/ui/views/file_manager_dialogs.cc +++ b/chrome/browser/ui/views/file_manager_dialogs.cc @@ -9,9 +9,8 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/browser_list.h" -#include "chrome/browser/ui/views/html_dialog_view.h" +#include "chrome/browser/ui/views/extensions/extension_dialog.h" #include "chrome/browser/ui/views/window.h" -#include "chrome/browser/ui/webui/html_dialog_ui.h" #include "content/browser/browser_thread.h" #include "content/browser/tab_contents/tab_contents.h" #include "content/browser/user_metrics.h" @@ -19,101 +18,27 @@ #include "ui/gfx/rect.h" #include "ui/gfx/size.h" +namespace { + +const int kFileManagerWidth = 720; // pixels +const int kFileManagerHeight = 580; // pixels + +} + // Shows a dialog box for selecting a file or a folder. class FileManagerDialog : public SelectFileDialog, - public HtmlDialogUIDelegate { + public ExtensionDialog::Observer { public: explicit FileManagerDialog(Listener* listener); - void CreateHtmlDialogView(Profile* profile, void* params) { - HtmlDialogView* html_view = new HtmlDialogView(profile, this); - browser::CreateViewsWindow(owner_window_, gfx::Rect(), html_view); - html_view->InitDialog(); - html_view->window()->Show(); - tab_id_ = html_view->tab_contents()->controller().session_id().id(); - - // Register our callback and associate it with our tab. - FileDialogFunction::Callback::Add(tab_id_, listener_, html_view, params); - } - // BaseShellDialog implementation. + virtual bool IsRunning(gfx::NativeWindow owner_window) const OVERRIDE; + virtual void ListenerDestroyed() OVERRIDE; - virtual bool IsRunning(gfx::NativeWindow owner_window) const { - return owner_window_ == owner_window; - } - - virtual void ListenerDestroyed() { - listener_ = NULL; - FileDialogFunction::Callback::Remove(tab_id_); - } - - // SelectFileDialog implementation. - virtual void set_browser_mode(bool value) { - browser_mode_ = value; - } - - // HtmlDialogUIDelegate implementation. - - virtual bool IsDialogModal() const { - return true; - } - - virtual std::wstring GetDialogTitle() const { - return title_; - } - - virtual GURL GetDialogContentURL() const { - return dialog_url_; - } - - virtual void GetWebUIMessageHandlers( - std::vector<WebUIMessageHandler*>* handlers) const { - } - - // Get the size of the dialog. - virtual void GetDialogSize(gfx::Size* size) const { - size->set_width(720); - size->set_height(580); - } - - virtual std::string GetDialogArgs() const { - return ""; - } - - // A callback to notify the delegate that the dialog closed. - virtual void OnDialogClosed(const std::string& json_retval) { - owner_window_ = NULL; - } - - virtual void OnWindowClosed() { - // Directly closing the window selects no files. - const FileDialogFunction::Callback& callback = - FileDialogFunction::Callback::Find(tab_id_); - if (!callback.IsNull()) - callback.listener()->FileSelectionCanceled(callback.params()); - } - - // A callback to notify the delegate that the contents have gone - // away. Only relevant if your dialog hosts code that calls - // windows.close() and you've allowed that. If the output parameter - // is set to true, then the dialog is closed. The default is false. - virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) { - *out_close_dialog = true; - } - - // A callback to allow the delegate to dictate that the window should not - // have a title bar. This is useful when presenting branded interfaces. - virtual bool ShouldShowDialogTitle() const { - return false; - } - - // A callback to allow the delegate to inhibit context menu or show - // customized menu. - virtual bool HandleContextMenu(const ContextMenuParams& params) { - return true; - } + // ExtensionDialog::Observer implementation. + virtual void ExtensionDialogIsClosing(ExtensionDialog* dialog) OVERRIDE; protected: // SelectFileDialog implementation. @@ -124,23 +49,15 @@ class FileManagerDialog int file_type_index, const FilePath::StringType& default_extension, gfx::NativeWindow owning_window, - void* params); + void* params) OVERRIDE; private: virtual ~FileManagerDialog() {} int32 tab_id_; - // True when opening in browser, otherwise in OOBE/login mode. - bool browser_mode_; - gfx::NativeWindow owner_window_; - std::wstring title_; - - // Base url plus query string. - GURL dialog_url_; - DISALLOW_COPY_AND_ASSIGN(FileManagerDialog); }; @@ -155,10 +72,22 @@ SelectFileDialog* SelectFileDialog::Create(Listener* listener) { FileManagerDialog::FileManagerDialog(Listener* listener) : SelectFileDialog(listener), tab_id_(0), - browser_mode_(true), owner_window_(0) { } +bool FileManagerDialog::IsRunning(gfx::NativeWindow owner_window) const { + return owner_window_ == owner_window; +} + +void FileManagerDialog::ListenerDestroyed() { + listener_ = NULL; + FileDialogFunction::Callback::Remove(tab_id_); +} + +void FileManagerDialog::ExtensionDialogIsClosing(ExtensionDialog* dialog) { + owner_window_ = NULL; +} + void FileManagerDialog::SelectFileImpl( Type type, const string16& title, @@ -168,32 +97,27 @@ void FileManagerDialog::SelectFileImpl( const FilePath::StringType& default_extension, gfx::NativeWindow owner_window, void* params) { - if (owner_window_) { LOG(ERROR) << "File dialog already in use!"; return; } + Browser* active_browser = BrowserList::GetLastActive(); + if (!active_browser) + return; - title_ = UTF16ToWide(title); - owner_window_ = owner_window; - - dialog_url_ = FileManagerUtil::GetFileBrowserUrlWithParams(type, title, - default_path, file_types, file_type_index, default_extension); + GURL file_browser_url = FileManagerUtil::GetFileBrowserUrlWithParams( + type, title, default_path, file_types, file_type_index, + default_extension); + ExtensionDialog* dialog = ExtensionDialog::Show(file_browser_url, + active_browser, kFileManagerWidth, kFileManagerHeight, + this /* ExtensionDialog::Observer */); - if (browser_mode_) { - Browser* browser = BrowserList::GetLastActive(); - if (browser) { - DCHECK_EQ(browser->type(), Browser::TYPE_TABBED); - CreateHtmlDialogView(browser->profile(), params); - return; - } - } + // Connect our listener to FileDialogFunction's per-tab callbacks. + Browser* extension_browser = dialog->host()->view()->browser(); + TabContents* contents = extension_browser->GetSelectedTabContents(); + int32 tab_id = (contents ? contents->controller().session_id().id() : 0); + FileDialogFunction::Callback::Add(tab_id, listener_, params); - BrowserThread::PostTask( - BrowserThread::UI, - FROM_HERE, - NewRunnableMethod(this, - &FileManagerDialog::CreateHtmlDialogView, - ProfileManager::GetDefaultProfile(), params)); + tab_id_ = tab_id; + owner_window_ = owner_window; } - diff --git a/chrome/browser/ui/views/select_file_dialog.cc b/chrome/browser/ui/views/select_file_dialog.cc index fba4762..563707c 100644 --- a/chrome/browser/ui/views/select_file_dialog.cc +++ b/chrome/browser/ui/views/select_file_dialog.cc @@ -43,10 +43,6 @@ class SelectFileDialogImpl : public SelectFileDialog { virtual bool IsRunning(gfx::NativeWindow parent_window) const; virtual void ListenerDestroyed(); - virtual void set_browser_mode(bool value) { - browser_mode_ = value; - } - protected: // SelectFileDialog implementation. // |params| is user data we pass back via the Listener interface. @@ -153,9 +149,6 @@ class SelectFileDialogImpl : public SelectFileDialog { // The set of all FileBrowseDelegate that we are currently running. std::set<FileBrowseDelegate*> delegates_; - // True when opening in browser, otherwise in OOBE/login mode. - bool browser_mode_; - DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImpl); }; @@ -167,8 +160,7 @@ SelectFileDialog* SelectFileDialog::Create(Listener* listener) { } SelectFileDialogImpl::SelectFileDialogImpl(Listener* listener) - : SelectFileDialog(listener), - browser_mode_(true) { + : SelectFileDialog(listener) { } SelectFileDialogImpl::~SelectFileDialogImpl() { @@ -224,21 +216,11 @@ void SelectFileDialogImpl::SelectFileImpl( default_extension, owning_window, params); delegates_.insert(file_browse_delegate); - if (browser_mode_) { - Browser* browser = BrowserList::GetLastActive(); - // As SelectFile may be invoked after a delay, it is entirely possible for - // it be invoked when no browser is around. Silently ignore this case. - if (browser) - browser->BrowserShowHtmlDialog(file_browse_delegate, owning_window); - } else { - BrowserThread::PostTask( - BrowserThread::UI, - FROM_HERE, - NewRunnableMethod(this, - &SelectFileDialogImpl::OpenHtmlDialog, - owning_window, - file_browse_delegate)); - } + Browser* browser = BrowserList::GetLastActive(); + // As SelectFile may be invoked after a delay, it is entirely possible for + // it be invoked when no browser is around. Silently ignore this case. + if (browser) + browser->BrowserShowHtmlDialog(file_browse_delegate, owning_window); } void SelectFileDialogImpl::OnDialogClosed(FileBrowseDelegate* delegate, diff --git a/chrome/browser/ui/webui/options/extension_settings_handler.cc b/chrome/browser/ui/webui/options/extension_settings_handler.cc index 7f0e369..bfc2ea7 100644 --- a/chrome/browser/ui/webui/options/extension_settings_handler.cc +++ b/chrome/browser/ui/webui/options/extension_settings_handler.cc @@ -864,7 +864,8 @@ void ExtensionsDOMHandler::GetActivePagesForExtensionProcess( continue; const RenderViewHost* host = static_cast<const RenderViewHost*>(widget); if (host == deleting_rvh_ || - ViewType::EXTENSION_POPUP == host->delegate()->GetRenderViewType()) + ViewType::EXTENSION_POPUP == host->delegate()->GetRenderViewType() || + ViewType::EXTENSION_DIALOG == host->delegate()->GetRenderViewType()) continue; GURL url = host->delegate()->GetURL(); diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 487ff92..55e7d36 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2986,6 +2986,8 @@ 'browser/ui/views/extensions/browser_action_drag_data.h', 'browser/ui/views/extensions/browser_action_overflow_menu_controller.cc', 'browser/ui/views/extensions/browser_action_overflow_menu_controller.h', + 'browser/ui/views/extensions/extension_dialog.cc', + 'browser/ui/views/extensions/extension_dialog.h', 'browser/ui/views/extensions/extension_install_dialog_view.cc', 'browser/ui/views/extensions/extension_installed_bubble.cc', 'browser/ui/views/extensions/extension_installed_bubble.h', @@ -4053,6 +4055,8 @@ ['include', '^browser/ui/views/extensions/browser_action_drag_data.h'], ['include', '^browser/ui/views/extensions/browser_action_overflow_menu_controller.cc'], ['include', '^browser/ui/views/extensions/browser_action_overflow_menu_controller.h'], + ['include', '^browser/ui/views/extensions/extension_dialog.cc'], + ['include', '^browser/ui/views/extensions/extension_dialog.h'], ['include', '^browser/ui/views/extensions/extension_install_dialog_view.cc'], ['include', '^browser/ui/views/extensions/extension_installed_bubble.cc'], ['include', '^browser/ui/views/extensions/extension_installed_bubble.h'], diff --git a/chrome/renderer/extensions/extension_process_bindings.cc b/chrome/renderer/extensions/extension_process_bindings.cc index efe5594..3c1b717 100644 --- a/chrome/renderer/extensions/extension_process_bindings.cc +++ b/chrome/renderer/extensions/extension_process_bindings.cc @@ -220,6 +220,8 @@ class ExtensionImpl : public ExtensionBase { view_type = ViewType::TAB_CONTENTS; } else if (view_type_string == ViewType::kPopup) { view_type = ViewType::EXTENSION_POPUP; + } else if (view_type_string == ViewType::kExtensionDialog) { + view_type = ViewType::EXTENSION_DIALOG; } else if (view_type_string != ViewType::kAll) { return v8::Undefined(); } |