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/ui/views/constrained_window_views.h"
9 #include "components/web_modal/web_contents_modal_dialog_host.h"
10 #include "components/web_modal/web_contents_modal_dialog_manager.h"
11 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.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 "content/public/browser/web_contents.h"
16 #include "grit/chromium_strings.h"
17 #include "grit/generated_resources.h"
18 #include "ui/base/l10n/l10n_util.h"
19 #include "ui/views/controls/button/label_button.h"
20 #include "ui/views/controls/label.h"
21 #include "ui/views/layout/grid_layout.h"
22 #include "ui/views/view.h"
23 #include "ui/views/widget/widget.h"
24 #include "ui/views/window/dialog_client_view.h"
25 #include "ui/views/window/dialog_delegate.h"
27 using content::BrowserThread
;
28 using web_modal::WebContentsModalDialogManager
;
29 using web_modal::WebContentsModalDialogManagerDelegate
;
33 const int kMessageWidth
= 320;
34 const int kParagraphPadding
= 15;
36 // Views-specific implementation of download danger prompt dialog. We use this
37 // class rather than a TabModalConfirmDialog so that we can use custom
38 // formatting on the text in the body of the dialog.
39 class DownloadDangerPromptViews
: public DownloadDangerPrompt
,
40 public content::DownloadItem::Observer
,
41 public views::DialogDelegate
{
43 DownloadDangerPromptViews(content::DownloadItem
* item
,
44 content::WebContents
* web_contents
,
48 // DownloadDangerPrompt methods:
49 virtual void InvokeActionForTesting(Action action
) OVERRIDE
;
51 // views::DialogDelegate methods:
52 virtual base::string16
GetDialogButtonLabel(
53 ui::DialogButton button
) const OVERRIDE
;
54 virtual base::string16
GetWindowTitle() const OVERRIDE
;
55 virtual void DeleteDelegate() OVERRIDE
;
56 virtual ui::ModalType
GetModalType() const OVERRIDE
;
57 virtual bool Cancel() OVERRIDE
;
58 virtual bool Accept() OVERRIDE
;
59 virtual bool Close() OVERRIDE
;
60 // TODO(wittman): Remove this override once we move to the new style frame
61 // view on all dialogs.
62 virtual views::NonClientFrameView
* CreateNonClientFrameView(
63 views::Widget
* widget
) OVERRIDE
;
64 virtual views::View
* GetInitiallyFocusedView() OVERRIDE
;
65 virtual views::View
* GetContentsView() OVERRIDE
;
66 virtual views::Widget
* GetWidget() OVERRIDE
;
67 virtual const views::Widget
* GetWidget() const OVERRIDE
;
69 // content::DownloadItem::Observer:
70 virtual void OnDownloadUpdated(content::DownloadItem
* download
) OVERRIDE
;
73 base::string16
GetAcceptButtonTitle() const;
74 base::string16
GetCancelButtonTitle() const;
75 // The message lead is separated from the main text and is bolded.
76 base::string16
GetMessageLead() const;
77 base::string16
GetMessageBody() const;
78 void RunDone(Action action
);
80 content::DownloadItem
* download_
;
81 content::WebContents
* web_contents_
;
85 views::View
* contents_view_
;
88 DownloadDangerPromptViews::DownloadDangerPromptViews(
89 content::DownloadItem
* item
,
90 content::WebContents
* web_contents
,
94 web_contents_(web_contents
),
95 show_context_(show_context
),
97 contents_view_(NULL
) {
98 DCHECK(!done_
.is_null());
99 download_
->AddObserver(this);
101 contents_view_
= new views::View
;
103 views::GridLayout
* layout
= views::GridLayout::CreatePanel(contents_view_
);
104 contents_view_
->SetLayoutManager(layout
);
106 views::ColumnSet
* column_set
= layout
->AddColumnSet(0);
107 column_set
->AddColumn(views::GridLayout::FILL
, views::GridLayout::FILL
, 1,
108 views::GridLayout::FIXED
, kMessageWidth
, 0);
110 const base::string16 message_lead
= GetMessageLead();
112 if (!message_lead
.empty()) {
113 views::Label
* message_lead_label
= new views::Label(message_lead
);
114 message_lead_label
->SetMultiLine(true);
115 message_lead_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
116 message_lead_label
->SetAllowCharacterBreak(true);
118 gfx::FontList
font_list(gfx::Font().DeriveFont(0, gfx::Font::BOLD
));
119 message_lead_label
->SetFontList(font_list
);
121 layout
->StartRow(0, 0);
122 layout
->AddView(message_lead_label
);
124 layout
->AddPaddingRow(0, kParagraphPadding
);
127 views::Label
* message_body_label
= new views::Label(GetMessageBody());
128 message_body_label
->SetMultiLine(true);
129 message_body_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
130 message_body_label
->SetAllowCharacterBreak(true);
132 layout
->StartRow(0, 0);
133 layout
->AddView(message_body_label
);
135 RecordOpenedDangerousConfirmDialog(download_
->GetDangerType());
138 // DownloadDangerPrompt methods:
139 void DownloadDangerPromptViews::InvokeActionForTesting(Action action
) {
156 // views::DialogDelegate methods:
157 base::string16
DownloadDangerPromptViews::GetDialogButtonLabel(
158 ui::DialogButton button
) const {
160 case ui::DIALOG_BUTTON_OK
:
161 return GetAcceptButtonTitle();
163 case ui::DIALOG_BUTTON_CANCEL
:
164 return GetCancelButtonTitle();
167 return DialogDelegate::GetDialogButtonLabel(button
);
171 base::string16
DownloadDangerPromptViews::GetWindowTitle() const {
173 return l10n_util::GetStringUTF16(IDS_CONFIRM_KEEP_DANGEROUS_DOWNLOAD_TITLE
);
175 return l10n_util::GetStringUTF16(IDS_RESTORE_KEEP_DANGEROUS_DOWNLOAD_TITLE
);
178 void DownloadDangerPromptViews::DeleteDelegate() {
179 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
184 ui::ModalType
DownloadDangerPromptViews::GetModalType() const {
186 return ui::MODAL_TYPE_CHILD
;
188 return views::WidgetDelegate::GetModalType();
192 bool DownloadDangerPromptViews::Cancel() {
193 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
199 bool DownloadDangerPromptViews::Accept() {
200 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
206 bool DownloadDangerPromptViews::Close() {
207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
213 // TODO(wittman): Remove this override once we move to the new style frame
214 // view on all dialogs.
215 views::NonClientFrameView
* DownloadDangerPromptViews::CreateNonClientFrameView(
216 views::Widget
* widget
) {
217 return CreateConstrainedStyleNonClientFrameView(
218 widget
, web_contents_
->GetBrowserContext());
221 views::View
* DownloadDangerPromptViews::GetInitiallyFocusedView() {
222 return GetDialogClientView()->cancel_button();
225 views::View
* DownloadDangerPromptViews::GetContentsView() {
226 return contents_view_
;
229 views::Widget
* DownloadDangerPromptViews::GetWidget() {
230 return contents_view_
->GetWidget();
233 const views::Widget
* DownloadDangerPromptViews::GetWidget() const {
234 return contents_view_
->GetWidget();
237 // content::DownloadItem::Observer:
238 void DownloadDangerPromptViews::OnDownloadUpdated(
239 content::DownloadItem
* download
) {
240 // If the download is nolonger dangerous (accepted externally) or the download
241 // is in a terminal state, then the download danger prompt is no longer
243 if (!download_
->IsDangerous() || download_
->IsDone()) {
249 base::string16
DownloadDangerPromptViews::GetAcceptButtonTitle() const {
251 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD
);
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_DOWNLOAD_AGAIN_MALICIOUS
);
259 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN
);
263 base::string16
DownloadDangerPromptViews::GetCancelButtonTitle() const {
265 return l10n_util::GetStringUTF16(IDS_CANCEL
);
266 switch (download_
->GetDangerType()) {
267 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
:
268 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT
:
269 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST
: {
270 return l10n_util::GetStringUTF16(IDS_CONFIRM_CANCEL_AGAIN_MALICIOUS
);
273 return l10n_util::GetStringUTF16(IDS_CANCEL
);
277 base::string16
DownloadDangerPromptViews::GetMessageLead() const {
278 if (!show_context_
) {
279 switch (download_
->GetDangerType()) {
280 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
:
281 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT
:
282 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST
:
283 return l10n_util::GetStringUTF16(
284 IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_LEAD
);
291 return base::string16();
294 base::string16
DownloadDangerPromptViews::GetMessageBody() const {
296 switch (download_
->GetDangerType()) {
297 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
: {
298 return l10n_util::GetStringFUTF16(
299 IDS_PROMPT_DANGEROUS_DOWNLOAD
,
300 download_
->GetFileNameToReportUser().LossyDisplayName());
302 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
: // Fall through
303 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT
:
304 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST
: {
305 return l10n_util::GetStringFUTF16(
306 IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT
,
307 download_
->GetFileNameToReportUser().LossyDisplayName());
309 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT
: {
310 return l10n_util::GetStringFUTF16(
311 IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT
,
312 download_
->GetFileNameToReportUser().LossyDisplayName());
314 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED
: {
315 return l10n_util::GetStringFUTF16(
316 IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS
,
317 download_
->GetFileNameToReportUser().LossyDisplayName());
319 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
:
320 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT
:
321 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED
:
322 case content::DOWNLOAD_DANGER_TYPE_MAX
: {
327 switch (download_
->GetDangerType()) {
328 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
:
329 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT
:
330 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST
: {
331 return l10n_util::GetStringUTF16(
332 IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_BODY
);
335 return l10n_util::GetStringUTF16(
336 IDS_PROMPT_CONFIRM_KEEP_DANGEROUS_DOWNLOAD
);
341 return base::string16();
344 void DownloadDangerPromptViews::RunDone(Action action
) {
345 // Invoking the callback can cause the download item state to change or cause
346 // the window to close, and |callback| refers to a member variable.
349 if (download_
!= NULL
) {
350 download_
->RemoveObserver(this);
359 DownloadDangerPrompt
* DownloadDangerPrompt::Create(
360 content::DownloadItem
* item
,
361 content::WebContents
* web_contents
,
363 const OnDone
& done
) {
364 DownloadDangerPromptViews
* download_danger_prompt
=
365 new DownloadDangerPromptViews(item
, web_contents
, show_context
, done
);
367 WebContentsModalDialogManager
* web_contents_modal_dialog_manager
=
368 WebContentsModalDialogManager::FromWebContents(web_contents
);
369 WebContentsModalDialogManagerDelegate
* modal_delegate
=
370 web_contents_modal_dialog_manager
->delegate();
371 CHECK(modal_delegate
);
372 views::Widget
* dialog
= views::Widget::CreateWindowAsFramelessChild(
373 download_danger_prompt
,
374 modal_delegate
->GetWebContentsModalDialogHost()->GetHostView());
375 web_contents_modal_dialog_manager
->ShowDialog(dialog
->GetNativeView());
377 return download_danger_prompt
;