diff options
author | avi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-01 16:30:47 +0000 |
---|---|---|
committer | avi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-01 16:30:47 +0000 |
commit | 6a7fb04b7475b355cb571c9aca6b192d2a96ca5f (patch) | |
tree | 189b6f31c49e34874d3308cbffb9beb6becd8b26 /chrome | |
parent | c702d70890ab023ce723dde7aea8c66adb7ef98e (diff) | |
download | chromium_src-6a7fb04b7475b355cb571c9aca6b192d2a96ca5f.zip chromium_src-6a7fb04b7475b355cb571c9aca6b192d2a96ca5f.tar.gz chromium_src-6a7fb04b7475b355cb571c9aca6b192d2a96ca5f.tar.bz2 |
Add temporary download progress overlay to the dock icon for the Mac (real UI coming soon), and provide the hooks for the Win7 implementation.
BUG=http://crbug.com/8039
TEST=download; see progress in the dock icon
Review URL: http://codereview.chromium.org/545157
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@37698 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/cocoa/dock_icon.h | 30 | ||||
-rw-r--r-- | chrome/browser/cocoa/dock_icon.mm | 221 | ||||
-rw-r--r-- | chrome/browser/cocoa/download_util_mac.mm | 11 | ||||
-rw-r--r-- | chrome/browser/download/download_manager.cc | 38 | ||||
-rw-r--r-- | chrome/browser/download/download_manager.h | 3 | ||||
-rw-r--r-- | chrome/browser/download/download_util.cc | 8 | ||||
-rw-r--r-- | chrome/browser/download/download_util.h | 9 | ||||
-rwxr-xr-x | chrome/chrome_browser.gypi | 2 |
8 files changed, 322 insertions, 0 deletions
diff --git a/chrome/browser/cocoa/dock_icon.h b/chrome/browser/cocoa/dock_icon.h new file mode 100644 index 0000000..4a96537 --- /dev/null +++ b/chrome/browser/cocoa/dock_icon.h @@ -0,0 +1,30 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <Cocoa/Cocoa.h> + +// A class representing the dock icon of the Chromium app. It's its own class +// since several parts of the app want to manipulate the display of the dock +// icon. +@interface DockIcon : NSObject { +} + ++ (DockIcon*)sharedDockIcon; + +// Updates the icon. Use the setters below to set the details first. +- (void)updateIcon; + +// Download progress /////////////////////////////////////////////////////////// + +// Indicates how many downloads are in progress. +- (void)setDownloads:(int)downloads; + +// Indicates whether the progress indicator should be in an indeterminate state +// or not. +- (void)setIndeterminate:(BOOL)indeterminate; + +// Indicates the amount of progress made of the download. Ranges from [0..1]. +- (void)setProgress:(float)progress; + +@end diff --git a/chrome/browser/cocoa/dock_icon.mm b/chrome/browser/cocoa/dock_icon.mm new file mode 100644 index 0000000..2b2b77e --- /dev/null +++ b/chrome/browser/cocoa/dock_icon.mm @@ -0,0 +1,221 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "chrome/browser/cocoa/dock_icon.h" + +#include "base/scoped_nsobject.h" + +// The fraction of the size of the dock icon that the badge is. +static const float kBadgeFraction = 0.4f; + +// The indentation of the badge. +static const float kBadgeIndent = 5.0f; + +// A view that draws our dock tile. +@interface DockTileView : NSView { + @private + int downloads_; + BOOL indeterminate_; + float progress_; +} + +// Indicates how many downloads are in progress. +@property (nonatomic) int downloads; + +// Indicates whether the progress indicator should be in an indeterminate state +// or not. +@property (nonatomic) BOOL indeterminate; + +// Indicates the amount of progress made of the download. Ranges from [0..1]. +@property (nonatomic) float progress; + +@end + +@implementation DockTileView + +@synthesize downloads = downloads_; +@synthesize indeterminate = indeterminate_; +@synthesize progress = progress_; + +- (void)drawRect:(NSRect)dirtyRect { + NSImage* appIcon = [[NSApplication sharedApplication] applicationIconImage]; + [appIcon drawInRect:[self bounds] + fromRect:NSZeroRect + operation:NSCompositeSourceOver + fraction:1.0]; + + if (downloads_ == 0) + return; + + NSRect badgeRect = [self bounds]; + badgeRect.size.height = (int)(kBadgeFraction * badgeRect.size.height); + int newWidth = kBadgeFraction * badgeRect.size.width; + badgeRect.origin.x = badgeRect.size.width - newWidth; + badgeRect.size.width = newWidth; + + CGFloat badgeRadius = NSMidY(badgeRect); + + badgeRect.origin.x -= kBadgeIndent; + badgeRect.origin.y += kBadgeIndent; + + NSPoint badgeCenter = NSMakePoint(NSMidX(badgeRect), + NSMidY(badgeRect)); + + // Background + NSColor* backgroundColor = [NSColor colorWithCalibratedRed:0.85 + green:0.85 + blue:0.85 + alpha:1.0]; + NSColor* backgroundHighlight = + [backgroundColor blendedColorWithFraction:0.85 + ofColor:[NSColor whiteColor]]; + scoped_nsobject<NSGradient> backgroundGradient( + [[NSGradient alloc] initWithStartingColor:backgroundHighlight + endingColor:backgroundColor]); + NSBezierPath* badgeEdge = [NSBezierPath bezierPathWithOvalInRect:badgeRect]; + [NSGraphicsContext saveGraphicsState]; + [badgeEdge addClip]; + [backgroundGradient drawFromCenter:badgeCenter + radius:0.0 + toCenter:badgeCenter + radius:badgeRadius + options:0]; + [NSGraphicsContext restoreGraphicsState]; + + // Slice + if (!indeterminate_) { + NSColor* sliceColor = [NSColor colorWithCalibratedRed:0.45 + green:0.8 + blue:0.25 + alpha:1.0]; + NSColor* sliceHighlight = + [sliceColor blendedColorWithFraction:0.4 + ofColor:[NSColor whiteColor]]; + scoped_nsobject<NSGradient> sliceGradient( + [[NSGradient alloc] initWithStartingColor:sliceHighlight + endingColor:sliceColor]); + NSBezierPath* progressSlice; + if (progress_ >= 1.0) { + progressSlice = [NSBezierPath bezierPathWithOvalInRect:badgeRect]; + } else { + CGFloat endAngle = 90.0 - 360.0 * progress_; + if (endAngle < 0.0) + endAngle += 360.0; + progressSlice = [NSBezierPath bezierPath]; + [progressSlice moveToPoint:badgeCenter]; + [progressSlice appendBezierPathWithArcWithCenter:badgeCenter + radius:badgeRadius + startAngle:90.0 + endAngle:endAngle + clockwise:YES]; + [progressSlice closePath]; + } + [NSGraphicsContext saveGraphicsState]; + [progressSlice addClip]; + [sliceGradient drawFromCenter:badgeCenter + radius:0.0 + toCenter:badgeCenter + radius:badgeRadius + options:0]; + [NSGraphicsContext restoreGraphicsState]; + } + + // Edge + [NSGraphicsContext saveGraphicsState]; + [[NSColor whiteColor] set]; + scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]); + [shadow setShadowOffset:NSMakeSize(0, -2)]; + [shadow setShadowBlurRadius:2]; + [shadow set]; + [badgeEdge setLineWidth:2]; + [badgeEdge stroke]; + [NSGraphicsContext restoreGraphicsState]; + + // Download count + scoped_nsobject<NSNumberFormatter> formatter( + [[NSNumberFormatter alloc] init]); + NSString* countString = + [formatter stringFromNumber:[NSNumber numberWithInt:downloads_]]; + + scoped_nsobject<NSShadow> countShadow([[NSShadow alloc] init]); + [countShadow setShadowBlurRadius:3.0]; + [countShadow setShadowColor:[NSColor whiteColor]]; + [countShadow setShadowOffset:NSMakeSize(0.0, 0.0)]; + NSMutableDictionary* countAttrsDict = + [NSMutableDictionary dictionaryWithObjectsAndKeys: + [NSColor blackColor], NSForegroundColorAttributeName, + countShadow.get(), NSShadowAttributeName, + nil]; + CGFloat countFontSize = badgeRadius; + NSSize countSize = NSZeroSize; + scoped_nsobject<NSAttributedString> countAttrString; + while (1) { + NSFont* countFont = [NSFont fontWithName:@"Helvetica-Bold" + size:countFontSize]; + [countAttrsDict setObject:countFont forKey:NSFontAttributeName]; + countAttrString.reset( + [[NSAttributedString alloc] initWithString:countString + attributes:countAttrsDict]); + countSize = [countAttrString size]; + if (countSize.width > badgeRadius * 1.5) { + countFontSize -= 1.0; + } else { + break; + } + } + + NSPoint countOrigin = badgeCenter; + countOrigin.x -= countSize.width / 2; + countOrigin.y -= countSize.height / 2.2; // tweak; otherwise too low + + [countAttrString.get() drawAtPoint:countOrigin]; +} + +@end + + +@implementation DockIcon + ++ (DockIcon*)sharedDockIcon { + static DockIcon* icon; + if (!icon) { + NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile]; + + scoped_nsobject<DockTileView> dockTileView([[DockTileView alloc] init]); + [dockTile setContentView:dockTileView]; + + icon = [[DockIcon alloc] init]; + } + + return icon; +} + +- (void)updateIcon { + NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile]; + + [dockTile display]; +} + +- (void)setDownloads:(int)downloads { + NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile]; + DockTileView* dockTileView = (DockTileView*)([dockTile contentView]); + + [dockTileView setDownloads:downloads]; +} + +- (void)setIndeterminate:(BOOL)indeterminate { + NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile]; + DockTileView* dockTileView = (DockTileView*)([dockTile contentView]); + + [dockTileView setIndeterminate:indeterminate]; +} + +- (void)setProgress:(float)progress { + NSDockTile* dockTile = [[NSApplication sharedApplication] dockTile]; + DockTileView* dockTileView = (DockTileView*)([dockTile contentView]); + + [dockTileView setProgress:progress]; +} + +@end diff --git a/chrome/browser/cocoa/download_util_mac.mm b/chrome/browser/cocoa/download_util_mac.mm index 479ab7f..3c77f08 100644 --- a/chrome/browser/cocoa/download_util_mac.mm +++ b/chrome/browser/cocoa/download_util_mac.mm @@ -8,6 +8,7 @@ #include "app/gfx/native_widget_types.h" #include "base/sys_string_conversions.h" +#import "chrome/browser/cocoa/dock_icon.h" #include "chrome/browser/download/download_manager.h" #include "skia/ext/skia_utils_mac.h" @@ -68,4 +69,14 @@ void DragDownload(const DownloadItem* download, slideBack:YES]; } +void UpdateAppIconDownloadProgress(int download_count, + bool progress_known, + float progress) { + DockIcon* dock_icon = [DockIcon sharedDockIcon]; + [dock_icon setDownloads:download_count]; + [dock_icon setIndeterminate:!progress_known]; + [dock_icon setProgress:progress]; + [dock_icon updateIcon]; +} + } // namespace download_util diff --git a/chrome/browser/download/download_manager.cc b/chrome/browser/download/download_manager.cc index c327944..252b43c 100644 --- a/chrome/browser/download/download_manager.cc +++ b/chrome/browser/download/download_manager.cc @@ -789,6 +789,8 @@ void DownloadManager::ContinueStartDownload(DownloadCreateInfo* info, NewCallback(this, &DownloadManager::OnCreateDownloadEntryComplete)); } } + + UpdateAppIcon(); } // Convenience function for updating the history service for a download. @@ -833,6 +835,7 @@ void DownloadManager::UpdateDownload(int32 download_id, int64 size) { download->Update(size); UpdateHistoryForDownload(download); } + UpdateAppIcon(); } void DownloadManager::DownloadFinished(int32 download_id, int64 size) { @@ -865,6 +868,8 @@ void DownloadManager::DownloadFinished(int32 download_id, int64 size) { UpdateHistoryForDownload(download); } + UpdateAppIcon(); + // If this a dangerous download not yet validated by the user, don't do // anything. When the user notifies us, it will trigger a call to // ProceedWithFinishedDangerousDownload. @@ -1018,6 +1023,7 @@ void DownloadManager::DownloadCancelled(int32 download_id) { DownloadCancelledInternal(download_id, download->render_process_id(), download->request_id()); + UpdateAppIcon(); } void DownloadManager::DownloadCancelledInternal(int download_id, @@ -1071,6 +1077,36 @@ bool DownloadManager::IsDangerous(const FilePath& file_name) { return IsExecutableFile(file_name); } +void DownloadManager::UpdateAppIcon() { + int64 total_bytes = 0; + int64 received_bytes = 0; + int download_count = 0; + bool progress_known = true; + + for (DownloadMap::iterator i = in_progress_.begin(); + i != in_progress_.end(); + ++i) { + ++download_count; + const DownloadItem* item = i->second; + if (item->total_bytes() > 0) { + total_bytes += item->total_bytes(); + received_bytes += item->received_bytes(); + } else { + // This download didn't specify a Content-Length, so the combined progress + // bar neeeds to be indeterminate. + progress_known = false; + } + } + + float progress = 0; + if (progress_known && download_count) + progress = (float)received_bytes / total_bytes; + + download_util::UpdateAppIconDownloadProgress(download_count, + progress_known, + progress); +} + void DownloadManager::RenameDownload(DownloadItem* download, const FilePath& new_path) { download->Rename(new_path); @@ -1640,6 +1676,8 @@ void DownloadManager::OnCreateDownloadEntryComplete(DownloadCreateInfo info, UpdateHistoryForDownload(download); download->UpdateObservers(); } + + UpdateAppIcon(); } // Called when the history service has retrieved the list of downloads that diff --git a/chrome/browser/download/download_manager.h b/chrome/browser/download/download_manager.h index b562bc2..4d7a709 100644 --- a/chrome/browser/download/download_manager.h +++ b/chrome/browser/download/download_manager.h @@ -600,6 +600,9 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>, // Checks whether a file represents a risk if downloaded. bool IsDangerous(const FilePath& file_name); + // Updates the app icon about the overall download progress. + void UpdateAppIcon(); + // Changes the paths and file name of the specified |download|, propagating // the change to the history system. void RenameDownload(DownloadItem* download, const FilePath& new_path); diff --git a/chrome/browser/download/download_util.cc b/chrome/browser/download/download_util.cc index 711c24c..48cb86f 100644 --- a/chrome/browser/download/download_util.cc +++ b/chrome/browser/download/download_util.cc @@ -400,4 +400,12 @@ std::wstring GetProgressStatusText(DownloadItem* download) { amount, time_remaining); } +#if !defined(OS_MACOSX) +void UpdateAppIconDownloadProgress(int download_count, + bool progress_known, + float progress) { + // Win7 Superbar wants some pixel lovin! http://crbug.com/8039 +} +#endif + } // namespace download_util diff --git a/chrome/browser/download/download_util.h b/chrome/browser/download/download_util.h index 93114fe..f14be9a 100644 --- a/chrome/browser/download/download_util.h +++ b/chrome/browser/download/download_util.h @@ -144,6 +144,15 @@ DictionaryValue* CreateDownloadItemValue(DownloadItem* download, int id); // Get the localized status text for an in-progress download. std::wstring GetProgressStatusText(DownloadItem* download); +// Update the application icon to indicate overall download progress. +// |download_count| is the number of downloads currently in progress. If +// |progress_known| is false, then at least one download is of indeterminate +// size and |progress| is invalid, otherwise |progress| indicates the overall +// download progress (float value from 0..1). +void UpdateAppIconDownloadProgress(int download_count, + bool progress_known, + float progress); + } // namespace download_util #endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_UTIL_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 06ca294..33976a9 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -432,6 +432,8 @@ 'browser/cocoa/custom_home_pages_model.mm', 'browser/cocoa/delayedmenu_button.h', 'browser/cocoa/delayedmenu_button.mm', + 'browser/cocoa/dock_icon.h', + 'browser/cocoa/dock_icon.mm', 'browser/cocoa/download_item_button.h', 'browser/cocoa/download_item_button.mm', 'browser/cocoa/download_item_cell.h', |