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/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"
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"
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"
86 #include "ash/shell.h"
89 using base::UserMetricsAction
;
90 using content::WebContents
;
94 #if !defined(OS_CHROMEOS)
97 return ash::Shell::HasInstance();
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;
116 const char ToolbarView::kViewClassName
[] = "ToolbarView";
118 ////////////////////////////////////////////////////////////////////////////////
119 // ToolbarView, public:
121 ToolbarView::ToolbarView(Browser
* browser
)
127 browser_actions_(NULL
),
130 badge_controller_(browser
->profile(), this) {
131 set_id(VIEW_ID_TOOLBAR
);
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());
153 registrar_
.Add(this, chrome::NOTIFICATION_CRITICAL_UPGRADE_INSTALLED
,
154 content::NotificationService::AllSources());
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
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
);
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
);
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
);
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
);
209 browser_actions_
= new BrowserActionsContainer(
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.
221 AddChildView(forward_
);
222 AddChildView(reload_
);
224 AddChildView(location_bar_
);
225 AddChildView(browser_actions_
);
226 AddChildView(app_menu_
);
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());
240 RecoveryInstallGlobalErrorFactory::GetForProfile(browser_
->profile());
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
,
270 extensions::ExtensionCommandsGlobalRegistry
* registry
=
271 extensions::ExtensionCommandsGlobalRegistry::Get(browser_
->profile());
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
) {
283 location_bar_
->Update(tab
);
284 if (browser_actions_
)
285 browser_actions_
->RefreshToolbarActionViews();
287 reload_
->set_menu_enabled(chrome::IsDebuggerAttachedToCurrentTab(browser_
));
290 void ToolbarView::ResetTabState(WebContents
* tab
) {
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())
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
);
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() {
352 wrench_menu_
->CloseMenu();
355 ////////////////////////////////////////////////////////////////////////////////
356 // ToolbarView, AccessiblePaneView overrides:
358 bool ToolbarView::SetPaneFocus(views::View
* initial_focus
) {
359 if (!AccessiblePaneView::SetPaneFocus(initial_focus
))
362 location_bar_
->SetShowFocusRect(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
,
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
;
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
) {
464 case chrome::NOTIFICATION_OUTDATED_INSTALL
:
465 ShowOutdatedInstallNotification(true);
467 case chrome::NOTIFICATION_OUTDATED_INSTALL_NO_AU
:
468 ShowOutdatedInstallNotification(false);
471 case chrome::NOTIFICATION_CRITICAL_UPGRADE_INSTALLED
:
472 ShowCriticalNotification();
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()
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()
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.
544 if (!is_display_mode_normal()) {
545 location_bar_
->SetBounds(0, PopupTopSpacing(), width(),
546 location_bar_
->GetPreferredSize().height());
550 // We assume all child elements except the location bar are the same height.
551 // Set child_y such that buttons appear vertically centered.
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
));
567 back_
->SetBounds(0, child_y
, back_width
+ insets
.left(), child_height
);
568 back_
->SetLeadingMargin(insets
.left());
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
);
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
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.
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())
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() {
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);
695 if (!AccessiblePaneView::SetPaneFocusAndFocusDefault())
697 browser_
->window()->RotatePaneFocus(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())
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
,
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
) {
747 content::RecordAction(UserMetricsAction("ConflictBadge"));
749 ConflictingModuleView::MaybeShow(browser_
, app_menu_
);
752 incompatibility_badge_showing
= true;
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
));
774 gfx::ImageSkia
* normal_background
=
775 GetThemeProvider()->GetImageSkiaNamed(IDR_CONTENT_TOP_CENTER
);
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
783 const int kAshBorderSpacing
= 1;
784 if (browser_
->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH
)
785 size
.Enlarge(0, kAshBorderSpacing
);
787 const int kPopupBottomSpacingGlass
= 1;
788 const int kPopupBottomSpacingNonGlass
= 2;
791 PopupTopSpacing() + (GetWidget()->ShouldWindowContentsBeTransparent() ?
792 kPopupBottomSpacingGlass
: kPopupBottomSpacingNonGlass
));
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() {
823 CriticalNotificationBubbleView
* bubble_delegate
=
824 new CriticalNotificationBubbleView(app_menu_
);
825 views::BubbleDelegateView::CreateBubble(bubble_delegate
)->Show();
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() {
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
);