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"
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/themes/theme_properties.h"
21 #include "chrome/browser/themes/theme_service.h"
22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/browser_command_controller.h"
24 #include "chrome/browser/ui/browser_commands.h"
25 #include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h"
26 #include "chrome/browser/ui/browser_tabstrip.h"
27 #include "chrome/browser/ui/browser_window.h"
28 #include "chrome/browser/ui/global_error/global_error_service.h"
29 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
30 #include "chrome/browser/ui/tabs/tab_strip_model.h"
31 #include "chrome/browser/ui/toolbar/wrench_menu_model.h"
32 #include "chrome/browser/ui/view_ids.h"
33 #include "chrome/browser/ui/views/extensions/extension_popup.h"
34 #include "chrome/browser/ui/views/frame/browser_view.h"
35 #include "chrome/browser/ui/views/location_bar/page_action_image_view.h"
36 #include "chrome/browser/ui/views/location_bar/page_action_with_badge_view.h"
37 #include "chrome/browser/ui/views/location_bar/star_view.h"
38 #include "chrome/browser/ui/views/location_bar/translate_icon_view.h"
39 #include "chrome/browser/ui/views/outdated_upgrade_bubble_view.h"
40 #include "chrome/browser/ui/views/toolbar/back_button.h"
41 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
42 #include "chrome/browser/ui/views/toolbar/home_button.h"
43 #include "chrome/browser/ui/views/toolbar/reload_button.h"
44 #include "chrome/browser/ui/views/toolbar/toolbar_button.h"
45 #include "chrome/browser/ui/views/toolbar/wrench_menu.h"
46 #include "chrome/browser/ui/views/toolbar/wrench_toolbar_button.h"
47 #include "chrome/common/chrome_switches.h"
48 #include "chrome/common/pref_names.h"
49 #include "chrome/grit/chromium_strings.h"
50 #include "chrome/grit/generated_resources.h"
51 #include "components/omnibox/browser/omnibox_view.h"
52 #include "content/public/browser/browser_accessibility_state.h"
53 #include "content/public/browser/notification_service.h"
54 #include "content/public/browser/render_view_host.h"
55 #include "content/public/browser/user_metrics.h"
56 #include "content/public/browser/web_contents.h"
57 #include "grit/theme_resources.h"
58 #include "ui/accessibility/ax_view_state.h"
59 #include "ui/base/l10n/l10n_util.h"
60 #include "ui/base/resource/material_design/material_design_controller.h"
61 #include "ui/base/theme_provider.h"
62 #include "ui/base/window_open_disposition.h"
63 #include "ui/compositor/layer.h"
64 #include "ui/gfx/canvas.h"
65 #include "ui/gfx/image/canvas_image_source.h"
66 #include "ui/keyboard/keyboard_controller.h"
67 #include "ui/native_theme/native_theme_aura.h"
68 #include "ui/views/controls/menu/menu_listener.h"
69 #include "ui/views/focus/view_storage.h"
70 #include "ui/views/view_targeter.h"
71 #include "ui/views/widget/tooltip_manager.h"
72 #include "ui/views/widget/widget.h"
73 #include "ui/views/window/non_client_view.h"
76 #include "chrome/browser/recovery/recovery_install_global_error_factory.h"
77 #include "chrome/browser/ui/views/conflicting_module_view_win.h"
78 #include "chrome/browser/ui/views/critical_notification_bubble_view.h"
81 #if !defined(OS_CHROMEOS)
82 #include "chrome/browser/signin/signin_global_error_factory.h"
83 #include "chrome/browser/sync/sync_global_error_factory.h"
87 #include "ash/shell.h"
90 using base::UserMetricsAction
;
91 using content::WebContents
;
95 #if !defined(OS_CHROMEOS)
98 return ash::Shell::HasInstance();
103 #endif // OS_CHROMEOS
108 const char ToolbarView::kViewClassName
[] = "ToolbarView";
110 ////////////////////////////////////////////////////////////////////////////////
111 // ToolbarView, public:
113 ToolbarView::ToolbarView(Browser
* browser
)
119 browser_actions_(NULL
),
122 badge_controller_(browser
->profile(), this) {
123 set_id(VIEW_ID_TOOLBAR
);
126 scoped_ptr
<views::ViewTargeter
>(new views::ViewTargeter(this)));
128 chrome::AddCommandObserver(browser_
, IDC_BACK
, this);
129 chrome::AddCommandObserver(browser_
, IDC_FORWARD
, this);
130 chrome::AddCommandObserver(browser_
, IDC_RELOAD
, this);
131 chrome::AddCommandObserver(browser_
, IDC_HOME
, this);
132 chrome::AddCommandObserver(browser_
, IDC_LOAD_NEW_TAB_PAGE
, this);
134 display_mode_
= DISPLAYMODE_LOCATION
;
135 if (browser
->SupportsWindowFeature(Browser::FEATURE_TABSTRIP
))
136 display_mode_
= DISPLAYMODE_NORMAL
;
138 if (OutdatedUpgradeBubbleView::IsAvailable()) {
139 registrar_
.Add(this, chrome::NOTIFICATION_OUTDATED_INSTALL
,
140 content::NotificationService::AllSources());
141 registrar_
.Add(this, chrome::NOTIFICATION_OUTDATED_INSTALL_NO_AU
,
142 content::NotificationService::AllSources());
145 registrar_
.Add(this, chrome::NOTIFICATION_CRITICAL_UPGRADE_INSTALLED
,
146 content::NotificationService::AllSources());
150 ToolbarView::~ToolbarView() {
151 // NOTE: Don't remove the command observers here. This object gets destroyed
152 // after the Browser (which owns the CommandUpdater), so the CommandUpdater is
156 void ToolbarView::Init() {
157 GetWidget()->AddObserver(this);
159 back_
= new BackButton(this, new BackForwardMenuModel(
160 browser_
, BackForwardMenuModel::BACKWARD_MENU
));
161 back_
->set_triggerable_event_flags(
162 ui::EF_LEFT_MOUSE_BUTTON
| ui::EF_MIDDLE_MOUSE_BUTTON
);
163 back_
->set_tag(IDC_BACK
);
164 back_
->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_BACK
));
165 back_
->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_BACK
));
166 back_
->set_id(VIEW_ID_BACK_BUTTON
);
169 forward_
= new ToolbarButton(this, new BackForwardMenuModel(
170 browser_
, BackForwardMenuModel::FORWARD_MENU
));
171 forward_
->set_triggerable_event_flags(
172 ui::EF_LEFT_MOUSE_BUTTON
| ui::EF_MIDDLE_MOUSE_BUTTON
);
173 forward_
->set_tag(IDC_FORWARD
);
174 forward_
->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_FORWARD
));
175 forward_
->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_FORWARD
));
176 forward_
->set_id(VIEW_ID_FORWARD_BUTTON
);
179 location_bar_
= new LocationBarView(
180 browser_
, browser_
->profile(),
181 browser_
->command_controller()->command_updater(), this,
182 display_mode_
== DISPLAYMODE_LOCATION
);
184 reload_
= new ReloadButton(browser_
->command_controller()->command_updater());
185 reload_
->set_triggerable_event_flags(
186 ui::EF_LEFT_MOUSE_BUTTON
| ui::EF_MIDDLE_MOUSE_BUTTON
);
187 reload_
->set_tag(IDC_RELOAD
);
188 reload_
->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_RELOAD
));
189 reload_
->set_id(VIEW_ID_RELOAD_BUTTON
);
192 home_
= new HomeButton(this, browser_
);
193 home_
->set_triggerable_event_flags(
194 ui::EF_LEFT_MOUSE_BUTTON
| ui::EF_MIDDLE_MOUSE_BUTTON
);
195 home_
->set_tag(IDC_HOME
);
196 home_
->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_HOME
));
197 home_
->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_HOME
));
198 home_
->set_id(VIEW_ID_HOME_BUTTON
);
201 browser_actions_
= new BrowserActionsContainer(
203 NULL
); // No master container for this one (it is master).
205 app_menu_
= new WrenchToolbarButton(this);
206 app_menu_
->EnableCanvasFlippingForRTLUI(true);
207 app_menu_
->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_APP
));
208 app_menu_
->SetTooltipText(l10n_util::GetStringUTF16(IDS_APPMENU_TOOLTIP
));
209 app_menu_
->set_id(VIEW_ID_APP_MENU
);
211 // Always add children in order from left to right, for accessibility.
213 AddChildView(forward_
);
214 AddChildView(reload_
);
216 AddChildView(location_bar_
);
217 AddChildView(browser_actions_
);
218 AddChildView(app_menu_
);
222 // Start global error services now so we badge the menu correctly.
223 #if !defined(OS_CHROMEOS)
224 if (!HasAshShell()) {
225 SigninGlobalErrorFactory::GetForProfile(browser_
->profile());
226 #if !defined(OS_ANDROID)
227 SyncGlobalErrorFactory::GetForProfile(browser_
->profile());
232 RecoveryInstallGlobalErrorFactory::GetForProfile(browser_
->profile());
234 #endif // OS_CHROMEOS
236 // Add any necessary badges to the menu item based on the system state.
237 // Do this after |app_menu_| has been added as a bubble may be shown that
238 // needs the widget (widget found by way of app_menu_->GetWidget()).
239 badge_controller_
.UpdateDelegate();
241 location_bar_
->Init();
243 show_home_button_
.Init(prefs::kShowHomeButton
,
244 browser_
->profile()->GetPrefs(),
245 base::Bind(&ToolbarView::OnShowHomeButtonChanged
,
246 base::Unretained(this)));
248 browser_actions_
->Init();
250 // Accessibility specific tooltip text.
251 if (content::BrowserAccessibilityState::GetInstance()->
252 IsAccessibleBrowser()) {
253 back_
->SetTooltipText(
254 l10n_util::GetStringUTF16(IDS_ACCNAME_TOOLTIP_BACK
));
255 forward_
->SetTooltipText(
256 l10n_util::GetStringUTF16(IDS_ACCNAME_TOOLTIP_FORWARD
));
260 void ToolbarView::OnWidgetActivationChanged(views::Widget
* widget
,
262 extensions::ExtensionCommandsGlobalRegistry
* registry
=
263 extensions::ExtensionCommandsGlobalRegistry::Get(browser_
->profile());
265 registry
->set_registry_for_active_window(
266 browser_actions_
->extension_keybinding_registry());
267 } else if (registry
->registry_for_active_window() ==
268 browser_actions_
->extension_keybinding_registry()) {
269 registry
->set_registry_for_active_window(nullptr);
273 void ToolbarView::Update(WebContents
* tab
) {
275 location_bar_
->Update(tab
);
276 if (browser_actions_
)
277 browser_actions_
->RefreshToolbarActionViews();
279 reload_
->set_menu_enabled(chrome::IsDebuggerAttachedToCurrentTab(browser_
));
282 void ToolbarView::ResetTabState(WebContents
* tab
) {
284 location_bar_
->ResetTabState(tab
);
287 void ToolbarView::SetPaneFocusAndFocusAppMenu() {
288 SetPaneFocus(app_menu_
);
291 bool ToolbarView::IsAppMenuFocused() {
292 return app_menu_
->HasFocus();
295 void ToolbarView::AddMenuListener(views::MenuListener
* listener
) {
296 menu_listeners_
.AddObserver(listener
);
299 void ToolbarView::RemoveMenuListener(views::MenuListener
* listener
) {
300 menu_listeners_
.RemoveObserver(listener
);
303 views::View
* ToolbarView::GetBookmarkBubbleAnchor() {
304 views::View
* star_view
= location_bar()->star_view();
305 return (star_view
&& star_view
->visible()) ? star_view
: app_menu_
;
308 views::View
* ToolbarView::GetTranslateBubbleAnchor() {
309 views::View
* translate_icon_view
= location_bar()->translate_icon_view();
310 return (translate_icon_view
&& translate_icon_view
->visible()) ?
311 translate_icon_view
: app_menu_
;
314 void ToolbarView::ExecuteExtensionCommand(
315 const extensions::Extension
* extension
,
316 const extensions::Command
& command
) {
317 browser_actions_
->ExecuteExtensionCommand(extension
, command
);
320 void ToolbarView::ShowAppMenu(bool for_drop
) {
321 if (wrench_menu_
.get() && wrench_menu_
->IsShowing())
324 #if defined(USE_AURA)
325 if (keyboard::KeyboardController::GetInstance() &&
326 keyboard::KeyboardController::GetInstance()->keyboard_visible()) {
327 keyboard::KeyboardController::GetInstance()->HideKeyboard(
328 keyboard::KeyboardController::HIDE_REASON_AUTOMATIC
);
333 new WrenchMenu(browser_
, for_drop
? WrenchMenu::FOR_DROP
: 0));
334 wrench_menu_model_
.reset(new WrenchMenuModel(this, browser_
));
335 wrench_menu_
->Init(wrench_menu_model_
.get());
337 FOR_EACH_OBSERVER(views::MenuListener
, menu_listeners_
, OnMenuOpened());
339 wrench_menu_
->RunMenu(app_menu_
);
342 void ToolbarView::CloseAppMenu() {
344 wrench_menu_
->CloseMenu();
347 ////////////////////////////////////////////////////////////////////////////////
348 // ToolbarView, AccessiblePaneView overrides:
350 bool ToolbarView::SetPaneFocus(views::View
* initial_focus
) {
351 if (!AccessiblePaneView::SetPaneFocus(initial_focus
))
354 location_bar_
->SetShowFocusRect(true);
358 void ToolbarView::GetAccessibleState(ui::AXViewState
* state
) {
359 state
->role
= ui::AX_ROLE_TOOLBAR
;
360 state
->name
= l10n_util::GetStringUTF16(IDS_ACCNAME_TOOLBAR
);
363 ////////////////////////////////////////////////////////////////////////////////
364 // ToolbarView, Menu::Delegate overrides:
366 bool ToolbarView::GetAcceleratorInfo(int id
, ui::Accelerator
* accel
) {
367 return GetWidget()->GetAccelerator(id
, accel
);
370 ////////////////////////////////////////////////////////////////////////////////
371 // ToolbarView, views::MenuButtonListener implementation:
373 void ToolbarView::OnMenuButtonClicked(views::View
* source
,
374 const gfx::Point
& point
) {
375 TRACE_EVENT0("views", "ToolbarView::OnMenuButtonClicked");
376 DCHECK_EQ(VIEW_ID_APP_MENU
, source
->id());
377 ShowAppMenu(false); // Not for drop.
380 ////////////////////////////////////////////////////////////////////////////////
381 // ToolbarView, LocationBarView::Delegate implementation:
383 WebContents
* ToolbarView::GetWebContents() {
384 return browser_
->tab_strip_model()->GetActiveWebContents();
387 ToolbarModel
* ToolbarView::GetToolbarModel() {
388 return browser_
->toolbar_model();
391 const ToolbarModel
* ToolbarView::GetToolbarModel() const {
392 return browser_
->toolbar_model();
395 ContentSettingBubbleModelDelegate
*
396 ToolbarView::GetContentSettingBubbleModelDelegate() {
397 return browser_
->content_setting_bubble_model_delegate();
400 void ToolbarView::ShowWebsiteSettings(content::WebContents
* web_contents
,
402 const content::SSLStatus
& ssl
) {
403 chrome::ShowWebsiteSettings(browser_
, web_contents
, url
, ssl
);
406 views::Widget
* ToolbarView::CreateViewsBubble(
407 views::BubbleDelegateView
* bubble_delegate
) {
408 return views::BubbleDelegateView::CreateBubble(bubble_delegate
);
411 PageActionImageView
* ToolbarView::CreatePageActionImageView(
412 LocationBarView
* owner
, ExtensionAction
* action
) {
413 return new PageActionImageView(owner
, action
, browser_
);
416 ////////////////////////////////////////////////////////////////////////////////
417 // ToolbarView, CommandObserver implementation:
419 void ToolbarView::EnabledStateChangedForCommand(int id
, bool enabled
) {
420 views::Button
* button
= NULL
;
436 button
->SetEnabled(enabled
);
439 ////////////////////////////////////////////////////////////////////////////////
440 // ToolbarView, views::Button::ButtonListener implementation:
442 void ToolbarView::ButtonPressed(views::Button
* sender
,
443 const ui::Event
& event
) {
444 chrome::ExecuteCommandWithDisposition(
445 browser_
, sender
->tag(), ui::DispositionFromEventFlags(event
.flags()));
448 ////////////////////////////////////////////////////////////////////////////////
449 // ToolbarView, content::NotificationObserver implementation:
451 void ToolbarView::Observe(int type
,
452 const content::NotificationSource
& source
,
453 const content::NotificationDetails
& details
) {
455 case chrome::NOTIFICATION_OUTDATED_INSTALL
:
456 ShowOutdatedInstallNotification(true);
458 case chrome::NOTIFICATION_OUTDATED_INSTALL_NO_AU
:
459 ShowOutdatedInstallNotification(false);
462 case chrome::NOTIFICATION_CRITICAL_UPGRADE_INSTALLED
:
463 ShowCriticalNotification();
471 ////////////////////////////////////////////////////////////////////////////////
472 // ToolbarView, ui::AcceleratorProvider implementation:
474 bool ToolbarView::GetAcceleratorForCommandId(int command_id
,
475 ui::Accelerator
* accelerator
) {
476 return GetWidget()->GetAccelerator(command_id
, accelerator
);
479 ////////////////////////////////////////////////////////////////////////////////
480 // ToolbarView, views::View overrides:
482 gfx::Size
ToolbarView::GetPreferredSize() const {
483 gfx::Size
size(location_bar_
->GetPreferredSize());
484 ui::ThemeProvider
* theme_provider
= GetThemeProvider();
485 if (is_display_mode_normal()) {
486 const int element_padding
= theme_provider
->GetDisplayProperty(
487 ThemeProperties::PROPERTY_TOOLBAR_VIEW_ELEMENT_PADDING
);
488 const int browser_actions_width
=
489 browser_actions_
->GetPreferredSize().width();
490 const int content_width
=
491 theme_provider
->GetDisplayProperty(
492 ThemeProperties::PROPERTY_TOOLBAR_VIEW_LEFT_EDGE_SPACING
) +
493 back_
->GetPreferredSize().width() + element_padding
+
494 forward_
->GetPreferredSize().width() + element_padding
+
495 reload_
->GetPreferredSize().width() +
496 (show_home_button_
.GetValue()
497 ? element_padding
+ home_
->GetPreferredSize().width()
499 theme_provider
->GetDisplayProperty(
500 ThemeProperties::PROPERTY_TOOLBAR_VIEW_STANDARD_SPACING
) +
501 theme_provider
->GetDisplayProperty(
502 ThemeProperties::PROPERTY_TOOLBAR_VIEW_LOCATION_BAR_RIGHT_PADDING
) +
503 browser_actions_width
+
504 (browser_actions_width
> 0 ? element_padding
: 0) +
505 app_menu_
->GetPreferredSize().width() +
506 theme_provider
->GetDisplayProperty(
507 ThemeProperties::PROPERTY_TOOLBAR_VIEW_RIGHT_EDGE_SPACING
);
508 size
.Enlarge(content_width
, 0);
510 return SizeForContentSize(size
);
513 gfx::Size
ToolbarView::GetMinimumSize() const {
514 gfx::Size
size(location_bar_
->GetMinimumSize());
515 ui::ThemeProvider
* theme_provider
= GetThemeProvider();
516 if (is_display_mode_normal()) {
517 const int element_padding
= theme_provider
->GetDisplayProperty(
518 ThemeProperties::PROPERTY_TOOLBAR_VIEW_ELEMENT_PADDING
);
519 const int browser_actions_width
=
520 browser_actions_
->GetMinimumSize().width();
521 const int content_width
=
522 theme_provider
->GetDisplayProperty(
523 ThemeProperties::PROPERTY_TOOLBAR_VIEW_LEFT_EDGE_SPACING
) +
524 back_
->GetMinimumSize().width() + element_padding
+
525 forward_
->GetMinimumSize().width() + element_padding
+
526 reload_
->GetMinimumSize().width() +
527 (show_home_button_
.GetValue()
528 ? element_padding
+ home_
->GetMinimumSize().width()
530 theme_provider
->GetDisplayProperty(
531 ThemeProperties::PROPERTY_TOOLBAR_VIEW_STANDARD_SPACING
) +
532 theme_provider
->GetDisplayProperty(
533 ThemeProperties::PROPERTY_TOOLBAR_VIEW_LOCATION_BAR_RIGHT_PADDING
) +
534 browser_actions_width
+
535 (browser_actions_width
> 0 ? element_padding
: 0) +
536 app_menu_
->GetMinimumSize().width() +
537 theme_provider
->GetDisplayProperty(
538 ThemeProperties::PROPERTY_TOOLBAR_VIEW_RIGHT_EDGE_SPACING
);
539 size
.Enlarge(content_width
, 0);
541 return SizeForContentSize(size
);
544 void ToolbarView::Layout() {
545 // If we have not been initialized yet just do nothing.
549 if (!is_display_mode_normal()) {
550 location_bar_
->SetBounds(0, PopupTopSpacing(), width(),
551 location_bar_
->GetPreferredSize().height());
555 // We assume all child elements except the location bar are the same height.
556 // Set child_y such that buttons appear vertically centered. We put any excess
557 // padding above the buttons.
559 std::min(back_
->GetPreferredSize().height(), height());
560 int child_y
= (height() - child_height
+ 1) / 2;
562 // If the window is maximized, we extend the back button to the left so that
563 // clicking on the left-most pixel will activate the back button.
564 // TODO(abarth): If the window becomes maximized but is not resized,
565 // then Layout() might not be called and the back button
566 // will be slightly the wrong size. We should force a
567 // Layout() in this case.
568 // http://crbug.com/5540
569 bool maximized
= browser_
->window() && browser_
->window()->IsMaximized();
570 int back_width
= back_
->GetPreferredSize().width();
571 ui::ThemeProvider
* theme_provider
= GetThemeProvider();
572 const int left_edge_spacing
= theme_provider
->GetDisplayProperty(
573 ThemeProperties::PROPERTY_TOOLBAR_VIEW_LEFT_EDGE_SPACING
);
575 back_
->SetBounds(0, child_y
, back_width
+ left_edge_spacing
, child_height
);
576 back_
->SetLeadingMargin(left_edge_spacing
);
578 back_
->SetBounds(left_edge_spacing
, child_y
, back_width
, child_height
);
579 back_
->SetLeadingMargin(0);
581 const int element_padding
= theme_provider
->GetDisplayProperty(
582 ThemeProperties::PROPERTY_TOOLBAR_VIEW_ELEMENT_PADDING
);
583 int next_element_x
= back_
->bounds().right() + element_padding
;
585 forward_
->SetBounds(next_element_x
, child_y
,
586 forward_
->GetPreferredSize().width(), child_height
);
587 next_element_x
= forward_
->bounds().right() + element_padding
;
589 reload_
->SetBounds(next_element_x
, child_y
,
590 reload_
->GetPreferredSize().width(), child_height
);
591 next_element_x
= reload_
->bounds().right();
593 if (show_home_button_
.GetValue() ||
594 (browser_
->is_app() && extensions::util::IsNewBookmarkAppsEnabled())) {
595 next_element_x
+= element_padding
;
596 home_
->SetVisible(true);
597 home_
->SetBounds(next_element_x
, child_y
,
598 home_
->GetPreferredSize().width(), child_height
);
600 home_
->SetVisible(false);
601 home_
->SetBounds(next_element_x
, child_y
, 0, child_height
);
603 next_element_x
= home_
->bounds().right() +
604 theme_provider
->GetDisplayProperty(
605 ThemeProperties::PROPERTY_TOOLBAR_VIEW_STANDARD_SPACING
);
607 int browser_actions_width
= browser_actions_
->GetPreferredSize().width();
608 int app_menu_width
= app_menu_
->GetPreferredSize().width();
609 const int right_edge_spacing
= theme_provider
->GetDisplayProperty(
610 ThemeProperties::PROPERTY_TOOLBAR_VIEW_RIGHT_EDGE_SPACING
);
611 const int location_bar_right_padding
= theme_provider
->GetDisplayProperty(
612 ThemeProperties::PROPERTY_TOOLBAR_VIEW_LOCATION_BAR_RIGHT_PADDING
);
613 int available_width
= std::max(
614 0, width() - right_edge_spacing
- app_menu_width
- browser_actions_width
-
615 (browser_actions_width
> 0 ? element_padding
: 0) -
616 location_bar_right_padding
- next_element_x
);
618 int location_height
= location_bar_
->GetPreferredSize().height();
619 int location_y
= (height() - location_height
+ 1) / 2;
620 location_bar_
->SetBounds(next_element_x
, location_y
,
621 std::max(available_width
, 0), location_height
);
622 next_element_x
= location_bar_
->bounds().right() + location_bar_right_padding
;
624 browser_actions_
->SetBounds(
625 next_element_x
, child_y
, browser_actions_width
, child_height
);
626 next_element_x
= browser_actions_
->bounds().right();
627 if (browser_actions_width
> 0)
628 next_element_x
+= element_padding
;
630 // The browser actions need to do a layout explicitly, because when an
631 // extension is loaded/unloaded/changed, BrowserActionContainer removes and
632 // re-adds everything, regardless of whether it has a page action. For a
633 // page action, browser action bounds do not change, as a result of which
634 // SetBounds does not do a layout at all.
635 // TODO(sidchat): Rework the above behavior so that explicit layout is not
637 browser_actions_
->Layout();
639 // Extend the app menu to the screen's right edge in maximized mode just like
640 // we extend the back button to the left edge.
642 app_menu_width
+= right_edge_spacing
;
643 app_menu_
->SetBounds(next_element_x
, child_y
, app_menu_width
, child_height
);
646 void ToolbarView::OnPaint(gfx::Canvas
* canvas
) {
647 View::OnPaint(canvas
);
649 if (is_display_mode_normal())
652 // For glass, we need to draw a black line below the location bar to separate
653 // it from the content area. For non-glass, the NonClientView draws the
654 // toolbar background below the location bar for us.
655 // NOTE: Keep this in sync with BrowserView::GetInfoBarSeparatorColor()!
656 if (GetWidget()->ShouldWindowContentsBeTransparent())
657 canvas
->FillRect(gfx::Rect(0, height() - 1, width(), 1), SK_ColorBLACK
);
660 void ToolbarView::OnThemeChanged() {
664 const char* ToolbarView::GetClassName() const {
665 return kViewClassName
;
668 bool ToolbarView::AcceleratorPressed(const ui::Accelerator
& accelerator
) {
669 const views::View
* focused_view
= focus_manager()->GetFocusedView();
670 if (focused_view
&& (focused_view
->id() == VIEW_ID_OMNIBOX
))
671 return false; // Let the omnibox handle all accelerator events.
672 return AccessiblePaneView::AcceleratorPressed(accelerator
);
675 bool ToolbarView::IsWrenchMenuShowing() const {
676 return wrench_menu_
.get() && wrench_menu_
->IsShowing();
679 bool ToolbarView::ShouldPaintBackground() const {
680 return display_mode_
== DISPLAYMODE_NORMAL
;
683 ////////////////////////////////////////////////////////////////////////////////
684 // ToolbarView, protected:
686 // Override this so that when the user presses F6 to rotate toolbar panes,
687 // the location bar gets focus, not the first control in the toolbar - and
688 // also so that it selects all content in the location bar.
689 bool ToolbarView::SetPaneFocusAndFocusDefault() {
690 if (!location_bar_
->HasFocus()) {
691 SetPaneFocus(location_bar_
);
692 location_bar_
->FocusLocation(true);
696 if (!AccessiblePaneView::SetPaneFocusAndFocusDefault())
698 browser_
->window()->RotatePaneFocus(true);
702 void ToolbarView::RemovePaneFocus() {
703 AccessiblePaneView::RemovePaneFocus();
704 location_bar_
->SetShowFocusRect(false);
707 ////////////////////////////////////////////////////////////////////////////////
708 // ToolbarView, private:
710 // views::ViewTargeterDelegate:
711 bool ToolbarView::DoesIntersectRect(const views::View
* target
,
712 const gfx::Rect
& rect
) const {
713 CHECK_EQ(target
, this);
715 // Fall through to the tab strip above us if none of |rect| intersects
716 // with this view (intersection with the top shadow edge does not
717 // count as intersection with this view).
718 if (rect
.bottom() < content_shadow_height())
720 // Otherwise let our superclass take care of it.
721 return ViewTargeterDelegate::DoesIntersectRect(this, rect
);
724 void ToolbarView::UpdateBadgeSeverity(WrenchMenuBadgeController::BadgeType type
,
725 WrenchIconPainter::Severity severity
,
727 // Showing the bubble requires |app_menu_| to be in a widget. See comment
728 // in ConflictingModuleView for details.
729 DCHECK(app_menu_
->GetWidget());
731 base::string16 accname_app
= l10n_util::GetStringUTF16(IDS_ACCNAME_APP
);
732 if (type
== WrenchMenuBadgeController::BADGE_TYPE_UPGRADE_NOTIFICATION
) {
733 accname_app
= l10n_util::GetStringFUTF16(
734 IDS_ACCNAME_APP_UPGRADE_RECOMMENDED
, accname_app
);
736 app_menu_
->SetAccessibleName(accname_app
);
737 app_menu_
->SetSeverity(severity
, animate
);
739 // Keep track of whether we were showing the badge before, so we don't send
740 // multiple UMA events for example when multiple Chrome windows are open.
741 static bool incompatibility_badge_showing
= false;
742 // Save the old value before resetting it.
743 bool was_showing
= incompatibility_badge_showing
;
744 incompatibility_badge_showing
= false;
746 if (type
== WrenchMenuBadgeController::BADGE_TYPE_INCOMPATIBILITY_WARNING
) {
748 content::RecordAction(UserMetricsAction("ConflictBadge"));
750 ConflictingModuleView::MaybeShow(browser_
, app_menu_
);
753 incompatibility_badge_showing
= true;
758 int ToolbarView::PopupTopSpacing() const {
759 const int kPopupTopSpacingNonGlass
= 3;
760 return GetWidget()->ShouldWindowContentsBeTransparent() ?
761 0 : kPopupTopSpacingNonGlass
;
764 gfx::Size
ToolbarView::SizeForContentSize(gfx::Size size
) const {
765 if (is_display_mode_normal()) {
766 // For Material Design the size of ToolbarView is encoded as a constant in
767 // ThemeProperties. For non-material the size is based on the provided
769 if (ui::MaterialDesignController::IsModeMaterial()) {
770 int content_height
= std::max(back_
->GetPreferredSize().height(),
771 location_bar_
->GetPreferredSize().height());
772 int padding
= GetThemeProvider()->GetDisplayProperty(
773 ThemeProperties::PROPERTY_TOOLBAR_VIEW_VERTICAL_PADDING
);
774 size
.SetToMax(gfx::Size(0, content_height
+ (padding
* 2)));
776 gfx::ImageSkia
* normal_background
=
777 GetThemeProvider()->GetImageSkiaNamed(IDR_CONTENT_TOP_CENTER
);
779 gfx::Size(0, normal_background
->height() - content_shadow_height()));
781 } else if (size
.height() == 0) {
782 // Location mode with a 0 height location bar. If on ash, expand by one
783 // pixel to show a border in the title bar, otherwise leave the size as zero
785 const int kAshBorderSpacing
= 1;
786 if (browser_
->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH
)
787 size
.Enlarge(0, kAshBorderSpacing
);
789 const int kPopupBottomSpacingGlass
= 1;
790 const int kPopupBottomSpacingNonGlass
= 2;
793 PopupTopSpacing() + (GetWidget()->ShouldWindowContentsBeTransparent() ?
794 kPopupBottomSpacingGlass
: kPopupBottomSpacingNonGlass
));
799 void ToolbarView::LoadImages() {
800 ui::ThemeProvider
* tp
= GetThemeProvider();
802 back_
->SetImage(views::Button::STATE_NORMAL
,
803 *(tp
->GetImageSkiaNamed(IDR_BACK
)));
804 back_
->SetImage(views::Button::STATE_DISABLED
,
805 *(tp
->GetImageSkiaNamed(IDR_BACK_D
)));
807 forward_
->SetImage(views::Button::STATE_NORMAL
,
808 *(tp
->GetImageSkiaNamed(IDR_FORWARD
)));
809 forward_
->SetImage(views::Button::STATE_DISABLED
,
810 *(tp
->GetImageSkiaNamed(IDR_FORWARD_D
)));
812 reload_
->LoadImages();
814 home_
->SetImage(views::Button::STATE_NORMAL
,
815 *(tp
->GetImageSkiaNamed(IDR_HOME
)));
817 if (ui::MaterialDesignController::IsModeMaterial()) {
818 app_menu_
->SetImage(views::Button::STATE_NORMAL
,
819 *(tp
->GetImageSkiaNamed(IDR_TOOLS
)));
823 void ToolbarView::ShowCriticalNotification() {
825 CriticalNotificationBubbleView
* bubble_delegate
=
826 new CriticalNotificationBubbleView(app_menu_
);
827 views::BubbleDelegateView::CreateBubble(bubble_delegate
)->Show();
831 void ToolbarView::ShowOutdatedInstallNotification(bool auto_update_enabled
) {
832 if (OutdatedUpgradeBubbleView::IsAvailable()) {
833 OutdatedUpgradeBubbleView::ShowBubble(
834 app_menu_
, browser_
, auto_update_enabled
);
838 void ToolbarView::OnShowHomeButtonChanged() {
843 int ToolbarView::content_shadow_height() const {
844 ui::ThemeProvider
* theme_provider
= GetThemeProvider();
845 return theme_provider
->GetDisplayProperty(
846 browser_
->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH
847 ? ThemeProperties::PROPERTY_TOOLBAR_VIEW_CONTENT_SHADOW_HEIGHT_ASH
848 : ThemeProperties::PROPERTY_TOOLBAR_VIEW_CONTENT_SHADOW_HEIGHT
);