download_danger_prompt_views.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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 "grit/chromium_strings.h" 16#include "grit/generated_resources.h" 17#include "ui/base/l10n/l10n_util.h" 18#include "ui/views/controls/button/label_button.h" 19#include "ui/views/controls/label.h" 20#include "ui/views/layout/grid_layout.h" 21#include "ui/views/view.h" 22#include "ui/views/widget/widget.h" 23#include "ui/views/window/dialog_client_view.h" 24#include "ui/views/window/dialog_delegate.h" 25 26using content::BrowserThread; 27using web_modal::WebContentsModalDialogManager; 28using web_modal::WebContentsModalDialogManagerDelegate; 29 30namespace { 31 32const int kMessageWidth = 320; 33const int kParagraphPadding = 15; 34 35// Views-specific implementation of download danger prompt dialog. We use this 36// class rather than a TabModalConfirmDialog so that we can use custom 37// formatting on the text in the body of the dialog. 38class DownloadDangerPromptViews : public DownloadDangerPrompt, 39 public content::DownloadItem::Observer, 40 public views::DialogDelegate { 41 public: 42 DownloadDangerPromptViews(content::DownloadItem* item, 43 content::WebContents* web_contents, 44 bool show_context, 45 const OnDone& done); 46 47 // DownloadDangerPrompt methods: 48 virtual void InvokeActionForTesting(Action action) OVERRIDE; 49 50 // views::DialogDelegate methods: 51 virtual base::string16 GetDialogButtonLabel( 52 ui::DialogButton button) const OVERRIDE; 53 virtual base::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 base::string16 GetAcceptButtonTitle() const; 73 base::string16 GetCancelButtonTitle() const; 74 // The message lead is separated from the main text and is bolded. 75 base::string16 GetMessageLead() const; 76 base::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 base::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: 154base::string16 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 168base::string16 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, web_contents_->GetBrowserContext()); 216} 217 218views::View* DownloadDangerPromptViews::GetInitiallyFocusedView() { 219 return GetDialogClientView()->cancel_button(); 220} 221 222views::View* DownloadDangerPromptViews::GetContentsView() { 223 return contents_view_; 224} 225 226views::Widget* DownloadDangerPromptViews::GetWidget() { 227 return contents_view_->GetWidget(); 228} 229 230const views::Widget* DownloadDangerPromptViews::GetWidget() const { 231 return contents_view_->GetWidget(); 232} 233 234// content::DownloadItem::Observer: 235void DownloadDangerPromptViews::OnDownloadUpdated( 236 content::DownloadItem* download) { 237 // If the download is nolonger dangerous (accepted externally) or the download 238 // is in a terminal state, then the download danger prompt is no longer 239 // necessary. 240 if (!download_->IsDangerous() || download_->IsDone()) { 241 RunDone(DISMISS); 242 Cancel(); 243 } 244} 245 246base::string16 DownloadDangerPromptViews::GetAcceptButtonTitle() const { 247 if (show_context_) 248 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD); 249 switch (download_->GetDangerType()) { 250 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: 251 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: 252 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: { 253 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN_MALICIOUS); 254 } 255 default: 256 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN); 257 } 258} 259 260base::string16 DownloadDangerPromptViews::GetCancelButtonTitle() const { 261 if (show_context_) 262 return l10n_util::GetStringUTF16(IDS_CANCEL); 263 switch (download_->GetDangerType()) { 264 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: 265 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: 266 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: { 267 return l10n_util::GetStringUTF16(IDS_CONFIRM_CANCEL_AGAIN_MALICIOUS); 268 } 269 default: 270 return l10n_util::GetStringUTF16(IDS_CANCEL); 271 } 272} 273 274base::string16 DownloadDangerPromptViews::GetMessageLead() const { 275 if (!show_context_) { 276 switch (download_->GetDangerType()) { 277 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: 278 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: 279 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: 280 return l10n_util::GetStringUTF16( 281 IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_LEAD); 282 283 default: 284 break; 285 } 286 } 287 288 return base::string16(); 289} 290 291base::string16 DownloadDangerPromptViews::GetMessageBody() const { 292 if (show_context_) { 293 switch (download_->GetDangerType()) { 294 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: { 295 return l10n_util::GetStringFUTF16( 296 IDS_PROMPT_DANGEROUS_DOWNLOAD, 297 download_->GetFileNameToReportUser().LossyDisplayName()); 298 } 299 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: // Fall through 300 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: 301 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: { 302 return l10n_util::GetStringFUTF16( 303 IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT, 304 download_->GetFileNameToReportUser().LossyDisplayName()); 305 } 306 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: { 307 return l10n_util::GetStringFUTF16( 308 IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT, 309 download_->GetFileNameToReportUser().LossyDisplayName()); 310 } 311 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: { 312 return l10n_util::GetStringFUTF16( 313 IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS, 314 download_->GetFileNameToReportUser().LossyDisplayName()); 315 } 316 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS: 317 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT: 318 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED: 319 case content::DOWNLOAD_DANGER_TYPE_MAX: { 320 break; 321 } 322 } 323 } else { 324 switch (download_->GetDangerType()) { 325 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: 326 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: 327 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: { 328 return l10n_util::GetStringUTF16( 329 IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_BODY); 330 } 331 default: { 332 return l10n_util::GetStringUTF16( 333 IDS_PROMPT_CONFIRM_KEEP_DANGEROUS_DOWNLOAD); 334 } 335 } 336 } 337 NOTREACHED(); 338 return base::string16(); 339} 340 341void DownloadDangerPromptViews::RunDone(Action action) { 342 // Invoking the callback can cause the download item state to change or cause 343 // the window to close, and |callback| refers to a member variable. 344 OnDone done = done_; 345 done_.Reset(); 346 if (download_ != NULL) { 347 download_->RemoveObserver(this); 348 download_ = NULL; 349 } 350 if (!done.is_null()) 351 done.Run(action); 352} 353 354} // namespace 355 356DownloadDangerPrompt* DownloadDangerPrompt::Create( 357 content::DownloadItem* item, 358 content::WebContents* web_contents, 359 bool show_context, 360 const OnDone& done) { 361 DownloadDangerPromptViews* download_danger_prompt = 362 new DownloadDangerPromptViews(item, web_contents, show_context, done); 363 364 WebContentsModalDialogManager* web_contents_modal_dialog_manager = 365 WebContentsModalDialogManager::FromWebContents(web_contents); 366 WebContentsModalDialogManagerDelegate* modal_delegate = 367 web_contents_modal_dialog_manager->delegate(); 368 CHECK(modal_delegate); 369 views::Widget* dialog = views::Widget::CreateWindowAsFramelessChild( 370 download_danger_prompt, 371 modal_delegate->GetWebContentsModalDialogHost()->GetHostView()); 372 web_contents_modal_dialog_manager->ShowDialog(dialog->GetNativeView()); 373 374 return download_danger_prompt; 375} 376