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/ui/views/constrained_window_views.h"
8 #include "components/web_modal/web_contents_modal_dialog_host.h"
9 #include "components/web_modal/web_contents_modal_dialog_manager.h"
10 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/download_danger_type.h"
13 #include "content/public/browser/download_item.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/public/browser/web_contents_view.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 string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE;
53 virtual string16 GetWindowTitle() const OVERRIDE;
54 virtual void DeleteDelegate() OVERRIDE;
55 virtual ui::ModalType GetModalType() const OVERRIDE;
56 virtual bool Cancel() OVERRIDE;
57 virtual bool Accept() OVERRIDE;
58 virtual bool Close() OVERRIDE;
59 // TODO(wittman): Remove this override once we move to the new style frame
60 // view on all dialogs.
61 virtual views::NonClientFrameView* CreateNonClientFrameView(
62 views::Widget* widget) OVERRIDE;
63 virtual views::View* GetInitiallyFocusedView() OVERRIDE;
64 virtual views::View* GetContentsView() OVERRIDE;
65 virtual views::Widget* GetWidget() OVERRIDE;
66 virtual const views::Widget* GetWidget() const OVERRIDE;
68 // content::DownloadItem::Observer:
69 virtual void OnDownloadUpdated(content::DownloadItem* download) OVERRIDE;
72 string16 GetAcceptButtonTitle() const;
73 string16 GetCancelButtonTitle() const;
74 // The message lead is separated from the main text and is bolded.
75 string16 GetMessageLead() const;
76 string16 GetMessageBody() const;
77 void RunDone(Action action);
79 content::DownloadItem* download_;
80 content::WebContents* web_contents_;
84 views::View* contents_view_;
87 DownloadDangerPromptViews::DownloadDangerPromptViews(
88 content::DownloadItem* item,
89 content::WebContents* web_contents,
93 web_contents_(web_contents),
94 show_context_(show_context),
96 contents_view_(NULL) {
97 DCHECK(!done_.is_null());
98 download_->AddObserver(this);
100 contents_view_ = new views::View;
102 views::GridLayout* layout = views::GridLayout::CreatePanel(contents_view_);
103 contents_view_->SetLayoutManager(layout);
105 views::ColumnSet* column_set = layout->AddColumnSet(0);
106 column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
107 views::GridLayout::FIXED, kMessageWidth, 0);
109 const string16 message_lead = GetMessageLead();
111 if (!message_lead.empty()) {
112 views::Label* message_lead_label = new views::Label(message_lead);
113 message_lead_label->SetMultiLine(true);
114 message_lead_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
115 message_lead_label->SetAllowCharacterBreak(true);
117 gfx::FontList font_list(gfx::Font().DeriveFont(0, gfx::Font::BOLD));
118 message_lead_label->SetFontList(font_list);
120 layout->StartRow(0, 0);
121 layout->AddView(message_lead_label);
123 layout->AddPaddingRow(0, kParagraphPadding);
126 views::Label* message_body_label = new views::Label(GetMessageBody());
127 message_body_label->SetMultiLine(true);
128 message_body_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
129 message_body_label->SetAllowCharacterBreak(true);
131 layout->StartRow(0, 0);
132 layout->AddView(message_body_label);
135 // DownloadDangerPrompt methods:
136 void DownloadDangerPromptViews::InvokeActionForTesting(Action action) {
153 // views::DialogDelegate methods:
154 string16 DownloadDangerPromptViews::GetDialogButtonLabel(
155 ui::DialogButton button) const {
157 case ui::DIALOG_BUTTON_OK:
158 return GetAcceptButtonTitle();
160 case ui::DIALOG_BUTTON_CANCEL:
161 return GetCancelButtonTitle();
164 return DialogDelegate::GetDialogButtonLabel(button);
168 string16 DownloadDangerPromptViews::GetWindowTitle() const {
170 return l10n_util::GetStringUTF16(IDS_CONFIRM_KEEP_DANGEROUS_DOWNLOAD_TITLE);
172 return l10n_util::GetStringUTF16(IDS_RESTORE_KEEP_DANGEROUS_DOWNLOAD_TITLE);
175 void DownloadDangerPromptViews::DeleteDelegate() {
176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
181 ui::ModalType DownloadDangerPromptViews::GetModalType() const {
183 return ui::MODAL_TYPE_CHILD;
185 return views::WidgetDelegate::GetModalType();
189 bool DownloadDangerPromptViews::Cancel() {
190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
196 bool DownloadDangerPromptViews::Accept() {
197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
203 bool DownloadDangerPromptViews::Close() {
204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
210 // TODO(wittman): Remove this override once we move to the new style frame
211 // view on all dialogs.
212 views::NonClientFrameView* DownloadDangerPromptViews::CreateNonClientFrameView(
213 views::Widget* widget) {
214 return CreateConstrainedStyleNonClientFrameView(
216 web_contents_->GetBrowserContext());
219 views::View* DownloadDangerPromptViews::GetInitiallyFocusedView() {
220 return GetDialogClientView()->cancel_button();
223 views::View* DownloadDangerPromptViews::GetContentsView() {
224 return contents_view_;
227 views::Widget* DownloadDangerPromptViews::GetWidget() {
228 return contents_view_->GetWidget();
231 const views::Widget* DownloadDangerPromptViews::GetWidget() const {
232 return contents_view_->GetWidget();
235 // content::DownloadItem::Observer:
236 void DownloadDangerPromptViews::OnDownloadUpdated(
237 content::DownloadItem* download) {
238 // If the download is nolonger dangerous (accepted externally) or the download
239 // is in a terminal state, then the download danger prompt is no longer
241 if (!download_->IsDangerous() || download_->IsDone()) {
247 string16 DownloadDangerPromptViews::GetAcceptButtonTitle() const {
249 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD);
250 switch (download_->GetDangerType()) {
251 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
252 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
253 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
254 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN_MALICIOUS);
257 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN);
261 string16 DownloadDangerPromptViews::GetCancelButtonTitle() const {
263 return l10n_util::GetStringUTF16(IDS_CANCEL);
264 switch (download_->GetDangerType()) {
265 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
266 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
267 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
268 return l10n_util::GetStringUTF16(IDS_CONFIRM_CANCEL_AGAIN_MALICIOUS);
271 return l10n_util::GetStringUTF16(IDS_CANCEL);
275 string16 DownloadDangerPromptViews::GetMessageLead() const {
276 if (!show_context_) {
277 switch (download_->GetDangerType()) {
278 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
279 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
280 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
281 return l10n_util::GetStringUTF16(
282 IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_LEAD);
292 string16 DownloadDangerPromptViews::GetMessageBody() const {
294 switch (download_->GetDangerType()) {
295 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: {
296 return l10n_util::GetStringFUTF16(
297 IDS_PROMPT_DANGEROUS_DOWNLOAD,
298 download_->GetFileNameToReportUser().LossyDisplayName());
300 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: // Fall through
301 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
302 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
303 return l10n_util::GetStringFUTF16(
304 IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT,
305 download_->GetFileNameToReportUser().LossyDisplayName());
307 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: {
308 return l10n_util::GetStringFUTF16(
309 IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT,
310 download_->GetFileNameToReportUser().LossyDisplayName());
312 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: {
313 return l10n_util::GetStringFUTF16(
314 IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS,
315 download_->GetFileNameToReportUser().LossyDisplayName());
317 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
318 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
319 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
320 case content::DOWNLOAD_DANGER_TYPE_MAX: {
325 switch (download_->GetDangerType()) {
326 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
327 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
328 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
329 return l10n_util::GetStringUTF16(
330 IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_BODY);
333 return l10n_util::GetStringUTF16(
334 IDS_PROMPT_CONFIRM_KEEP_DANGEROUS_DOWNLOAD);
342 void DownloadDangerPromptViews::RunDone(Action action) {
343 // Invoking the callback can cause the download item state to change or cause
344 // the window to close, and |callback| refers to a member variable.
347 if (download_ != NULL) {
348 download_->RemoveObserver(this);
357 DownloadDangerPrompt* DownloadDangerPrompt::Create(
358 content::DownloadItem* item,
359 content::WebContents* web_contents,
361 const OnDone& done) {
362 DownloadDangerPromptViews* download_danger_prompt =
363 new DownloadDangerPromptViews(item, web_contents, show_context, done);
365 WebContentsModalDialogManager* web_contents_modal_dialog_manager =
366 WebContentsModalDialogManager::FromWebContents(web_contents);
367 WebContentsModalDialogManagerDelegate* modal_delegate =
368 web_contents_modal_dialog_manager->delegate();
369 CHECK(modal_delegate);
370 views::Widget* dialog = views::Widget::CreateWindowAsFramelessChild(
371 download_danger_prompt,
372 web_contents->GetView()->GetNativeView(),
373 modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
374 web_contents_modal_dialog_manager->ShowDialog(dialog->GetNativeView());
376 return download_danger_prompt;