| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 #import "chrome/browser/ui/cocoa/clear_browsing_data_controller.h" | |
| 6 | |
| 7 #include "base/lazy_instance.h" | |
| 8 #include "base/mac/mac_util.h" | |
| 9 #include "base/scoped_nsobject.h" | |
| 10 #include "chrome/browser/browsing_data_remover.h" | |
| 11 #include "chrome/browser/prefs/pref_service.h" | |
| 12 #include "chrome/browser/profiles/profile.h" | |
| 13 #include "chrome/browser/ui/browser.h" | |
| 14 #include "chrome/browser/ui/browser_window.h" | |
| 15 #include "chrome/common/pref_names.h" | |
| 16 #include "grit/locale_settings.h" | |
| 17 #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" | |
| 18 #include "ui/base/l10n/l10n_util.h" | |
| 19 | |
| 20 NSString* const kClearBrowsingDataControllerDidDelete = | |
| 21 @"kClearBrowsingDataControllerDidDelete"; | |
| 22 NSString* const kClearBrowsingDataControllerRemoveMask = | |
| 23 @"kClearBrowsingDataControllerRemoveMask"; | |
| 24 | |
| 25 @interface ClearBrowsingDataController(Private) | |
| 26 - (void)initFromPrefs; | |
| 27 - (void)persistToPrefs; | |
| 28 - (void)dataRemoverDidFinish; | |
| 29 @end | |
| 30 | |
| 31 class ClearBrowsingObserver : public BrowsingDataRemover::Observer { | |
| 32 public: | |
| 33 ClearBrowsingObserver(ClearBrowsingDataController* controller) | |
| 34 : controller_(controller) { } | |
| 35 void OnBrowsingDataRemoverDone() { [controller_ dataRemoverDidFinish]; } | |
| 36 private: | |
| 37 ClearBrowsingDataController* controller_; | |
| 38 }; | |
| 39 | |
| 40 namespace { | |
| 41 | |
| 42 typedef std::map<Profile*, ClearBrowsingDataController*> ProfileControllerMap; | |
| 43 | |
| 44 static base::LazyInstance<ProfileControllerMap> g_profile_controller_map( | |
| 45 base::LINKER_INITIALIZED); | |
| 46 | |
| 47 } // namespace | |
| 48 | |
| 49 @implementation ClearBrowsingDataController | |
| 50 | |
| 51 @synthesize clearBrowsingHistory = clearBrowsingHistory_; | |
| 52 @synthesize clearDownloadHistory = clearDownloadHistory_; | |
| 53 @synthesize emptyCache = emptyCache_; | |
| 54 @synthesize deleteCookies = deleteCookies_; | |
| 55 @synthesize clearSavedPasswords = clearSavedPasswords_; | |
| 56 @synthesize clearFormData = clearFormData_; | |
| 57 @synthesize timePeriod = timePeriod_; | |
| 58 @synthesize isClearing = isClearing_; | |
| 59 | |
| 60 + (void)showClearBrowsingDialogForProfile:(Profile*)profile { | |
| 61 ClearBrowsingDataController* controller = | |
| 62 [ClearBrowsingDataController controllerForProfile:profile]; | |
| 63 if (![controller isWindowLoaded]) { | |
| 64 // This function needs to return instead of blocking, to match the windows | |
| 65 // api call. It caused problems when launching the dialog from the | |
| 66 // WebUI history page. See bug and code review for more details. | |
| 67 // http://crbug.com/37976 | |
| 68 [controller performSelector:@selector(runModalDialog) | |
| 69 withObject:nil | |
| 70 afterDelay:0]; | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 + (ClearBrowsingDataController *)controllerForProfile:(Profile*)profile { | |
| 75 // Get the original profile in case we get here from an incognito window | |
| 76 // |GetOriginalProfile()| will return the same profile if it is the original | |
| 77 // profile. | |
| 78 profile = profile->GetOriginalProfile(); | |
| 79 | |
| 80 ProfileControllerMap* map = g_profile_controller_map.Pointer(); | |
| 81 DCHECK(map != NULL); | |
| 82 ProfileControllerMap::iterator it = map->find(profile); | |
| 83 if (it == map->end()) { | |
| 84 // Since we don't currently support multiple profiles, this class | |
| 85 // has not been tested against this case. | |
| 86 if (!map->empty()) | |
| 87 return nil; | |
| 88 | |
| 89 ClearBrowsingDataController* controller = | |
| 90 [[self alloc] initWithProfile:profile]; | |
| 91 it = map->insert(std::make_pair(profile, controller)).first; | |
| 92 } | |
| 93 return it->second; | |
| 94 } | |
| 95 | |
| 96 - (id)initWithProfile:(Profile*)profile { | |
| 97 DCHECK(profile); | |
| 98 // Use initWithWindowNibPath:: instead of initWithWindowNibName: so we | |
| 99 // can override it in a unit test. | |
| 100 NSString *nibpath = [base::mac::MainAppBundle() | |
| 101 pathForResource:@"ClearBrowsingData" | |
| 102 ofType:@"nib"]; | |
| 103 if ((self = [super initWithWindowNibPath:nibpath owner:self])) { | |
| 104 profile_ = profile; | |
| 105 observer_.reset(new ClearBrowsingObserver(self)); | |
| 106 [self initFromPrefs]; | |
| 107 } | |
| 108 return self; | |
| 109 } | |
| 110 | |
| 111 - (void)dealloc { | |
| 112 if (remover_) { | |
| 113 // We were destroyed while clearing history was in progress. This can only | |
| 114 // occur during automated tests (normally the user can't close the dialog | |
| 115 // while clearing is in progress as the dialog is modal and not closeable). | |
| 116 remover_->RemoveObserver(observer_.get()); | |
| 117 } | |
| 118 | |
| 119 [super dealloc]; | |
| 120 } | |
| 121 | |
| 122 // Run application modal. | |
| 123 - (void)runModalDialog { | |
| 124 // Check again to make sure there is only one window. Since we use | |
| 125 // |performSelector:afterDelay:| it is possible for this to somehow be | |
| 126 // triggered twice. | |
| 127 DCHECK([NSThread isMainThread]); | |
| 128 if (![self isWindowLoaded]) { | |
| 129 // The Window size in the nib is a min size, loop over the views collecting | |
| 130 // the max they grew by, that is how much the window needs to be widened by. | |
| 131 CGFloat maxWidthGrowth = 0.0; | |
| 132 NSWindow* window = [self window]; | |
| 133 NSView* contentView = [window contentView]; | |
| 134 Class widthBasedTweakerClass = [GTMWidthBasedTweaker class]; | |
| 135 for (id subView in [contentView subviews]) { | |
| 136 if ([subView isKindOfClass:widthBasedTweakerClass]) { | |
| 137 GTMWidthBasedTweaker* tweaker = subView; | |
| 138 CGFloat delta = [tweaker changedWidth]; | |
| 139 maxWidthGrowth = std::max(maxWidthGrowth, delta); | |
| 140 } | |
| 141 } | |
| 142 if (maxWidthGrowth > 0.0) { | |
| 143 NSRect rect = [contentView convertRect:[window frame] fromView:nil]; | |
| 144 rect.size.width += maxWidthGrowth; | |
| 145 rect = [contentView convertRect:rect toView:nil]; | |
| 146 [window setFrame:rect display:NO]; | |
| 147 // For some reason the content view is resizing, but some times not | |
| 148 // adjusting its origin, so correct it manually. | |
| 149 [contentView setFrameOrigin:NSZeroPoint]; | |
| 150 } | |
| 151 // Now start the modal loop. | |
| 152 [NSApp runModalForWindow:window]; | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 - (int)removeMask { | |
| 157 int removeMask = 0L; | |
| 158 if (clearBrowsingHistory_) | |
| 159 removeMask |= BrowsingDataRemover::REMOVE_HISTORY; | |
| 160 if (clearDownloadHistory_) | |
| 161 removeMask |= BrowsingDataRemover::REMOVE_DOWNLOADS; | |
| 162 if (emptyCache_) | |
| 163 removeMask |= BrowsingDataRemover::REMOVE_CACHE; | |
| 164 if (deleteCookies_) | |
| 165 removeMask |= BrowsingDataRemover::REMOVE_COOKIES; | |
| 166 if (clearSavedPasswords_) | |
| 167 removeMask |= BrowsingDataRemover::REMOVE_PASSWORDS; | |
| 168 if (clearFormData_) | |
| 169 removeMask |= BrowsingDataRemover::REMOVE_FORM_DATA; | |
| 170 return removeMask; | |
| 171 } | |
| 172 | |
| 173 // Called when the user clicks the "clear" button. Do the work and persist | |
| 174 // the prefs for next time. We don't stop the modal session until we get | |
| 175 // the callback from the BrowsingDataRemover so the window stays on the screen. | |
| 176 // While we're working, dim the buttons so the user can't click them. | |
| 177 - (IBAction)clearData:(id)sender { | |
| 178 // Set that we're working so that the buttons disable. | |
| 179 [self setIsClearing:YES]; | |
| 180 | |
| 181 [self persistToPrefs]; | |
| 182 | |
| 183 // BrowsingDataRemover deletes itself when done. | |
| 184 remover_ = new BrowsingDataRemover(profile_, | |
| 185 static_cast<BrowsingDataRemover::TimePeriod>(timePeriod_), | |
| 186 base::Time()); | |
| 187 remover_->AddObserver(observer_.get()); | |
| 188 remover_->Remove([self removeMask]); | |
| 189 } | |
| 190 | |
| 191 // Called when the user clicks the cancel button. All we need to do is stop | |
| 192 // the modal session. | |
| 193 - (IBAction)cancel:(id)sender { | |
| 194 [self closeDialog]; | |
| 195 } | |
| 196 | |
| 197 // Called when the user clicks the "Flash Player storage settings" button. | |
| 198 - (IBAction)openFlashPlayerSettings:(id)sender { | |
| 199 // The "Clear Data" dialog is app-modal on OS X. Hence, close it before | |
| 200 // opening a tab with flash settings. | |
| 201 [self closeDialog]; | |
| 202 | |
| 203 Browser* browser = Browser::Create(profile_); | |
| 204 browser->OpenURL(GURL(l10n_util::GetStringUTF8(IDS_FLASH_STORAGE_URL)), | |
| 205 GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK); | |
| 206 browser->window()->Show(); | |
| 207 } | |
| 208 | |
| 209 - (void)closeDialog { | |
| 210 ProfileControllerMap* map = g_profile_controller_map.Pointer(); | |
| 211 ProfileControllerMap::iterator it = map->find(profile_); | |
| 212 if (it != map->end()) { | |
| 213 map->erase(it); | |
| 214 } | |
| 215 [self autorelease]; | |
| 216 [[self window] orderOut:self]; | |
| 217 [NSApp stopModal]; | |
| 218 } | |
| 219 | |
| 220 // Initialize the bools from prefs using the setters to be KVO-compliant. | |
| 221 - (void)initFromPrefs { | |
| 222 PrefService* prefs = profile_->GetPrefs(); | |
| 223 [self setClearBrowsingHistory: | |
| 224 prefs->GetBoolean(prefs::kDeleteBrowsingHistory)]; | |
| 225 [self setClearDownloadHistory: | |
| 226 prefs->GetBoolean(prefs::kDeleteDownloadHistory)]; | |
| 227 [self setEmptyCache:prefs->GetBoolean(prefs::kDeleteCache)]; | |
| 228 [self setDeleteCookies:prefs->GetBoolean(prefs::kDeleteCookies)]; | |
| 229 [self setClearSavedPasswords:prefs->GetBoolean(prefs::kDeletePasswords)]; | |
| 230 [self setClearFormData:prefs->GetBoolean(prefs::kDeleteFormData)]; | |
| 231 [self setTimePeriod:prefs->GetInteger(prefs::kDeleteTimePeriod)]; | |
| 232 } | |
| 233 | |
| 234 // Save the checkbox values to the preferences. | |
| 235 - (void)persistToPrefs { | |
| 236 PrefService* prefs = profile_->GetPrefs(); | |
| 237 prefs->SetBoolean(prefs::kDeleteBrowsingHistory, | |
| 238 [self clearBrowsingHistory]); | |
| 239 prefs->SetBoolean(prefs::kDeleteDownloadHistory, | |
| 240 [self clearDownloadHistory]); | |
| 241 prefs->SetBoolean(prefs::kDeleteCache, [self emptyCache]); | |
| 242 prefs->SetBoolean(prefs::kDeleteCookies, [self deleteCookies]); | |
| 243 prefs->SetBoolean(prefs::kDeletePasswords, [self clearSavedPasswords]); | |
| 244 prefs->SetBoolean(prefs::kDeleteFormData, [self clearFormData]); | |
| 245 prefs->SetInteger(prefs::kDeleteTimePeriod, [self timePeriod]); | |
| 246 } | |
| 247 | |
| 248 // Called when the data remover object is done with its work. Close the window. | |
| 249 // The remover will delete itself. End the modal session at this point. | |
| 250 - (void)dataRemoverDidFinish { | |
| 251 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; | |
| 252 int removeMask = [self removeMask]; | |
| 253 NSDictionary* userInfo = | |
| 254 [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:removeMask] | |
| 255 forKey:kClearBrowsingDataControllerRemoveMask]; | |
| 256 [center postNotificationName:kClearBrowsingDataControllerDidDelete | |
| 257 object:self | |
| 258 userInfo:userInfo]; | |
| 259 | |
| 260 [self closeDialog]; | |
| 261 [[self window] orderOut:self]; | |
| 262 [self setIsClearing:NO]; | |
| 263 remover_ = NULL; | |
| 264 } | |
| 265 | |
| 266 @end | |
| OLD | NEW |