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 |