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