Infobar material design refresh: layout
[chromium-blink-merge.git] / chrome / browser / ui / views / download / download_danger_prompt_views.cc
blobef7bbfbb06f7c2abbb1c223fa115c6cfe3418899
1 // Copyright 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.
5 #include "base/compiler_specific.h"
6 #include "chrome/browser/download/download_danger_prompt.h"
7 #include "chrome/browser/download/download_stats.h"
8 #include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
9 #include "chrome/grit/chromium_strings.h"
10 #include "chrome/grit/generated_resources.h"
11 #include "components/constrained_window/constrained_window_views.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/download_danger_type.h"
14 #include "content/public/browser/download_item.h"
15 #include "ui/base/l10n/l10n_util.h"
16 #include "ui/base/resource/resource_bundle.h"
17 #include "ui/views/controls/button/label_button.h"
18 #include "ui/views/controls/label.h"
19 #include "ui/views/layout/grid_layout.h"
20 #include "ui/views/view.h"
21 #include "ui/views/widget/widget.h"
22 #include "ui/views/window/dialog_client_view.h"
23 #include "ui/views/window/dialog_delegate.h"
25 using extensions::ExperienceSamplingEvent;
27 namespace {
29 const int kMessageWidth = 320;
30 const int kParagraphPadding = 15;
32 // Views-specific implementation of download danger prompt dialog. We use this
33 // class rather than a TabModalConfirmDialog so that we can use custom
34 // formatting on the text in the body of the dialog.
35 class DownloadDangerPromptViews : public DownloadDangerPrompt,
36 public content::DownloadItem::Observer,
37 public views::DialogDelegate {
38 public:
39 DownloadDangerPromptViews(content::DownloadItem* item,
40 bool show_context,
41 const OnDone& done);
43 // DownloadDangerPrompt methods:
44 void InvokeActionForTesting(Action action) override;
46 // views::DialogDelegate methods:
47 base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
48 base::string16 GetWindowTitle() const override;
49 void DeleteDelegate() override;
50 ui::ModalType GetModalType() const override;
51 bool Cancel() override;
52 bool Accept() override;
53 bool Close() override;
54 views::View* GetInitiallyFocusedView() override;
55 views::View* GetContentsView() override;
56 views::Widget* GetWidget() override;
57 const views::Widget* GetWidget() const override;
59 // content::DownloadItem::Observer:
60 void OnDownloadUpdated(content::DownloadItem* download) override;
62 private:
63 base::string16 GetAcceptButtonTitle() const;
64 base::string16 GetCancelButtonTitle() const;
65 // The message lead is separated from the main text and is bolded.
66 base::string16 GetMessageLead() const;
67 base::string16 GetMessageBody() const;
68 void RunDone(Action action);
70 content::DownloadItem* download_;
71 bool show_context_;
72 OnDone done_;
74 scoped_ptr<ExperienceSamplingEvent> sampling_event_;
76 views::View* contents_view_;
79 DownloadDangerPromptViews::DownloadDangerPromptViews(
80 content::DownloadItem* item,
81 bool show_context,
82 const OnDone& done)
83 : download_(item),
84 show_context_(show_context),
85 done_(done),
86 contents_view_(NULL) {
87 DCHECK(!done_.is_null());
88 download_->AddObserver(this);
90 contents_view_ = new views::View;
92 views::GridLayout* layout = views::GridLayout::CreatePanel(contents_view_);
93 contents_view_->SetLayoutManager(layout);
95 views::ColumnSet* column_set = layout->AddColumnSet(0);
96 column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
97 views::GridLayout::FIXED, kMessageWidth, 0);
99 const base::string16 message_lead = GetMessageLead();
101 if (!message_lead.empty()) {
102 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
103 views::Label* message_lead_label = new views::Label(
104 message_lead, rb->GetFontList(ui::ResourceBundle::BoldFont));
105 message_lead_label->SetMultiLine(true);
106 message_lead_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
107 message_lead_label->SetAllowCharacterBreak(true);
109 layout->StartRow(0, 0);
110 layout->AddView(message_lead_label);
112 layout->AddPaddingRow(0, kParagraphPadding);
115 views::Label* message_body_label = new views::Label(GetMessageBody());
116 message_body_label->SetMultiLine(true);
117 message_body_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
118 message_body_label->SetAllowCharacterBreak(true);
120 layout->StartRow(0, 0);
121 layout->AddView(message_body_label);
123 RecordOpenedDangerousConfirmDialog(download_->GetDangerType());
125 // ExperienceSampling: A malicious download warning is being shown to the
126 // user, so we start a new SamplingEvent and track it.
127 sampling_event_.reset(new ExperienceSamplingEvent(
128 ExperienceSamplingEvent::kDownloadDangerPrompt,
129 item->GetURL(),
130 item->GetReferrerUrl(),
131 item->GetBrowserContext()));
134 // DownloadDangerPrompt methods:
135 void DownloadDangerPromptViews::InvokeActionForTesting(Action action) {
136 switch (action) {
137 case ACCEPT:
138 Accept();
139 break;
141 case CANCEL:
142 case DISMISS:
143 Cancel();
144 break;
146 default:
147 NOTREACHED();
148 break;
152 // views::DialogDelegate methods:
153 base::string16 DownloadDangerPromptViews::GetDialogButtonLabel(
154 ui::DialogButton button) const {
155 switch (button) {
156 case ui::DIALOG_BUTTON_OK:
157 return GetAcceptButtonTitle();
159 case ui::DIALOG_BUTTON_CANCEL:
160 return GetCancelButtonTitle();
162 default:
163 return DialogDelegate::GetDialogButtonLabel(button);
167 base::string16 DownloadDangerPromptViews::GetWindowTitle() const {
168 if (show_context_)
169 return l10n_util::GetStringUTF16(IDS_CONFIRM_KEEP_DANGEROUS_DOWNLOAD_TITLE);
170 else
171 return l10n_util::GetStringUTF16(IDS_RESTORE_KEEP_DANGEROUS_DOWNLOAD_TITLE);
174 void DownloadDangerPromptViews::DeleteDelegate() {
175 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
176 delete this;
179 ui::ModalType DownloadDangerPromptViews::GetModalType() const {
180 return ui::MODAL_TYPE_CHILD;
183 bool DownloadDangerPromptViews::Cancel() {
184 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
185 // ExperienceSampling: User canceled the warning.
186 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
187 RunDone(CANCEL);
188 return true;
191 bool DownloadDangerPromptViews::Accept() {
192 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
193 // ExperienceSampling: User proceeded through the warning.
194 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed);
195 RunDone(ACCEPT);
196 return true;
199 bool DownloadDangerPromptViews::Close() {
200 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
201 // ExperienceSampling: User canceled the warning.
202 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
203 RunDone(DISMISS);
204 return true;
207 views::View* DownloadDangerPromptViews::GetInitiallyFocusedView() {
208 return GetDialogClientView()->cancel_button();
211 views::View* DownloadDangerPromptViews::GetContentsView() {
212 return contents_view_;
215 views::Widget* DownloadDangerPromptViews::GetWidget() {
216 return contents_view_->GetWidget();
219 const views::Widget* DownloadDangerPromptViews::GetWidget() const {
220 return contents_view_->GetWidget();
223 // content::DownloadItem::Observer:
224 void DownloadDangerPromptViews::OnDownloadUpdated(
225 content::DownloadItem* download) {
226 // If the download is nolonger dangerous (accepted externally) or the download
227 // is in a terminal state, then the download danger prompt is no longer
228 // necessary.
229 if (!download_->IsDangerous() || download_->IsDone()) {
230 RunDone(DISMISS);
231 Cancel();
235 base::string16 DownloadDangerPromptViews::GetAcceptButtonTitle() const {
236 if (show_context_)
237 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD);
238 switch (download_->GetDangerType()) {
239 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
240 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
241 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
242 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN_MALICIOUS);
244 default:
245 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN);
249 base::string16 DownloadDangerPromptViews::GetCancelButtonTitle() const {
250 if (show_context_)
251 return l10n_util::GetStringUTF16(IDS_CANCEL);
252 switch (download_->GetDangerType()) {
253 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
254 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
255 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
256 return l10n_util::GetStringUTF16(IDS_CONFIRM_CANCEL_AGAIN_MALICIOUS);
258 default:
259 return l10n_util::GetStringUTF16(IDS_CANCEL);
263 base::string16 DownloadDangerPromptViews::GetMessageLead() const {
264 if (!show_context_) {
265 switch (download_->GetDangerType()) {
266 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
267 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
268 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
269 return l10n_util::GetStringUTF16(
270 IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_LEAD);
272 default:
273 break;
277 return base::string16();
280 base::string16 DownloadDangerPromptViews::GetMessageBody() const {
281 if (show_context_) {
282 switch (download_->GetDangerType()) {
283 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: {
284 return l10n_util::GetStringFUTF16(
285 IDS_PROMPT_DANGEROUS_DOWNLOAD,
286 download_->GetFileNameToReportUser().LossyDisplayName());
288 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: // Fall through
289 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
290 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
291 return l10n_util::GetStringFUTF16(
292 IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT,
293 download_->GetFileNameToReportUser().LossyDisplayName());
295 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: {
296 return l10n_util::GetStringFUTF16(
297 IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT,
298 download_->GetFileNameToReportUser().LossyDisplayName());
300 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: {
301 return l10n_util::GetStringFUTF16(
302 IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS,
303 download_->GetFileNameToReportUser().LossyDisplayName());
305 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
306 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
307 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
308 case content::DOWNLOAD_DANGER_TYPE_MAX: {
309 break;
312 } else {
313 switch (download_->GetDangerType()) {
314 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
315 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
316 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
317 return l10n_util::GetStringUTF16(
318 IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_BODY);
320 default: {
321 return l10n_util::GetStringUTF16(
322 IDS_PROMPT_CONFIRM_KEEP_DANGEROUS_DOWNLOAD);
326 NOTREACHED();
327 return base::string16();
330 void DownloadDangerPromptViews::RunDone(Action action) {
331 // Invoking the callback can cause the download item state to change or cause
332 // the window to close, and |callback| refers to a member variable.
333 OnDone done = done_;
334 done_.Reset();
335 if (download_ != NULL) {
336 download_->RemoveObserver(this);
337 download_ = NULL;
339 if (!done.is_null())
340 done.Run(action);
343 } // namespace
345 DownloadDangerPrompt* DownloadDangerPrompt::Create(
346 content::DownloadItem* item,
347 content::WebContents* web_contents,
348 bool show_context,
349 const OnDone& done) {
350 DownloadDangerPromptViews* download_danger_prompt =
351 new DownloadDangerPromptViews(item, show_context, done);
352 constrained_window::ShowWebModalDialogViews(download_danger_prompt,
353 web_contents);
354 return download_danger_prompt;