diff options
author | pinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-29 14:30:38 +0000 |
---|---|---|
committer | pinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-29 14:30:38 +0000 |
commit | 93e18176c674291dc8f6cf6dfdc2d9b7227f561c (patch) | |
tree | 366da45470e2fa32cd4a91a6fbf7d955eec29192 /chrome/browser/cocoa | |
parent | 2946da155c393685c6cc3f7fe5e28d347bf6642d (diff) | |
download | chromium_src-93e18176c674291dc8f6cf6dfdc2d9b7227f561c.zip chromium_src-93e18176c674291dc8f6cf6dfdc2d9b7227f561c.tar.gz chromium_src-93e18176c674291dc8f6cf6dfdc2d9b7227f561c.tar.bz2 |
Implement Clear Browser Data for Mac as an app modal dialog. Uses the profile of the given window or the default profile if run with no windows open. Add a setter to the throbber so it can be used in a nib file.
BUG=none
TEST=clear browser functionality (note that clearing passwords doesn't work) and checkbox persistance.
Review URL: http://codereview.chromium.org/112065
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17186 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa')
-rw-r--r-- | chrome/browser/cocoa/browser_window_cocoa.mm | 8 | ||||
-rw-r--r-- | chrome/browser/cocoa/clear_browsing_data_controller.h | 67 | ||||
-rw-r--r-- | chrome/browser/cocoa/clear_browsing_data_controller.mm | 157 | ||||
-rw-r--r-- | chrome/browser/cocoa/throbber_view.h | 4 | ||||
-rw-r--r-- | chrome/browser/cocoa/throbber_view.mm | 99 |
5 files changed, 291 insertions, 44 deletions
diff --git a/chrome/browser/cocoa/browser_window_cocoa.mm b/chrome/browser/cocoa/browser_window_cocoa.mm index 447d42c..429c0be 100644 --- a/chrome/browser/cocoa/browser_window_cocoa.mm +++ b/chrome/browser/cocoa/browser_window_cocoa.mm @@ -7,7 +7,8 @@ #include "base/sys_string_conversions.h" #include "chrome/browser/bookmarks/bookmark_utils.h" #include "chrome/browser/cocoa/browser_window_cocoa.h" -#include "chrome/browser/cocoa/browser_window_controller.h" +#import "chrome/browser/cocoa/browser_window_controller.h" +#import "chrome/browser/cocoa/clear_browsing_data_controller.h" #include "chrome/browser/browser.h" #include "chrome/common/notification_service.h" #include "chrome/common/pref_names.h" @@ -186,7 +187,10 @@ void BrowserWindowCocoa::ShowReportBugDialog() { } void BrowserWindowCocoa::ShowClearBrowsingDataDialog() { - NOTIMPLEMENTED(); + scoped_nsobject<ClearBrowsingDataController> controller( + [[ClearBrowsingDataController alloc] + initWithProfile:browser_->profile()]); + [controller runModalDialog]; } void BrowserWindowCocoa::ShowImportDialog() { diff --git a/chrome/browser/cocoa/clear_browsing_data_controller.h b/chrome/browser/cocoa/clear_browsing_data_controller.h new file mode 100644 index 0000000..78ef39c --- /dev/null +++ b/chrome/browser/cocoa/clear_browsing_data_controller.h @@ -0,0 +1,67 @@ +// Copyright (c) 2009 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. + +#ifndef CHROME_BROWSER_COCOA_CLEAR_BROWSING_DATA_CONTROLLER_ +#define CHROME_BROWSER_COCOA_CLEAR_BROWSING_DATA_CONTROLLER_ + +#import <Cocoa/Cocoa.h> + +#include "base/scoped_ptr.h" + +class BrowsingDataRemover; +class ClearBrowsingObserver; +class Profile; +@class ThrobberView; + +// A window controller for managing the "Clear Browsing Data" feature. Modally +// presents a dialog offering the user a set of choices of what browsing data +// to delete and does so if the user chooses. + +@interface ClearBrowsingDataController : NSWindowController { + @private + Profile* profile_; // Weak, owned by browser. + // If non-null means there is a removal in progress. Member used mainly for + // automated tests. The remove deletes itself when it's done, so this is a + // weak reference. + BrowsingDataRemover* remover_; + scoped_ptr<ClearBrowsingObserver> observer_; + BOOL isClearing_; // YES while clearing data is ongoing. + IBOutlet ThrobberView* progress_; + + // Values for checkboxes, kept in sync with bindings. These values get + // persisted into prefs if the user accepts the dialog. + BOOL clearBrowsingHistory_; + BOOL clearDownloadHistory_; + BOOL emptyCache_; + BOOL deleteCookies_; + BOOL clearSavedPasswords_; + BOOL clearFormData_; + NSInteger timePeriod_; +} + +// Create the controller with the given profile (which must not be NULL). +- (id)initWithProfile:(Profile*)profile; + +// Run the dialog with an application-modal event loop. If the user accepts, +// performs the deletion of the selected browsing data. The values of the +// checkboxes will be persisted into prefs for next time. +- (void)runModalDialog; + +// IBActions for the dialog buttons +- (IBAction)clearData:(id)sender; +- (IBAction)cancel:(id)sender; + +// Properties for bindings +@property BOOL clearBrowsingHistory; +@property BOOL clearDownloadHistory; +@property BOOL emptyCache; +@property BOOL deleteCookies; +@property BOOL clearSavedPasswords; +@property BOOL clearFormData; +@property NSInteger timePeriod; +@property BOOL isClearing; + +@end + +#endif // CHROME_BROWSER_COCOA_CLEAR_BROWSING_DATA_CONTROLLER_ diff --git a/chrome/browser/cocoa/clear_browsing_data_controller.mm b/chrome/browser/cocoa/clear_browsing_data_controller.mm new file mode 100644 index 0000000..f8ca39a --- /dev/null +++ b/chrome/browser/cocoa/clear_browsing_data_controller.mm @@ -0,0 +1,157 @@ +// Copyright (c) 2009 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/clear_browsing_data_controller.h" + +#include "base/mac_util.h" +#include "base/scoped_nsobject.h" +#include "chrome/browser/browsing_data_remover.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/pref_service.h" +#include "chrome/browser/profile.h" + +@interface ClearBrowsingDataController(Private) +- (void)initFromPrefs; +- (void)persistToPrefs; +- (void)dataRemoverDidFinish; +@end + +class ClearBrowsingObserver : public BrowsingDataRemover::Observer { + public: + ClearBrowsingObserver(ClearBrowsingDataController* controller) + : controller_(controller) { } + void OnBrowsingDataRemoverDone() { [controller_ dataRemoverDidFinish]; } + private: + ClearBrowsingDataController* controller_; +}; + +@implementation ClearBrowsingDataController + +@synthesize clearBrowsingHistory = clearBrowsingHistory_; +@synthesize clearDownloadHistory = clearDownloadHistory_; +@synthesize emptyCache = emptyCache_; +@synthesize deleteCookies = deleteCookies_; +@synthesize clearSavedPasswords = clearSavedPasswords_; +@synthesize clearFormData = clearFormData_; +@synthesize timePeriod = timePeriod_; +@synthesize isClearing = isClearing_; + + +- (id)initWithProfile:(Profile*)profile { + DCHECK(profile); + // Use initWithWindowNibPath:: instead of initWithWindowNibName: so we + // can override it in a unit test. + NSString *nibpath = [mac_util::MainAppBundle() + pathForResource:@"ClearBrowsingData" + ofType:@"nib"]; + if ((self = [super initWithWindowNibPath:nibpath owner:self])) { + profile_ = profile; + observer_.reset(new ClearBrowsingObserver(self)); + [self initFromPrefs]; + } + return self; +} + +- (void)dealloc { + if (remover_) { + // We were destroyed while clearing history was in progress. This can only + // occur during automated tests (normally the user can't close the dialog + // while clearing is in progress as the dialog is modal and not closeable). + remover_->RemoveObserver(observer_.get()); + } + [super dealloc]; +} + +// Called when outlets are available. Set the throbber icon. +- (void)awakeFromNib { + NSString *imagePath = [mac_util::MainAppBundle() + pathForResource:@"throbber" + ofType:@"png"]; + scoped_nsobject<NSImage> throbberImage( + [[NSImage alloc] initWithContentsOfFile:imagePath]); + [progress_ setImage:throbberImage]; +} + +// Run application modal. +- (void)runModalDialog { + [[NSApplication sharedApplication] runModalForWindow:[self window]]; +} + +// Called when the user clicks the "clear" button. Do the work and persist +// the prefs for next time. We don't stop the modal session until we get +// the callback from the BrowsingDataRemover so the window stays on the screen. +// While we're working, dim the buttons so the user can't click them. +- (IBAction)clearData:(id)sender { + // Set that we're working so that the buttons disable. + [self setIsClearing:YES]; + + [self persistToPrefs]; + + int removeMask = 0L; + if (clearBrowsingHistory_) + removeMask |= BrowsingDataRemover::REMOVE_HISTORY; + if (clearDownloadHistory_) + removeMask |= BrowsingDataRemover::REMOVE_DOWNLOADS; + if (emptyCache_) + removeMask |= BrowsingDataRemover::REMOVE_CACHE; + if (deleteCookies_) + removeMask |= BrowsingDataRemover::REMOVE_COOKIES; + if (clearSavedPasswords_) + removeMask |= BrowsingDataRemover::REMOVE_PASSWORDS; + if (clearFormData_) + removeMask |= BrowsingDataRemover::REMOVE_PASSWORDS; + + // BrowsingDataRemover deletes itself when done. + remover_ = new BrowsingDataRemover(profile_, + static_cast<BrowsingDataRemover::TimePeriod>(timePeriod_), + base::Time()); + remover_->AddObserver(observer_.get()); + remover_->Remove(removeMask); +} + +// Called when the user clicks the cancel button. All we need to do is stop +// the modal session. +- (IBAction)cancel:(id)sender { + [[NSApplication sharedApplication] stopModal]; + [[self window] orderOut:self]; +} + +// Initialize the bools from prefs using the setters to be KVO-compliant. +- (void)initFromPrefs { + PrefService* prefs = profile_->GetPrefs(); + [self setClearBrowsingHistory: + prefs->GetBoolean(prefs::kDeleteBrowsingHistory)]; + [self setClearDownloadHistory: + prefs->GetBoolean(prefs::kDeleteDownloadHistory)]; + [self setEmptyCache:prefs->GetBoolean(prefs::kDeleteCache)]; + [self setDeleteCookies:prefs->GetBoolean(prefs::kDeleteCookies)]; + [self setClearSavedPasswords:prefs->GetBoolean(prefs::kDeletePasswords)]; + [self setClearFormData:prefs->GetBoolean(prefs::kDeleteFormData)]; + [self setTimePeriod:prefs->GetInteger(prefs::kDeleteTimePeriod)]; +} + +// Save the checkbox values to the preferences. +- (void)persistToPrefs { + PrefService* prefs = profile_->GetPrefs(); + prefs->SetBoolean(prefs::kDeleteBrowsingHistory, + [self clearBrowsingHistory]); + prefs->SetBoolean(prefs::kDeleteDownloadHistory, + [self clearDownloadHistory]); + prefs->SetBoolean(prefs::kDeleteCache, [self emptyCache]); + prefs->SetBoolean(prefs::kDeleteCookies, [self deleteCookies]); + prefs->SetBoolean(prefs::kDeletePasswords, [self clearSavedPasswords]); + prefs->SetBoolean(prefs::kDeleteFormData, [self clearFormData]); + prefs->SetInteger(prefs::kDeleteTimePeriod, [self timePeriod]); +} + +// Called when the data remover object is done with its work. Close the window. +// The remover will delete itself. End the modal session at this point. +- (void)dataRemoverDidFinish { + [[NSApplication sharedApplication] stopModal]; + [[self window] orderOut:self]; + [self setIsClearing:NO]; + remover_ = NULL; +} + +@end diff --git a/chrome/browser/cocoa/throbber_view.h b/chrome/browser/cocoa/throbber_view.h index 00f83ed..e0b06ba 100644 --- a/chrome/browser/cocoa/throbber_view.h +++ b/chrome/browser/cocoa/throbber_view.h @@ -32,6 +32,10 @@ // the width. Takes ownership of |image|. - (id)initWithFrame:(NSRect)frame image:(NSImage*)image; +// Allows changing the image once the view has been created, such as when the +// view is loaded from a nib. The same restrictions as above apply. +- (void)setImage:(NSImage*)image; + @end #endif // CHROME_BROWSER_COCOA_THROBBER_VIEW_H_ diff --git a/chrome/browser/cocoa/throbber_view.mm b/chrome/browser/cocoa/throbber_view.mm index 26f8ec5..2f9b491 100644 --- a/chrome/browser/cocoa/throbber_view.mm +++ b/chrome/browser/cocoa/throbber_view.mm @@ -39,48 +39,7 @@ const float kAnimationIntervalSeconds = 0.03; // 30ms, same as windows - (id)initWithFrame:(NSRect)frame image:(NSImage*)image { if ((self = [super initWithFrame:frame])) { - // Ensure that the height divides evenly into the width. Cache the - // number of frames in the animation for later. - NSSize imageSize = [image size]; - DCHECK(imageSize.height && imageSize.width); - if (!imageSize.height) - return nil; - DCHECK((int)imageSize.width % (int)imageSize.height == 0); - numFrames_ = (int)imageSize.width / (int)imageSize.height; - DCHECK(numFrames_); - - // First check if we have a bitmap image rep and use it, otherwise fall - // back to creating one. - NSBitmapImageRep* rep = [[image representations] objectAtIndex:0]; - if (![rep isKindOfClass:[NSBitmapImageRep class]]) { - [image lockFocus]; - NSRect imageRect = NSMakeRect(0, 0, imageSize.width, imageSize.height); - rep = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:imageRect] - autorelease]; - [image unlockFocus]; - } - image_.reset([[CIImage alloc] initWithBitmapImageRep:rep]); - -#if 0 -// TODO(pinkerton): The invalidation of the view to trigger re-draw causes -// the entire title-bar to redraw (you can see it with QuartzDebug). For some -// reason, setting isOpaque on this view, or any of its parent views, doesn't -// help. As a result, enabling this timer causes new tab to take a very long -// time on a loaded machine, crushing our perf bot when it's under load. For -// now, I'm disabling the timer so we draw the first frame of the animation, -// but nothing more. There are a couple of ways we can fix this: -// 1) Try to figure out why the invalidate is invalidating the entire title bar -// 2) Find some way to draw only the pixels we want and nothing else, but I -// don't know how we'd do that. - // Start a timer for the animation frames. - target_.reset([[TimerTarget alloc] initWithThrobber:self]); - timer_ = - [NSTimer scheduledTimerWithTimeInterval:kAnimationIntervalSeconds - target:target_.get() - selector:@selector(animate:) - userInfo:nil - repeats:YES]; -#endif + [self setImage:image]; } return self; } @@ -116,4 +75,60 @@ const float kAnimationIntervalSeconds = 0.03; // 30ms, same as windows fraction:1.0]; } +// Stores the internal representation of the image from |image|. We use +// CoreImage for speed (though this doesn't seem to help perf issues). We +// validate that the image is of the appropriate ratio. If the image has more +// than one frame, restarts the timer. +- (void)setImage:(NSImage*)image { + // Reset the animation counter so there's no chance we are off the end. + animationFrame_ = 0; + [timer_ invalidate]; + timer_ = nil; + + // Ensure that the height divides evenly into the width. Cache the + // number of frames in the animation for later. + NSSize imageSize = [image size]; + DCHECK(imageSize.height && imageSize.width); + if (!imageSize.height) + return; + DCHECK((int)imageSize.width % (int)imageSize.height == 0); + numFrames_ = (int)imageSize.width / (int)imageSize.height; + DCHECK(numFrames_); + + // First check if we have a bitmap image rep and use it, otherwise fall + // back to creating one. + NSBitmapImageRep* rep = [[image representations] objectAtIndex:0]; + if (![rep isKindOfClass:[NSBitmapImageRep class]]) { + [image lockFocus]; + NSRect imageRect = NSMakeRect(0, 0, imageSize.width, imageSize.height); + rep = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:imageRect] + autorelease]; + [image unlockFocus]; + } + image_.reset([[CIImage alloc] initWithBitmapImageRep:rep]); + +#if 0 +// TODO(pinkerton): The invalidation of the view to trigger re-draw causes +// the entire title-bar to redraw (you can see it with QuartzDebug). For some +// reason, setting isOpaque on this view, or any of its parent views, doesn't +// help. As a result, enabling this timer causes new tab to take a very long +// time on a loaded machine, crushing our perf bot when it's under load. For +// now, I'm disabling the timer so we draw the first frame of the animation, +// but nothing more. There are a couple of ways we can fix this: +// 1) Try to figure out why the invalidate is invalidating the entire title bar +// 2) Find some way to draw only the pixels we want and nothing else, but I +// don't know how we'd do that. + if (numFrames_ > 1) { + // Start a timer for the animation frames. + target_.reset([[TimerTarget alloc] initWithThrobber:self]); + timer_ = + [NSTimer scheduledTimerWithTimeInterval:kAnimationIntervalSeconds + target:target_.get() + selector:@selector(animate:) + userInfo:nil + repeats:YES]; + } +#endif +} + @end |