1 // Copyright (c) 2012 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. 4 5 #include "chrome/browser/ui/views/accessibility/invert_bubble_view.h" 6 7 #include "base/prefs/pref_service.h" 8 #include "chrome/browser/profiles/profile.h" 9 #include "chrome/browser/ui/browser.h" 10 #include "chrome/browser/ui/views/frame/browser_view.h" 11 #include "chrome/browser/ui/views/toolbar/toolbar_view.h" 12 #include "chrome/common/pref_names.h" 13 #include "chrome/grit/generated_resources.h" 14 #include "content/public/browser/page_navigator.h" 15 #include "grit/components_strings.h" 16 #include "ui/base/l10n/l10n_util.h" 17 #include "ui/base/resource/resource_bundle.h" 18 #include "ui/base/window_open_disposition.h" 19 #include "ui/gfx/sys_color_change_listener.h" 20 #include "ui/views/bubble/bubble_delegate.h" 21 #include "ui/views/controls/label.h" 22 #include "ui/views/controls/link.h" 23 #include "ui/views/controls/link_listener.h" 24 #include "ui/views/layout/grid_layout.h" 25 #include "ui/views/layout/layout_constants.h" 26 #include "ui/views/widget/widget.h" 27 28 namespace { 29 30 const char kHighContrastExtensionUrl[] = 31 "https://chrome.google.com/webstore/detail/djcfdncoelnlbldjfhinnjlhdjlikmph"; 32 const char kDarkThemeSearchUrl[] = 33 "https://chrome.google.com/webstore/search-themes/dark"; 34 const char kLearnMoreUrl[] = 35 "https://groups.google.com/a/googleproductforums.com/d/topic/chrome/Xrco2HsXS-8/discussion"; 36 37 class InvertBubbleView : public views::BubbleDelegateView, 38 public views::LinkListener { 39 public: 40 InvertBubbleView(Browser* browser, views::View* anchor_view); 41 virtual ~InvertBubbleView(); 42 43 private: 44 // Overridden from views::BubbleDelegateView: 45 virtual void Init() OVERRIDE; 46 47 // Overridden from views::LinkListener: 48 virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE; 49 50 void OpenLink(const std::string& url, int event_flags); 51 52 Browser* browser_; 53 views::Link* high_contrast_; 54 views::Link* dark_theme_; 55 views::Link* learn_more_; 56 views::Link* close_; 57 58 DISALLOW_COPY_AND_ASSIGN(InvertBubbleView); 59 }; 60 61 InvertBubbleView::InvertBubbleView(Browser* browser, views::View* anchor_view) 62 : views::BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT), 63 browser_(browser), 64 high_contrast_(NULL), 65 dark_theme_(NULL), 66 learn_more_(NULL), 67 close_(NULL) { 68 } 69 70 InvertBubbleView::~InvertBubbleView() { 71 } 72 73 void InvertBubbleView::Init() { 74 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 75 const gfx::FontList& original_font_list = 76 rb.GetFontList(ui::ResourceBundle::MediumFont); 77 78 views::Label* title = new views::Label( 79 base::string16(), original_font_list.Derive(2, gfx::Font::BOLD)); 80 title->SetMultiLine(true); 81 82 learn_more_ = new views::Link(l10n_util::GetStringUTF16(IDS_LEARN_MORE)); 83 learn_more_->SetFontList(original_font_list); 84 learn_more_->set_listener(this); 85 86 high_contrast_ = 87 new views::Link(l10n_util::GetStringUTF16(IDS_HIGH_CONTRAST_EXT)); 88 high_contrast_->SetFontList(original_font_list); 89 high_contrast_->set_listener(this); 90 91 dark_theme_ = new views::Link(l10n_util::GetStringUTF16(IDS_DARK_THEME)); 92 dark_theme_->SetFontList(original_font_list); 93 dark_theme_->set_listener(this); 94 95 close_ = new views::Link(l10n_util::GetStringUTF16(IDS_CLOSE)); 96 close_->SetFontList(original_font_list); 97 close_->set_listener(this); 98 99 views::GridLayout* layout = views::GridLayout::CreatePanel(this); 100 SetLayoutManager(layout); 101 102 views::ColumnSet* columns = layout->AddColumnSet(0); 103 for (int i = 0; i < 4; i++) { 104 columns->AddColumn(views::GridLayout::LEADING, 105 views::GridLayout::LEADING, 0, 106 views::GridLayout::USE_PREF, 0, 0); 107 } 108 109 layout->StartRow(0, 0); 110 layout->AddView(title, 4, 1); 111 layout->StartRowWithPadding(0, 0, 0, 112 views::kRelatedControlSmallVerticalSpacing); 113 layout->AddView(high_contrast_); 114 layout->AddView(dark_theme_); 115 layout->AddView(learn_more_); 116 layout->AddView(close_); 117 118 // Fit the message to the width of the links in the bubble. 119 const gfx::Size size(GetPreferredSize()); 120 title->SetText(l10n_util::GetStringUTF16(IDS_HIGH_CONTRAST_NOTIFICATION)); 121 title->SizeToFit(size.width()); 122 123 // Switching to high-contrast mode has a nasty habit of causing Chrome 124 // top-level windows to lose focus, so closing the bubble on deactivate 125 // makes it disappear before the user has even seen it. This forces the 126 // user to close it explicitly, which should be okay because it affects 127 // a small minority of users, and only once. 128 set_close_on_deactivate(false); 129 } 130 131 void InvertBubbleView::LinkClicked(views::Link* source, int event_flags) { 132 if (source == high_contrast_) 133 OpenLink(kHighContrastExtensionUrl, event_flags); 134 else if (source == dark_theme_) 135 OpenLink(kDarkThemeSearchUrl, event_flags); 136 else if (source == learn_more_) 137 OpenLink(kLearnMoreUrl, event_flags); 138 else if (source == close_) 139 GetWidget()->Close(); 140 else 141 NOTREACHED(); 142 } 143 144 void InvertBubbleView::OpenLink(const std::string& url, int event_flags) { 145 WindowOpenDisposition disposition = 146 ui::DispositionFromEventFlags(event_flags); 147 content::OpenURLParams params( 148 GURL(url), content::Referrer(), 149 disposition == CURRENT_TAB ? NEW_FOREGROUND_TAB : disposition, 150 ui::PAGE_TRANSITION_LINK, false); 151 browser_->OpenURL(params); 152 } 153 154 } // namespace 155 156 namespace chrome { 157 158 void MaybeShowInvertBubbleView(BrowserView* browser_view) { 159 Browser* browser = browser_view->browser(); 160 PrefService* pref_service = browser->profile()->GetPrefs(); 161 views::View* anchor = browser_view->toolbar()->app_menu(); 162 if (gfx::IsInvertedColorScheme() && anchor && anchor->GetWidget() && 163 !pref_service->GetBoolean(prefs::kInvertNotificationShown)) { 164 pref_service->SetBoolean(prefs::kInvertNotificationShown, true); 165 InvertBubbleView* delegate = new InvertBubbleView(browser, anchor); 166 views::BubbleDelegateView::CreateBubble(delegate)->Show(); 167 } 168 } 169 170 } // namespace chrome 171