Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / conflicting_module_view_win.cc
1 // Copyright (c) 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.
4
5 #include "chrome/browser/ui/views/conflicting_module_view_win.h"
6
7 #include "base/metrics/histogram.h"
8 #include "chrome/browser/chrome_notification_types.h"
9 #include "chrome/browser/enumerate_modules_model_win.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/common/pref_names.h"
13 #include "chrome/grit/chromium_strings.h"
14 #include "chrome/grit/generated_resources.h"
15 #include "chrome/grit/locale_settings.h"
16 #include "content/public/browser/notification_service.h"
17 #include "content/public/browser/user_metrics.h"
18 #include "grit/theme_resources.h"
19 #include "ui/accessibility/ax_view_state.h"
20 #include "ui/base/l10n/l10n_util.h"
21 #include "ui/base/resource/resource_bundle.h"
22 #include "ui/views/controls/button/label_button.h"
23 #include "ui/views/controls/image_view.h"
24 #include "ui/views/controls/label.h"
25 #include "ui/views/layout/grid_layout.h"
26 #include "ui/views/layout/layout_constants.h"
27 #include "ui/views/widget/widget.h"
28
29 using base::UserMetricsAction;
30
31 namespace {
32
33 // Layout constants.
34 const int kInsetBottomRight = 13;
35 const int kInsetLeft = 14;
36 const int kInsetTop = 9;
37 const int kHeadlineMessagePadding = 4;
38 const int kMessageBubblePadding = 11;
39
40 // How often to show this bubble.
41 const int kShowConflictingModuleBubbleMax = 3;
42
43 }  // namespace
44
45 ////////////////////////////////////////////////////////////////////////////////
46 // ConflictingModuleView
47
48 ConflictingModuleView::ConflictingModuleView(
49     views::View* anchor_view,
50     Browser* browser,
51     const GURL& help_center_url)
52     : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT),
53       browser_(browser),
54       explanation_(NULL),
55       learn_more_button_(NULL),
56       not_now_button_(NULL),
57       help_center_url_(help_center_url) {
58   set_close_on_deactivate(false);
59   set_close_on_esc(true);
60
61   // Compensate for built-in vertical padding in the anchor view's image.
62   set_anchor_view_insets(gfx::Insets(5, 0, 5, 0));
63
64   registrar_.Add(this, chrome::NOTIFICATION_MODULE_INCOMPATIBILITY_BADGE_CHANGE,
65                  content::NotificationService::AllSources());
66 }
67
68 // static
69 void ConflictingModuleView::MaybeShow(Browser* browser,
70                                       views::View* anchor_view) {
71   static bool done_checking = false;
72   if (done_checking)
73     return;  // Only show the bubble once per launch.
74
75   EnumerateModulesModel* model = EnumerateModulesModel::GetInstance();
76   GURL url = model->GetFirstNotableConflict();
77   if (!url.is_valid()) {
78     done_checking = true;
79     return;
80   }
81
82   // A pref that counts how often the Sideload Wipeout bubble has been shown.
83   IntegerPrefMember bubble_shown;
84   bubble_shown.Init(prefs::kModuleConflictBubbleShown,
85                     browser->profile()->GetPrefs());
86   if (bubble_shown.GetValue() >= kShowConflictingModuleBubbleMax) {
87     done_checking = true;
88     return;
89   }
90
91   // |anchor_view| must be in a widget (the browser's widget). If not, |browser|
92   // may be destroyed before us, and we'll crash trying to access |browser|
93   // later on. We can't DCHECK |browser|'s widget here as we may be called from
94   // creation of BrowserWindow, which means browser->window() may return NULL.
95   DCHECK(anchor_view);
96   DCHECK(anchor_view->GetWidget());
97
98   ConflictingModuleView* bubble_delegate =
99       new ConflictingModuleView(anchor_view, browser, url);
100   views::BubbleDelegateView::CreateBubble(bubble_delegate);
101   bubble_delegate->ShowBubble();
102
103   done_checking = true;
104 }
105
106 ////////////////////////////////////////////////////////////////////////////////
107 // ConflictingModuleView - private.
108
109 ConflictingModuleView::~ConflictingModuleView() {
110 }
111
112 void ConflictingModuleView::ShowBubble() {
113   GetWidget()->Show();
114
115   IntegerPrefMember bubble_shown;
116   bubble_shown.Init(
117       prefs::kModuleConflictBubbleShown,
118       browser_->profile()->GetPrefs());
119   bubble_shown.SetValue(bubble_shown.GetValue() + 1);
120 }
121
122 void ConflictingModuleView::DismissBubble() {
123   GetWidget()->Close();
124
125   content::RecordAction(
126       UserMetricsAction("ConflictingModuleNotificationDismissed"));
127 }
128
129 void ConflictingModuleView::Init() {
130   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
131
132   views::GridLayout* layout = views::GridLayout::CreatePanel(this);
133   layout->SetInsets(kInsetTop, kInsetLeft,
134                     kInsetBottomRight, kInsetBottomRight);
135   SetLayoutManager(layout);
136
137   views::ImageView* icon = new views::ImageView();
138   icon->SetImage(rb.GetNativeImageNamed(IDR_INPUT_ALERT_MENU).ToImageSkia());
139   gfx::Size icon_size = icon->GetPreferredSize();
140
141   const int text_column_set_id = 0;
142   views::ColumnSet* upper_columns = layout->AddColumnSet(text_column_set_id);
143   upper_columns->AddColumn(
144       views::GridLayout::LEADING, views::GridLayout::LEADING,
145       0, views::GridLayout::FIXED, icon_size.width(), icon_size.height());
146   upper_columns->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
147   upper_columns->AddColumn(
148       views::GridLayout::LEADING, views::GridLayout::LEADING,
149       0, views::GridLayout::USE_PREF, 0, 0);
150
151   layout->StartRowWithPadding(
152       0, text_column_set_id, 0, kHeadlineMessagePadding);
153   layout->AddView(icon);
154   explanation_ = new views::Label();
155   explanation_->SetMultiLine(true);
156   explanation_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
157   explanation_->SetText(l10n_util::GetStringUTF16(
158       IDS_OPTIONS_CONFLICTING_MODULE));
159   explanation_->SizeToFit(views::Widget::GetLocalizedContentsWidth(
160       IDS_CONFLICTING_MODULE_BUBBLE_WIDTH_CHARS));
161   layout->AddView(explanation_);
162
163   const int action_row_column_set_id = 1;
164   views::ColumnSet* bottom_columns =
165       layout->AddColumnSet(action_row_column_set_id);
166   bottom_columns->AddPaddingColumn(1, 0);
167   bottom_columns->AddColumn(views::GridLayout::TRAILING,
168       views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
169   bottom_columns->AddPaddingColumn(0, views::kRelatedButtonHSpacing);
170   bottom_columns->AddColumn(views::GridLayout::TRAILING,
171       views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
172   layout->AddPaddingRow(0, 7);
173
174   layout->StartRowWithPadding(0, action_row_column_set_id,
175                               0, kMessageBubblePadding);
176   learn_more_button_ = new views::LabelButton(this,
177       l10n_util::GetStringUTF16(IDS_CONFLICTS_LEARN_MORE));
178   learn_more_button_->SetStyle(views::Button::STYLE_BUTTON);
179   layout->AddView(learn_more_button_);
180   not_now_button_ = new views::LabelButton(this,
181       l10n_util::GetStringUTF16(IDS_CONFLICTS_NOT_NOW));
182   not_now_button_->SetStyle(views::Button::STYLE_BUTTON);
183   layout->AddView(not_now_button_);
184
185   content::RecordAction(
186       UserMetricsAction("ConflictingModuleNotificationShown"));
187
188   UMA_HISTOGRAM_ENUMERATION("ConflictingModule.UserSelection",
189       EnumerateModulesModel::ACTION_BUBBLE_SHOWN,
190       EnumerateModulesModel::ACTION_BOUNDARY);
191 }
192
193 void ConflictingModuleView::ButtonPressed(views::Button* sender,
194                                           const ui::Event& event) {
195   if (sender == learn_more_button_) {
196     browser_->OpenURL(
197         content::OpenURLParams(help_center_url_,
198                                content::Referrer(),
199                                NEW_FOREGROUND_TAB,
200                                ui::PAGE_TRANSITION_LINK,
201                                false));
202
203     EnumerateModulesModel* model = EnumerateModulesModel::GetInstance();
204     model->AcknowledgeConflictNotification();
205     DismissBubble();
206   } else if (sender == not_now_button_) {
207     DismissBubble();
208   }
209 }
210
211 void ConflictingModuleView::GetAccessibleState(
212     ui::AXViewState* state) {
213   state->role = ui::AX_ROLE_ALERT;
214 }
215
216 void ConflictingModuleView::ViewHierarchyChanged(
217   const ViewHierarchyChangedDetails& details) {
218   if (details.is_add && details.child == this)
219     NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true);
220 }
221
222 void ConflictingModuleView::Observe(
223     int type,
224     const content::NotificationSource& source,
225     const content::NotificationDetails& details) {
226   DCHECK(type == chrome::NOTIFICATION_MODULE_INCOMPATIBILITY_BADGE_CHANGE);
227   EnumerateModulesModel* model = EnumerateModulesModel::GetInstance();
228   if (!model->ShouldShowConflictWarning())
229     GetWidget()->Close();
230 }