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_service.h"
21 #include "chrome/browser/ui/browser.h"
22 #include "chrome/browser/ui/browser_command_controller.h"
23 #include "chrome/browser/ui/browser_commands.h"
24 #include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h"
25 #include "chrome/browser/ui/browser_instant_controller.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/omnibox/omnibox_view.h"
31 #include "chrome/browser/ui/tabs/tab_strip_model.h"
32 #include "chrome/browser/ui/toolbar/wrench_menu_model.h"
33 #include "chrome/browser/ui/view_ids.h"
34 #include "chrome/browser/ui/views/extensions/extension_message_bubble_view.h"
35 #include "chrome/browser/ui/views/extensions/extension_popup.h"
36 #include "chrome/browser/ui/views/frame/browser_view.h"
37 #include "chrome/browser/ui/views/location_bar/page_action_image_view.h"
38 #include "chrome/browser/ui/views/location_bar/page_action_with_badge_view.h"
39 #include "chrome/browser/ui/views/location_bar/star_view.h"
40 #include "chrome/browser/ui/views/location_bar/translate_icon_view.h"
41 #include "chrome/browser/ui/views/outdated_upgrade_bubble_view.h"
42 #include "chrome/browser/ui/views/toolbar/back_button.h"
43 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
44 #include "chrome/browser/ui/views/toolbar/home_button.h"
45 #include "chrome/browser/ui/views/toolbar/reload_button.h"
46 #include "chrome/browser/ui/views/toolbar/toolbar_button.h"
47 #include "chrome/browser/ui/views/toolbar/wrench_menu.h"
48 #include "chrome/browser/ui/views/toolbar/wrench_toolbar_button.h"
49 #include "chrome/common/chrome_switches.h"
50 #include "chrome/common/pref_names.h"
51 #include "chrome/grit/chromium_strings.h"
52 #include "chrome/grit/generated_resources.h"
53 #include "content/public/browser/browser_accessibility_state.h"
54 #include "content/public/browser/notification_service.h"
55 #include "content/public/browser/render_view_host.h"
56 #include "content/public/browser/user_metrics.h"
57 #include "content/public/browser/web_contents.h"
58 #include "grit/theme_resources.h"
59 #include "ui/accessibility/ax_view_state.h"
60 #include "ui/base/l10n/l10n_util.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 // The edge graphics have some built-in spacing/shadowing, so we have to adjust
96 // our spacing to make it match.
97 const int kLeftEdgeSpacing
= 3;
98 const int kRightEdgeSpacing
= 2;
100 // Ash doesn't use a rounded content area and its top edge has an extra shadow.
101 const int kContentShadowHeightAsh
= 2;
103 // Non-ash uses a rounded content area with no shadow in the assets.
104 const int kContentShadowHeight
= 0;
106 #if !defined(OS_CHROMEOS)
109 return ash::Shell::HasInstance();
114 #endif // OS_CHROMEOS
119 const char ToolbarView::kViewClassName
[] = "ToolbarView";
121 ////////////////////////////////////////////////////////////////////////////////
122 // ToolbarView, public:
124 ToolbarView::ToolbarView(Browser
* browser
)
130 browser_actions_(NULL
),
133 badge_controller_(browser
->profile(), this),
134 extension_message_bubble_factory_(
135 new extensions::ExtensionMessageBubbleFactory(browser
->profile(),
137 set_id(VIEW_ID_TOOLBAR
);
140 scoped_ptr
<views::ViewTargeter
>(new views::ViewTargeter(this)));
142 chrome::AddCommandObserver(browser_
, IDC_BACK
, this);
143 chrome::AddCommandObserver(browser_
, IDC_FORWARD
, this);
144 chrome::AddCommandObserver(browser_
, IDC_RELOAD
, this);
145 chrome::AddCommandObserver(browser_
, IDC_HOME
, this);
146 chrome::AddCommandObserver(browser_
, IDC_LOAD_NEW_TAB_PAGE
, this);
148 display_mode_
= DISPLAYMODE_LOCATION
;
149 if (browser
->SupportsWindowFeature(Browser::FEATURE_TABSTRIP
))
150 display_mode_
= DISPLAYMODE_NORMAL
;
152 if (OutdatedUpgradeBubbleView::IsAvailable()) {
153 registrar_
.Add(this, chrome::NOTIFICATION_OUTDATED_INSTALL
,
154 content::NotificationService::AllSources());
155 registrar_
.Add(this, chrome::NOTIFICATION_OUTDATED_INSTALL_NO_AU
,
156 content::NotificationService::AllSources());
159 registrar_
.Add(this, chrome::NOTIFICATION_CRITICAL_UPGRADE_INSTALLED
,
160 content::NotificationService::AllSources());
164 ToolbarView::~ToolbarView() {
165 // NOTE: Don't remove the command observers here. This object gets destroyed
166 // after the Browser (which owns the CommandUpdater), so the CommandUpdater is
170 void ToolbarView::Init() {
171 GetWidget()->AddObserver(this);
173 back_
= new BackButton(this, new BackForwardMenuModel(
174 browser_
, BackForwardMenuModel::BACKWARD_MENU
));
175 back_
->set_triggerable_event_flags(
176 ui::EF_LEFT_MOUSE_BUTTON
| ui::EF_MIDDLE_MOUSE_BUTTON
);
177 back_
->set_tag(IDC_BACK
);
178 back_
->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_BACK
));
179 back_
->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_BACK
));
180 back_
->set_id(VIEW_ID_BACK_BUTTON
);
183 forward_
= new ToolbarButton(this, new BackForwardMenuModel(
184 browser_
, BackForwardMenuModel::FORWARD_MENU
));
185 forward_
->set_triggerable_event_flags(
186 ui::EF_LEFT_MOUSE_BUTTON
| ui::EF_MIDDLE_MOUSE_BUTTON
);
187 forward_
->set_tag(IDC_FORWARD
);
188 forward_
->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_FORWARD
));
189 forward_
->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_FORWARD
));
190 forward_
->set_id(VIEW_ID_FORWARD_BUTTON
);
193 location_bar_
= new LocationBarView(
194 browser_
, browser_
->profile(),
195 browser_
->command_controller()->command_updater(), this,
196 display_mode_
== DISPLAYMODE_LOCATION
);
198 reload_
= new ReloadButton(browser_
->command_controller()->command_updater());
199 reload_
->set_triggerable_event_flags(
200 ui::EF_LEFT_MOUSE_BUTTON
| ui::EF_MIDDLE_MOUSE_BUTTON
);
201 reload_
->set_tag(IDC_RELOAD
);
202 reload_
->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_RELOAD
));
203 reload_
->set_id(VIEW_ID_RELOAD_BUTTON
);
206 home_
= new HomeButton(this, browser_
);
207 home_
->set_triggerable_event_flags(
208 ui::EF_LEFT_MOUSE_BUTTON
| ui::EF_MIDDLE_MOUSE_BUTTON
);
209 home_
->set_tag(IDC_HOME
);
210 home_
->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_HOME
));
211 home_
->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_HOME
));
212 home_
->set_id(VIEW_ID_HOME_BUTTON
);
215 browser_actions_
= new BrowserActionsContainer(
217 NULL
); // No master container for this one (it is master).
219 app_menu_
= new WrenchToolbarButton(this);
220 app_menu_
->EnableCanvasFlippingForRTLUI(true);
221 app_menu_
->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_APP
));
222 app_menu_
->SetTooltipText(l10n_util::GetStringUTF16(IDS_APPMENU_TOOLTIP
));
223 app_menu_
->set_id(VIEW_ID_APP_MENU
);
225 // Always add children in order from left to right, for accessibility.
227 AddChildView(forward_
);
228 AddChildView(reload_
);
230 AddChildView(location_bar_
);
231 AddChildView(browser_actions_
);
232 AddChildView(app_menu_
);
236 // Start global error services now so we badge the menu correctly.
237 #if !defined(OS_CHROMEOS)
238 if (!HasAshShell()) {
239 SigninGlobalErrorFactory::GetForProfile(browser_
->profile());
240 #if !defined(OS_ANDROID)
241 SyncGlobalErrorFactory::GetForProfile(browser_
->profile());
246 RecoveryInstallGlobalErrorFactory::GetForProfile(browser_
->profile());
248 #endif // OS_CHROMEOS
250 // Add any necessary badges to the menu item based on the system state.
251 // Do this after |app_menu_| has been added as a bubble may be shown that
252 // needs the widget (widget found by way of app_menu_->GetWidget()).
253 badge_controller_
.UpdateDelegate();
255 location_bar_
->Init();
257 show_home_button_
.Init(prefs::kShowHomeButton
,
258 browser_
->profile()->GetPrefs(),
259 base::Bind(&ToolbarView::OnShowHomeButtonChanged
,
260 base::Unretained(this)));
262 browser_actions_
->Init();
264 // Accessibility specific tooltip text.
265 if (content::BrowserAccessibilityState::GetInstance()->
266 IsAccessibleBrowser()) {
267 back_
->SetTooltipText(
268 l10n_util::GetStringUTF16(IDS_ACCNAME_TOOLTIP_BACK
));
269 forward_
->SetTooltipText(
270 l10n_util::GetStringUTF16(IDS_ACCNAME_TOOLTIP_FORWARD
));
274 void ToolbarView::OnWidgetVisibilityChanged(views::Widget
* widget
,
277 // Safe to call multiple times; the bubble will only appear once.
278 extension_message_bubble_factory_
->MaybeShow(app_menu_
);
282 void ToolbarView::OnWidgetActivationChanged(views::Widget
* widget
,
284 extensions::ExtensionCommandsGlobalRegistry
* registry
=
285 extensions::ExtensionCommandsGlobalRegistry::Get(browser_
->profile());
287 registry
->set_registry_for_active_window(
288 browser_actions_
->extension_keybinding_registry());
289 } else if (registry
->registry_for_active_window() ==
290 browser_actions_
->extension_keybinding_registry()) {
291 registry
->set_registry_for_active_window(nullptr);
295 void ToolbarView::Update(WebContents
* tab
) {
297 location_bar_
->Update(tab
);
298 if (browser_actions_
)
299 browser_actions_
->RefreshToolbarActionViews();
301 reload_
->set_menu_enabled(chrome::IsDebuggerAttachedToCurrentTab(browser_
));
304 void ToolbarView::ResetTabState(WebContents
* tab
) {
306 location_bar_
->ResetTabState(tab
);
309 void ToolbarView::SetPaneFocusAndFocusAppMenu() {
310 SetPaneFocus(app_menu_
);
313 bool ToolbarView::IsAppMenuFocused() {
314 return app_menu_
->HasFocus();
317 void ToolbarView::AddMenuListener(views::MenuListener
* listener
) {
318 menu_listeners_
.AddObserver(listener
);
321 void ToolbarView::RemoveMenuListener(views::MenuListener
* listener
) {
322 menu_listeners_
.RemoveObserver(listener
);
325 views::View
* ToolbarView::GetBookmarkBubbleAnchor() {
326 views::View
* star_view
= location_bar()->star_view();
327 return (star_view
&& star_view
->visible()) ? star_view
: app_menu_
;
330 views::View
* ToolbarView::GetTranslateBubbleAnchor() {
331 views::View
* translate_icon_view
= location_bar()->translate_icon_view();
332 return (translate_icon_view
&& translate_icon_view
->visible()) ?
333 translate_icon_view
: app_menu_
;
336 void ToolbarView::ExecuteExtensionCommand(
337 const extensions::Extension
* extension
,
338 const extensions::Command
& command
) {
339 browser_actions_
->ExecuteExtensionCommand(extension
, command
);
342 void ToolbarView::ShowAppMenu(bool for_drop
) {
343 if (wrench_menu_
.get() && wrench_menu_
->IsShowing())
346 #if defined(USE_AURA)
347 if (keyboard::KeyboardController::GetInstance() &&
348 keyboard::KeyboardController::GetInstance()->keyboard_visible()) {
349 keyboard::KeyboardController::GetInstance()->HideKeyboard(
350 keyboard::KeyboardController::HIDE_REASON_AUTOMATIC
);
355 new WrenchMenu(browser_
, for_drop
? WrenchMenu::FOR_DROP
: 0));
356 wrench_menu_model_
.reset(new WrenchMenuModel(this, browser_
));
357 wrench_menu_
->Init(wrench_menu_model_
.get());
359 FOR_EACH_OBSERVER(views::MenuListener
, menu_listeners_
, OnMenuOpened());
361 wrench_menu_
->RunMenu(app_menu_
);
364 ////////////////////////////////////////////////////////////////////////////////
365 // ToolbarView, AccessiblePaneView overrides:
367 bool ToolbarView::SetPaneFocus(views::View
* initial_focus
) {
368 if (!AccessiblePaneView::SetPaneFocus(initial_focus
))
371 location_bar_
->SetShowFocusRect(true);
375 void ToolbarView::GetAccessibleState(ui::AXViewState
* state
) {
376 state
->role
= ui::AX_ROLE_TOOLBAR
;
377 state
->name
= l10n_util::GetStringUTF16(IDS_ACCNAME_TOOLBAR
);
380 ////////////////////////////////////////////////////////////////////////////////
381 // ToolbarView, Menu::Delegate overrides:
383 bool ToolbarView::GetAcceleratorInfo(int id
, ui::Accelerator
* accel
) {
384 return GetWidget()->GetAccelerator(id
, accel
);
387 ////////////////////////////////////////////////////////////////////////////////
388 // ToolbarView, views::MenuButtonListener implementation:
390 void ToolbarView::OnMenuButtonClicked(views::View
* source
,
391 const gfx::Point
& point
) {
392 TRACE_EVENT0("views", "ToolbarView::OnMenuButtonClicked");
393 DCHECK_EQ(VIEW_ID_APP_MENU
, source
->id());
394 ShowAppMenu(false); // Not for drop.
397 ////////////////////////////////////////////////////////////////////////////////
398 // ToolbarView, LocationBarView::Delegate implementation:
400 WebContents
* ToolbarView::GetWebContents() {
401 return browser_
->tab_strip_model()->GetActiveWebContents();
404 ToolbarModel
* ToolbarView::GetToolbarModel() {
405 return browser_
->toolbar_model();
408 const ToolbarModel
* ToolbarView::GetToolbarModel() const {
409 return browser_
->toolbar_model();
412 InstantController
* ToolbarView::GetInstant() {
413 return browser_
->instant_controller() ?
414 browser_
->instant_controller()->instant() : NULL
;
417 ContentSettingBubbleModelDelegate
*
418 ToolbarView::GetContentSettingBubbleModelDelegate() {
419 return browser_
->content_setting_bubble_model_delegate();
422 void ToolbarView::ShowWebsiteSettings(content::WebContents
* web_contents
,
424 const content::SSLStatus
& ssl
) {
425 chrome::ShowWebsiteSettings(browser_
, web_contents
, url
, ssl
);
428 views::Widget
* ToolbarView::CreateViewsBubble(
429 views::BubbleDelegateView
* bubble_delegate
) {
430 return views::BubbleDelegateView::CreateBubble(bubble_delegate
);
433 PageActionImageView
* ToolbarView::CreatePageActionImageView(
434 LocationBarView
* owner
, ExtensionAction
* action
) {
435 return new PageActionImageView(owner
, action
, browser_
);
438 ////////////////////////////////////////////////////////////////////////////////
439 // ToolbarView, CommandObserver implementation:
441 void ToolbarView::EnabledStateChangedForCommand(int id
, bool enabled
) {
442 views::Button
* button
= NULL
;
458 button
->SetEnabled(enabled
);
461 ////////////////////////////////////////////////////////////////////////////////
462 // ToolbarView, views::Button::ButtonListener implementation:
464 void ToolbarView::ButtonPressed(views::Button
* sender
,
465 const ui::Event
& event
) {
466 chrome::ExecuteCommandWithDisposition(
467 browser_
, sender
->tag(), ui::DispositionFromEventFlags(event
.flags()));
470 ////////////////////////////////////////////////////////////////////////////////
471 // ToolbarView, content::NotificationObserver implementation:
473 void ToolbarView::Observe(int type
,
474 const content::NotificationSource
& source
,
475 const content::NotificationDetails
& details
) {
477 case chrome::NOTIFICATION_OUTDATED_INSTALL
:
478 ShowOutdatedInstallNotification(true);
480 case chrome::NOTIFICATION_OUTDATED_INSTALL_NO_AU
:
481 ShowOutdatedInstallNotification(false);
484 case chrome::NOTIFICATION_CRITICAL_UPGRADE_INSTALLED
:
485 ShowCriticalNotification();
493 ////////////////////////////////////////////////////////////////////////////////
494 // ToolbarView, ui::AcceleratorProvider implementation:
496 bool ToolbarView::GetAcceleratorForCommandId(int command_id
,
497 ui::Accelerator
* accelerator
) {
498 return GetWidget()->GetAccelerator(command_id
, accelerator
);
501 ////////////////////////////////////////////////////////////////////////////////
502 // ToolbarView, views::View overrides:
504 gfx::Size
ToolbarView::GetPreferredSize() const {
505 gfx::Size
size(location_bar_
->GetPreferredSize());
506 if (is_display_mode_normal()) {
507 int content_width
= kLeftEdgeSpacing
+ back_
->GetPreferredSize().width() +
508 forward_
->GetPreferredSize().width() +
509 reload_
->GetPreferredSize().width() +
510 (show_home_button_
.GetValue() ? home_
->GetPreferredSize().width() : 0) +
511 kStandardSpacing
+ browser_actions_
->GetPreferredSize().width() +
512 app_menu_
->GetPreferredSize().width() + kRightEdgeSpacing
;
513 size
.Enlarge(content_width
, 0);
515 return SizeForContentSize(size
);
518 gfx::Size
ToolbarView::GetMinimumSize() const {
519 gfx::Size
size(location_bar_
->GetMinimumSize());
520 if (is_display_mode_normal()) {
521 int content_width
= kLeftEdgeSpacing
+ back_
->GetMinimumSize().width() +
522 forward_
->GetMinimumSize().width() + reload_
->GetMinimumSize().width() +
523 (show_home_button_
.GetValue() ? home_
->GetMinimumSize().width() : 0) +
524 kStandardSpacing
+ browser_actions_
->GetMinimumSize().width() +
525 app_menu_
->GetMinimumSize().width() + kRightEdgeSpacing
;
526 size
.Enlarge(content_width
, 0);
528 return SizeForContentSize(size
);
531 void ToolbarView::Layout() {
532 // If we have not been initialized yet just do nothing.
536 if (!is_display_mode_normal()) {
537 location_bar_
->SetBounds(0, PopupTopSpacing(), width(),
538 location_bar_
->GetPreferredSize().height());
542 // We assume all child elements except the location bar are the same height.
543 // Set child_y such that buttons appear vertically centered. We put any excess
544 // padding above the buttons.
546 std::min(back_
->GetPreferredSize().height(), height());
547 int child_y
= (height() - child_height
+ 1) / 2;
549 // If the window is maximized, we extend the back button to the left so that
550 // clicking on the left-most pixel will activate the back button.
551 // TODO(abarth): If the window becomes maximized but is not resized,
552 // then Layout() might not be called and the back button
553 // will be slightly the wrong size. We should force a
554 // Layout() in this case.
555 // http://crbug.com/5540
556 bool maximized
= browser_
->window() && browser_
->window()->IsMaximized();
557 int back_width
= back_
->GetPreferredSize().width();
559 back_
->SetBounds(0, child_y
, back_width
+ kLeftEdgeSpacing
, child_height
);
560 back_
->SetLeadingMargin(kLeftEdgeSpacing
);
562 back_
->SetBounds(kLeftEdgeSpacing
, child_y
, back_width
, child_height
);
563 back_
->SetLeadingMargin(0);
565 int next_element_x
= back_
->bounds().right();
567 forward_
->SetBounds(next_element_x
, child_y
,
568 forward_
->GetPreferredSize().width(), child_height
);
569 next_element_x
= forward_
->bounds().right();
571 reload_
->SetBounds(next_element_x
, child_y
,
572 reload_
->GetPreferredSize().width(), child_height
);
573 next_element_x
= reload_
->bounds().right();
575 if (show_home_button_
.GetValue() ||
576 (browser_
->is_app() && extensions::util::IsNewBookmarkAppsEnabled())) {
577 home_
->SetVisible(true);
578 home_
->SetBounds(next_element_x
, child_y
,
579 home_
->GetPreferredSize().width(), child_height
);
581 home_
->SetVisible(false);
582 home_
->SetBounds(next_element_x
, child_y
, 0, child_height
);
584 next_element_x
= home_
->bounds().right() + kStandardSpacing
;
586 int browser_actions_width
= browser_actions_
->GetPreferredSize().width();
587 int app_menu_width
= app_menu_
->GetPreferredSize().width();
588 int available_width
= std::max(0, width() - kRightEdgeSpacing
-
589 app_menu_width
- browser_actions_width
- next_element_x
);
591 int location_height
= location_bar_
->GetPreferredSize().height();
592 int location_y
= (height() - location_height
+ 1) / 2;
593 location_bar_
->SetBounds(next_element_x
, location_y
,
594 std::max(available_width
, 0), location_height
);
595 next_element_x
= location_bar_
->bounds().right();
597 browser_actions_
->SetBounds(
598 next_element_x
, child_y
, browser_actions_width
, child_height
);
599 next_element_x
= browser_actions_
->bounds().right();
601 // The browser actions need to do a layout explicitly, because when an
602 // extension is loaded/unloaded/changed, BrowserActionContainer removes and
603 // re-adds everything, regardless of whether it has a page action. For a
604 // page action, browser action bounds do not change, as a result of which
605 // SetBounds does not do a layout at all.
606 // TODO(sidchat): Rework the above behavior so that explicit layout is not
608 browser_actions_
->Layout();
610 // Extend the app menu to the screen's right edge in maximized mode just like
611 // we extend the back button to the left edge.
613 app_menu_width
+= kRightEdgeSpacing
;
614 app_menu_
->SetBounds(next_element_x
, child_y
, app_menu_width
, child_height
);
617 void ToolbarView::OnPaint(gfx::Canvas
* canvas
) {
618 View::OnPaint(canvas
);
620 if (is_display_mode_normal())
623 // For glass, we need to draw a black line below the location bar to separate
624 // it from the content area. For non-glass, the NonClientView draws the
625 // toolbar background below the location bar for us.
626 // NOTE: Keep this in sync with BrowserView::GetInfoBarSeparatorColor()!
627 if (GetWidget()->ShouldWindowContentsBeTransparent())
628 canvas
->FillRect(gfx::Rect(0, height() - 1, width(), 1), SK_ColorBLACK
);
631 void ToolbarView::OnThemeChanged() {
635 const char* ToolbarView::GetClassName() const {
636 return kViewClassName
;
639 bool ToolbarView::AcceleratorPressed(const ui::Accelerator
& accelerator
) {
640 const views::View
* focused_view
= focus_manager()->GetFocusedView();
641 if (focused_view
&& (focused_view
->id() == VIEW_ID_OMNIBOX
))
642 return false; // Let the omnibox handle all accelerator events.
643 return AccessiblePaneView::AcceleratorPressed(accelerator
);
646 bool ToolbarView::IsWrenchMenuShowing() const {
647 return wrench_menu_
.get() && wrench_menu_
->IsShowing();
650 bool ToolbarView::ShouldPaintBackground() const {
651 return display_mode_
== DISPLAYMODE_NORMAL
;
654 ////////////////////////////////////////////////////////////////////////////////
655 // ToolbarView, protected:
657 // Override this so that when the user presses F6 to rotate toolbar panes,
658 // the location bar gets focus, not the first control in the toolbar - and
659 // also so that it selects all content in the location bar.
660 bool ToolbarView::SetPaneFocusAndFocusDefault() {
661 if (!location_bar_
->HasFocus()) {
662 SetPaneFocus(location_bar_
);
663 location_bar_
->FocusLocation(true);
667 if (!AccessiblePaneView::SetPaneFocusAndFocusDefault())
669 browser_
->window()->RotatePaneFocus(true);
673 void ToolbarView::RemovePaneFocus() {
674 AccessiblePaneView::RemovePaneFocus();
675 location_bar_
->SetShowFocusRect(false);
678 ////////////////////////////////////////////////////////////////////////////////
679 // ToolbarView, private:
681 // views::ViewTargeterDelegate:
682 bool ToolbarView::DoesIntersectRect(const views::View
* target
,
683 const gfx::Rect
& rect
) const {
684 CHECK_EQ(target
, this);
686 // Fall through to the tab strip above us if none of |rect| intersects
687 // with this view (intersection with the top shadow edge does not
688 // count as intersection with this view).
689 if (rect
.bottom() < content_shadow_height())
691 // Otherwise let our superclass take care of it.
692 return ViewTargeterDelegate::DoesIntersectRect(this, rect
);
695 void ToolbarView::UpdateBadgeSeverity(WrenchMenuBadgeController::BadgeType type
,
696 WrenchIconPainter::Severity severity
,
698 // Showing the bubble requires |app_menu_| to be in a widget. See comment
699 // in ConflictingModuleView for details.
700 DCHECK(app_menu_
->GetWidget());
702 base::string16 accname_app
= l10n_util::GetStringUTF16(IDS_ACCNAME_APP
);
703 if (type
== WrenchMenuBadgeController::BADGE_TYPE_UPGRADE_NOTIFICATION
) {
704 accname_app
= l10n_util::GetStringFUTF16(
705 IDS_ACCNAME_APP_UPGRADE_RECOMMENDED
, accname_app
);
707 app_menu_
->SetAccessibleName(accname_app
);
708 app_menu_
->SetSeverity(severity
, animate
);
710 // Keep track of whether we were showing the badge before, so we don't send
711 // multiple UMA events for example when multiple Chrome windows are open.
712 static bool incompatibility_badge_showing
= false;
713 // Save the old value before resetting it.
714 bool was_showing
= incompatibility_badge_showing
;
715 incompatibility_badge_showing
= false;
717 if (type
== WrenchMenuBadgeController::BADGE_TYPE_INCOMPATIBILITY_WARNING
) {
719 content::RecordAction(UserMetricsAction("ConflictBadge"));
721 ConflictingModuleView::MaybeShow(browser_
, app_menu_
);
724 incompatibility_badge_showing
= true;
729 int ToolbarView::PopupTopSpacing() const {
730 const int kPopupTopSpacingNonGlass
= 3;
731 return GetWidget()->ShouldWindowContentsBeTransparent() ?
732 0 : kPopupTopSpacingNonGlass
;
735 gfx::Size
ToolbarView::SizeForContentSize(gfx::Size size
) const {
736 if (is_display_mode_normal()) {
737 gfx::ImageSkia
* normal_background
=
738 GetThemeProvider()->GetImageSkiaNamed(IDR_CONTENT_TOP_CENTER
);
740 gfx::Size(0, normal_background
->height() - content_shadow_height()));
742 const int kPopupBottomSpacingGlass
= 1;
743 const int kPopupBottomSpacingNonGlass
= 2;
746 PopupTopSpacing() + (GetWidget()->ShouldWindowContentsBeTransparent() ?
747 kPopupBottomSpacingGlass
: kPopupBottomSpacingNonGlass
));
752 void ToolbarView::LoadImages() {
753 ui::ThemeProvider
* tp
= GetThemeProvider();
755 back_
->SetImage(views::Button::STATE_NORMAL
,
756 *(tp
->GetImageSkiaNamed(IDR_BACK
)));
757 back_
->SetImage(views::Button::STATE_DISABLED
,
758 *(tp
->GetImageSkiaNamed(IDR_BACK_D
)));
760 forward_
->SetImage(views::Button::STATE_NORMAL
,
761 *(tp
->GetImageSkiaNamed(IDR_FORWARD
)));
762 forward_
->SetImage(views::Button::STATE_DISABLED
,
763 *(tp
->GetImageSkiaNamed(IDR_FORWARD_D
)));
765 reload_
->LoadImages();
767 home_
->SetImage(views::Button::STATE_NORMAL
,
768 *(tp
->GetImageSkiaNamed(IDR_HOME
)));
771 void ToolbarView::ShowCriticalNotification() {
773 CriticalNotificationBubbleView
* bubble_delegate
=
774 new CriticalNotificationBubbleView(app_menu_
);
775 views::BubbleDelegateView::CreateBubble(bubble_delegate
)->Show();
779 void ToolbarView::ShowOutdatedInstallNotification(bool auto_update_enabled
) {
780 if (OutdatedUpgradeBubbleView::IsAvailable()) {
781 OutdatedUpgradeBubbleView::ShowBubble(
782 app_menu_
, browser_
, auto_update_enabled
);
786 void ToolbarView::OnShowHomeButtonChanged() {
791 int ToolbarView::content_shadow_height() const {
792 return browser_
->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH
?
793 kContentShadowHeightAsh
: kContentShadowHeight
;