Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(377)

Side by Side Diff: chrome/browser/ui/extensions/extension_action_view_controller.cc

Issue 1168383002: Implement sidebar support for extension action popups Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix assertion failure at extension_view_host.cc Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/extensions/extension_action_view_controller.h" 5 #include "chrome/browser/ui/extensions/extension_action_view_controller.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/strings/utf_string_conversions.h" 8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/extensions/api/commands/command_service.h" 9 #include "chrome/browser/extensions/api/commands/command_service.h"
10 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" 10 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
11 #include "chrome/browser/extensions/extension_action.h" 11 #include "chrome/browser/extensions/extension_action.h"
12 #include "chrome/browser/extensions/extension_view.h" 12 #include "chrome/browser/extensions/extension_view.h"
13 #include "chrome/browser/extensions/extension_view_host.h" 13 #include "chrome/browser/extensions/extension_view_host.h"
14 #include "chrome/browser/extensions/extension_view_host_factory.h" 14 #include "chrome/browser/extensions/extension_view_host_factory.h"
15 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/sessions/session_tab_helper.h" 16 #include "chrome/browser/sessions/session_tab_helper.h"
17 #include "chrome/browser/ui/browser.h" 17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/extensions/accelerator_priority.h" 18 #include "chrome/browser/ui/extensions/accelerator_priority.h"
19 #include "chrome/browser/ui/extensions/extension_action_platform_delegate.h" 19 #include "chrome/browser/ui/extensions/extension_action_platform_delegate.h"
20 #include "chrome/browser/ui/tabs/tab_strip_model.h"
20 #include "chrome/browser/ui/toolbar/toolbar_action_view_delegate.h" 21 #include "chrome/browser/ui/toolbar/toolbar_action_view_delegate.h"
21 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h" 22 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
22 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
23 #include "chrome/common/extensions/api/extension_action/action_info.h" 23 #include "chrome/common/extensions/api/extension_action/action_info.h"
24 #include "chrome/common/icon_with_badge_image_source.h" 24 #include "chrome/common/icon_with_badge_image_source.h"
25 #include "chrome/common/pref_names.h"
25 #include "extensions/browser/extension_host.h" 26 #include "extensions/browser/extension_host.h"
26 #include "extensions/browser/extension_registry.h" 27 #include "extensions/browser/extension_registry.h"
27 #include "extensions/common/extension.h" 28 #include "extensions/common/extension.h"
28 #include "extensions/common/feature_switch.h" 29 #include "extensions/common/feature_switch.h"
29 #include "extensions/common/manifest_constants.h" 30 #include "extensions/common/manifest_constants.h"
30 #include "ui/gfx/image/image_skia.h" 31 #include "ui/gfx/image/image_skia.h"
31 #include "ui/gfx/image/image_skia_operations.h" 32 #include "ui/gfx/image/image_skia_operations.h"
32 33
33 using extensions::ActionInfo; 34 using extensions::ActionInfo;
34 using extensions::CommandService; 35 using extensions::CommandService;
(...skipping 30 matching lines...) Expand all
65 return extension_->id(); 66 return extension_->id();
66 } 67 }
67 68
68 void ExtensionActionViewController::SetDelegate( 69 void ExtensionActionViewController::SetDelegate(
69 ToolbarActionViewDelegate* delegate) { 70 ToolbarActionViewDelegate* delegate) {
70 DCHECK((delegate == nullptr) ^ (view_delegate_ == nullptr)); 71 DCHECK((delegate == nullptr) ^ (view_delegate_ == nullptr));
71 if (delegate) { 72 if (delegate) {
72 view_delegate_ = delegate; 73 view_delegate_ = delegate;
73 platform_delegate_->OnDelegateSet(); 74 platform_delegate_->OnDelegateSet();
74 } else { 75 } else {
75 if (is_showing_popup()) 76 if (popup_host_)
76 HidePopup(); 77 HidePopup();
77 platform_delegate_.reset(); 78 platform_delegate_.reset();
78 view_delegate_ = nullptr; 79 view_delegate_ = nullptr;
79 } 80 }
80 } 81 }
81 82
82 gfx::Image ExtensionActionViewController::GetIcon( 83 gfx::Image ExtensionActionViewController::GetIcon(
83 content::WebContents* web_contents, 84 content::WebContents* web_contents,
84 const gfx::Size& size) { 85 const gfx::Size& size) {
85 if (!ExtensionIsValid()) 86 if (!ExtensionIsValid())
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 bool ExtensionActionViewController::HasPopup( 132 bool ExtensionActionViewController::HasPopup(
132 content::WebContents* web_contents) const { 133 content::WebContents* web_contents) const {
133 if (!ExtensionIsValid()) 134 if (!ExtensionIsValid())
134 return false; 135 return false;
135 136
136 int tab_id = SessionTabHelper::IdForTab(web_contents); 137 int tab_id = SessionTabHelper::IdForTab(web_contents);
137 return (tab_id < 0) ? false : extension_action_->HasPopup(tab_id); 138 return (tab_id < 0) ? false : extension_action_->HasPopup(tab_id);
138 } 139 }
139 140
140 void ExtensionActionViewController::HidePopup() { 141 void ExtensionActionViewController::HidePopup() {
141 if (is_showing_popup()) { 142 if (!is_showing_popup())
142 popup_host_->Close(); 143 return;
143 // We need to do these actions synchronously (instead of closing and then 144
144 // performing the rest of the cleanup in OnExtensionHostDestroyed()) because 145 popup_host_->Close();
145 // the extension host may close asynchronously, and we need to keep the view 146 // We need to do these actions synchronously (instead of closing and then
146 // delegate up-to-date. 147 // performing the rest of the cleanup in OnExtensionHostDestroyed()) because
147 if (popup_host_) 148 // the extension host may close asynchronously, and we need to keep the view
148 OnPopupClosed(); 149 // delegate up-to-date.
149 } 150 if (popup_host_)
151 OnPopupClosed();
150 } 152 }
151 153
152 gfx::NativeView ExtensionActionViewController::GetPopupNativeView() { 154 gfx::NativeView ExtensionActionViewController::GetPopupNativeView() {
153 return popup_host_ ? popup_host_->view()->GetNativeView() : nullptr; 155 return popup_host_ ? popup_host_->view()->GetNativeView() : nullptr;
154 } 156 }
155 157
156 ui::MenuModel* ExtensionActionViewController::GetContextMenu() { 158 ui::MenuModel* ExtensionActionViewController::GetContextMenu() {
157 if (!ExtensionIsValid() || !extension()->ShowConfigureContextMenus()) 159 if (!ExtensionIsValid() || !extension()->ShowConfigureContextMenus())
158 return nullptr; 160 return nullptr;
159 161
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 bool grant_tab_permissions) { 197 bool grant_tab_permissions) {
196 if (!ExtensionIsValid()) 198 if (!ExtensionIsValid())
197 return false; 199 return false;
198 200
199 if (extensions::ExtensionActionAPI::Get(browser_->profile()) 201 if (extensions::ExtensionActionAPI::Get(browser_->profile())
200 ->ExecuteExtensionAction( 202 ->ExecuteExtensionAction(
201 extension_.get(), browser_, grant_tab_permissions) == 203 extension_.get(), browser_, grant_tab_permissions) ==
202 ExtensionAction::ACTION_SHOW_POPUP) { 204 ExtensionAction::ACTION_SHOW_POPUP) {
203 GURL popup_url = extension_action_->GetPopupUrl( 205 GURL popup_url = extension_action_->GetPopupUrl(
204 SessionTabHelper::IdForTab(view_delegate_->GetCurrentWebContents())); 206 SessionTabHelper::IdForTab(view_delegate_->GetCurrentWebContents()));
205 return GetPreferredPopupViewController() 207
206 ->TriggerPopupWithUrl(show_action, popup_url, grant_tab_permissions); 208 if (extension_action_->open_in_sidebar())
209 return GetPreferredPopupViewController()->TriggerSidebarWithUrl(
210 popup_url);
211 else
212 return GetPreferredPopupViewController()->TriggerPopupWithUrl(
213 show_action, popup_url, grant_tab_permissions);
207 } 214 }
208 return false; 215 return false;
209 } 216 }
210 217
211 void ExtensionActionViewController::RegisterCommand() { 218 void ExtensionActionViewController::RegisterCommand() {
212 if (!ExtensionIsValid()) 219 if (!ExtensionIsValid())
213 return; 220 return;
214 221
215 platform_delegate_->RegisterCommand(); 222 platform_delegate_->RegisterCommand();
216 } 223 }
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
281 toolbar_actions_bar_->GetMainControllerForAction(this)); 288 toolbar_actions_bar_->GetMainControllerForAction(this));
282 } 289 }
283 290
284 return this; 291 return this;
285 } 292 }
286 293
287 bool ExtensionActionViewController::TriggerPopupWithUrl( 294 bool ExtensionActionViewController::TriggerPopupWithUrl(
288 PopupShowAction show_action, 295 PopupShowAction show_action,
289 const GURL& popup_url, 296 const GURL& popup_url,
290 bool grant_tab_permissions) { 297 bool grant_tab_permissions) {
291 if (!ExtensionIsValid()) 298
299 // If we were showing a popup already, then we treat the action to open the
300 // same one as a desire to close it (like clicking a menu button that was
301 // already open).
302 if (is_showing_popup()) {
303 HideActivePopup();
292 return false; 304 return false;
293 305 }
294 bool already_showing = is_showing_popup();
295 306
296 // Always hide the current popup, even if it's not owned by this extension. 307 // Always hide the current popup, even if it's not owned by this extension.
297 // Only one popup should be visible at a time. 308 // Only one popup should be visible at a time.
298 HideActivePopup(); 309 HideActivePopup();
299 310
300 // If we were showing a popup already, then we treat the action to open the
301 // same one as a desire to close it (like clicking a menu button that was
302 // already open).
303 if (already_showing)
304 return false;
305
306 scoped_ptr<extensions::ExtensionViewHost> host( 311 scoped_ptr<extensions::ExtensionViewHost> host(
307 extensions::ExtensionViewHostFactory::CreatePopupHost(popup_url, 312 extensions::ExtensionViewHostFactory::CreatePopupHost(popup_url,
308 browser_)); 313 browser_));
309 if (!host) 314 if (!host)
310 return false; 315 return false;
311 316
312 popup_host_ = host.get(); 317 popup_host_ = host.get();
313 popup_host_observer_.Add(popup_host_); 318 popup_host_observer_.Add(popup_host_);
314 if (toolbar_actions_bar_) 319 if (toolbar_actions_bar_)
315 toolbar_actions_bar_->SetPopupOwner(this); 320 toolbar_actions_bar_->SetPopupOwner(this);
316 321
317 if (toolbar_actions_bar_ && 322 PressButtonWithSlideOutIfEnabled(base::Bind(
318 !toolbar_actions_bar_->IsActionVisibleOnMainBar(this) && 323 &ExtensionActionViewController::ShowPopup, weak_factory_.GetWeakPtr(),
319 extensions::FeatureSwitch::extension_action_redesign()->IsEnabled()) { 324 base::Passed(host.Pass()), grant_tab_permissions, show_action));
320 platform_delegate_->CloseOverflowMenu();
321 toolbar_actions_bar_->PopOutAction(
322 this,
323 base::Bind(&ExtensionActionViewController::ShowPopup,
324 weak_factory_.GetWeakPtr(),
325 base::Passed(host.Pass()),
326 grant_tab_permissions,
327 show_action));
328 } else {
329 ShowPopup(host.Pass(), grant_tab_permissions, show_action);
330 }
331 325
332 return true; 326 return true;
333 } 327 }
334 328
329 bool ExtensionActionViewController::TriggerSidebarWithUrl(
330 const GURL& sidebar_url) {
331 // Sidebar is only allowed via browser action
332 if (ActionInfo::TYPE_BROWSER != extension_action_->action_type())
333 return false;
334
335 DCHECK(toolbar_actions_bar_);
336
337 if (sidebar_host_) {
338 HideActiveSidebar();
339 return false;
340 }
341
342 HideActiveSidebar();
343
344 sidebar_host_.reset(extensions::ExtensionViewHostFactory::CreateSidebarHost(
345 sidebar_url, browser_));
346
347 sidebar_host_->CreateRenderViewSoon();
348 sidebar_host_->host_contents()->SetInitialFocus();
349
350 DCHECK(toolbar_actions_bar_);
351 toolbar_actions_bar_->SetSidebarOwner(this);
352
353 PressButtonWithSlideOutIfEnabled(
354 base::Bind(&ExtensionActionViewController::PressButton,
355 weak_factory_.GetWeakPtr(), true));
356 return true;
357 }
358
335 void ExtensionActionViewController::ShowPopup( 359 void ExtensionActionViewController::ShowPopup(
336 scoped_ptr<extensions::ExtensionViewHost> popup_host, 360 scoped_ptr<extensions::ExtensionViewHost> popup_host,
337 bool grant_tab_permissions, 361 bool grant_tab_permissions,
338 PopupShowAction show_action) { 362 PopupShowAction show_action) {
339 // It's possible that the popup should be closed before it finishes opening 363 // It's possible that the popup should be closed before it finishes opening
340 // (since it can open asynchronously). Check before proceeding. 364 // (since it can open asynchronously). Check before proceeding.
341 if (!popup_host_) 365 if (!popup_host_)
342 return; 366 return;
343 platform_delegate_->ShowPopup( 367 platform_delegate_->ShowPopup(
344 popup_host.Pass(), grant_tab_permissions, show_action); 368 popup_host.Pass(), grant_tab_permissions, show_action);
345 view_delegate_->OnPopupShown(grant_tab_permissions); 369 PressButton(grant_tab_permissions);
346 } 370 }
347 371
348 void ExtensionActionViewController::OnPopupClosed() { 372 void ExtensionActionViewController::OnPopupClosed() {
349 popup_host_observer_.Remove(popup_host_); 373 if (popup_host_) {
350 popup_host_ = nullptr; 374 popup_host_observer_.Remove(popup_host_);
375 popup_host_ = nullptr;
376 }
377 if (toolbar_actions_bar_)
378 toolbar_actions_bar_->SetPopupOwner(nullptr);
379
380 RaiseButton();
381 }
382
383 void ExtensionActionViewController::HideActiveSidebar() {
384 DCHECK(toolbar_actions_bar_);
385 DCHECK_EQ(ActionInfo::TYPE_BROWSER, extension_action_->action_type());
386 toolbar_actions_bar_->HideActiveSidebar();
387 }
388
389 void ExtensionActionViewController::HideSidebar() {
390 if (!sidebar_host_)
391 return;
392
393 sidebar_host_.reset();
394 if (toolbar_actions_bar_)
395 toolbar_actions_bar_->SetSidebarOwner(nullptr);
396
397 RaiseButton();
398 }
399
400 void ExtensionActionViewController::RaiseButton() {
401 // Reset button state
351 if (toolbar_actions_bar_) { 402 if (toolbar_actions_bar_) {
352 toolbar_actions_bar_->SetPopupOwner(nullptr);
353 if (toolbar_actions_bar_->popped_out_action() == this && 403 if (toolbar_actions_bar_->popped_out_action() == this &&
354 !view_delegate_->IsMenuRunning()) 404 !view_delegate_->IsMenuRunning()) {
355 toolbar_actions_bar_->UndoPopOut(); 405 toolbar_actions_bar_->UndoPopOut();
406 }
356 } 407 }
357 view_delegate_->OnPopupClosed(); 408 view_delegate_->OnPopupClosed();
358 } 409 }
359 410
411 void ExtensionActionViewController::PressButtonWithSlideOutIfEnabled(
412 const base::Closure& closure) {
413 if (!toolbar_actions_bar_ ||
414 toolbar_actions_bar_->IsActionVisibleOnMainBar(this) ||
415 !extensions::FeatureSwitch::extension_action_redesign()->IsEnabled()) {
416 closure.Run();
417 return;
418 }
419
420 // We disabled PopOutAction for sidebar
421 if (extension_action_->open_in_sidebar()) {
422 closure.Run();
423 return;
424 }
425
426 platform_delegate_->CloseOverflowMenu();
427 toolbar_actions_bar_->PopOutAction(this, closure);
428 }
429
430 void ExtensionActionViewController::PressButton(bool grant_tab_permissions) {
431 view_delegate_->OnPopupShown(grant_tab_permissions);
432 }
433
360 scoped_ptr<IconWithBadgeImageSource> 434 scoped_ptr<IconWithBadgeImageSource>
361 ExtensionActionViewController::GetIconImageSource( 435 ExtensionActionViewController::GetIconImageSource(
362 content::WebContents* web_contents, 436 content::WebContents* web_contents,
363 const gfx::Size& size) { 437 const gfx::Size& size) {
364 int tab_id = SessionTabHelper::IdForTab(web_contents); 438 int tab_id = SessionTabHelper::IdForTab(web_contents);
365 scoped_ptr<IconWithBadgeImageSource> image_source( 439 scoped_ptr<IconWithBadgeImageSource> image_source(
366 new IconWithBadgeImageSource(size)); 440 new IconWithBadgeImageSource(size));
367 image_source->SetIcon(icon_factory_.GetIcon(tab_id)); 441 image_source->SetIcon(icon_factory_.GetIcon(tab_id));
368 scoped_ptr<IconWithBadgeImageSource::Badge> badge; 442 scoped_ptr<IconWithBadgeImageSource::Badge> badge;
369 std::string badge_text = extension_action_->GetBadgeText(tab_id); 443 std::string badge_text = extension_action_->GetBadgeText(tab_id);
(...skipping 15 matching lines...) Expand all
385 // overflowed, we add a decoration so that the user can see which overflowed 459 // overflowed, we add a decoration so that the user can see which overflowed
386 // action wants to run (since they wouldn't be able to see the change from 460 // action wants to run (since they wouldn't be able to see the change from
387 // grayscale to color). 461 // grayscale to color).
388 bool is_overflow = 462 bool is_overflow =
389 toolbar_actions_bar_ && toolbar_actions_bar_->in_overflow_mode(); 463 toolbar_actions_bar_ && toolbar_actions_bar_->in_overflow_mode();
390 image_source->set_paint_decoration(WantsToRun(web_contents) && is_overflow); 464 image_source->set_paint_decoration(WantsToRun(web_contents) && is_overflow);
391 } 465 }
392 466
393 return image_source.Pass(); 467 return image_source.Pass();
394 } 468 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698