download_danger_prompt_views.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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. 4 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" 26 27using content::BrowserThread; 28using web_modal::WebContentsModalDialogManager; 29using web_modal::WebContentsModalDialogManagerDelegate; 30 31namespace { 32 33const int kMessageWidth = 320; 34const int kParagraphPadding = 15; 35 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. 39class DownloadDangerPromptViews : public DownloadDangerPrompt, 40 public content::DownloadItem::Observer, 41 public views::DialogDelegate { 42 public: 43 DownloadDangerPromptViews(content::DownloadItem* item, 44 content::WebContents* web_contents, 45 bool show_context, 46 const OnDone& done); 47 48 // DownloadDangerPrompt methods: 49 virtual void InvokeActionForTesting(Action action) OVERRIDE; 50 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; 67 68 // content::DownloadItem::Observer: 69 virtual void OnDownloadUpdated(content::DownloadItem* download) OVERRIDE; 70 71 private: 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); 78 79 content::DownloadItem* download_; 80 content::WebContents* web_contents_; 81 bool show_context_; 82 OnDone done_; 83 84 views::View* contents_view_; 85}; 86 87DownloadDangerPromptViews::DownloadDangerPromptViews( 88 content::DownloadItem* item, 89 content::WebContents* web_contents, 90 bool show_context, 91 const OnDone& done) 92 : download_(item), 93 web_contents_(web_contents), 94 show_context_(show_context), 95 done_(done), 96 contents_view_(NULL) { 97 DCHECK(!done_.is_null()); 98 download_->AddObserver(this); 99 100 contents_view_ = new views::View; 101 102 views::GridLayout* layout = views::GridLayout::CreatePanel(contents_view_); 103 contents_view_->SetLayoutManager(layout); 104 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); 108 109 const string16 message_lead = GetMessageLead(); 110 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); 116 117 gfx::FontList font_list(gfx::Font().DeriveFont(0, gfx::Font::BOLD)); 118 message_lead_label->SetFontList(font_list); 119 120 layout->StartRow(0, 0); 121 layout->AddView(message_lead_label); 122 123 layout->AddPaddingRow(0, kParagraphPadding); 124 } 125 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); 130 131 layout->StartRow(0, 0); 132 layout->AddView(message_body_label); 133} 134 135// DownloadDangerPrompt methods: 136void DownloadDangerPromptViews::InvokeActionForTesting(Action action) { 137 switch (action) { 138 case ACCEPT: 139 Accept(); 140 break; 141 142 case CANCEL: 143 case DISMISS: 144 Cancel(); 145 break; 146 147 default: 148 NOTREACHED(); 149 break; 150 } 151} 152 153// views::DialogDelegate methods: 154string16 DownloadDangerPromptViews::GetDialogButtonLabel( 155 ui::DialogButton button) const { 156 switch (button) { 157 case ui::DIALOG_BUTTON_OK: 158 return GetAcceptButtonTitle(); 159 160 case ui::DIALOG_BUTTON_CANCEL: 161 return GetCancelButtonTitle(); 162 163 default: 164 return DialogDelegate::GetDialogButtonLabel(button); 165 }; 166} 167 168string16 DownloadDangerPromptViews::GetWindowTitle() const { 169 if (show_context_) 170 return l10n_util::GetStringUTF16(IDS_CONFIRM_KEEP_DANGEROUS_DOWNLOAD_TITLE); 171 else 172 return l10n_util::GetStringUTF16(IDS_RESTORE_KEEP_DANGEROUS_DOWNLOAD_TITLE); 173} 174 175void DownloadDangerPromptViews::DeleteDelegate() { 176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 177 178 delete this; 179} 180 181ui::ModalType DownloadDangerPromptViews::GetModalType() const { 182#if defined(USE_ASH) 183 return ui::MODAL_TYPE_CHILD; 184#else 185 return views::WidgetDelegate::GetModalType(); 186#endif 187} 188 189bool DownloadDangerPromptViews::Cancel() { 190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 191 192 RunDone(CANCEL); 193 return true; 194} 195 196bool DownloadDangerPromptViews::Accept() { 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 198 199 RunDone(ACCEPT); 200 return true; 201} 202 203bool DownloadDangerPromptViews::Close() { 204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 205 206 RunDone(DISMISS); 207 return true; 208} 209 210// TODO(wittman): Remove this override once we move to the new style frame 211// view on all dialogs. 212views::NonClientFrameView* DownloadDangerPromptViews::CreateNonClientFrameView( 213 views::Widget* widget) { 214 return CreateConstrainedStyleNonClientFrameView( 215 widget, 216 web_contents_->GetBrowserContext()); 217} 218 219views::View* DownloadDangerPromptViews::GetInitiallyFocusedView() { 220 return GetDialogClientView()->cancel_button(); 221} 222 223views::View* DownloadDangerPromptViews::GetContentsView() { 224 return contents_view_; 225} 226 227views::Widget* DownloadDangerPromptViews::GetWidget() { 228 return contents_view_->GetWidget(); 229} 230 231const views::Widget* DownloadDangerPromptViews::GetWidget() const { 232 return contents_view_->GetWidget(); 233} 234 235// content::DownloadItem::Observer: 236void 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 240 // necessary. 241 if (!download_->IsDangerous() || download_->IsDone()) { 242 RunDone(DISMISS); 243 Cancel(); 244 } 245} 246 247string16 DownloadDangerPromptViews::GetAcceptButtonTitle() const { 248 if (show_context_) 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); 255 } 256 default: 257 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN); 258 } 259} 260 261string16 DownloadDangerPromptViews::GetCancelButtonTitle() const { 262 if (show_context_) 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); 269 } 270 default: 271 return l10n_util::GetStringUTF16(IDS_CANCEL); 272 } 273} 274 275string16 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); 283 284 default: 285 break; 286 } 287 } 288 289 return string16(); 290} 291 292string16 DownloadDangerPromptViews::GetMessageBody() const { 293 if (show_context_) { 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()); 299 } 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()); 306 } 307 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: { 308 return l10n_util::GetStringFUTF16( 309 IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT, 310 download_->GetFileNameToReportUser().LossyDisplayName()); 311 } 312 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: { 313 return l10n_util::GetStringFUTF16( 314 IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS, 315 download_->GetFileNameToReportUser().LossyDisplayName()); 316 } 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: { 321 break; 322 } 323 } 324 } else { 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); 331 } 332 default: { 333 return l10n_util::GetStringUTF16( 334 IDS_PROMPT_CONFIRM_KEEP_DANGEROUS_DOWNLOAD); 335 } 336 } 337 } 338 NOTREACHED(); 339 return string16(); 340} 341 342void 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. 345 OnDone done = done_; 346 done_.Reset(); 347 if (download_ != NULL) { 348 download_->RemoveObserver(this); 349 download_ = NULL; 350 } 351 if (!done.is_null()) 352 done.Run(action); 353} 354 355} // namespace 356 357DownloadDangerPrompt* DownloadDangerPrompt::Create( 358 content::DownloadItem* item, 359 content::WebContents* web_contents, 360 bool show_context, 361 const OnDone& done) { 362 DownloadDangerPromptViews* download_danger_prompt = 363 new DownloadDangerPromptViews(item, web_contents, show_context, done); 364 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()); 375 376 return download_danger_prompt; 377} 378