Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / views / extensions / extension_dialog.cc
blobfac0c3d8c7be5b7d263db092996f311d0f0949a8
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/views/extensions/extension_dialog.h"
7 #include "chrome/browser/chrome_notification_types.h"
8 #include "chrome/browser/extensions/extension_view_host.h"
9 #include "chrome/browser/extensions/extension_view_host_factory.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/views/extensions/extension_dialog_observer.h"
12 #include "chrome/browser/ui/views/extensions/extension_view_views.h"
13 #include "components/constrained_window/constrained_window_views.h"
14 #include "content/public/browser/notification_details.h"
15 #include "content/public/browser/notification_source.h"
16 #include "content/public/browser/render_view_host.h"
17 #include "content/public/browser/render_widget_host_view.h"
18 #include "content/public/browser/web_contents.h"
19 #include "ui/base/base_window.h"
20 #include "ui/gfx/screen.h"
21 #include "ui/views/background.h"
22 #include "ui/views/widget/widget.h"
23 #include "url/gurl.h"
25 using content::BrowserContext;
26 using content::WebContents;
28 namespace {
30 ExtensionViewViews* GetExtensionView(extensions::ExtensionViewHost* host) {
31 return static_cast<ExtensionViewViews*>(host->view());
34 } // namespace
36 ExtensionDialog::ExtensionDialog(extensions::ExtensionViewHost* host,
37 ExtensionDialogObserver* observer)
38 : host_(host),
39 observer_(observer) {
40 AddRef(); // Balanced in DeleteDelegate();
42 registrar_.Add(this,
43 extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_FIRST_LOAD,
44 content::Source<BrowserContext>(host->browser_context()));
45 // Listen for the containing view calling window.close();
46 registrar_.Add(this,
47 extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
48 content::Source<BrowserContext>(host->browser_context()));
49 // Listen for a crash or other termination of the extension process.
50 registrar_.Add(this,
51 extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
52 content::Source<BrowserContext>(host->browser_context()));
55 ExtensionDialog::~ExtensionDialog() {
58 // static
59 ExtensionDialog* ExtensionDialog::Show(
60 const GURL& url,
61 gfx::NativeWindow parent_window,
62 Profile* profile,
63 WebContents* web_contents,
64 int width,
65 int height,
66 int min_width,
67 int min_height,
68 const base::string16& title,
69 ExtensionDialogObserver* observer) {
70 extensions::ExtensionViewHost* host =
71 extensions::ExtensionViewHostFactory::CreateDialogHost(url, profile);
72 if (!host)
73 return NULL;
74 // Preferred size must be set before views::Widget::CreateWindowWithParent
75 // is called because CreateWindowWithParent refers the result of CanResize().
76 ExtensionViewViews* view = GetExtensionView(host);
77 view->SetPreferredSize(gfx::Size(width, height));
78 view->set_minimum_size(gfx::Size(min_width, min_height));
79 host->SetAssociatedWebContents(web_contents);
81 DCHECK(parent_window);
82 ExtensionDialog* dialog = new ExtensionDialog(host, observer);
83 dialog->set_title(title);
84 dialog->InitWindow(parent_window, width, height);
86 // Show a white background while the extension loads. This is prettier than
87 // flashing a black unfilled window frame.
88 view->set_background(
89 views::Background::CreateSolidBackground(0xFF, 0xFF, 0xFF));
90 view->SetVisible(true);
92 // Ensure the DOM JavaScript can respond immediately to keyboard shortcuts.
93 host->host_contents()->Focus();
94 return dialog;
97 void ExtensionDialog::InitWindow(gfx::NativeWindow parent,
98 int width,
99 int height) {
100 views::Widget* window =
101 constrained_window::CreateBrowserModalDialogViews(this, parent);
103 // Center the window over the browser.
104 views::Widget* parent_widget =
105 views::Widget::GetWidgetForNativeWindow(parent);
106 gfx::Point center = parent_widget->GetWindowBoundsInScreen().CenterPoint();
107 int x = center.x() - width / 2;
108 int y = center.y() - height / 2;
109 // Ensure the top left and top right of the window are on screen, with
110 // priority given to the top left.
111 gfx::Rect screen_rect =
112 gfx::Screen::GetScreenFor(parent_widget->GetNativeView())
113 ->GetDisplayNearestPoint(center).bounds();
114 gfx::Rect bounds_rect = gfx::Rect(x, y, width, height);
115 bounds_rect.AdjustToFit(screen_rect);
116 window->SetBounds(bounds_rect);
118 window->Show();
119 // TODO(jamescook): Remove redundant call to Activate()?
120 window->Activate();
123 void ExtensionDialog::ObserverDestroyed() {
124 observer_ = NULL;
127 void ExtensionDialog::MaybeFocusRenderView() {
128 views::FocusManager* focus_manager = GetWidget()->GetFocusManager();
129 DCHECK(focus_manager != NULL);
131 // Already there's a focused view, so no need to switch the focus.
132 if (focus_manager->GetFocusedView())
133 return;
135 content::RenderWidgetHostView* view = host()->render_view_host()->GetView();
136 if (!view)
137 return;
139 view->Focus();
142 /////////////////////////////////////////////////////////////////////////////
143 // views::DialogDelegate overrides.
145 int ExtensionDialog::GetDialogButtons() const {
146 // The only user, SelectFileDialogExtension, provides its own buttons.
147 return ui::DIALOG_BUTTON_NONE;
150 bool ExtensionDialog::CanResize() const {
151 // Can resize only if minimum contents size set.
152 return static_cast<views::View*>(GetExtensionView(host_.get()))->
153 GetPreferredSize() != gfx::Size();
156 void ExtensionDialog::SetMinimumContentsSize(int width, int height) {
157 GetExtensionView(host_.get())->SetPreferredSize(gfx::Size(width, height));
160 ui::ModalType ExtensionDialog::GetModalType() const {
161 return ui::MODAL_TYPE_WINDOW;
164 bool ExtensionDialog::ShouldShowWindowTitle() const {
165 return !window_title_.empty();
168 base::string16 ExtensionDialog::GetWindowTitle() const {
169 return window_title_;
172 void ExtensionDialog::WindowClosing() {
173 if (observer_)
174 observer_->ExtensionDialogClosing(this);
177 void ExtensionDialog::DeleteDelegate() {
178 // The window has finished closing. Allow ourself to be deleted.
179 Release();
182 views::Widget* ExtensionDialog::GetWidget() {
183 return GetExtensionView(host_.get())->GetWidget();
186 const views::Widget* ExtensionDialog::GetWidget() const {
187 return GetExtensionView(host_.get())->GetWidget();
190 views::View* ExtensionDialog::GetContentsView() {
191 return GetExtensionView(host_.get());
194 bool ExtensionDialog::UseNewStyleForThisDialog() const {
195 return false;
198 /////////////////////////////////////////////////////////////////////////////
199 // content::NotificationObserver overrides.
201 void ExtensionDialog::Observe(int type,
202 const content::NotificationSource& source,
203 const content::NotificationDetails& details) {
204 switch (type) {
205 case extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_FIRST_LOAD:
206 // Avoid potential overdraw by removing the temporary background after
207 // the extension finishes loading.
208 GetExtensionView(host_.get())->set_background(NULL);
209 // The render view is created during the LoadURL(), so we should
210 // set the focus to the view if nobody else takes the focus.
211 if (content::Details<extensions::ExtensionHost>(host()) == details)
212 MaybeFocusRenderView();
213 break;
214 case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE:
215 // If we aren't the host of the popup, then disregard the notification.
216 if (content::Details<extensions::ExtensionHost>(host()) != details)
217 return;
218 GetWidget()->Close();
219 break;
220 case extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED:
221 if (content::Details<extensions::ExtensionHost>(host()) != details)
222 return;
223 if (observer_)
224 observer_->ExtensionTerminated(this);
225 break;
226 default:
227 NOTREACHED() << L"Received unexpected notification";
228 break;