Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / views / toolbar / toolbar_view.cc
blob62764c7e6c904bac11caa190bd96a416c5e9dd8e
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 "base/command_line.h"
8 #include "base/debug/trace_event.h"
9 #include "base/i18n/number_formatting.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/app/chrome_command_ids.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/command_updater.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/search/search.h"
17 #include "chrome/browser/themes/theme_service.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_command_controller.h"
20 #include "chrome/browser/ui/browser_commands.h"
21 #include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h"
22 #include "chrome/browser/ui/browser_instant_controller.h"
23 #include "chrome/browser/ui/browser_tabstrip.h"
24 #include "chrome/browser/ui/browser_window.h"
25 #include "chrome/browser/ui/global_error/global_error_service.h"
26 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
27 #include "chrome/browser/ui/omnibox/omnibox_view.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_message_bubble_view.h"
32 #include "chrome/browser/ui/views/frame/browser_view.h"
33 #include "chrome/browser/ui/views/location_bar/page_action_image_view.h"
34 #include "chrome/browser/ui/views/location_bar/star_view.h"
35 #include "chrome/browser/ui/views/location_bar/translate_icon_view.h"
36 #include "chrome/browser/ui/views/outdated_upgrade_bubble_view.h"
37 #include "chrome/browser/ui/views/toolbar/back_button.h"
38 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
39 #include "chrome/browser/ui/views/toolbar/home_button.h"
40 #include "chrome/browser/ui/views/toolbar/reload_button.h"
41 #include "chrome/browser/ui/views/toolbar/site_chip_view.h"
42 #include "chrome/browser/ui/views/toolbar/toolbar_button.h"
43 #include "chrome/browser/ui/views/toolbar/wrench_menu.h"
44 #include "chrome/browser/ui/views/toolbar/wrench_toolbar_button.h"
45 #include "chrome/browser/upgrade_detector.h"
46 #include "chrome/common/chrome_switches.h"
47 #include "chrome/common/pref_names.h"
48 #include "content/public/browser/browser_accessibility_state.h"
49 #include "content/public/browser/notification_service.h"
50 #include "content/public/browser/render_view_host.h"
51 #include "content/public/browser/user_metrics.h"
52 #include "content/public/browser/web_contents.h"
53 #include "content/public/browser/web_contents_view.h"
54 #include "grit/chromium_strings.h"
55 #include "grit/generated_resources.h"
56 #include "grit/theme_resources.h"
57 #include "ui/base/accessibility/accessible_view_state.h"
58 #include "ui/base/l10n/l10n_util.h"
59 #include "ui/base/layout.h"
60 #include "ui/base/theme_provider.h"
61 #include "ui/base/window_open_disposition.h"
62 #include "ui/gfx/canvas.h"
63 #include "ui/gfx/image/canvas_image_source.h"
64 #include "ui/views/controls/menu/menu_listener.h"
65 #include "ui/views/focus/view_storage.h"
66 #include "ui/views/widget/tooltip_manager.h"
67 #include "ui/views/widget/widget.h"
68 #include "ui/views/window/non_client_view.h"
70 #if defined(OS_WIN)
71 #include "base/win/windows_version.h"
72 #include "chrome/browser/enumerate_modules_model_win.h"
73 #include "chrome/browser/ui/views/conflicting_module_view_win.h"
74 #include "chrome/browser/ui/views/critical_notification_bubble_view.h"
75 #endif
77 #if defined(USE_AURA)
78 #include "ui/aura/window.h"
79 #include "ui/compositor/layer.h"
80 #include "ui/native_theme/native_theme_aura.h"
81 #endif
83 using base::UserMetricsAction;
84 using content::WebContents;
86 namespace {
88 // The edge graphics have some built-in spacing/shadowing, so we have to adjust
89 // our spacing to make it match.
90 const int kLeftEdgeSpacing = 3;
91 const int kRightEdgeSpacing = 2;
93 // Ash doesn't use a rounded content area and its top edge has an extra shadow.
94 const int kContentShadowHeightAsh = 2;
96 // Non-ash uses a rounded content area with no shadow in the assets.
97 const int kContentShadowHeight = 0;
99 int GetButtonSpacing() {
100 return (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH) ?
101 ToolbarView::kStandardSpacing : 0;
104 } // namespace
106 // static
107 const char ToolbarView::kViewClassName[] = "ToolbarView";
109 ////////////////////////////////////////////////////////////////////////////////
110 // ToolbarView, public:
112 ToolbarView::ToolbarView(Browser* browser)
113 : back_(NULL),
114 forward_(NULL),
115 reload_(NULL),
116 home_(NULL),
117 location_bar_(NULL),
118 site_chip_view_(NULL),
119 browser_actions_(NULL),
120 app_menu_(NULL),
121 browser_(browser) {
122 set_id(VIEW_ID_TOOLBAR);
124 chrome::AddCommandObserver(browser_, IDC_BACK, this);
125 chrome::AddCommandObserver(browser_, IDC_FORWARD, this);
126 chrome::AddCommandObserver(browser_, IDC_RELOAD, this);
127 chrome::AddCommandObserver(browser_, IDC_HOME, this);
128 chrome::AddCommandObserver(browser_, IDC_LOAD_NEW_TAB_PAGE, this);
130 display_mode_ = DISPLAYMODE_LOCATION;
131 if (browser->SupportsWindowFeature(Browser::FEATURE_TABSTRIP) ||
132 (browser->is_app() && CommandLine::ForCurrentProcess()->HasSwitch(
133 switches::kEnableStreamlinedHostedApps)))
134 display_mode_ = DISPLAYMODE_NORMAL;
136 registrar_.Add(this, chrome::NOTIFICATION_UPGRADE_RECOMMENDED,
137 content::NotificationService::AllSources());
138 if (OutdatedUpgradeBubbleView::IsAvailable()) {
139 registrar_.Add(this, chrome::NOTIFICATION_OUTDATED_INSTALL,
140 content::NotificationService::AllSources());
142 #if defined(OS_WIN)
143 registrar_.Add(this, chrome::NOTIFICATION_CRITICAL_UPGRADE_INSTALLED,
144 content::NotificationService::AllSources());
145 if (base::win::GetVersion() == base::win::VERSION_XP) {
146 registrar_.Add(this, chrome::NOTIFICATION_MODULE_LIST_ENUMERATED,
147 content::NotificationService::AllSources());
149 #endif
150 registrar_.Add(this,
151 chrome::NOTIFICATION_MODULE_INCOMPATIBILITY_BADGE_CHANGE,
152 content::NotificationService::AllSources());
153 registrar_.Add(this, chrome::NOTIFICATION_GLOBAL_ERRORS_CHANGED,
154 content::Source<Profile>(browser_->profile()));
157 ToolbarView::~ToolbarView() {
158 // NOTE: Don't remove the command observers here. This object gets destroyed
159 // after the Browser (which owns the CommandUpdater), so the CommandUpdater is
160 // already gone.
163 void ToolbarView::Init() {
164 GetWidget()->AddObserver(this);
166 back_ = new BackButton(this, new BackForwardMenuModel(
167 browser_, BackForwardMenuModel::BACKWARD_MENU));
168 back_->set_triggerable_event_flags(
169 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_MIDDLE_MOUSE_BUTTON);
170 back_->set_tag(IDC_BACK);
171 back_->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_BACK));
172 back_->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_BACK));
173 back_->set_id(VIEW_ID_BACK_BUTTON);
174 back_->Init();
176 forward_ = new ToolbarButton(this, new BackForwardMenuModel(
177 browser_, BackForwardMenuModel::FORWARD_MENU));
178 forward_->set_triggerable_event_flags(
179 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_MIDDLE_MOUSE_BUTTON);
180 forward_->set_tag(IDC_FORWARD);
181 forward_->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_FORWARD));
182 forward_->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_FORWARD));
183 forward_->set_id(VIEW_ID_FORWARD_BUTTON);
184 forward_->Init();
186 // Have to create this before |reload_| as |reload_|'s constructor needs it.
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(location_bar_,
193 browser_->command_controller()->command_updater());
194 reload_->set_triggerable_event_flags(
195 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_MIDDLE_MOUSE_BUTTON);
196 reload_->set_tag(IDC_RELOAD);
197 reload_->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_RELOAD));
198 reload_->set_id(VIEW_ID_RELOAD_BUTTON);
199 reload_->Init();
201 home_ = new HomeButton(this, browser_);
202 home_->set_triggerable_event_flags(
203 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_MIDDLE_MOUSE_BUTTON);
204 home_->set_tag(IDC_HOME);
205 home_->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_HOME));
206 home_->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_HOME));
207 home_->set_id(VIEW_ID_HOME_BUTTON);
208 home_->Init();
210 browser_actions_ = new BrowserActionsContainer(browser_, this);
212 app_menu_ = new WrenchToolbarButton(this);
213 app_menu_->set_border(NULL);
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 site_chip_view_ = new SiteChipView(this);
221 chrome::OriginChipPosition origin_chip_position =
222 chrome::GetOriginChipPosition();
223 AddChildView(back_);
224 AddChildView(forward_);
225 AddChildView(reload_);
226 AddChildView(home_);
227 if (origin_chip_position == chrome::ORIGIN_CHIP_LEADING_LOCATION_BAR)
228 AddChildView(site_chip_view_);
229 AddChildView(location_bar_);
230 if (origin_chip_position == chrome::ORIGIN_CHIP_TRAILING_LOCATION_BAR)
231 AddChildView(site_chip_view_);
232 AddChildView(browser_actions_);
233 if (origin_chip_position == chrome::ORIGIN_CHIP_LEADING_MENU_BUTTON ||
234 origin_chip_position == chrome::ORIGIN_CHIP_DISABLED)
235 AddChildView(site_chip_view_);
236 AddChildView(app_menu_);
238 LoadImages();
240 // Add any necessary badges to the menu item based on the system state.
241 // Do this after |app_menu_| has been added as a bubble may be shown that
242 // needs the widget (widget found by way of app_menu_->GetWidget()).
243 UpdateAppMenuState();
245 location_bar_->Init();
247 site_chip_view_->Init();
248 if (site_chip_view_->ShouldShow())
249 location_bar_->set_site_chip_view(site_chip_view_);
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::OnWidgetVisibilityChanged(views::Widget* widget,
269 bool visible) {
270 if (visible) {
271 extensions::ExtensionMessageBubbleView::MaybeShow(
272 browser_, this, app_menu_);
273 GetWidget()->RemoveObserver(this);
277 void ToolbarView::Update(WebContents* tab) {
278 if (location_bar_)
279 location_bar_->Update(tab);
280 if (site_chip_view_->ShouldShow())
281 site_chip_view_->Update(tab);
283 if (browser_actions_)
284 browser_actions_->RefreshBrowserActionViews();
286 if (reload_)
287 reload_->set_menu_enabled(chrome::IsDebuggerAttachedToCurrentTab(browser_));
290 void ToolbarView::SetPaneFocusAndFocusAppMenu() {
291 SetPaneFocus(app_menu_);
294 bool ToolbarView::IsAppMenuFocused() {
295 return app_menu_->HasFocus();
298 void ToolbarView::AddMenuListener(views::MenuListener* listener) {
299 menu_listeners_.AddObserver(listener);
302 void ToolbarView::RemoveMenuListener(views::MenuListener* listener) {
303 menu_listeners_.RemoveObserver(listener);
306 views::View* ToolbarView::GetBookmarkBubbleAnchor() {
307 views::View* star_view = location_bar()->star_view();
308 return (star_view && star_view->visible()) ? star_view : app_menu_;
311 views::View* ToolbarView::GetTranslateBubbleAnchor() {
312 views::View* translate_icon_view = location_bar()->translate_icon_view();
313 return (translate_icon_view && translate_icon_view->visible()) ?
314 translate_icon_view : app_menu_;
317 views::MenuButton* ToolbarView::app_menu() const {
318 return app_menu_;
321 ////////////////////////////////////////////////////////////////////////////////
322 // ToolbarView, AccessiblePaneView overrides:
324 bool ToolbarView::SetPaneFocus(views::View* initial_focus) {
325 if (!AccessiblePaneView::SetPaneFocus(initial_focus))
326 return false;
328 location_bar_->SetShowFocusRect(true);
329 return true;
332 void ToolbarView::GetAccessibleState(ui::AccessibleViewState* state) {
333 state->role = ui::AccessibilityTypes::ROLE_TOOLBAR;
334 state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_TOOLBAR);
337 ////////////////////////////////////////////////////////////////////////////////
338 // ToolbarView, Menu::Delegate overrides:
340 bool ToolbarView::GetAcceleratorInfo(int id, ui::Accelerator* accel) {
341 return GetWidget()->GetAccelerator(id, accel);
344 ////////////////////////////////////////////////////////////////////////////////
345 // ToolbarView, views::MenuButtonListener implementation:
347 void ToolbarView::OnMenuButtonClicked(views::View* source,
348 const gfx::Point& point) {
349 TRACE_EVENT0("views", "ToolbarView::OnMenuButtonClicked");
350 DCHECK_EQ(VIEW_ID_APP_MENU, source->id());
352 bool use_new_menu = false;
353 bool supports_new_separators = false;
354 // TODO: remove this.
355 #if defined(USE_AURA)
356 supports_new_separators =
357 GetNativeTheme() == ui::NativeThemeAura::instance();
358 use_new_menu = supports_new_separators;
359 #endif
360 #if defined(OS_WIN)
361 use_new_menu = use_new_menu || ui::GetDisplayLayout() == ui::LAYOUT_TOUCH;
362 #endif
364 wrench_menu_.reset(new WrenchMenu(browser_, use_new_menu,
365 supports_new_separators));
366 wrench_menu_model_.reset(new WrenchMenuModel(this, browser_, use_new_menu));
367 wrench_menu_->Init(wrench_menu_model_.get());
369 FOR_EACH_OBSERVER(views::MenuListener, menu_listeners_, OnMenuOpened());
371 wrench_menu_->RunMenu(app_menu_);
374 ////////////////////////////////////////////////////////////////////////////////
375 // ToolbarView, LocationBarView::Delegate implementation:
377 WebContents* ToolbarView::GetWebContents() {
378 return browser_->tab_strip_model()->GetActiveWebContents();
381 ToolbarModel* ToolbarView::GetToolbarModel() {
382 return browser_->toolbar_model();
385 const ToolbarModel* ToolbarView::GetToolbarModel() const {
386 return browser_->toolbar_model();
389 InstantController* ToolbarView::GetInstant() {
390 return browser_->instant_controller() ?
391 browser_->instant_controller()->instant() : NULL;
394 ContentSettingBubbleModelDelegate*
395 ToolbarView::GetContentSettingBubbleModelDelegate() {
396 return browser_->content_setting_bubble_model_delegate();
399 void ToolbarView::ShowWebsiteSettings(content::WebContents* web_contents,
400 const GURL& url,
401 const content::SSLStatus& ssl) {
402 chrome::ShowWebsiteSettings(browser_, web_contents, url, ssl);
405 views::Widget* ToolbarView::CreateViewsBubble(
406 views::BubbleDelegateView* bubble_delegate) {
407 return views::BubbleDelegateView::CreateBubble(bubble_delegate);
410 PageActionImageView* ToolbarView::CreatePageActionImageView(
411 LocationBarView* owner, ExtensionAction* action) {
412 return new PageActionImageView(owner, action, browser_);
415 ////////////////////////////////////////////////////////////////////////////////
416 // ToolbarView, CommandObserver implementation:
418 void ToolbarView::EnabledStateChangedForCommand(int id, bool enabled) {
419 views::Button* button = NULL;
420 switch (id) {
421 case IDC_BACK:
422 button = back_;
423 break;
424 case IDC_FORWARD:
425 button = forward_;
426 break;
427 case IDC_RELOAD:
428 button = reload_;
429 break;
430 case IDC_HOME:
431 button = home_;
432 break;
434 if (button)
435 button->SetEnabled(enabled);
438 ////////////////////////////////////////////////////////////////////////////////
439 // ToolbarView, views::Button::ButtonListener implementation:
441 void ToolbarView::ButtonPressed(views::Button* sender,
442 const ui::Event& event) {
443 int command = sender->tag();
444 WindowOpenDisposition disposition =
445 ui::DispositionFromEventFlags(event.flags());
446 if ((disposition == CURRENT_TAB) &&
447 ((command == IDC_BACK) || (command == IDC_FORWARD))) {
448 // Forcibly reset the location bar, since otherwise it won't discard any
449 // ongoing user edits, since it doesn't realize this is a user-initiated
450 // action.
451 location_bar_->Revert();
453 chrome::ExecuteCommandWithDisposition(browser_, command, disposition);
456 ////////////////////////////////////////////////////////////////////////////////
457 // ToolbarView, content::NotificationObserver implementation:
459 void ToolbarView::Observe(int type,
460 const content::NotificationSource& source,
461 const content::NotificationDetails& details) {
462 switch (type) {
463 case chrome::NOTIFICATION_UPGRADE_RECOMMENDED:
464 case chrome::NOTIFICATION_MODULE_INCOMPATIBILITY_BADGE_CHANGE:
465 case chrome::NOTIFICATION_GLOBAL_ERRORS_CHANGED:
466 case chrome::NOTIFICATION_MODULE_LIST_ENUMERATED:
467 UpdateAppMenuState();
468 break;
469 case chrome::NOTIFICATION_OUTDATED_INSTALL:
470 ShowOutdatedInstallNotification();
471 break;
472 #if defined(OS_WIN)
473 case chrome::NOTIFICATION_CRITICAL_UPGRADE_INSTALLED:
474 ShowCriticalNotification();
475 break;
476 #endif
477 default:
478 NOTREACHED();
482 ////////////////////////////////////////////////////////////////////////////////
483 // ToolbarView, ui::AcceleratorProvider implementation:
485 bool ToolbarView::GetAcceleratorForCommandId(int command_id,
486 ui::Accelerator* accelerator) {
487 return GetWidget()->GetAccelerator(command_id, accelerator);
490 ////////////////////////////////////////////////////////////////////////////////
491 // ToolbarView, views::View overrides:
493 gfx::Size ToolbarView::GetPreferredSize() {
494 gfx::Size size(location_bar_->GetPreferredSize());
495 if (is_display_mode_normal()) {
496 int button_spacing = GetButtonSpacing();
497 size.Enlarge(
498 kLeftEdgeSpacing + back_->GetPreferredSize().width() + button_spacing +
499 forward_->GetPreferredSize().width() + button_spacing +
500 reload_->GetPreferredSize().width() + kStandardSpacing +
501 (show_home_button_.GetValue() ?
502 (home_->GetPreferredSize().width() + button_spacing) : 0) +
503 (site_chip_view_->ShouldShow() ?
504 (site_chip_view_->GetPreferredSize().width() +
505 2 * kStandardSpacing) :
506 0) +
507 browser_actions_->GetPreferredSize().width() +
508 app_menu_->GetPreferredSize().width() + kRightEdgeSpacing,
510 gfx::ImageSkia* normal_background =
511 GetThemeProvider()->GetImageSkiaNamed(IDR_CONTENT_TOP_CENTER);
512 size.SetToMax(
513 gfx::Size(0, normal_background->height() - content_shadow_height()));
514 } else {
515 const int kPopupBottomSpacingGlass = 1;
516 const int kPopupBottomSpacingNonGlass = 2;
517 size.Enlarge(
519 PopupTopSpacing() + (GetWidget()->ShouldUseNativeFrame() ?
520 kPopupBottomSpacingGlass : kPopupBottomSpacingNonGlass));
522 return size;
525 void ToolbarView::Layout() {
526 // If we have not been initialized yet just do nothing.
527 if (back_ == NULL)
528 return;
530 if (!is_display_mode_normal()) {
531 location_bar_->SetBounds(0, PopupTopSpacing(), width(),
532 location_bar_->GetPreferredSize().height());
533 return;
536 // We assume all child elements except the location bar are the same height.
537 // Set child_y such that buttons appear vertically centered. We put any excess
538 // padding above the buttons.
539 int child_height =
540 std::min(back_->GetPreferredSize().height(), height());
541 int child_y = (height() - child_height + 1) / 2;
543 // If the window is maximized, we extend the back button to the left so that
544 // clicking on the left-most pixel will activate the back button.
545 // TODO(abarth): If the window becomes maximized but is not resized,
546 // then Layout() might not be called and the back button
547 // will be slightly the wrong size. We should force a
548 // Layout() in this case.
549 // http://crbug.com/5540
550 bool maximized = browser_->window() && browser_->window()->IsMaximized();
551 int back_width = back_->GetPreferredSize().width();
552 if (maximized) {
553 back_->SetBounds(0, child_y, back_width + kLeftEdgeSpacing, child_height);
554 back_->SetLeadingMargin(kLeftEdgeSpacing);
555 } else {
556 back_->SetBounds(kLeftEdgeSpacing, child_y, back_width, child_height);
557 back_->SetLeadingMargin(0);
559 int button_spacing = GetButtonSpacing();
560 int next_element_x = back_->bounds().right() + button_spacing;
562 forward_->SetBounds(next_element_x, child_y,
563 forward_->GetPreferredSize().width(), child_height);
564 next_element_x = forward_->bounds().right() + button_spacing;
566 reload_->SetBounds(next_element_x, child_y,
567 reload_->GetPreferredSize().width(), child_height);
568 next_element_x = reload_->bounds().right();
570 if (show_home_button_.GetValue()) {
571 home_->SetVisible(true);
572 home_->SetBounds(next_element_x + button_spacing, child_y,
573 home_->GetPreferredSize().width(), child_height);
574 } else {
575 home_->SetVisible(false);
576 home_->SetBounds(next_element_x, child_y, 0, child_height);
578 next_element_x = home_->bounds().right() + kStandardSpacing;
580 int browser_actions_width = browser_actions_->GetPreferredSize().width();
581 int app_menu_width = app_menu_->GetPreferredSize().width();
582 int available_width = std::max(0, width() - kRightEdgeSpacing -
583 app_menu_width - browser_actions_width - next_element_x);
585 // Cap site chip width at 1/2 the size available to the location bar.
586 site_chip_view_->SetVisible(site_chip_view_->ShouldShow());
587 int site_chip_width = site_chip_view_->GetPreferredSize().width();
588 site_chip_width = std::max(0, std::min(site_chip_width,
589 (available_width - kStandardSpacing) / 2));
590 if (site_chip_view_->visible())
591 available_width -= site_chip_width + kStandardSpacing;
593 chrome::OriginChipPosition origin_chip_position =
594 chrome::GetOriginChipPosition();
595 if (origin_chip_position == chrome::ORIGIN_CHIP_LEADING_LOCATION_BAR) {
596 site_chip_view_->SetBounds(next_element_x, child_y,
597 site_chip_width, child_height);
598 next_element_x = site_chip_view_->bounds().right() + kStandardSpacing;
601 int location_height = location_bar_->GetPreferredSize().height();
602 int location_y = (height() - location_height + 1) / 2;
603 location_bar_->SetBounds(next_element_x, location_y,
604 std::max(available_width, 0), location_height);
605 next_element_x = location_bar_->bounds().right();
607 if (origin_chip_position == chrome::ORIGIN_CHIP_TRAILING_LOCATION_BAR) {
608 site_chip_view_->SetBounds(next_element_x + kStandardSpacing, child_y,
609 site_chip_width, child_height);
610 next_element_x = site_chip_view_->bounds().right();
613 browser_actions_->SetBounds(next_element_x, 0,
614 browser_actions_width, height());
615 next_element_x = browser_actions_->bounds().right();
617 // The browser actions need to do a layout explicitly, because when an
618 // extension is loaded/unloaded/changed, BrowserActionContainer removes and
619 // re-adds everything, regardless of whether it has a page action. For a
620 // page action, browser action bounds do not change, as a result of which
621 // SetBounds does not do a layout at all.
622 // TODO(sidchat): Rework the above behavior so that explicit layout is not
623 // required.
624 browser_actions_->Layout();
626 if (origin_chip_position == chrome::ORIGIN_CHIP_LEADING_MENU_BUTTON) {
627 site_chip_view_->SetBounds(next_element_x, child_y,
628 site_chip_width, child_height);
629 next_element_x = site_chip_view_->bounds().right() + kStandardSpacing;
632 // Extend the app menu to the screen's right edge in maximized mode just like
633 // we extend the back button to the left edge.
634 if (maximized)
635 app_menu_width += kRightEdgeSpacing;
636 app_menu_->SetBounds(next_element_x, child_y, app_menu_width, child_height);
639 bool ToolbarView::HitTestRect(const gfx::Rect& rect) const {
640 // Fall through to the tab strip above us if none of |rect| intersects
641 // with this view (intersection with the top shadow edge does not
642 // count as intersection with this view).
643 if (rect.bottom() < content_shadow_height())
644 return false;
645 // Otherwise let our superclass take care of it.
646 return AccessiblePaneView::HitTestRect(rect);
649 void ToolbarView::OnPaint(gfx::Canvas* canvas) {
650 View::OnPaint(canvas);
652 if (is_display_mode_normal())
653 return;
655 // For glass, we need to draw a black line below the location bar to separate
656 // it from the content area. For non-glass, the NonClientView draws the
657 // toolbar background below the location bar for us.
658 // NOTE: Keep this in sync with BrowserView::GetInfoBarSeparatorColor()!
659 if (GetWidget()->ShouldUseNativeFrame())
660 canvas->FillRect(gfx::Rect(0, height() - 1, width(), 1), SK_ColorBLACK);
663 void ToolbarView::OnThemeChanged() {
664 LoadImages();
667 const char* ToolbarView::GetClassName() const {
668 return kViewClassName;
671 bool ToolbarView::AcceleratorPressed(const ui::Accelerator& accelerator) {
672 const views::View* focused_view = focus_manager()->GetFocusedView();
673 if (focused_view && (focused_view->id() == VIEW_ID_OMNIBOX))
674 return false; // Let the omnibox handle all accelerator events.
675 return AccessiblePaneView::AcceleratorPressed(accelerator);
678 bool ToolbarView::IsWrenchMenuShowing() const {
679 return wrench_menu_.get() && wrench_menu_->IsShowing();
682 bool ToolbarView::ShouldPaintBackground() const {
683 return display_mode_ == DISPLAYMODE_NORMAL;
686 ////////////////////////////////////////////////////////////////////////////////
687 // ToolbarView, protected:
689 // Override this so that when the user presses F6 to rotate toolbar panes,
690 // the location bar gets focus, not the first control in the toolbar - and
691 // also so that it selects all content in the location bar.
692 bool ToolbarView::SetPaneFocusAndFocusDefault() {
693 if (!location_bar_->HasFocus()) {
694 SetPaneFocus(location_bar_);
695 location_bar_->FocusLocation(true);
696 return true;
699 if (!AccessiblePaneView::SetPaneFocusAndFocusDefault())
700 return false;
701 browser_->window()->RotatePaneFocus(true);
702 return true;
705 void ToolbarView::RemovePaneFocus() {
706 AccessiblePaneView::RemovePaneFocus();
707 location_bar_->SetShowFocusRect(false);
710 ////////////////////////////////////////////////////////////////////////////////
711 // ToolbarView, private:
713 bool ToolbarView::ShouldShowUpgradeRecommended() {
714 #if defined(OS_CHROMEOS)
715 // In chromeos, the update recommendation is shown in the system tray. So it
716 // should not be displayed in the wrench menu.
717 return false;
718 #else
719 return (UpgradeDetector::GetInstance()->notify_upgrade());
720 #endif
723 bool ToolbarView::ShouldShowIncompatibilityWarning() {
724 #if defined(OS_WIN)
725 EnumerateModulesModel* loaded_modules = EnumerateModulesModel::GetInstance();
726 loaded_modules->MaybePostScanningTask();
727 return loaded_modules->ShouldShowConflictWarning();
728 #else
729 return false;
730 #endif
733 int ToolbarView::PopupTopSpacing() const {
734 const int kPopupTopSpacingNonGlass = 3;
735 return GetWidget()->ShouldUseNativeFrame() ? 0 : kPopupTopSpacingNonGlass;
738 void ToolbarView::LoadImages() {
739 ui::ThemeProvider* tp = GetThemeProvider();
741 back_->SetImage(views::Button::STATE_NORMAL,
742 *(tp->GetImageSkiaNamed(IDR_BACK)));
743 back_->SetImage(views::Button::STATE_DISABLED,
744 *(tp->GetImageSkiaNamed(IDR_BACK_D)));
746 forward_->SetImage(views::Button::STATE_NORMAL,
747 *(tp->GetImageSkiaNamed(IDR_FORWARD)));
748 forward_->SetImage(views::Button::STATE_DISABLED,
749 *(tp->GetImageSkiaNamed(IDR_FORWARD_D)));
751 reload_->LoadImages();
753 home_->SetImage(views::Button::STATE_NORMAL,
754 *(tp->GetImageSkiaNamed(IDR_HOME)));
757 void ToolbarView::ShowCriticalNotification() {
758 #if defined(OS_WIN)
759 CriticalNotificationBubbleView* bubble_delegate =
760 new CriticalNotificationBubbleView(app_menu_);
761 views::BubbleDelegateView::CreateBubble(bubble_delegate);
762 bubble_delegate->StartFade(true);
763 #endif
766 void ToolbarView::ShowOutdatedInstallNotification() {
767 if (OutdatedUpgradeBubbleView::IsAvailable())
768 OutdatedUpgradeBubbleView::ShowBubble(app_menu_, browser_);
771 void ToolbarView::UpdateAppMenuState() {
772 base::string16 accname_app = l10n_util::GetStringUTF16(IDS_ACCNAME_APP);
773 if (ShouldShowUpgradeRecommended()) {
774 accname_app = l10n_util::GetStringFUTF16(
775 IDS_ACCNAME_APP_UPGRADE_RECOMMENDED, accname_app);
777 app_menu_->SetAccessibleName(accname_app);
779 UpdateWrenchButtonSeverity();
780 SchedulePaint();
783 void ToolbarView::UpdateWrenchButtonSeverity() {
784 // Showing the bubble requires |app_menu_| to be in a widget. See comment
785 // in ConflictingModuleView for details.
786 DCHECK(app_menu_->GetWidget());
788 // Keep track of whether we were showing the badge before, so we don't send
789 // multiple UMA events for example when multiple Chrome windows are open.
790 static bool incompatibility_badge_showing = false;
791 // Save the old value before resetting it.
792 bool was_showing = incompatibility_badge_showing;
793 incompatibility_badge_showing = false;
795 if (ShouldShowUpgradeRecommended()) {
796 UpgradeDetector::UpgradeNotificationAnnoyanceLevel level =
797 UpgradeDetector::GetInstance()->upgrade_notification_stage();
798 app_menu_->SetSeverity(WrenchIconPainter::SeverityFromUpgradeLevel(level),
799 WrenchIconPainter::ShouldAnimateUpgradeLevel(level));
800 return;
803 if (ShouldShowIncompatibilityWarning()) {
804 if (!was_showing) {
805 content::RecordAction(UserMetricsAction("ConflictBadge"));
806 #if defined(OS_WIN)
807 ConflictingModuleView::MaybeShow(browser_, app_menu_);
808 #endif
810 app_menu_->SetSeverity(WrenchIconPainter::SEVERITY_MEDIUM, true);
811 incompatibility_badge_showing = true;
812 return;
815 GlobalErrorService* service =
816 GlobalErrorServiceFactory::GetForProfile(browser_->profile());
817 GlobalError* error =
818 service->GetHighestSeverityGlobalErrorWithWrenchMenuItem();
819 if (error) {
820 app_menu_->SetSeverity(WrenchIconPainter::GlobalErrorSeverity(), true);
821 return;
824 app_menu_->SetSeverity(WrenchIconPainter::SEVERITY_NONE, true);
827 void ToolbarView::OnShowHomeButtonChanged() {
828 Layout();
829 SchedulePaint();
832 int ToolbarView::content_shadow_height() const {
833 return browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH ?
834 kContentShadowHeightAsh : kContentShadowHeight;