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 |