// 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 "chrome/browser/ui/webui/constrained_web_dialog_delegate_base.h" #import #include "base/mac/scoped_nsobject.h" #include "base/macros.h" #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h" #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h" #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_web_dialog_sheet.h" #include "chrome/browser/ui/webui/chrome_web_contents_handler.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h" #include "ui/base/cocoa/window_size_constants.h" #include "ui/gfx/geometry/size.h" #include "ui/web_dialogs/web_dialog_delegate.h" #include "ui/web_dialogs/web_dialog_ui.h" #include "ui/web_dialogs/web_dialog_web_contents_delegate.h" using content::WebContents; using ui::WebDialogDelegate; using ui::WebDialogWebContentsDelegate; namespace { class ConstrainedWebDialogDelegateMac; // This class is to trigger a resize to the dialog window when // ResizeDueToAutoResize() is invoked. class WebDialogWebContentsDelegateMac : public ui::WebDialogWebContentsDelegate { public: WebDialogWebContentsDelegateMac(content::BrowserContext* browser_context, content::WebContentsObserver* observer, ConstrainedWebDialogDelegateBase* delegate) : ui::WebDialogWebContentsDelegate(browser_context, new ChromeWebContentsHandler()), observer_(observer), delegate_(delegate) { } ~WebDialogWebContentsDelegateMac() override {} void ResizeDueToAutoResize(content::WebContents* source, const gfx::Size& preferred_size) override { if (!observer_->web_contents()) return; delegate_->ResizeToGivenSize(preferred_size); } private: // These members must outlive the instance. content::WebContentsObserver* const observer_; ConstrainedWebDialogDelegateBase* delegate_; DISALLOW_COPY_AND_ASSIGN(WebDialogWebContentsDelegateMac); }; class ConstrainedWebDialogDelegateMac : public ConstrainedWebDialogDelegateBase { public: ConstrainedWebDialogDelegateMac( content::BrowserContext* browser_context, WebDialogDelegate* delegate, content::WebContentsObserver* observer) : ConstrainedWebDialogDelegateBase(browser_context, delegate, new WebDialogWebContentsDelegateMac(browser_context, observer, this)) {} // WebDialogWebContentsDelegate interface. void CloseContents(WebContents* source) override { window_->CloseWebContentsModalDialog(); } // ConstrainedWebDialogDelegateBase: void ResizeToGivenSize(const gfx::Size size) override { NSSize updated_preferred_size = NSMakeSize(size.width(), size.height()); [window_->sheet() resizeWithNewSize:updated_preferred_size]; } void set_window(ConstrainedWindowMac* window) { window_ = window; } ConstrainedWindowMac* window() const { return window_; } private: // Weak, owned by ConstrainedWebDialogDelegateViewMac. ConstrainedWindowMac* window_; DISALLOW_COPY_AND_ASSIGN(ConstrainedWebDialogDelegateMac); }; } // namespace class ConstrainedWebDialogDelegateViewMac : public ConstrainedWindowMacDelegate, public ConstrainedWebDialogDelegate, public content::WebContentsObserver { public: ConstrainedWebDialogDelegateViewMac( content::BrowserContext* browser_context, WebDialogDelegate* delegate, content::WebContents* web_contents, const gfx::Size& min_size, const gfx::Size& max_size); ~ConstrainedWebDialogDelegateViewMac() override {} // ConstrainedWebDialogDelegate interface const WebDialogDelegate* GetWebDialogDelegate() const override { return impl_->GetWebDialogDelegate(); } WebDialogDelegate* GetWebDialogDelegate() override { return impl_->GetWebDialogDelegate(); } void OnDialogCloseFromWebUI() override { return impl_->OnDialogCloseFromWebUI(); } void ReleaseWebContentsOnDialogClose() override { return impl_->ReleaseWebContentsOnDialogClose(); } gfx::NativeWindow GetNativeDialog() override { return window_; } WebContents* GetWebContents() override { return impl_->GetWebContents(); } gfx::Size GetMinimumSize() const override { return min_size_; } gfx::Size GetMaximumSize() const override { return max_size_; } gfx::Size GetPreferredSize() const override { gfx::Size size; if (!impl_->closed_via_webui()) { NSRect frame = [window_ frame]; size = gfx::Size(frame.size.width, frame.size.height); } return size; } // content::WebContentsObserver: void RenderViewCreated(content::RenderViewHost* render_view_host) override { if (IsDialogAutoResizable()) EnableAutoResize(); } void RenderViewHostChanged(content::RenderViewHost* old_host, content::RenderViewHost* new_host) override { if (IsDialogAutoResizable()) EnableAutoResize(); } void DocumentOnLoadCompletedInMainFrame() override { if (!IsDialogAutoResizable()) return; EnableAutoResize(); if (GetWebContents()) constrained_window_->ShowWebContentsModalDialog(); } // ConstrainedWindowMacDelegate interface void OnConstrainedWindowClosed(ConstrainedWindowMac* window) override { if (!impl_->closed_via_webui()) GetWebDialogDelegate()->OnDialogClosed(""); delete this; } private: void EnableAutoResize() { if (!GetWebContents()) return; content::RenderViewHost* render_view_host = GetWebContents()->GetRenderViewHost(); render_view_host->EnableAutoResize(min_size_, max_size_); } // Whether or not the dialog is autoresizable is determined based on whether // |max_size_| was specified. bool IsDialogAutoResizable() { return !max_size_.IsEmpty(); } scoped_ptr impl_; scoped_ptr constrained_window_; base::scoped_nsobject window_; // Minimum and maximum sizes to determine dialog bounds for auto-resizing. const gfx::Size min_size_; const gfx::Size max_size_; DISALLOW_COPY_AND_ASSIGN(ConstrainedWebDialogDelegateViewMac); }; ConstrainedWebDialogDelegateViewMac::ConstrainedWebDialogDelegateViewMac( content::BrowserContext* browser_context, WebDialogDelegate* delegate, content::WebContents* web_contents, const gfx::Size& min_size, const gfx::Size& max_size) : content::WebContentsObserver(web_contents), impl_(new ConstrainedWebDialogDelegateMac(browser_context, delegate, this)), min_size_(min_size), max_size_(max_size) { if (IsDialogAutoResizable()) Observe(GetWebContents()); // Create a window to hold web_contents in the constrained sheet: gfx::Size size; delegate->GetDialogSize(&size); // The window size for autoresizing dialogs will be determined at a later // time. NSRect frame = IsDialogAutoResizable() ? ui::kWindowSizeDeterminedLater : NSMakeRect(0, 0, size.width(), size.height()); window_.reset([[ConstrainedWindowCustomWindow alloc] initWithContentRect:frame]); [GetWebContents()->GetNativeView() setFrame:frame]; [GetWebContents()->GetNativeView() setAutoresizingMask: NSViewWidthSizable|NSViewHeightSizable]; [[window_ contentView] addSubview:GetWebContents()->GetNativeView()]; base::scoped_nsobject sheet( [[WebDialogConstrainedWindowSheet alloc] initWithCustomWindow:window_ webDialogDelegate:delegate]); if (IsDialogAutoResizable()) { constrained_window_ = CreateWebModalDialogMac( this, web_contents, sheet); } else { constrained_window_ = CreateAndShowWebModalDialogMac( this, web_contents, sheet); } impl_->set_window(constrained_window_.get()); } ConstrainedWebDialogDelegate* ShowConstrainedWebDialog( content::BrowserContext* browser_context, WebDialogDelegate* delegate, content::WebContents* web_contents) { // Deleted when the dialog closes. ConstrainedWebDialogDelegateViewMac* constrained_delegate = new ConstrainedWebDialogDelegateViewMac( browser_context, delegate, web_contents, gfx::Size(), gfx::Size()); return constrained_delegate; } ConstrainedWebDialogDelegate* ShowConstrainedWebDialogWithAutoResize( content::BrowserContext* browser_context, WebDialogDelegate* delegate, content::WebContents* web_contents, const gfx::Size& min_size, const gfx::Size& max_size) { DCHECK(!min_size.IsEmpty()); DCHECK(!max_size.IsEmpty()); // Deleted when the dialog closes. ConstrainedWebDialogDelegateViewMac* constrained_delegate = new ConstrainedWebDialogDelegateViewMac( browser_context, delegate, web_contents, min_size, max_size); return constrained_delegate; }