Home | History | Annotate | Download | only in accessibility
      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