Refactor WebsiteSettings to operate on a SecurityInfo
[chromium-blink-merge.git] / chrome / browser / ui / views / toolbar / toolbar_view.cc
blob1aa2989db185a2815fd2be6aa06e601fe418d66c
1 // Copyright 2013 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/toolbar/toolbar_view.h"
7 #include <algorithm>
9 #include "base/command_line.h"
10 #include "base/i18n/number_formatting.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/trace_event/trace_event.h"
14 #include "chrome/app/chrome_command_ids.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/command_updater.h"
17 #include "chrome/browser/extensions/extension_commands_global_registry.h"
18 #include "chrome/browser/extensions/extension_util.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/browser_command_controller.h"
22 #include "chrome/browser/ui/browser_commands.h"
23 #include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h"
24 #include "chrome/browser/ui/browser_tabstrip.h"
25 #include "chrome/browser/ui/browser_window.h"
26 #include "chrome/browser/ui/global_error/global_error_service.h"
27 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
28 #include "chrome/browser/ui/tabs/tab_strip_model.h"
29 #include "chrome/browser/ui/toolbar/wrench_menu_model.h"
30 #include "chrome/browser/ui/view_ids.h"
31 #include "chrome/browser/ui/views/extensions/extension_popup.h"
32 #include "chrome/browser/ui/views/frame/browser_view.h"
33 #include "chrome/browser/ui/views/layout_constants.h"
34 #include "chrome/browser/ui/views/location_bar/page_action_image_view.h"
35 #include "chrome/browser/ui/views/location_bar/page_action_with_badge_view.h"
36 #include "chrome/browser/ui/views/location_bar/star_view.h"
37 #include "chrome/browser/ui/views/location_bar/translate_icon_view.h"
38 #include "chrome/browser/ui/views/outdated_upgrade_bubble_view.h"
39 #include "chrome/browser/ui/views/toolbar/back_button.h"
40 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
41 #include "chrome/browser/ui/views/toolbar/home_button.h"
42 #include "chrome/browser/ui/views/toolbar/reload_button.h"
43 #include "chrome/browser/ui/views/toolbar/toolbar_button.h"
44 #include "chrome/browser/ui/views/toolbar/wrench_menu.h"
45 #include "chrome/browser/ui/views/toolbar/wrench_toolbar_button.h"
46 #include "chrome/common/chrome_switches.h"
47 #include "chrome/common/pref_names.h"
48 #include "chrome/grit/chromium_strings.h"
49 #include "chrome/grit/generated_resources.h"
50 #include "components/omnibox/browser/omnibox_view.h"
51 #include "content/public/browser/browser_accessibility_state.h"
52 #include "content/public/browser/notification_service.h"
53 #include "content/public/browser/render_view_host.h"
54 #include "content/public/browser/user_metrics.h"
55 #include "content/public/browser/web_contents.h"
56 #include "grit/theme_resources.h"
57 #include "ui/accessibility/ax_view_state.h"
58 #include "ui/base/l10n/l10n_util.h"
59 #include "ui/base/resource/material_design/material_design_controller.h"
60 #include "ui/base/theme_provider.h"
61 #include "ui/base/window_open_disposition.h"
62 #include "ui/compositor/layer.h"
63 #include "ui/gfx/canvas.h"
64 #include "ui/gfx/image/canvas_image_source.h"
65 #include "ui/keyboard/keyboard_controller.h"
66 #include "ui/native_theme/native_theme_aura.h"
67 #include "ui/views/controls/menu/menu_listener.h"
68 #include "ui/views/focus/view_storage.h"
69 #include "ui/views/view_targeter.h"
70 #include "ui/views/widget/tooltip_manager.h"
71 #include "ui/views/widget/widget.h"
72 #include "ui/views/window/non_client_view.h"
74 #if defined(OS_WIN)
75 #include "chrome/browser/recovery/recovery_install_global_error_factory.h"
76 #include "chrome/browser/ui/views/conflicting_module_view_win.h"
77 #include "chrome/browser/ui/views/critical_notification_bubble_view.h"
78 #endif
80 #if !defined(OS_CHROMEOS)
81 #include "chrome/browser/signin/signin_global_error_factory.h"
82 #include "chrome/browser/sync/sync_global_error_factory.h"
83 #endif
85 #if defined(USE_ASH)
86 #include "ash/shell.h"
87 #endif
89 using base::UserMetricsAction;
90 using content::WebContents;
92 namespace {
94 #if !defined(OS_CHROMEOS)
95 bool HasAshShell() {
96 #if defined(USE_ASH)
97 return ash::Shell::HasInstance();
98 #else
99 return false;
100 #endif // USE_ASH
102 #endif // OS_CHROMEOS
104 // Returns the y-position that will center an element of height
105 // |child_height| inside an element of height |parent_height|. For
106 // material design excess padding is placed below, for non-material
107 // it is placed above.
108 int CenteredChildY(int parent_height, int child_height) {
109 int roundoff_amount = ui::MaterialDesignController::IsModeMaterial() ? 0 : 1;
110 return (parent_height - child_height + roundoff_amount) / 2;
113 } // namespace
115 // static
116 const char ToolbarView::kViewClassName[] = "ToolbarView";
118 ////////////////////////////////////////////////////////////////////////////////
119 // ToolbarView, public:
121 ToolbarView::ToolbarView(Browser* browser)
122 : back_(NULL),
123 forward_(NULL),
124 reload_(NULL),
125 home_(NULL),
126 location_bar_(NULL),
127 browser_actions_(NULL),
128 app_menu_(NULL),
129 browser_(browser),
130 badge_controller_(browser->profile(), this) {
131 set_id(VIEW_ID_TOOLBAR);
133 SetEventTargeter(
134 scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(this)));
136 chrome::AddCommandObserver(browser_, IDC_BACK, this);
137 chrome::AddCommandObserver(browser_, IDC_FORWARD, this);
138 chrome::AddCommandObserver(browser_, IDC_RELOAD, this);
139 chrome::AddCommandObserver(browser_, IDC_HOME, this);
140 chrome::AddCommandObserver(browser_, IDC_LOAD_NEW_TAB_PAGE, this);
142 display_mode_ = DISPLAYMODE_LOCATION;
143 if (browser->SupportsWindowFeature(Browser::FEATURE_TABSTRIP))
144 display_mode_ = DISPLAYMODE_NORMAL;
146 if (OutdatedUpgradeBubbleView::IsAvailable()) {
147 registrar_.Add(this, chrome::NOTIFICATION_OUTDATED_INSTALL,
148 content::NotificationService::AllSources());
149 registrar_.Add(this, chrome::NOTIFICATION_OUTDATED_INSTALL_NO_AU,
150 content::NotificationService::AllSources());
152 #if defined(OS_WIN)
153 registrar_.Add(this, chrome::NOTIFICATION_CRITICAL_UPGRADE_INSTALLED,
154 content::NotificationService::AllSources());
155 #endif
158 ToolbarView::~ToolbarView() {
159 // NOTE: Don't remove the command observers here. This object gets destroyed
160 // after the Browser (which owns the CommandUpdater), so the CommandUpdater is
161 // already gone.
164 void ToolbarView::Init() {
165 GetWidget()->AddObserver(this);
167 back_ = new BackButton(this, new BackForwardMenuModel(
168 browser_, BackForwardMenuModel::BACKWARD_MENU));
169 back_->set_triggerable_event_flags(
170 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_MIDDLE_MOUSE_BUTTON);
171 back_->set_tag(IDC_BACK);
172 back_->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_BACK));
173 back_->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_BACK));
174 back_->set_id(VIEW_ID_BACK_BUTTON);
175 back_->Init();
177 forward_ = new ToolbarButton(this, new BackForwardMenuModel(
178 browser_, BackForwardMenuModel::FORWARD_MENU));
179 forward_->set_triggerable_event_flags(
180 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_MIDDLE_MOUSE_BUTTON);
181 forward_->set_tag(IDC_FORWARD);
182 forward_->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_FORWARD));
183 forward_->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_FORWARD));
184 forward_->set_id(VIEW_ID_FORWARD_BUTTON);
185 forward_->Init();
187 location_bar_ = new LocationBarView(
188 browser_, browser_->profile(),
189 browser_->command_controller()->command_updater(), this,
190 display_mode_ == DISPLAYMODE_LOCATION);
192 reload_ = new ReloadButton(browser_->command_controller()->command_updater());
193 reload_->set_triggerable_event_flags(
194 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_MIDDLE_MOUSE_BUTTON);
195 reload_->set_tag(IDC_RELOAD);
196 reload_->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_RELOAD));
197 reload_->set_id(VIEW_ID_RELOAD_BUTTON);
198 reload_->Init();
200 home_ = new HomeButton(this, browser_);
201 home_->set_triggerable_event_flags(
202 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_MIDDLE_MOUSE_BUTTON);
203 home_->set_tag(IDC_HOME);
204 home_->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_HOME));
205 home_->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_HOME));
206 home_->set_id(VIEW_ID_HOME_BUTTON);
207 home_->Init();
209 browser_actions_ = new BrowserActionsContainer(
210 browser_,
211 NULL); // No master container for this one (it is master).
213 app_menu_ = new WrenchToolbarButton(this);
214 app_menu_->EnableCanvasFlippingForRTLUI(true);
215 app_menu_->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_APP));
216 app_menu_->SetTooltipText(l10n_util::GetStringUTF16(IDS_APPMENU_TOOLTIP));
217 app_menu_->set_id(VIEW_ID_APP_MENU);
219 // Always add children in order from left to right, for accessibility.
220 AddChildView(back_);
221 AddChildView(forward_);
222 AddChildView(reload_);
223 AddChildView(home_);
224 AddChildView(location_bar_);
225 AddChildView(browser_actions_);
226 AddChildView(app_menu_);
228 LoadImages();
230 // Start global error services now so we badge the menu correctly.
231 #if !defined(OS_CHROMEOS)
232 if (!HasAshShell()) {
233 SigninGlobalErrorFactory::GetForProfile(browser_->profile());
234 #if !defined(OS_ANDROID)
235 SyncGlobalErrorFactory::GetForProfile(browser_->profile());
236 #endif
239 #if defined(OS_WIN)
240 RecoveryInstallGlobalErrorFactory::GetForProfile(browser_->profile());
241 #endif
242 #endif // OS_CHROMEOS
244 // Add any necessary badges to the menu item based on the system state.
245 // Do this after |app_menu_| has been added as a bubble may be shown that
246 // needs the widget (widget found by way of app_menu_->GetWidget()).
247 badge_controller_.UpdateDelegate();
249 location_bar_->Init();
251 show_home_button_.Init(prefs::kShowHomeButton,
252 browser_->profile()->GetPrefs(),
253 base::Bind(&ToolbarView::OnShowHomeButtonChanged,
254 base::Unretained(this)));
256 browser_actions_->Init();
258 // Accessibility specific tooltip text.
259 if (content::BrowserAccessibilityState::GetInstance()->
260 IsAccessibleBrowser()) {
261 back_->SetTooltipText(
262 l10n_util::GetStringUTF16(IDS_ACCNAME_TOOLTIP_BACK));
263 forward_->SetTooltipText(
264 l10n_util::GetStringUTF16(IDS_ACCNAME_TOOLTIP_FORWARD));
268 void ToolbarView::OnWidgetActivationChanged(views::Widget* widget,
269 bool active) {
270 extensions::ExtensionCommandsGlobalRegistry* registry =
271 extensions::ExtensionCommandsGlobalRegistry::Get(browser_->profile());
272 if (active) {
273 registry->set_registry_for_active_window(
274 browser_actions_->extension_keybinding_registry());
275 } else if (registry->registry_for_active_window() ==
276 browser_actions_->extension_keybinding_registry()) {
277 registry->set_registry_for_active_window(nullptr);
281 void ToolbarView::Update(WebContents* tab) {
282 if (location_bar_)
283 location_bar_->Update(tab);
284 if (browser_actions_)
285 browser_actions_->RefreshToolbarActionViews();
286 if (reload_)
287 reload_->set_menu_enabled(chrome::IsDebuggerAttachedToCurrentTab(browser_));
290 void ToolbarView::ResetTabState(WebContents* tab) {
291 if (location_bar_)
292 location_bar_->ResetTabState(tab);
295 void ToolbarView::SetPaneFocusAndFocusAppMenu() {
296 SetPaneFocus(app_menu_);
299 bool ToolbarView::IsAppMenuFocused() {
300 return app_menu_->HasFocus();
303 void ToolbarView::AddMenuListener(views::MenuListener* listener) {
304 menu_listeners_.AddObserver(listener);
307 void ToolbarView::RemoveMenuListener(views::MenuListener* listener) {
308 menu_listeners_.RemoveObserver(listener);
311 views::View* ToolbarView::GetBookmarkBubbleAnchor() {
312 views::View* star_view = location_bar()->star_view();
313 return (star_view && star_view->visible()) ? star_view : app_menu_;
316 views::View* ToolbarView::GetTranslateBubbleAnchor() {
317 views::View* translate_icon_view = location_bar()->translate_icon_view();
318 return (translate_icon_view && translate_icon_view->visible()) ?
319 translate_icon_view : app_menu_;
322 void ToolbarView::ExecuteExtensionCommand(
323 const extensions::Extension* extension,
324 const extensions::Command& command) {
325 browser_actions_->ExecuteExtensionCommand(extension, command);
328 void ToolbarView::ShowAppMenu(bool for_drop) {
329 if (wrench_menu_.get() && wrench_menu_->IsShowing())
330 return;
332 #if defined(USE_AURA)
333 if (keyboard::KeyboardController::GetInstance() &&
334 keyboard::KeyboardController::GetInstance()->keyboard_visible()) {
335 keyboard::KeyboardController::GetInstance()->HideKeyboard(
336 keyboard::KeyboardController::HIDE_REASON_AUTOMATIC);
338 #endif
340 wrench_menu_.reset(
341 new WrenchMenu(browser_, for_drop ? WrenchMenu::FOR_DROP : 0));
342 wrench_menu_model_.reset(new WrenchMenuModel(this, browser_));
343 wrench_menu_->Init(wrench_menu_model_.get());
345 FOR_EACH_OBSERVER(views::MenuListener, menu_listeners_, OnMenuOpened());
347 wrench_menu_->RunMenu(app_menu_);
350 void ToolbarView::CloseAppMenu() {
351 if (wrench_menu_)
352 wrench_menu_->CloseMenu();
355 ////////////////////////////////////////////////////////////////////////////////
356 // ToolbarView, AccessiblePaneView overrides:
358 bool ToolbarView::SetPaneFocus(views::View* initial_focus) {
359 if (!AccessiblePaneView::SetPaneFocus(initial_focus))
360 return false;
362 location_bar_->SetShowFocusRect(true);
363 return true;
366 void ToolbarView::GetAccessibleState(ui::AXViewState* state) {
367 state->role = ui::AX_ROLE_TOOLBAR;
368 state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_TOOLBAR);
371 ////////////////////////////////////////////////////////////////////////////////
372 // ToolbarView, Menu::Delegate overrides:
374 bool ToolbarView::GetAcceleratorInfo(int id, ui::Accelerator* accel) {
375 return GetWidget()->GetAccelerator(id, accel);
378 ////////////////////////////////////////////////////////////////////////////////
379 // ToolbarView, views::MenuButtonListener implementation:
381 void ToolbarView::OnMenuButtonClicked(views::View* source,
382 const gfx::Point& point) {
383 TRACE_EVENT0("views", "ToolbarView::OnMenuButtonClicked");
384 DCHECK_EQ(VIEW_ID_APP_MENU, source->id());
385 ShowAppMenu(false); // Not for drop.
388 ////////////////////////////////////////////////////////////////////////////////
389 // ToolbarView, LocationBarView::Delegate implementation:
391 WebContents* ToolbarView::GetWebContents() {
392 return browser_->tab_strip_model()->GetActiveWebContents();
395 ToolbarModel* ToolbarView::GetToolbarModel() {
396 return browser_->toolbar_model();
399 const ToolbarModel* ToolbarView::GetToolbarModel() const {
400 return browser_->toolbar_model();
403 ContentSettingBubbleModelDelegate*
404 ToolbarView::GetContentSettingBubbleModelDelegate() {
405 return browser_->content_setting_bubble_model_delegate();
408 void ToolbarView::ShowWebsiteSettings(
409 content::WebContents* web_contents,
410 const GURL& url,
411 const SecurityStateModel::SecurityInfo& security_info) {
412 chrome::ShowWebsiteSettings(browser_, web_contents, url, security_info);
415 views::Widget* ToolbarView::CreateViewsBubble(
416 views::BubbleDelegateView* bubble_delegate) {
417 return views::BubbleDelegateView::CreateBubble(bubble_delegate);
420 PageActionImageView* ToolbarView::CreatePageActionImageView(
421 LocationBarView* owner, ExtensionAction* action) {
422 return new PageActionImageView(owner, action, browser_);
425 ////////////////////////////////////////////////////////////////////////////////
426 // ToolbarView, CommandObserver implementation:
428 void ToolbarView::EnabledStateChangedForCommand(int id, bool enabled) {
429 views::Button* button = NULL;
430 switch (id) {
431 case IDC_BACK:
432 button = back_;
433 break;
434 case IDC_FORWARD:
435 button = forward_;
436 break;
437 case IDC_RELOAD:
438 button = reload_;
439 break;
440 case IDC_HOME:
441 button = home_;
442 break;
444 if (button)
445 button->SetEnabled(enabled);
448 ////////////////////////////////////////////////////////////////////////////////
449 // ToolbarView, views::Button::ButtonListener implementation:
451 void ToolbarView::ButtonPressed(views::Button* sender,
452 const ui::Event& event) {
453 chrome::ExecuteCommandWithDisposition(
454 browser_, sender->tag(), ui::DispositionFromEventFlags(event.flags()));
457 ////////////////////////////////////////////////////////////////////////////////
458 // ToolbarView, content::NotificationObserver implementation:
460 void ToolbarView::Observe(int type,
461 const content::NotificationSource& source,
462 const content::NotificationDetails& details) {
463 switch (type) {
464 case chrome::NOTIFICATION_OUTDATED_INSTALL:
465 ShowOutdatedInstallNotification(true);
466 break;
467 case chrome::NOTIFICATION_OUTDATED_INSTALL_NO_AU:
468 ShowOutdatedInstallNotification(false);
469 break;
470 #if defined(OS_WIN)
471 case chrome::NOTIFICATION_CRITICAL_UPGRADE_INSTALLED:
472 ShowCriticalNotification();
473 break;
474 #endif
475 default:
476 NOTREACHED();
480 ////////////////////////////////////////////////////////////////////////////////
481 // ToolbarView, ui::AcceleratorProvider implementation:
483 bool ToolbarView::GetAcceleratorForCommandId(int command_id,
484 ui::Accelerator* accelerator) {
485 return GetWidget()->GetAccelerator(command_id, accelerator);
488 ////////////////////////////////////////////////////////////////////////////////
489 // ToolbarView, views::View overrides:
491 gfx::Size ToolbarView::GetPreferredSize() const {
492 gfx::Size size(location_bar_->GetPreferredSize());
493 if (is_display_mode_normal()) {
494 const int element_padding = GetLayoutConstant(TOOLBAR_VIEW_ELEMENT_PADDING);
495 const int browser_actions_width =
496 browser_actions_->GetPreferredSize().width();
497 const int content_width =
498 GetLayoutInsets(TOOLBAR_VIEW).width() +
499 back_->GetPreferredSize().width() + element_padding +
500 forward_->GetPreferredSize().width() + element_padding +
501 reload_->GetPreferredSize().width() +
502 (show_home_button_.GetValue()
503 ? element_padding + home_->GetPreferredSize().width()
504 : 0) +
505 GetLayoutConstant(TOOLBAR_VIEW_STANDARD_SPACING) +
506 GetLayoutConstant(TOOLBAR_VIEW_LOCATION_BAR_RIGHT_PADDING) +
507 browser_actions_width +
508 (browser_actions_width > 0 ? element_padding : 0) +
509 app_menu_->GetPreferredSize().width();
510 size.Enlarge(content_width, 0);
512 return SizeForContentSize(size);
515 gfx::Size ToolbarView::GetMinimumSize() const {
516 gfx::Size size(location_bar_->GetMinimumSize());
517 if (is_display_mode_normal()) {
518 const int element_padding = GetLayoutConstant(TOOLBAR_VIEW_ELEMENT_PADDING);
519 const int browser_actions_width =
520 browser_actions_->GetMinimumSize().width();
521 const int content_width =
522 GetLayoutInsets(TOOLBAR_VIEW).width() +
523 back_->GetMinimumSize().width() + element_padding +
524 forward_->GetMinimumSize().width() + element_padding +
525 reload_->GetMinimumSize().width() +
526 (show_home_button_.GetValue()
527 ? element_padding + home_->GetMinimumSize().width()
528 : 0) +
529 GetLayoutConstant(TOOLBAR_VIEW_STANDARD_SPACING) +
530 GetLayoutConstant(TOOLBAR_VIEW_LOCATION_BAR_RIGHT_PADDING) +
531 browser_actions_width +
532 (browser_actions_width > 0 ? element_padding : 0) +
533 app_menu_->GetMinimumSize().width();
534 size.Enlarge(content_width, 0);
536 return SizeForContentSize(size);
539 void ToolbarView::Layout() {
540 // If we have not been initialized yet just do nothing.
541 if (back_ == NULL)
542 return;
544 if (!is_display_mode_normal()) {
545 location_bar_->SetBounds(0, PopupTopSpacing(), width(),
546 location_bar_->GetPreferredSize().height());
547 return;
550 // We assume all child elements except the location bar are the same height.
551 // Set child_y such that buttons appear vertically centered.
552 int child_height =
553 std::min(back_->GetPreferredSize().height(), height());
554 int child_y = CenteredChildY(height(), child_height);
556 // If the window is maximized, we extend the back button to the left so that
557 // clicking on the left-most pixel will activate the back button.
558 // TODO(abarth): If the window becomes maximized but is not resized,
559 // then Layout() might not be called and the back button
560 // will be slightly the wrong size. We should force a
561 // Layout() in this case.
562 // http://crbug.com/5540
563 bool maximized = browser_->window() && browser_->window()->IsMaximized();
564 int back_width = back_->GetPreferredSize().width();
565 const gfx::Insets insets(GetLayoutInsets(TOOLBAR_VIEW));
566 if (maximized) {
567 back_->SetBounds(0, child_y, back_width + insets.left(), child_height);
568 back_->SetLeadingMargin(insets.left());
569 } else {
570 back_->SetBounds(insets.left(), child_y, back_width, child_height);
571 back_->SetLeadingMargin(0);
573 const int element_padding = GetLayoutConstant(TOOLBAR_VIEW_ELEMENT_PADDING);
574 int next_element_x = back_->bounds().right() + element_padding;
576 forward_->SetBounds(next_element_x, child_y,
577 forward_->GetPreferredSize().width(), child_height);
578 next_element_x = forward_->bounds().right() + element_padding;
580 reload_->SetBounds(next_element_x, child_y,
581 reload_->GetPreferredSize().width(), child_height);
582 next_element_x = reload_->bounds().right();
584 if (show_home_button_.GetValue() ||
585 (browser_->is_app() && extensions::util::IsNewBookmarkAppsEnabled())) {
586 next_element_x += element_padding;
587 home_->SetVisible(true);
588 home_->SetBounds(next_element_x, child_y,
589 home_->GetPreferredSize().width(), child_height);
590 } else {
591 home_->SetVisible(false);
592 home_->SetBounds(next_element_x, child_y, 0, child_height);
594 next_element_x = home_->bounds().right() +
595 GetLayoutConstant(TOOLBAR_VIEW_STANDARD_SPACING);
597 int browser_actions_desired_width =
598 browser_actions_->GetPreferredSize().width();
599 int app_menu_width = app_menu_->GetPreferredSize().width();
600 const int location_bar_right_padding =
601 GetLayoutConstant(TOOLBAR_VIEW_LOCATION_BAR_RIGHT_PADDING);
603 int available_width = std::max(
604 0, width() - insets.right() - app_menu_width -
605 (browser_actions_desired_width > 0 ? element_padding : 0) -
606 location_bar_right_padding - next_element_x);
607 // Don't allow the omnibox to shrink to the point of non-existence, so
608 // subtract its minimum width from the available width to reserve it.
609 int minimum_location_bar_width = location_bar_->GetMinimumSize().width();
610 int browser_actions_width =
611 std::min(std::max(available_width - minimum_location_bar_width, 0),
612 browser_actions_desired_width);
613 available_width -= browser_actions_width;
614 int location_bar_width = available_width;
616 int location_height = location_bar_->GetPreferredSize().height();
617 int location_y = CenteredChildY(height(), location_height);
619 location_bar_->SetBounds(next_element_x, location_y,
620 location_bar_width, location_height);
621 next_element_x = location_bar_->bounds().right() + location_bar_right_padding;
623 browser_actions_->SetBounds(
624 next_element_x, child_y, browser_actions_width, child_height);
625 next_element_x = browser_actions_->bounds().right();
626 if (browser_actions_width > 0)
627 next_element_x += element_padding;
629 // The browser actions need to do a layout explicitly, because when an
630 // extension is loaded/unloaded/changed, BrowserActionContainer removes and
631 // re-adds everything, regardless of whether it has a page action. For a
632 // page action, browser action bounds do not change, as a result of which
633 // SetBounds does not do a layout at all.
634 // TODO(sidchat): Rework the above behavior so that explicit layout is not
635 // required.
636 browser_actions_->Layout();
638 // Extend the app menu to the screen's right edge in maximized mode just like
639 // we extend the back button to the left edge.
640 if (maximized)
641 app_menu_width += insets.right();
642 app_menu_->SetBounds(next_element_x, child_y, app_menu_width, child_height);
645 void ToolbarView::OnPaint(gfx::Canvas* canvas) {
646 View::OnPaint(canvas);
648 if (is_display_mode_normal())
649 return;
651 // For glass, we need to draw a black line below the location bar to separate
652 // it from the content area. For non-glass, the NonClientView draws the
653 // toolbar background below the location bar for us.
654 // NOTE: Keep this in sync with BrowserView::GetInfoBarSeparatorColor()!
655 if (GetWidget()->ShouldWindowContentsBeTransparent())
656 canvas->FillRect(gfx::Rect(0, height() - 1, width(), 1), SK_ColorBLACK);
659 void ToolbarView::OnThemeChanged() {
660 LoadImages();
663 const char* ToolbarView::GetClassName() const {
664 return kViewClassName;
667 bool ToolbarView::AcceleratorPressed(const ui::Accelerator& accelerator) {
668 const views::View* focused_view = focus_manager()->GetFocusedView();
669 if (focused_view && (focused_view->id() == VIEW_ID_OMNIBOX))
670 return false; // Let the omnibox handle all accelerator events.
671 return AccessiblePaneView::AcceleratorPressed(accelerator);
674 bool ToolbarView::IsWrenchMenuShowing() const {
675 return wrench_menu_.get() && wrench_menu_->IsShowing();
678 bool ToolbarView::ShouldPaintBackground() const {
679 return display_mode_ == DISPLAYMODE_NORMAL;
682 ////////////////////////////////////////////////////////////////////////////////
683 // ToolbarView, protected:
685 // Override this so that when the user presses F6 to rotate toolbar panes,
686 // the location bar gets focus, not the first control in the toolbar - and
687 // also so that it selects all content in the location bar.
688 bool ToolbarView::SetPaneFocusAndFocusDefault() {
689 if (!location_bar_->HasFocus()) {
690 SetPaneFocus(location_bar_);
691 location_bar_->FocusLocation(true);
692 return true;
695 if (!AccessiblePaneView::SetPaneFocusAndFocusDefault())
696 return false;
697 browser_->window()->RotatePaneFocus(true);
698 return true;
701 void ToolbarView::RemovePaneFocus() {
702 AccessiblePaneView::RemovePaneFocus();
703 location_bar_->SetShowFocusRect(false);
706 ////////////////////////////////////////////////////////////////////////////////
707 // ToolbarView, private:
709 // views::ViewTargeterDelegate:
710 bool ToolbarView::DoesIntersectRect(const views::View* target,
711 const gfx::Rect& rect) const {
712 CHECK_EQ(target, this);
714 // Fall through to the tab strip above us if none of |rect| intersects
715 // with this view (intersection with the top shadow edge does not
716 // count as intersection with this view).
717 if (rect.bottom() < content_shadow_height())
718 return false;
719 // Otherwise let our superclass take care of it.
720 return ViewTargeterDelegate::DoesIntersectRect(this, rect);
723 void ToolbarView::UpdateBadgeSeverity(WrenchMenuBadgeController::BadgeType type,
724 WrenchIconPainter::Severity severity,
725 bool animate) {
726 // Showing the bubble requires |app_menu_| to be in a widget. See comment
727 // in ConflictingModuleView for details.
728 DCHECK(app_menu_->GetWidget());
730 base::string16 accname_app = l10n_util::GetStringUTF16(IDS_ACCNAME_APP);
731 if (type == WrenchMenuBadgeController::BADGE_TYPE_UPGRADE_NOTIFICATION) {
732 accname_app = l10n_util::GetStringFUTF16(
733 IDS_ACCNAME_APP_UPGRADE_RECOMMENDED, accname_app);
735 app_menu_->SetAccessibleName(accname_app);
736 app_menu_->SetSeverity(severity, animate);
738 // Keep track of whether we were showing the badge before, so we don't send
739 // multiple UMA events for example when multiple Chrome windows are open.
740 static bool incompatibility_badge_showing = false;
741 // Save the old value before resetting it.
742 bool was_showing = incompatibility_badge_showing;
743 incompatibility_badge_showing = false;
745 if (type == WrenchMenuBadgeController::BADGE_TYPE_INCOMPATIBILITY_WARNING) {
746 if (!was_showing) {
747 content::RecordAction(UserMetricsAction("ConflictBadge"));
748 #if defined(OS_WIN)
749 ConflictingModuleView::MaybeShow(browser_, app_menu_);
750 #endif
752 incompatibility_badge_showing = true;
753 return;
757 int ToolbarView::PopupTopSpacing() const {
758 const int kPopupTopSpacingNonGlass = 3;
759 return GetWidget()->ShouldWindowContentsBeTransparent() ?
760 0 : kPopupTopSpacingNonGlass;
763 gfx::Size ToolbarView::SizeForContentSize(gfx::Size size) const {
764 if (is_display_mode_normal()) {
765 // For Material Design the size of the toolbar is computed using the size
766 // of the location bar and constant padding values. For non-material the
767 // size is based on the provided assets.
768 if (ui::MaterialDesignController::IsModeMaterial()) {
769 int content_height = std::max(back_->GetPreferredSize().height(),
770 location_bar_->GetPreferredSize().height());
771 int padding = GetLayoutInsets(TOOLBAR_VIEW).height();
772 size.SetToMax(gfx::Size(0, content_height + padding));
773 } else {
774 gfx::ImageSkia* normal_background =
775 GetThemeProvider()->GetImageSkiaNamed(IDR_CONTENT_TOP_CENTER);
776 size.SetToMax(
777 gfx::Size(0, normal_background->height() - content_shadow_height()));
779 } else if (size.height() == 0) {
780 // Location mode with a 0 height location bar. If on ash, expand by one
781 // pixel to show a border in the title bar, otherwise leave the size as zero
782 // height.
783 const int kAshBorderSpacing = 1;
784 if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
785 size.Enlarge(0, kAshBorderSpacing);
786 } else {
787 const int kPopupBottomSpacingGlass = 1;
788 const int kPopupBottomSpacingNonGlass = 2;
789 size.Enlarge(
791 PopupTopSpacing() + (GetWidget()->ShouldWindowContentsBeTransparent() ?
792 kPopupBottomSpacingGlass : kPopupBottomSpacingNonGlass));
794 return size;
797 void ToolbarView::LoadImages() {
798 ui::ThemeProvider* tp = GetThemeProvider();
800 back_->SetImage(views::Button::STATE_NORMAL,
801 *(tp->GetImageSkiaNamed(IDR_BACK)));
802 back_->SetImage(views::Button::STATE_DISABLED,
803 *(tp->GetImageSkiaNamed(IDR_BACK_D)));
805 forward_->SetImage(views::Button::STATE_NORMAL,
806 *(tp->GetImageSkiaNamed(IDR_FORWARD)));
807 forward_->SetImage(views::Button::STATE_DISABLED,
808 *(tp->GetImageSkiaNamed(IDR_FORWARD_D)));
810 reload_->LoadImages();
812 home_->SetImage(views::Button::STATE_NORMAL,
813 *(tp->GetImageSkiaNamed(IDR_HOME)));
815 if (ui::MaterialDesignController::IsModeMaterial()) {
816 app_menu_->SetImage(views::Button::STATE_NORMAL,
817 *(tp->GetImageSkiaNamed(IDR_TOOLS)));
821 void ToolbarView::ShowCriticalNotification() {
822 #if defined(OS_WIN)
823 CriticalNotificationBubbleView* bubble_delegate =
824 new CriticalNotificationBubbleView(app_menu_);
825 views::BubbleDelegateView::CreateBubble(bubble_delegate)->Show();
826 #endif
829 void ToolbarView::ShowOutdatedInstallNotification(bool auto_update_enabled) {
830 if (OutdatedUpgradeBubbleView::IsAvailable()) {
831 OutdatedUpgradeBubbleView::ShowBubble(
832 app_menu_, browser_, auto_update_enabled);
836 void ToolbarView::OnShowHomeButtonChanged() {
837 Layout();
838 SchedulePaint();
841 int ToolbarView::content_shadow_height() const {
842 return GetLayoutConstant(
843 (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
844 ? TOOLBAR_VIEW_CONTENT_SHADOW_HEIGHT_ASH
845 : TOOLBAR_VIEW_CONTENT_SHADOW_HEIGHT);