blob: dcf1cd296ea3abc8ab71cda44fa65121a5497fe5 [file] [log] [blame]
// Copyright (c) 2012 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 "ui/views/controls/webview/web_dialog_view.h"
#include <vector>
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/widget.h"
#include "ui/web_dialogs/web_dialog_delegate.h"
#include "ui/web_dialogs/web_dialog_ui.h"
using content::NativeWebKeyboardEvent;
using content::WebContents;
using content::WebUIMessageHandler;
using ui::WebDialogDelegate;
using ui::WebDialogUIBase;
using ui::WebDialogWebContentsDelegate;
namespace views {
////////////////////////////////////////////////////////////////////////////////
// WebDialogView, public:
WebDialogView::WebDialogView(content::BrowserContext* context,
WebDialogDelegate* delegate,
WebContentsHandler* handler)
: ClientView(nullptr, nullptr),
WebDialogWebContentsDelegate(context, handler),
delegate_(delegate),
web_view_(new views::WebView(context)) {
web_view_->set_allow_accelerators(true);
AddChildView(web_view_);
set_contents_view(web_view_);
SetLayoutManager(std::make_unique<views::FillLayout>());
// Pressing the ESC key will close the dialog.
AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
if (delegate_) {
for (const auto& accelerator : delegate_->GetAccelerators())
AddAccelerator(accelerator);
}
}
WebDialogView::~WebDialogView() {
}
content::WebContents* WebDialogView::web_contents() {
return web_view_->web_contents();
}
////////////////////////////////////////////////////////////////////////////////
// WebDialogView, views::View implementation:
gfx::Size WebDialogView::CalculatePreferredSize() const {
gfx::Size out;
if (delegate_)
delegate_->GetDialogSize(&out);
return out;
}
gfx::Size WebDialogView::GetMinimumSize() const {
gfx::Size out;
if (delegate_)
delegate_->GetMinimumDialogSize(&out);
return out;
}
bool WebDialogView::AcceleratorPressed(const ui::Accelerator& accelerator) {
if (delegate_ && delegate_->AcceleratorPressed(accelerator))
return true;
// Pressing ESC closes the dialog.
DCHECK_EQ(ui::VKEY_ESCAPE, accelerator.key_code());
if (GetWidget())
GetWidget()->Close();
return true;
}
void WebDialogView::ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) {
if (details.is_add && GetWidget())
InitDialog();
}
bool WebDialogView::CanClose() {
// Don't close UI if |delegate_| does not allow users to close it by
// clicking on "x" button or pressing Esc shortcut key on hosting dialog.
if (!delegate_->CanCloseDialog() && !close_contents_called_)
return false;
// If CloseContents() is called before CanClose(), which is called by
// RenderViewHostImpl::ClosePageIgnoringUnloadEvents, it indicates
// beforeunload event should not be fired during closing.
if ((is_attempting_close_dialog_ && before_unload_fired_) ||
close_contents_called_) {
is_attempting_close_dialog_ = false;
before_unload_fired_ = false;
return true;
}
if (!is_attempting_close_dialog_) {
// Fire beforeunload event when user attempts to close the dialog.
is_attempting_close_dialog_ = true;
web_view_->web_contents()->DispatchBeforeUnload(false /* auto_cancel */);
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
// WebDialogView, views::WidgetDelegate implementation:
bool WebDialogView::CanResize() const {
if (delegate_)
return delegate_->CanResizeDialog();
return true;
}
ui::ModalType WebDialogView::GetModalType() const {
return GetDialogModalType();
}
base::string16 WebDialogView::GetWindowTitle() const {
if (delegate_)
return delegate_->GetDialogTitle();
return base::string16();
}
base::string16 WebDialogView::GetAccessibleWindowTitle() const {
if (delegate_)
return delegate_->GetAccessibleDialogTitle();
return GetWindowTitle();
}
std::string WebDialogView::GetWindowName() const {
if (delegate_)
return delegate_->GetDialogName();
return std::string();
}
void WebDialogView::WindowClosing() {
// If we still have a delegate that means we haven't notified it of the
// dialog closing. This happens if the user clicks the Close button on the
// dialog.
if (delegate_)
OnDialogClosed("");
}
views::View* WebDialogView::GetContentsView() {
return this;
}
views::ClientView* WebDialogView::CreateClientView(views::Widget* widget) {
return this;
}
views::View* WebDialogView::GetInitiallyFocusedView() {
return web_view_;
}
bool WebDialogView::ShouldShowWindowTitle() const {
return ShouldShowDialogTitle();
}
views::Widget* WebDialogView::GetWidget() {
return View::GetWidget();
}
const views::Widget* WebDialogView::GetWidget() const {
return View::GetWidget();
}
////////////////////////////////////////////////////////////////////////////////
// WebDialogDelegate implementation:
ui::ModalType WebDialogView::GetDialogModalType() const {
if (delegate_)
return delegate_->GetDialogModalType();
return ui::MODAL_TYPE_NONE;
}
base::string16 WebDialogView::GetDialogTitle() const {
return GetWindowTitle();
}
GURL WebDialogView::GetDialogContentURL() const {
if (delegate_)
return delegate_->GetDialogContentURL();
return GURL();
}
void WebDialogView::GetWebUIMessageHandlers(
std::vector<WebUIMessageHandler*>* handlers) const {
if (delegate_)
delegate_->GetWebUIMessageHandlers(handlers);
}
void WebDialogView::GetDialogSize(gfx::Size* size) const {
if (delegate_)
delegate_->GetDialogSize(size);
}
void WebDialogView::GetMinimumDialogSize(gfx::Size* size) const {
if (delegate_)
delegate_->GetMinimumDialogSize(size);
}
std::string WebDialogView::GetDialogArgs() const {
if (delegate_)
return delegate_->GetDialogArgs();
return std::string();
}
void WebDialogView::OnDialogShown(content::WebUI* webui,
content::RenderViewHost* render_view_host) {
if (delegate_)
delegate_->OnDialogShown(webui, render_view_host);
}
void WebDialogView::OnDialogClosed(const std::string& json_retval) {
Detach();
if (delegate_) {
// Store the dialog content area size.
delegate_->StoreDialogSize(GetContentsBounds().size());
}
if (GetWidget())
GetWidget()->Close();
if (delegate_) {
delegate_->OnDialogClosed(json_retval);
delegate_ = nullptr; // We will not communicate further with the delegate.
}
}
void WebDialogView::OnDialogCloseFromWebUI(const std::string& json_retval) {
closed_via_webui_ = true;
dialog_close_retval_ = json_retval;
if (GetWidget())
GetWidget()->Close();
}
void WebDialogView::OnCloseContents(WebContents* source,
bool* out_close_dialog) {
DCHECK(out_close_dialog);
if (delegate_)
delegate_->OnCloseContents(source, out_close_dialog);
}
bool WebDialogView::ShouldShowDialogTitle() const {
if (delegate_)
return delegate_->ShouldShowDialogTitle();
return true;
}
bool WebDialogView::HandleContextMenu(
const content::ContextMenuParams& params) {
if (delegate_)
return delegate_->HandleContextMenu(params);
return WebDialogWebContentsDelegate::HandleContextMenu(params);
}
////////////////////////////////////////////////////////////////////////////////
// content::WebContentsDelegate implementation:
void WebDialogView::SetContentsBounds(WebContents* source,
const gfx::Rect& bounds) {
// The contained web page wishes to resize itself. We let it do this because
// if it's a dialog we know about, we trust it not to be mean to the user.
GetWidget()->SetBounds(bounds);
}
// A simplified version of BrowserView::HandleKeyboardEvent().
// We don't handle global keyboard shortcuts here, but that's fine since
// they're all browser-specific. (This may change in the future.)
bool WebDialogView::HandleKeyboardEvent(content::WebContents* source,
const NativeWebKeyboardEvent& event) {
if (!event.os_event)
return false;
return unhandled_keyboard_event_handler_.HandleKeyboardEvent(
event, GetFocusManager());
}
void WebDialogView::CloseContents(WebContents* source) {
close_contents_called_ = true;
bool close_dialog = false;
OnCloseContents(source, &close_dialog);
if (close_dialog)
OnDialogClosed(closed_via_webui_ ? dialog_close_retval_ : std::string());
}
content::WebContents* WebDialogView::OpenURLFromTab(
content::WebContents* source,
const content::OpenURLParams& params) {
content::WebContents* new_contents = nullptr;
if (delegate_ &&
delegate_->HandleOpenURLFromTab(source, params, &new_contents)) {
return new_contents;
}
return WebDialogWebContentsDelegate::OpenURLFromTab(source, params);
}
void WebDialogView::AddNewContents(
content::WebContents* source,
std::unique_ptr<content::WebContents> new_contents,
WindowOpenDisposition disposition,
const gfx::Rect& initial_rect,
bool user_gesture,
bool* was_blocked) {
WebDialogWebContentsDelegate::AddNewContents(source, std::move(new_contents),
disposition, initial_rect,
user_gesture, was_blocked);
}
void WebDialogView::LoadingStateChanged(content::WebContents* source,
bool to_different_document) {
if (delegate_)
delegate_->OnLoadingStateChanged(source);
}
void WebDialogView::BeforeUnloadFired(content::WebContents* tab,
bool proceed,
bool* proceed_to_fire_unload) {
before_unload_fired_ = true;
*proceed_to_fire_unload = proceed;
}
bool WebDialogView::ShouldCreateWebContents(
content::WebContents* web_contents,
content::RenderFrameHost* opener,
content::SiteInstance* source_site_instance,
int32_t route_id,
int32_t main_frame_route_id,
int32_t main_frame_widget_route_id,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
const std::string& frame_name,
const GURL& target_url,
const std::string& partition_id,
content::SessionStorageNamespace* session_storage_namespace) {
if (delegate_)
return delegate_->HandleShouldCreateWebContents();
return true;
}
////////////////////////////////////////////////////////////////////////////////
// WebDialogView, private:
void WebDialogView::InitDialog() {
content::WebContents* web_contents = web_view_->GetWebContents();
if (web_contents->GetDelegate() == this)
return;
web_contents->SetDelegate(this);
// Set the delegate. This must be done before loading the page. See
// the comment above WebDialogUI in its header file for why.
WebDialogUIBase::SetDelegate(web_contents, this);
web_view_->LoadInitialURL(GetDialogContentURL());
}
} // namespace views