| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/ui/cocoa/download/download_item_controller.h" | 5 #import "chrome/browser/ui/cocoa/download/download_item_controller.h" |
| 6 | 6 |
| 7 #include "base/mac/bundle_locations.h" | 7 #include "base/mac/bundle_locations.h" |
| 8 #include "base/mac/mac_util.h" | 8 #include "base/mac/mac_util.h" |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/strings/string16.h" | 10 #include "base/strings/string16.h" |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 content::PageNavigator* navigator) | 78 content::PageNavigator* navigator) |
| 79 : DownloadShelfContextMenu(downloadItem, navigator) { } | 79 : DownloadShelfContextMenu(downloadItem, navigator) { } |
| 80 | 80 |
| 81 // DownloadShelfContextMenu::GetMenuModel is protected. | 81 // DownloadShelfContextMenu::GetMenuModel is protected. |
| 82 using DownloadShelfContextMenu::GetMenuModel; | 82 using DownloadShelfContextMenu::GetMenuModel; |
| 83 }; | 83 }; |
| 84 | 84 |
| 85 @interface DownloadItemController (Private) | 85 @interface DownloadItemController (Private) |
| 86 - (void)themeDidChangeNotification:(NSNotification*)aNotification; | 86 - (void)themeDidChangeNotification:(NSNotification*)aNotification; |
| 87 - (void)updateTheme:(ui::ThemeProvider*)themeProvider; | 87 - (void)updateTheme:(ui::ThemeProvider*)themeProvider; |
| 88 - (void)setState:(DownoadItemState)state; | 88 - (void)setState:(DownloadItemState)state; |
| 89 - (void)initExperienceSamplingEvent:(const char*)event; |
| 90 - (void)updateExperienceSamplingEvent:(const char*)event; |
| 89 @end | 91 @end |
| 90 | 92 |
| 91 // Implementation of DownloadItemController | 93 // Implementation of DownloadItemController |
| 92 | 94 |
| 93 @implementation DownloadItemController | 95 @implementation DownloadItemController |
| 94 | 96 |
| 95 - (id)initWithDownload:(DownloadItem*)downloadItem | 97 - (id)initWithDownload:(DownloadItem*)downloadItem |
| 96 shelf:(DownloadShelfController*)shelf | 98 shelf:(DownloadShelfController*)shelf |
| 97 navigator:(content::PageNavigator*)navigator { | 99 navigator:(content::PageNavigator*)navigator { |
| 98 if ((self = [super initWithNibName:@"DownloadItem" | 100 if ((self = [super initWithNibName:@"DownloadItem" |
| (...skipping 12 matching lines...) Expand all Loading... |
| 111 state_ = kNormal; | 113 state_ = kNormal; |
| 112 creationTime_ = base::Time::Now(); | 114 creationTime_ = base::Time::Now(); |
| 113 font_list_.reset(new gfx::FontList( | 115 font_list_.reset(new gfx::FontList( |
| 114 ui::ResourceBundle::GetSharedInstance().GetFontList( | 116 ui::ResourceBundle::GetSharedInstance().GetFontList( |
| 115 ui::ResourceBundle::BaseFont))); | 117 ui::ResourceBundle::BaseFont))); |
| 116 } | 118 } |
| 117 return self; | 119 return self; |
| 118 } | 120 } |
| 119 | 121 |
| 120 - (void)dealloc { | 122 - (void)dealloc { |
| 121 if (sampling_event_.get()) | 123 [self updateExperienceSamplingEvent:ExperienceSamplingEvent::kIgnore]; |
| 122 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kIgnore); | |
| 123 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 124 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 124 [progressView_ setController:nil]; | 125 [progressView_ setController:nil]; |
| 125 [[self view] removeFromSuperview]; | 126 [[self view] removeFromSuperview]; |
| 126 [super dealloc]; | 127 [super dealloc]; |
| 127 } | 128 } |
| 128 | 129 |
| 129 - (void)awakeFromNib { | 130 - (void)awakeFromNib { |
| 130 [progressView_ setController:self]; | 131 [progressView_ setController:self]; |
| 131 | 132 |
| 132 GTMUILocalizerAndLayoutTweaker* localizerAndLayoutTweaker = | 133 GTMUILocalizerAndLayoutTweaker* localizerAndLayoutTweaker = |
| 133 [[[GTMUILocalizerAndLayoutTweaker alloc] init] autorelease]; | 134 [[[GTMUILocalizerAndLayoutTweaker alloc] init] autorelease]; |
| 134 [localizerAndLayoutTweaker applyLocalizer:localizer_ tweakingUI:[self view]]; | 135 [localizerAndLayoutTweaker applyLocalizer:localizer_ tweakingUI:[self view]]; |
| 135 | 136 |
| 136 [self setStateFromDownload:bridge_->download_model()]; | 137 [self setStateFromDownload:bridge_->download_model()]; |
| 137 | 138 |
| 138 bridge_->LoadIcon(); | 139 bridge_->LoadIcon(); |
| 139 [self updateToolTip]; | 140 [self updateToolTip]; |
| 140 } | 141 } |
| 141 | 142 |
| 142 - (void)showDangerousWarning:(DownloadItemModel*)downloadModel { | 143 - (void)showDangerousWarning:(DownloadItemModel*)downloadModel { |
| 143 // The transition from safe -> dangerous should only happen once. The code | 144 // The transition from safe -> dangerous should only happen once. The code |
| 144 // assumes that the danger type of the download doesn't change once it's set. | 145 // assumes that the danger type of the download doesn't change once it's set. |
| 145 if ([self isDangerousMode]) | 146 if ([self isDangerousMode]) |
| 146 return; | 147 return; |
| 147 | 148 |
| 148 [self setState:kDangerous]; | 149 [self setState:kDangerous]; |
| 149 | 150 |
| 150 // ExperienceSampling: Dangerous or malicious download warning is being shown | 151 // ExperienceSampling: Dangerous or malicious download warning is being shown |
| 151 // to the user, so we start a new SamplingEvent and track it. | 152 // to the user, so we start a new SamplingEvent and track it. |
| 152 std::string event_name = downloadModel->MightBeMalicious() | 153 const char* event_name = downloadModel->MightBeMalicious() |
| 153 ? ExperienceSamplingEvent::kMaliciousDownload | 154 ? ExperienceSamplingEvent::kMaliciousDownload |
| 154 : ExperienceSamplingEvent::kDangerousDownload; | 155 : ExperienceSamplingEvent::kDangerousDownload; |
| 155 sampling_event_.reset(new ExperienceSamplingEvent( | 156 [self updateExperienceSamplingEvent:event_name]; |
| 156 event_name, | |
| 157 downloadModel->download()->GetURL(), | |
| 158 downloadModel->download()->GetReferrerUrl(), | |
| 159 downloadModel->download()->GetBrowserContext())); | |
| 160 | 157 |
| 161 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 158 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| 162 NSImage* alertIcon; | 159 NSImage* alertIcon; |
| 163 | 160 |
| 164 NSString* dangerousWarning = base::SysUTF16ToNSString( | 161 NSString* dangerousWarning = base::SysUTF16ToNSString( |
| 165 downloadModel->GetWarningText(*font_list_, kTextWidth)); | 162 downloadModel->GetWarningText(*font_list_, kTextWidth)); |
| 166 DCHECK(dangerousWarning); | 163 DCHECK(dangerousWarning); |
| 167 [dangerousDownloadLabel_ setStringValue:dangerousWarning]; | 164 [dangerousDownloadLabel_ setStringValue:dangerousWarning]; |
| 168 CGFloat labelWidthChange = | 165 CGFloat labelWidthChange = |
| 169 [GTMUILocalizerAndLayoutTweaker | 166 [GTMUILocalizerAndLayoutTweaker |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 203 NSPoint frameOrigin = [dangerousButtonTweaker_ frame].origin; | 200 NSPoint frameOrigin = [dangerousButtonTweaker_ frame].origin; |
| 204 frameOrigin.x += labelWidthChange; | 201 frameOrigin.x += labelWidthChange; |
| 205 [dangerousButtonTweaker_ setFrameOrigin:frameOrigin]; | 202 [dangerousButtonTweaker_ setFrameOrigin:frameOrigin]; |
| 206 | 203 |
| 207 [dangerousButtonTweaker_ setHidden:NO]; | 204 [dangerousButtonTweaker_ setHidden:NO]; |
| 208 [maliciousButtonTweaker_ setHidden:YES]; | 205 [maliciousButtonTweaker_ setHidden:YES]; |
| 209 } | 206 } |
| 210 DCHECK(alertIcon); | 207 DCHECK(alertIcon); |
| 211 [image_ setImage:alertIcon]; | 208 [image_ setImage:alertIcon]; |
| 212 | 209 |
| 213 // Grow the parent views | |
| 214 WidenView([self view], labelWidthChange + buttonWidthChange); | |
| 215 WidenView(dangerousDownloadView_, labelWidthChange + buttonWidthChange); | 210 WidenView(dangerousDownloadView_, labelWidthChange + buttonWidthChange); |
| 211 [shelf_ layoutItems]; |
| 216 } | 212 } |
| 217 | 213 |
| 218 - (void)setStateFromDownload:(DownloadItemModel*)downloadModel { | 214 - (void)setStateFromDownload:(DownloadItemModel*)downloadModel { |
| 219 DCHECK_EQ([self download], downloadModel->download()); | 215 DCHECK_EQ([self download], downloadModel->download()); |
| 220 | 216 |
| 221 // Handle dangerous downloads. | 217 // Handle dangerous downloads. |
| 222 if (downloadModel->IsDangerous()) { | 218 if (downloadModel->IsDangerous()) { |
| 223 [self showDangerousWarning:downloadModel]; | 219 [self showDangerousWarning:downloadModel]; |
| 224 return; | 220 return; |
| 225 } | 221 } |
| 226 | 222 |
| 227 // Set path to draggable download on completion. | 223 // Set path to draggable download on completion. |
| 228 if (downloadModel->download()->GetState() == DownloadItem::COMPLETE) | 224 if (downloadModel->download()->GetState() == DownloadItem::COMPLETE) |
| 229 [progressView_ setDownload:downloadModel->download()->GetTargetFilePath()]; | 225 [progressView_ setDownload:downloadModel->download()->GetTargetFilePath()]; |
| 230 | 226 |
| 231 [cell_ setStateFromDownload:downloadModel]; | 227 [cell_ setStateFromDownload:downloadModel]; |
| 232 } | 228 } |
| 233 | 229 |
| 234 - (void)setIcon:(NSImage*)icon { | 230 - (void)setIcon:(NSImage*)icon { |
| 235 [cell_ setImage:icon]; | 231 [cell_ setImage:icon]; |
| 236 } | 232 } |
| 237 | 233 |
| 238 - (void)remove { | 234 - (void)remove { |
| 239 // We are deleted after this! | 235 // We are deleted after this! |
| 236 // If the download is destroyed before DownloadItemController, then we'd end |
| 237 // up here. Reset the bridege_ so that it can clean up after itself before |
| 238 // the DownloadItemController is deallocd. |
| 239 bridge_.reset(); |
| 240 [shelf_ remove:self]; | 240 [shelf_ remove:self]; |
| 241 } | 241 } |
| 242 | 242 |
| 243 - (void)updateVisibility:(id)sender { | 243 - (void)updateVisibility:(id)sender { |
| 244 if ([[self view] window]) | 244 if ([[self view] window]) |
| 245 [self updateTheme:[[[self view] window] themeProvider]]; | 245 [self updateTheme:[[[self view] window] themeProvider]]; |
| 246 | 246 |
| 247 NSView* view = [self view]; | 247 NSView* view = [self view]; |
| 248 NSRect containerFrame = [[view superview] frame]; | 248 NSRect containerFrame = [[view superview] frame]; |
| 249 [view setHidden:(NSMaxX([view frame]) > NSWidth(containerFrame))]; | 249 [view setHidden:(NSMaxX([view frame]) > NSWidth(containerFrame))]; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 290 // The state change hide the dangerouse download view and is now showing the | 290 // The state change hide the dangerouse download view and is now showing the |
| 291 // download progress view. This means the view is likely to be a different | 291 // download progress view. This means the view is likely to be a different |
| 292 // size, so trigger a shelf layout to fix up spacing. | 292 // size, so trigger a shelf layout to fix up spacing. |
| 293 [shelf_ layoutItems]; | 293 [shelf_ layoutItems]; |
| 294 } | 294 } |
| 295 | 295 |
| 296 - (BOOL)isDangerousMode { | 296 - (BOOL)isDangerousMode { |
| 297 return state_ == kDangerous; | 297 return state_ == kDangerous; |
| 298 } | 298 } |
| 299 | 299 |
| 300 - (void)setState:(DownoadItemState)state { | 300 - (void)setState:(DownloadItemState)state { |
| 301 if (state_ == state) | 301 if (state_ == state) |
| 302 return; | 302 return; |
| 303 state_ = state; | 303 state_ = state; |
| 304 if (state_ == kNormal) { | 304 if (state_ == kNormal) { |
| 305 [progressView_ setHidden:NO]; | 305 [progressView_ setHidden:NO]; |
| 306 [dangerousDownloadView_ setHidden:YES]; | 306 [dangerousDownloadView_ setHidden:YES]; |
| 307 } else { | 307 } else { |
| 308 DCHECK_EQ(kDangerous, state_); | 308 DCHECK_EQ(kDangerous, state_); |
| 309 [progressView_ setHidden:YES]; | 309 [progressView_ setHidden:YES]; |
| 310 [dangerousDownloadView_ setHidden:NO]; | 310 [dangerousDownloadView_ setHidden:NO]; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 322 // Adapt appearance to the current theme. Called after theme changes and before | 322 // Adapt appearance to the current theme. Called after theme changes and before |
| 323 // this is shown for the first time. | 323 // this is shown for the first time. |
| 324 - (void)updateTheme:(ui::ThemeProvider*)themeProvider { | 324 - (void)updateTheme:(ui::ThemeProvider*)themeProvider { |
| 325 if (!themeProvider) | 325 if (!themeProvider) |
| 326 return; | 326 return; |
| 327 | 327 |
| 328 NSColor* color = themeProvider->GetNSColor(ThemeProperties::COLOR_TAB_TEXT); | 328 NSColor* color = themeProvider->GetNSColor(ThemeProperties::COLOR_TAB_TEXT); |
| 329 [dangerousDownloadLabel_ setTextColor:color]; | 329 [dangerousDownloadLabel_ setTextColor:color]; |
| 330 } | 330 } |
| 331 | 331 |
| 332 - (void)initExperienceSamplingEvent:(const char*)event { |
| 333 sampling_event_.reset(new ExperienceSamplingEvent( |
| 334 event, |
| 335 bridge_->download_model()->download()->GetURL(), |
| 336 bridge_->download_model()->download()->GetReferrerUrl(), |
| 337 bridge_->download_model()->download()->GetBrowserContext())); |
| 338 } |
| 339 |
| 340 - (void)updateExperienceSamplingEvent:(const char*)event { |
| 341 if (sampling_event_.get()) { |
| 342 sampling_event_->CreateUserDecisionEvent(event); |
| 343 sampling_event_.reset(NULL); |
| 344 } |
| 345 } |
| 346 |
| 332 - (IBAction)saveDownload:(id)sender { | 347 - (IBAction)saveDownload:(id)sender { |
| 333 // The user has confirmed a dangerous download. We record how quickly the | 348 // The user has confirmed a dangerous download. We record how quickly the |
| 334 // user did this to detect whether we're being clickjacked. | 349 // user did this to detect whether we're being clickjacked. |
| 335 UMA_HISTOGRAM_LONG_TIMES("clickjacking.save_download", | 350 UMA_HISTOGRAM_LONG_TIMES("clickjacking.save_download", |
| 336 base::Time::Now() - creationTime_); | 351 base::Time::Now() - creationTime_); |
| 337 // ExperienceSampling: User chose to proceed with dangerous download. | 352 // ExperienceSampling: User chose to proceed with dangerous download. |
| 338 if (sampling_event_.get()) { | 353 [self updateExperienceSamplingEvent:ExperienceSamplingEvent::kProceed]; |
| 339 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed); | |
| 340 sampling_event_.reset(NULL); | |
| 341 } | |
| 342 // This will change the state and notify us. | 354 // This will change the state and notify us. |
| 343 bridge_->download_model()->download()->ValidateDangerousDownload(); | 355 bridge_->download_model()->download()->ValidateDangerousDownload(); |
| 344 } | 356 } |
| 345 | 357 |
| 346 - (IBAction)discardDownload:(id)sender { | 358 - (IBAction)discardDownload:(id)sender { |
| 347 UMA_HISTOGRAM_LONG_TIMES("clickjacking.discard_download", | 359 UMA_HISTOGRAM_LONG_TIMES("clickjacking.discard_download", |
| 348 base::Time::Now() - creationTime_); | 360 base::Time::Now() - creationTime_); |
| 349 DownloadItem* download = bridge_->download_model()->download(); | 361 DownloadItem* download = bridge_->download_model()->download(); |
| 350 download->Remove(); | 362 download->Remove(); |
| 351 // WARNING: we are deleted at this point. Don't access 'this'. | 363 // WARNING: we are deleted at this point. Don't access 'this'. |
| 352 } | 364 } |
| 353 | 365 |
| 354 - (IBAction)dismissMaliciousDownload:(id)sender { | 366 - (IBAction)dismissMaliciousDownload:(id)sender { |
| 355 // ExperienceSampling: User dismissed the dangerous download. | 367 // ExperienceSampling: User dismissed the dangerous download. |
| 356 if (sampling_event_.get()) { | 368 [self updateExperienceSamplingEvent:ExperienceSamplingEvent::kDeny]; |
| 357 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny); | |
| 358 sampling_event_.reset(NULL); | |
| 359 } | |
| 360 [self remove]; | 369 [self remove]; |
| 361 // WARNING: we are deleted at this point. | 370 // WARNING: we are deleted at this point. |
| 362 } | 371 } |
| 363 | 372 |
| 364 - (IBAction)showContextMenu:(id)sender { | 373 - (IBAction)showContextMenu:(id)sender { |
| 365 base::scoped_nsobject<DownloadShelfContextMenuController> menuController( | 374 base::scoped_nsobject<DownloadShelfContextMenuController> menuController( |
| 366 [[DownloadShelfContextMenuController alloc] | 375 [[DownloadShelfContextMenuController alloc] |
| 367 initWithItemController:self | 376 initWithItemController:self |
| 368 withDelegate:nil]); | 377 withDelegate:nil]); |
| 369 [NSMenu popUpContextMenu:[menuController menu] | 378 [NSMenu popUpContextMenu:[menuController menu] |
| 370 withEvent:[NSApp currentEvent] | 379 withEvent:[NSApp currentEvent] |
| 371 forView:[self view]]; | 380 forView:[self view]]; |
| 372 } | 381 } |
| 373 | 382 |
| 374 @end | 383 @end |
| OLD | NEW |