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