Chromium Code Reviews| OLD | NEW | 
|---|---|
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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/preferences_window_controller.h" | 5 #import "chrome/browser/cocoa/preferences_window_controller.h" | 
| 6 | 6 | 
| 7 #include <algorithm> | 7 #include <algorithm> | 
| 8 #include "app/l10n_util.h" | 8 #include "app/l10n_util.h" | 
| 9 #include "base/mac_util.h" | 9 #include "base/mac_util.h" | 
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" | 
| (...skipping 19 matching lines...) Expand all Loading... | |
| 30 #include "chrome/common/notification_observer.h" | 30 #include "chrome/common/notification_observer.h" | 
| 31 #include "chrome/common/notification_type.h" | 31 #include "chrome/common/notification_type.h" | 
| 32 #include "chrome/common/pref_names.h" | 32 #include "chrome/common/pref_names.h" | 
| 33 #include "chrome/common/pref_service.h" | 33 #include "chrome/common/pref_service.h" | 
| 34 #include "chrome/common/url_constants.h" | 34 #include "chrome/common/url_constants.h" | 
| 35 #include "chrome/installer/util/google_update_settings.h" | 35 #include "chrome/installer/util/google_update_settings.h" | 
| 36 #include "grit/chromium_strings.h" | 36 #include "grit/chromium_strings.h" | 
| 37 #include "grit/generated_resources.h" | 37 #include "grit/generated_resources.h" | 
| 38 #include "grit/locale_settings.h" | 38 #include "grit/locale_settings.h" | 
| 39 #include "net/base/cookie_policy.h" | 39 #include "net/base/cookie_policy.h" | 
| 40 #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" | |
| 40 | 41 | 
| 41 NSString* const kUserDoneEditingPrefsNotification = | 42 NSString* const kUserDoneEditingPrefsNotification = | 
| 42 @"kUserDoneEditingPrefsNotification"; | 43 @"kUserDoneEditingPrefsNotification"; | 
| 43 | 44 | 
| 44 namespace { | 45 namespace { | 
| 45 | 46 | 
| 46 std::wstring GetNewTabUIURLString() { | 47 std::wstring GetNewTabUIURLString() { | 
| 47 std::wstring temp = UTF8ToWide(chrome::kChromeUINewTabURL); | 48 std::wstring temp = UTF8ToWide(chrome::kChromeUINewTabURL); | 
| 48 return URLFixerUpper::FixupURL(temp, std::wstring()); | 49 return URLFixerUpper::FixupURL(temp, std::wstring()); | 
| 49 } | 50 } | 
| 50 | 51 | 
| 51 // Adjusts the views origin so it will be centered if in a given width parent. | 52 // Adjusts the views origin so it will be centered if in a given width parent. | 
| 52 void CenterViewForWidth(NSView* view, CGFloat width) { | 53 void CenterViewForWidth(NSView* view, CGFloat width) { | 
| 53 NSRect frame = [view frame]; | 54 NSRect frame = [view frame]; | 
| 54 frame.origin.x = (width - NSWidth(frame)) / 2.0; | 55 frame.origin.x = (width - NSWidth(frame)) / 2.0; | 
| 55 [view setFrame:frame]; | 56 [view setFrame:frame]; | 
| 56 } | 57 } | 
| 57 | 58 | 
| 58 // Helper to remove all but the last view from the view heirarchy. | 59 // Helper to remove all but the last view from the view heirarchy. | 
| 59 void RemoveAllButLastView(NSArray* views) { | 60 void RemoveAllButLastView(NSArray* views) { | 
| 60 NSArray* toRemove = [views subarrayWithRange:NSMakeRange(0, [views count]-1)]; | 61 NSArray* toRemove = [views subarrayWithRange:NSMakeRange(0, [views count]-1)]; | 
| 61 for (NSView* view in toRemove) { | 62 for (NSView* view in toRemove) { | 
| 62 [view removeFromSuperviewWithoutNeedingDisplay]; | 63 [view removeFromSuperviewWithoutNeedingDisplay]; | 
| 63 } | 64 } | 
| 64 } | 65 } | 
| 65 | 66 | 
| 67 // Helper for tweaking the prefs window, if view is a: | |
| 68 // checkbox, radio group or label: it gets a forced wrap at current size | |
| 69 // editable field: left as is | |
| 70 // anything else: do +[GTMUILocalizerAndLayoutTweaker sizeToFitView:] | |
| 71 NSSize WrapOrSizeToFit(NSView* view) { | |
| 72 if ([view isKindOfClass:[NSTextField class]]) { | |
| 73 NSTextField* textField = static_cast<NSTextField*>(view); | |
| 74 if ([textField isEditable]) | |
| 75 return NSZeroSize; | |
| 76 CGFloat heightChange = | |
| 77 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:textField]; | |
| 78 return NSMakeSize(0.0, heightChange); | |
| 79 } | |
| 80 if ([view isKindOfClass:[NSMatrix class]]) { | |
| 81 NSMatrix* radioGroup = static_cast<NSMatrix*>(view); | |
| 82 [GTMUILocalizerAndLayoutTweaker wrapRadioGroupForWidth:radioGroup]; | |
| 83 return [GTMUILocalizerAndLayoutTweaker sizeToFitView:view]; | |
| 84 } | |
| 85 if ([view isKindOfClass:[NSButton class]]) { | |
| 86 NSButton* button = static_cast<NSButton*>(view); | |
| 87 NSButtonCell* buttonCell = [button cell]; | |
| 88 // Decide it's a checkbox via showsStateBy and highlightsBy. | |
| 89 if (([buttonCell showsStateBy] == NSCellState) && | |
| 90 ([buttonCell highlightsBy] == NSCellState)) { | |
| 91 [GTMUILocalizerAndLayoutTweaker wrapButtonTitleForWidth:button]; | |
| 92 return [GTMUILocalizerAndLayoutTweaker sizeToFitView:view]; | |
| 93 } | |
| 94 } | |
| 95 return [GTMUILocalizerAndLayoutTweaker sizeToFitView:view]; | |
| 96 } | |
| 97 | |
| 98 // The different behaviors for the "pref group" auto sizing. | |
| 99 enum AutoSizeGroupBehavior { | |
| 100 kAutoSizeGroupBehaviorVerticalToFit, | |
| 101 kAutoSizeGroupBehaviorVerticalFirstToFit, | |
| 102 kAutoSizeGroupBehaviorHorizontalToFit, | |
| 103 kAutoSizeGroupBehaviorHorizontalFirstGrows | |
| 104 }; | |
| 105 | |
| 106 // Helper to tweak the layout of the "pref groups" and also ripple any height | |
| 107 // changes from one group to the next groups' origins. | |
| 108 // |views| is an ordered list of views with first being the label for the | |
| 109 // group and the rest being top down or left to right ordering of the views. | |
| 110 // The label is assumed to already be the same height as all the views it is | |
| 111 // next too. | |
| 112 CGFloat AutoSizeGroup(NSArray* views, AutoSizeGroupBehavior behavior, | |
| 113 CGFloat verticalShift) { | |
| 114 DCHECK_GE([views count], 2U) << "Should be at least a label and a control"; | |
| 115 NSTextField* label = [views objectAtIndex:0]; | |
| 116 | |
| 117 #ifndef NDEBUG | |
| 118 // Validate the helpers assumptions in debug builds. | |
| 119 DCHECK([label isKindOfClass:[NSTextField class]]) | |
| 120 << "First view should be the label for the group"; | |
| 121 NSRect initialLabelRect = [label frame]; | |
| 122 for (NSView* view in views) { | |
| 123 if (view != label) { | |
| 124 DCHECK_GE(NSMaxY(initialLabelRect), NSMaxY([view frame])) | |
| 125 << "Got a view that goes above the group label"; | |
| 126 DCHECK_LE(NSMinY(initialLabelRect), NSMinY([view frame])) | |
| 127 << "Got a view that goes below the group label"; | |
| 128 } | |
| 129 } | |
| 130 #endif // DEBUG | |
| 
 
Mark Mentovai
2009/10/30 22:19:27
NDEBUG
 
 | |
| 131 | |
| 132 // Auto size the label to see if we need more vertical space for its localized | |
| 133 // string. | |
| 134 CGFloat labelHeightChange = | |
| 135 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:label]; | |
| 136 | |
| 137 CGFloat localVerticalShift = 0.0; | |
| 138 switch (behavior) { | |
| 139 case kAutoSizeGroupBehaviorVerticalToFit: { | |
| 140 // Walk bottom up doing the sizing and moves. | |
| 141 for (NSUInteger idx = [views count] - 1; idx > 0; --idx) { | |
| 142 NSView* view = [views objectAtIndex:idx]; | |
| 143 NSSize delta = WrapOrSizeToFit(view); | |
| 144 DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height"; | |
| 145 if (localVerticalShift) { | |
| 146 NSPoint origin = [view frame].origin; | |
| 147 origin.y += localVerticalShift; | |
| 148 [view setFrameOrigin:origin]; | |
| 149 } | |
| 150 localVerticalShift += delta.height; | |
| 151 } | |
| 152 break; | |
| 153 } | |
| 154 case kAutoSizeGroupBehaviorVerticalFirstToFit: { | |
| 155 // Just size the top one. | |
| 156 NSView* view = [views objectAtIndex:1]; | |
| 157 NSSize delta = WrapOrSizeToFit(view); | |
| 158 DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height"; | |
| 159 localVerticalShift += delta.height; | |
| 160 break; | |
| 161 } | |
| 162 case kAutoSizeGroupBehaviorHorizontalToFit: { | |
| 163 // Walk left to right doing the sizing and moves. | |
| 164 // NOTE: Don't worry about vertical, assume it always fits. | |
| 165 CGFloat horizontalShift = 0.0; | |
| 166 for (NSUInteger idx = 1; idx < [views count]; ++idx) { | |
| 167 NSView* view = [views objectAtIndex:idx]; | |
| 168 NSSize delta = WrapOrSizeToFit(view); | |
| 169 DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height"; | |
| 170 if (horizontalShift) { | |
| 171 NSPoint origin = [view frame].origin; | |
| 172 origin.x += horizontalShift; | |
| 173 [view setFrameOrigin:origin]; | |
| 174 } | |
| 175 horizontalShift += delta.width; | |
| 176 } | |
| 177 break; | |
| 178 } | |
| 179 case kAutoSizeGroupBehaviorHorizontalFirstGrows: { | |
| 180 // Walk right to left doing the sizing and moves, then apply the space | |
| 181 // collected into the first. | |
| 182 // NOTE: Don't worry about vertical, assume it always all fits. | |
| 183 CGFloat horizontalShift = 0.0; | |
| 184 for (NSUInteger idx = [views count] - 1; idx > 1; --idx) { | |
| 185 NSView* view = [views objectAtIndex:idx]; | |
| 186 NSSize delta = WrapOrSizeToFit(view); | |
| 187 DCHECK_GE(delta.height, 0.0) << "Should NOT shrink in height"; | |
| 188 horizontalShift -= delta.width; | |
| 189 NSPoint origin = [view frame].origin; | |
| 190 origin.x += horizontalShift; | |
| 191 [view setFrameOrigin:origin]; | |
| 192 } | |
| 193 if (horizontalShift) { | |
| 194 NSView* view = [views objectAtIndex:1]; | |
| 195 NSSize delta = NSMakeSize(horizontalShift, 0.0); | |
| 196 [GTMUILocalizerAndLayoutTweaker | |
| 197 resizeViewWithoutAutoResizingSubViews:view | |
| 198 delta:delta]; | |
| 199 } | |
| 200 break; | |
| 201 } | |
| 202 default: | |
| 203 NOTREACHED(); | |
| 204 break; | |
| 205 } | |
| 206 | |
| 207 // If the label grew more then the views, the other views get an extra shift. | |
| 208 // Otherwise, move the label to its top is aligned with the other views. | |
| 209 CGFloat nonLabelShift = 0.0; | |
| 210 if (labelHeightChange > localVerticalShift) { | |
| 211 // Since the lable is taller, centering the other views looks best, just | |
| 212 // shift the views by 1/2 of the size difference. | |
| 213 nonLabelShift = (labelHeightChange - localVerticalShift) / 2.0; | |
| 214 } else { | |
| 215 NSPoint origin = [label frame].origin; | |
| 216 origin.y += localVerticalShift - labelHeightChange; | |
| 217 [label setFrameOrigin:origin]; | |
| 218 } | |
| 219 | |
| 220 // Apply the input shift requested along with any the shift from label being | |
| 221 // taller then the rest of the group. | |
| 222 for (NSView* view in views) { | |
| 223 NSPoint origin = [view frame].origin; | |
| 224 origin.y += verticalShift; | |
| 225 if (view != label) { | |
| 226 origin.y += nonLabelShift; | |
| 227 } | |
| 228 [view setFrameOrigin:origin]; | |
| 229 } | |
| 230 | |
| 231 // Return how much the group grew. | |
| 232 return localVerticalShift + nonLabelShift; | |
| 233 } | |
| 234 | |
| 66 } // namespace | 235 } // namespace | 
| 67 | 236 | 
| 68 //------------------------------------------------------------------------- | 237 //------------------------------------------------------------------------- | 
| 69 | 238 | 
| 70 @interface PreferencesWindowController(Private) | 239 @interface PreferencesWindowController(Private) | 
| 71 // Callback when preferences are changed. |prefName| is the name of the | 240 // Callback when preferences are changed. |prefName| is the name of the | 
| 72 // pref that has changed. | 241 // pref that has changed. | 
| 73 - (void)prefChanged:(std::wstring*)prefName; | 242 - (void)prefChanged:(std::wstring*)prefName; | 
| 74 // Record the user performed a certain action and save the preferences. | 243 // Record the user performed a certain action and save the preferences. | 
| 75 - (void)recordUserAction:(const wchar_t*)action; | 244 - (void)recordUserAction:(const wchar_t*)action; | 
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 171 [animation_ setDelegate:self]; | 340 [animation_ setDelegate:self]; | 
| 172 // The default duration is 0.5s, which actually feels slow in here, so speed | 341 // The default duration is 0.5s, which actually feels slow in here, so speed | 
| 173 // it up a bit. | 342 // it up a bit. | 
| 174 [animation_ setDuration:0.2]; | 343 [animation_ setDuration:0.2]; | 
| 175 [animation_ setAnimationBlockingMode:NSAnimationNonblocking]; | 344 [animation_ setAnimationBlockingMode:NSAnimationNonblocking]; | 
| 176 } | 345 } | 
| 177 return self; | 346 return self; | 
| 178 } | 347 } | 
| 179 | 348 | 
| 180 - (void)awakeFromNib { | 349 - (void)awakeFromNib { | 
| 181 NSRect underTheHoodFrame = [underTheHoodView_ frame]; | 350 | 
| 351 // Do runtime fixup of the "basics" and "personal stuff" pages for the | |
| 352 // strings. Work bottom up shifting views up as needed, and then resize the | |
| 353 // page. | |
| 354 CGFloat verticalShift = 0.0; | |
| 355 verticalShift += AutoSizeGroup(basicsGroupDefaultBrowser_, | |
| 356 kAutoSizeGroupBehaviorVerticalFirstToFit, | |
| 357 verticalShift); | |
| 358 verticalShift += AutoSizeGroup(basicsGroupSearchEngine_, | |
| 359 kAutoSizeGroupBehaviorHorizontalFirstGrows, | |
| 360 verticalShift); | |
| 361 verticalShift += AutoSizeGroup(basicsGroupToolbar_, | |
| 362 kAutoSizeGroupBehaviorVerticalToFit, | |
| 363 verticalShift); | |
| 364 verticalShift += AutoSizeGroup(basicsGroupHomePage_, | |
| 365 kAutoSizeGroupBehaviorVerticalToFit, | |
| 366 verticalShift); | |
| 367 verticalShift += AutoSizeGroup(basicsGroupStartup_, | |
| 368 kAutoSizeGroupBehaviorVerticalFirstToFit, | |
| 369 verticalShift); | |
| 370 [GTMUILocalizerAndLayoutTweaker | |
| 371 resizeViewWithoutAutoResizingSubViews:basicsView_ | |
| 372 delta:NSMakeSize(0.0, verticalShift)]; | |
| 373 verticalShift = 0.0; | |
| 
 
Mark Mentovai
2009/10/30 22:19:27
nit: blank line before doing the second pane.
 
 | |
| 374 verticalShift += AutoSizeGroup(personalStuffGroupThemes_, | |
| 375 kAutoSizeGroupBehaviorHorizontalToFit, | |
| 376 verticalShift); | |
| 377 verticalShift += AutoSizeGroup(personalStuffGroupBrowserData_, | |
| 378 kAutoSizeGroupBehaviorVerticalToFit, | |
| 379 verticalShift); | |
| 380 verticalShift += AutoSizeGroup(personalStuffGroupAutofill_, | |
| 381 kAutoSizeGroupBehaviorVerticalToFit, | |
| 382 verticalShift); | |
| 383 verticalShift += AutoSizeGroup(personalStuffGroupPasswords_, | |
| 384 kAutoSizeGroupBehaviorVerticalFirstToFit, | |
| 385 verticalShift); | |
| 386 [GTMUILocalizerAndLayoutTweaker | |
| 387 resizeViewWithoutAutoResizingSubViews:personalStuffView_ | |
| 388 delta:NSMakeSize(0.0, verticalShift)]; | |
| 182 | 389 | 
| 183 // Make sure the window is wide enough to fit the the widest view | 390 // Make sure the window is wide enough to fit the the widest view | 
| 391 NSRect underTheHoodFrame = [underTheHoodView_ frame]; | |
| 184 CGFloat widest = std::max(NSWidth([basicsView_ frame]), | 392 CGFloat widest = std::max(NSWidth([basicsView_ frame]), | 
| 185 NSWidth([personalStuffView_ frame])); | 393 NSWidth([personalStuffView_ frame])); | 
| 186 widest = std::max(widest, NSWidth(underTheHoodFrame)); | 394 widest = std::max(widest, NSWidth(underTheHoodFrame)); | 
| 187 NSWindow* prefsWindow = [self window]; | 395 NSWindow* prefsWindow = [self window]; | 
| 188 NSRect frame = [prefsWindow frame]; | 396 NSRect frame = [prefsWindow frame]; | 
| 189 frame.size.width = widest; | 397 frame.size.width = widest; | 
| 190 [prefsWindow setFrame:frame display:NO]; | 398 [prefsWindow setFrame:frame display:NO]; | 
| 191 | 399 | 
| 192 // The Under the Hood prefs is a scroller, it shouldn't get any border, so it | 400 // The Under the Hood prefs is a scroller, it shouldn't get any border, so it | 
| 193 // gets resized to the as wide as the window ends up. | 401 // gets resized to the as wide as the window ends up. | 
| 194 underTheHoodFrame.size.width = widest; | 402 underTheHoodFrame.size.width = widest; | 
| 195 [underTheHoodView_ setFrame:underTheHoodFrame]; | 403 [underTheHoodView_ setFrame:underTheHoodFrame]; | 
| 196 // Widen the Under the Hood content so things can rewrap | 404 // Widen the Under the Hood content so things can rewrap | 
| 197 NSSize advancedContentSize = [advancedView_ frame].size; | 405 NSSize advancedContentSize = [advancedView_ frame].size; | 
| 198 advancedContentSize.width = [advancedScroller_ contentSize].width; | 406 advancedContentSize.width = [advancedScroller_ contentSize].width; | 
| 199 [advancedView_ setFrameSize:advancedContentSize]; | 407 [advancedView_ setFrameSize:advancedContentSize]; | 
| 200 | 408 | 
| 201 // Put the advanced view into the scroller and scroll it to the top. | |
| 202 [advancedScroller_ setDocumentView:advancedView_]; | |
| 203 [advancedView_ scrollPoint:NSMakePoint(0, advancedContentSize.height)]; | |
| 204 | |
| 205 // Adjust the view origins so they show up centered. | 409 // Adjust the view origins so they show up centered. | 
| 206 CenterViewForWidth(basicsView_, widest); | 410 CenterViewForWidth(basicsView_, widest); | 
| 207 CenterViewForWidth(personalStuffView_, widest); | 411 CenterViewForWidth(personalStuffView_, widest); | 
| 208 CenterViewForWidth(underTheHoodView_, widest); | 412 CenterViewForWidth(underTheHoodView_, widest); | 
| 209 | 413 | 
| 210 // Ensure the "basics" is selected. | 414 // Put the advanced view into the scroller and scroll it to the top. | 
| 415 [advancedScroller_ setDocumentView:advancedView_]; | |
| 416 [advancedView_ scrollPoint:NSMakePoint(0, advancedContentSize.height)]; | |
| 417 | |
| 418 // Ensure the "basics" page is selected. | |
| 211 // TODO: change this to remember what's selected in a preference and restore | 419 // TODO: change this to remember what's selected in a preference and restore | 
| 212 // it. | 420 // it. | 
| 213 | |
| 214 NSToolbarItem* firstItem = [[toolbar_ items] objectAtIndex:0]; | 421 NSToolbarItem* firstItem = [[toolbar_ items] objectAtIndex:0]; | 
| 215 [self displayPreferenceViewForToolbarItem:firstItem animate:NO]; | 422 [self displayPreferenceViewForToolbarItem:firstItem animate:NO]; | 
| 216 [toolbar_ setSelectedItemIdentifier:[firstItem itemIdentifier]]; | 423 [toolbar_ setSelectedItemIdentifier:[firstItem itemIdentifier]]; | 
| 217 | 424 | 
| 218 // TODO(pinkerton): save/restore position based on prefs. | 425 // TODO(pinkerton): save/restore position based on prefs. | 
| 219 [[self window] center]; | 426 [[self window] center]; | 
| 220 } | 427 } | 
| 221 | 428 | 
| 222 - (void)dealloc { | 429 - (void)dealloc { | 
| 223 [customPagesSource_ removeObserver:self forKeyPath:@"customHomePages"]; | 430 [customPagesSource_ removeObserver:self forKeyPath:@"customHomePages"]; | 
| (...skipping 918 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1142 [[NSNotificationCenter defaultCenter] | 1349 [[NSNotificationCenter defaultCenter] | 
| 1143 postNotificationName:kUserDoneEditingPrefsNotification | 1350 postNotificationName:kUserDoneEditingPrefsNotification | 
| 1144 object:self]; | 1351 object:self]; | 
| 1145 } | 1352 } | 
| 1146 | 1353 | 
| 1147 - (void)controlTextDidEndEditing:(NSNotification*)notification { | 1354 - (void)controlTextDidEndEditing:(NSNotification*)notification { | 
| 1148 [customPagesSource_ validateURLs]; | 1355 [customPagesSource_ validateURLs]; | 
| 1149 } | 1356 } | 
| 1150 | 1357 | 
| 1151 @end | 1358 @end | 
| OLD | NEW |