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
28namespace {
29
30const char kHighContrastExtensionUrl[] =
31    "https://chrome.google.com/webstore/detail/djcfdncoelnlbldjfhinnjlhdjlikmph";
32const char kDarkThemeSearchUrl[] =
33    "https://chrome.google.com/webstore/search-themes/dark";
34const char kLearnMoreUrl[] =
35    "https://groups.google.com/a/googleproductforums.com/d/topic/chrome/Xrco2HsXS-8/discussion";
36
37class 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
61InvertBubbleView::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
70InvertBubbleView::~InvertBubbleView() {
71}
72
73void 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
131void 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
144void 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
156namespace chrome {
157
158void 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