OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/cocoa/clear_browsing_data_controller.h" | 5 #import "chrome/browser/cocoa/clear_browsing_data_controller.h" |
6 | 6 |
7 #include "app/l10n_util.h" | 7 #include "app/l10n_util.h" |
| 8 #include "base/command_line.h" |
8 #include "base/mac_util.h" | 9 #include "base/mac_util.h" |
9 #include "base/scoped_nsobject.h" | 10 #include "base/scoped_nsobject.h" |
10 #include "base/singleton.h" | 11 #include "base/singleton.h" |
11 #include "chrome/browser/browser.h" | 12 #include "chrome/browser/browser.h" |
12 #include "chrome/browser/browser_window.h" | 13 #include "chrome/browser/browser_window.h" |
13 #include "chrome/browser/browsing_data_remover.h" | 14 #include "chrome/browser/browsing_data_remover.h" |
| 15 #include "chrome/browser/platform_util.h" |
14 #include "chrome/browser/prefs/pref_service.h" | 16 #include "chrome/browser/prefs/pref_service.h" |
15 #include "chrome/browser/profile.h" | 17 #include "chrome/browser/profile.h" |
| 18 #include "chrome/browser/sync/profile_sync_service.h" |
| 19 #include "chrome/common/chrome_switches.h" |
16 #include "chrome/common/pref_names.h" | 20 #include "chrome/common/pref_names.h" |
| 21 #include "grit/generated_resources.h" |
17 #include "grit/locale_settings.h" | 22 #include "grit/locale_settings.h" |
18 #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" | 23 #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" |
19 | 24 |
20 NSString* const kClearBrowsingDataControllerDidDelete = | 25 NSString* const kClearBrowsingDataControllerDidDelete = |
21 @"kClearBrowsingDataControllerDidDelete"; | 26 @"kClearBrowsingDataControllerDidDelete"; |
22 NSString* const kClearBrowsingDataControllerRemoveMask = | 27 NSString* const kClearBrowsingDataControllerRemoveMask = |
23 @"kClearBrowsingDataControllerRemoveMask"; | 28 @"kClearBrowsingDataControllerRemoveMask"; |
24 | 29 |
| 30 namespace { |
| 31 |
| 32 // Compare function for -[NSArray sortedArrayUsingFunction:context:] that |
| 33 // sorts the views in Y order top down. |
| 34 NSInteger CompareFrameY(id view1, id view2, void* context) { |
| 35 CGFloat y1 = NSMinY([view1 frame]); |
| 36 CGFloat y2 = NSMinY([view2 frame]); |
| 37 if (y1 < y2) |
| 38 return NSOrderedDescending; |
| 39 else if (y1 > y2) |
| 40 return NSOrderedAscending; |
| 41 else |
| 42 return NSOrderedSame; |
| 43 } |
| 44 |
| 45 typedef std::map<Profile*, ClearBrowsingDataController*> ProfileControllerMap; |
| 46 |
| 47 } // namespace |
| 48 |
25 @interface ClearBrowsingDataController(Private) | 49 @interface ClearBrowsingDataController(Private) |
26 - (void)initFromPrefs; | 50 - (void)initFromPrefs; |
27 - (void)persistToPrefs; | 51 - (void)persistToPrefs; |
28 - (void)dataRemoverDidFinish; | 52 - (void)dataRemoverDidFinish; |
| 53 - (void)syncStateChanged; |
29 @end | 54 @end |
30 | 55 |
31 class ClearBrowsingObserver : public BrowsingDataRemover::Observer { | 56 class ClearBrowsingObserver : public BrowsingDataRemover::Observer, |
| 57 public ProfileSyncServiceObserver { |
32 public: | 58 public: |
33 ClearBrowsingObserver(ClearBrowsingDataController* controller) | 59 ClearBrowsingObserver(ClearBrowsingDataController* controller) |
34 : controller_(controller) { } | 60 : controller_(controller) { } |
35 void OnBrowsingDataRemoverDone() { [controller_ dataRemoverDidFinish]; } | 61 void OnBrowsingDataRemoverDone() { [controller_ dataRemoverDidFinish]; } |
| 62 void OnStateChanged() { [controller_ syncStateChanged]; } |
36 private: | 63 private: |
37 ClearBrowsingDataController* controller_; | 64 ClearBrowsingDataController* controller_; |
38 }; | 65 }; |
39 | 66 |
40 namespace { | |
41 | |
42 typedef std::map<Profile*, ClearBrowsingDataController*> ProfileControllerMap; | |
43 | |
44 } // namespace | |
45 | |
46 @implementation ClearBrowsingDataController | 67 @implementation ClearBrowsingDataController |
47 | 68 |
48 @synthesize clearBrowsingHistory = clearBrowsingHistory_; | 69 @synthesize clearBrowsingHistory = clearBrowsingHistory_; |
49 @synthesize clearDownloadHistory = clearDownloadHistory_; | 70 @synthesize clearDownloadHistory = clearDownloadHistory_; |
50 @synthesize emptyCache = emptyCache_; | 71 @synthesize emptyCache = emptyCache_; |
51 @synthesize deleteCookies = deleteCookies_; | 72 @synthesize deleteCookies = deleteCookies_; |
52 @synthesize clearSavedPasswords = clearSavedPasswords_; | 73 @synthesize clearSavedPasswords = clearSavedPasswords_; |
53 @synthesize clearFormData = clearFormData_; | 74 @synthesize clearFormData = clearFormData_; |
54 @synthesize timePeriod = timePeriod_; | 75 @synthesize timePeriod = timePeriod_; |
55 @synthesize isClearing = isClearing_; | 76 @synthesize isClearing = isClearing_; |
| 77 @synthesize clearingStatus = clearingStatus_; |
56 | 78 |
57 + (void)showClearBrowsingDialogForProfile:(Profile*)profile { | 79 + (void)showClearBrowsingDialogForProfile:(Profile*)profile { |
58 ClearBrowsingDataController* controller = | 80 ClearBrowsingDataController* controller = |
59 [ClearBrowsingDataController controllerForProfile:profile]; | 81 [ClearBrowsingDataController controllerForProfile:profile]; |
60 if (![controller isWindowLoaded]) { | 82 if (![controller isWindowLoaded]) { |
61 // This function needs to return instead of blocking, to match the windows | 83 // This function needs to return instead of blocking, to match the Windows |
62 // api call. It caused problems when launching the dialog from the | 84 // version. It caused problems when launching the dialog from the |
63 // DomUI history page. See bug and code review for more details. | 85 // DomUI history page. See bug and code review for more details. |
64 // http://crbug.com/37976 | 86 // http://crbug.com/37976 |
65 [controller performSelector:@selector(runModalDialog) | 87 [controller performSelector:@selector(runModalDialog) |
66 withObject:nil | 88 withObject:nil |
67 afterDelay:0]; | 89 afterDelay:0]; |
68 } | 90 } |
69 } | 91 } |
70 | 92 |
71 + (ClearBrowsingDataController *)controllerForProfile:(Profile*)profile { | 93 + (ClearBrowsingDataController *)controllerForProfile:(Profile*)profile { |
72 // Get the original profile in case we get here from an incognito window | 94 // Get the original profile in case we get here from an incognito window |
73 // |GetOriginalProfile()| will return the same profile if it is the original | 95 // |GetOriginalProfile()| will return the same profile if it is the original |
(...skipping 20 matching lines...) Expand all Loading... |
94 - (id)initWithProfile:(Profile*)profile { | 116 - (id)initWithProfile:(Profile*)profile { |
95 DCHECK(profile); | 117 DCHECK(profile); |
96 // Use initWithWindowNibPath:: instead of initWithWindowNibName: so we | 118 // Use initWithWindowNibPath:: instead of initWithWindowNibName: so we |
97 // can override it in a unit test. | 119 // can override it in a unit test. |
98 NSString *nibpath = [mac_util::MainAppBundle() | 120 NSString *nibpath = [mac_util::MainAppBundle() |
99 pathForResource:@"ClearBrowsingData" | 121 pathForResource:@"ClearBrowsingData" |
100 ofType:@"nib"]; | 122 ofType:@"nib"]; |
101 if ((self = [super initWithWindowNibPath:nibpath owner:self])) { | 123 if ((self = [super initWithWindowNibPath:nibpath owner:self])) { |
102 profile_ = profile; | 124 profile_ = profile; |
103 observer_.reset(new ClearBrowsingObserver(self)); | 125 observer_.reset(new ClearBrowsingObserver(self)); |
| 126 profile_->GetProfileSyncService()->ResetClearServerDataState(); |
| 127 profile_->GetProfileSyncService()->AddObserver(observer_.get()); |
104 [self initFromPrefs]; | 128 [self initFromPrefs]; |
105 } | 129 } |
106 return self; | 130 return self; |
107 } | 131 } |
108 | 132 |
109 - (void)dealloc { | 133 - (void)dealloc { |
110 if (remover_) { | 134 if (remover_) { |
111 // We were destroyed while clearing history was in progress. This can only | 135 // We were destroyed while clearing history was in progress. This can only |
112 // occur during automated tests (normally the user can't close the dialog | 136 // occur during automated tests (normally the user can't close the dialog |
113 // while clearing is in progress as the dialog is modal and not closeable). | 137 // while clearing is in progress as the dialog is modal and not closeable). |
114 remover_->RemoveObserver(observer_.get()); | 138 remover_->RemoveObserver(observer_.get()); |
115 } | 139 } |
| 140 profile_->GetProfileSyncService()->RemoveObserver(observer_.get()); |
| 141 [self setClearingStatus:nil]; |
116 | 142 |
117 [super dealloc]; | 143 [super dealloc]; |
118 } | 144 } |
119 | 145 |
120 // Run application modal. | 146 // Run application modal. |
121 - (void)runModalDialog { | 147 - (void)runModalDialog { |
122 // Check again to make sure there is only one window. Since we use | 148 // Check again to make sure there is only one window. Since we use |
123 // |performSelector:afterDelay:| it is possible for this to somehow be | 149 // |performSelector:afterDelay:| it is possible for this to somehow be |
124 // triggered twice. | 150 // triggered twice. |
125 DCHECK([NSThread isMainThread]); | 151 DCHECK([NSThread isMainThread]); |
126 if (![self isWindowLoaded]) { | 152 if (![self isWindowLoaded]) { |
127 // The Window size in the nib is a min size, loop over the views collecting | 153 // It takes two passes to adjust the window size. The first pass is to |
128 // the max they grew by, that is how much the window needs to be widened by. | 154 // determine the width of all the non-wrappable items. The window is then |
| 155 // resized to that width. Once the width is fixed, the heights of the |
| 156 // variable-height items can then be calculated, the items can be spaced, |
| 157 // and the window resized (again) if necessary. |
| 158 |
| 159 NSWindow* window = [self window]; |
| 160 |
| 161 // Adjust the widths of non-wrappable items. |
129 CGFloat maxWidthGrowth = 0.0; | 162 CGFloat maxWidthGrowth = 0.0; |
130 NSWindow* window = [self window]; | |
131 NSView* contentView = [window contentView]; | |
132 Class widthBasedTweakerClass = [GTMWidthBasedTweaker class]; | 163 Class widthBasedTweakerClass = [GTMWidthBasedTweaker class]; |
133 for (id subView in [contentView subviews]) { | 164 for (NSTabViewItem* tabViewItem in [tabView_ tabViewItems]) |
134 if ([subView isKindOfClass:widthBasedTweakerClass]) { | 165 for (NSView* subView in [[tabViewItem view] subviews]) |
135 GTMWidthBasedTweaker* tweaker = subView; | 166 if ([subView isKindOfClass:widthBasedTweakerClass]) { |
136 CGFloat delta = [tweaker changedWidth]; | 167 GTMWidthBasedTweaker* tweaker = (GTMWidthBasedTweaker*)subView; |
137 maxWidthGrowth = std::max(maxWidthGrowth, delta); | 168 CGFloat delta = [tweaker changedWidth]; |
| 169 maxWidthGrowth = std::max(maxWidthGrowth, delta); |
| 170 } |
| 171 |
| 172 // Adjust the width of the window. |
| 173 if (maxWidthGrowth > 0.0) { |
| 174 NSSize adjustSize = NSMakeSize(maxWidthGrowth, 0); |
| 175 adjustSize = [[window contentView] convertSize:adjustSize toView:nil]; |
| 176 NSRect windowFrame = [window frame]; |
| 177 windowFrame.size.width += adjustSize.width; |
| 178 [window setFrame:windowFrame display:NO]; |
| 179 } |
| 180 |
| 181 // Adjust the heights and locations of the items on the "Other data" tab. |
| 182 CGFloat cumulativeHeightGrowth = 0.0; |
| 183 NSArray* subViews = |
| 184 [[otherDataTab_ subviews] sortedArrayUsingFunction:CompareFrameY |
| 185 context:NULL]; |
| 186 for (NSView* view in subViews) { |
| 187 if ([view isHidden]) |
| 188 continue; |
| 189 |
| 190 if ([objectsToVerticallySize_ containsObject:view]) { |
| 191 DCHECK([view isKindOfClass:[NSTextField class]]); |
| 192 CGFloat viewHeightGrowth = [GTMUILocalizerAndLayoutTweaker |
| 193 sizeToFitFixedWidthTextField:(NSTextField*)view]; |
| 194 if (viewHeightGrowth > 0.0) |
| 195 cumulativeHeightGrowth += viewHeightGrowth; |
138 } | 196 } |
| 197 |
| 198 NSRect viewFrame = [view frame]; |
| 199 viewFrame.origin.y -= cumulativeHeightGrowth; |
| 200 [view setFrame:viewFrame]; |
139 } | 201 } |
140 if (maxWidthGrowth > 0.0) { | 202 |
141 NSRect rect = [contentView convertRect:[window frame] fromView:nil]; | 203 // Adjust the height of the window. |
142 rect.size.width += maxWidthGrowth; | 204 if (cumulativeHeightGrowth > 0.0) { |
143 rect = [contentView convertRect:rect toView:nil]; | 205 NSSize adjustSize = NSMakeSize(0, cumulativeHeightGrowth); |
144 [window setFrame:rect display:NO]; | 206 adjustSize = [[window contentView] convertSize:adjustSize toView:nil]; |
145 // For some reason the content view is resizing, but some times not | 207 NSRect windowFrame = [window frame]; |
146 // adjusting its origin, so correct it manually. | 208 windowFrame.size.height += adjustSize.height; |
147 [contentView setFrameOrigin:NSZeroPoint]; | 209 [window setFrame:windowFrame display:NO]; |
148 } | 210 } |
| 211 |
149 // Now start the modal loop. | 212 // Now start the modal loop. |
150 [NSApp runModalForWindow:window]; | 213 [NSApp runModalForWindow:window]; |
151 } | 214 } |
152 } | 215 } |
153 | 216 |
154 - (int)removeMask { | 217 - (int)removeMask { |
155 int removeMask = 0L; | 218 int removeMask = 0L; |
156 if (clearBrowsingHistory_) | 219 if (clearBrowsingHistory_) |
157 removeMask |= BrowsingDataRemover::REMOVE_HISTORY; | 220 removeMask |= BrowsingDataRemover::REMOVE_HISTORY; |
158 if (clearDownloadHistory_) | 221 if (clearDownloadHistory_) |
159 removeMask |= BrowsingDataRemover::REMOVE_DOWNLOADS; | 222 removeMask |= BrowsingDataRemover::REMOVE_DOWNLOADS; |
160 if (emptyCache_) | 223 if (emptyCache_) |
161 removeMask |= BrowsingDataRemover::REMOVE_CACHE; | 224 removeMask |= BrowsingDataRemover::REMOVE_CACHE; |
162 if (deleteCookies_) | 225 if (deleteCookies_) |
163 removeMask |= BrowsingDataRemover::REMOVE_COOKIES; | 226 removeMask |= BrowsingDataRemover::REMOVE_COOKIES; |
164 if (clearSavedPasswords_) | 227 if (clearSavedPasswords_) |
165 removeMask |= BrowsingDataRemover::REMOVE_PASSWORDS; | 228 removeMask |= BrowsingDataRemover::REMOVE_PASSWORDS; |
166 if (clearFormData_) | 229 if (clearFormData_) |
167 removeMask |= BrowsingDataRemover::REMOVE_FORM_DATA; | 230 removeMask |= BrowsingDataRemover::REMOVE_FORM_DATA; |
168 return removeMask; | 231 return removeMask; |
169 } | 232 } |
170 | 233 |
171 // Called when the user clicks the "clear" button. Do the work and persist | 234 // Called when the user clicks the "clear" button. Do the work and persist |
172 // the prefs for next time. We don't stop the modal session until we get | 235 // the prefs for next time. We don't stop the modal session until we get |
173 // the callback from the BrowsingDataRemover so the window stays on the screen. | 236 // the callback from the BrowsingDataRemover so the window stays on the screen. |
174 // While we're working, dim the buttons so the user can't click them. | 237 // While we're working, dim the buttons so the user can't click them. |
175 - (IBAction)clearData:(id)sender { | 238 - (IBAction)clearData:(id)sender { |
176 // Set that we're working so that the buttons disable. | 239 // Set that we're working so that the buttons disable. |
| 240 [self setClearingStatus:l10n_util::GetNSString(IDS_CLEAR_DATA_DELETING)]; |
177 [self setIsClearing:YES]; | 241 [self setIsClearing:YES]; |
178 | 242 |
179 [self persistToPrefs]; | 243 [self persistToPrefs]; |
180 | 244 |
181 // BrowsingDataRemover deletes itself when done. | 245 // BrowsingDataRemover deletes itself when done. |
182 remover_ = new BrowsingDataRemover(profile_, | 246 remover_ = new BrowsingDataRemover(profile_, |
183 static_cast<BrowsingDataRemover::TimePeriod>(timePeriod_), | 247 static_cast<BrowsingDataRemover::TimePeriod>(timePeriod_), |
184 base::Time()); | 248 base::Time()); |
185 remover_->AddObserver(observer_.get()); | 249 remover_->AddObserver(observer_.get()); |
186 remover_->Remove([self removeMask]); | 250 remover_->Remove([self removeMask]); |
(...skipping 10 matching lines...) Expand all Loading... |
197 // The "Clear Data" dialog is app-modal on OS X. Hence, close it before | 261 // The "Clear Data" dialog is app-modal on OS X. Hence, close it before |
198 // opening a tab with flash settings. | 262 // opening a tab with flash settings. |
199 [self closeDialog]; | 263 [self closeDialog]; |
200 | 264 |
201 Browser* browser = Browser::Create(profile_); | 265 Browser* browser = Browser::Create(profile_); |
202 browser->OpenURL(GURL(l10n_util::GetStringUTF8(IDS_FLASH_STORAGE_URL)), | 266 browser->OpenURL(GURL(l10n_util::GetStringUTF8(IDS_FLASH_STORAGE_URL)), |
203 GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK); | 267 GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK); |
204 browser->window()->Show(); | 268 browser->window()->Show(); |
205 } | 269 } |
206 | 270 |
| 271 - (IBAction)openGoogleDashboard:(id)sender { |
| 272 // The "Clear Data" dialog is app-modal on OS X. Hence, close it before |
| 273 // opening a tab with the dashboard. |
| 274 [self closeDialog]; |
| 275 |
| 276 Browser* browser = Browser::Create(profile_); |
| 277 browser->OpenURL(GURL(l10n_util::GetStringUTF8(IDS_PRIVACY_DASHBOARD_URL)), |
| 278 GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK); |
| 279 browser->window()->Show(); |
| 280 } |
| 281 |
207 - (void)closeDialog { | 282 - (void)closeDialog { |
208 ProfileControllerMap* map = Singleton<ProfileControllerMap>::get(); | 283 ProfileControllerMap* map = Singleton<ProfileControllerMap>::get(); |
209 ProfileControllerMap::iterator it = map->find(profile_); | 284 ProfileControllerMap::iterator it = map->find(profile_); |
210 if (it != map->end()) { | 285 if (it != map->end()) { |
211 map->erase(it); | 286 map->erase(it); |
212 } | 287 } |
213 [self autorelease]; | 288 [self autorelease]; |
214 [[self window] orderOut:self]; | 289 [[self window] orderOut:self]; |
215 [NSApp stopModal]; | 290 [NSApp stopModal]; |
216 } | 291 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
249 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; | 324 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; |
250 int removeMask = [self removeMask]; | 325 int removeMask = [self removeMask]; |
251 NSDictionary* userInfo = | 326 NSDictionary* userInfo = |
252 [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:removeMask] | 327 [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:removeMask] |
253 forKey:kClearBrowsingDataControllerRemoveMask]; | 328 forKey:kClearBrowsingDataControllerRemoveMask]; |
254 [center postNotificationName:kClearBrowsingDataControllerDidDelete | 329 [center postNotificationName:kClearBrowsingDataControllerDidDelete |
255 object:self | 330 object:self |
256 userInfo:userInfo]; | 331 userInfo:userInfo]; |
257 | 332 |
258 [self closeDialog]; | 333 [self closeDialog]; |
259 [[self window] orderOut:self]; | 334 [self setClearingStatus:nil]; |
260 [self setIsClearing:NO]; | 335 [self setIsClearing:NO]; |
261 remover_ = NULL; | 336 remover_ = NULL; |
262 } | 337 } |
263 | 338 |
| 339 - (IBAction)stopSyncAndDeleteData:(id)sender { |
| 340 // Protect against the unlikely case where the server received a message, and |
| 341 // the syncer syncs and resets itself before the user tries pressing the Clear |
| 342 // button in this dialog again. TODO(raz) Confirm whether we have an issue |
| 343 // here |
| 344 if (profile_->GetProfileSyncService()->HasSyncSetupCompleted()) { |
| 345 bool clear = platform_util::SimpleYesNoBox( |
| 346 nil, |
| 347 l10n_util::GetStringUTF16(IDS_CONFIRM_CLEAR_TITLE), |
| 348 l10n_util::GetStringUTF16(IDS_CONFIRM_CLEAR_DESCRIPTION)); |
| 349 if (clear) { |
| 350 profile_->GetProfileSyncService()->ClearServerData(); |
| 351 [self syncStateChanged]; |
| 352 } |
| 353 } |
| 354 } |
| 355 |
| 356 - (void)syncStateChanged { |
| 357 bool deleteInProgress = false; |
| 358 |
| 359 ProfileSyncService::ClearServerDataState clearState = |
| 360 profile_->GetProfileSyncService()->GetClearServerDataState(); |
| 361 profile_->GetProfileSyncService()->ResetClearServerDataState(); |
| 362 |
| 363 switch (clearState) { |
| 364 case ProfileSyncService::CLEAR_NOT_STARTED: |
| 365 // This can occur on a first start and after a failed clear (which does |
| 366 // not close the tab). Do nothing. |
| 367 break; |
| 368 case ProfileSyncService::CLEAR_CLEARING: |
| 369 // Clearing buttons on all tabs are disabled at this point, throbber is |
| 370 // going. |
| 371 [self setClearingStatus:l10n_util::GetNSString(IDS_CLEAR_DATA_SENDING)]; |
| 372 deleteInProgress = true; |
| 373 break; |
| 374 case ProfileSyncService::CLEAR_FAILED: |
| 375 // Show an error and reallow clearing. |
| 376 [self setClearingStatus:l10n_util::GetNSString(IDS_CLEAR_DATA_ERROR)]; |
| 377 deleteInProgress = false; |
| 378 break; |
| 379 case ProfileSyncService::CLEAR_SUCCEEDED: |
| 380 // Close the dialog box, success! |
| 381 [self setClearingStatus:nil]; |
| 382 deleteInProgress = false; |
| 383 [self closeDialog]; |
| 384 break; |
| 385 } |
| 386 |
| 387 [self setIsClearing:deleteInProgress]; |
| 388 } |
| 389 |
| 390 - (BOOL)isSyncEnabled { |
| 391 BOOL allowClearServerDataUI = |
| 392 CommandLine::ForCurrentProcess()->HasSwitch( |
| 393 switches::kEnableClearServerData); |
| 394 |
| 395 return allowClearServerDataUI && |
| 396 profile_->GetProfileSyncService()->HasSyncSetupCompleted(); |
| 397 } |
| 398 |
| 399 - (NSFont*)labelFont { |
| 400 return [NSFont boldSystemFontOfSize:13]; |
| 401 } |
| 402 |
264 @end | 403 @end |
OLD | NEW |