OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/ui/cocoa/profiles/avatar_menu_bubble_controller.h" | 5 #import "chrome/browser/ui/cocoa/profiles/avatar_menu_bubble_controller.h" |
6 | 6 |
7 #include "base/mac/bundle_locations.h" | 7 #include "base/mac/bundle_locations.h" |
8 #include "base/mac/mac_util.h" | 8 #include "base/mac/mac_util.h" |
9 #include "base/strings/sys_string_conversions.h" | 9 #include "base/strings/sys_string_conversions.h" |
10 #include "chrome/browser/browser_process.h" | 10 #include "chrome/browser/browser_process.h" |
11 #include "chrome/browser/profiles/avatar_menu.h" | 11 #include "chrome/browser/profiles/avatar_menu.h" |
12 #include "chrome/browser/profiles/profile_info_cache.h" | 12 #include "chrome/browser/profiles/profile_info_cache.h" |
13 #include "chrome/browser/profiles/profile_manager.h" | 13 #include "chrome/browser/profiles/profile_manager.h" |
14 #include "chrome/browser/profiles/profile_metrics.h" | 14 #include "chrome/browser/profiles/profile_metrics.h" |
15 #include "chrome/browser/ui/browser.h" | 15 #include "chrome/browser/ui/browser.h" |
16 #include "chrome/browser/ui/browser_window.h" | 16 #include "chrome/browser/ui/browser_window.h" |
17 #import "chrome/browser/ui/cocoa/info_bubble_view.h" | 17 #import "chrome/browser/ui/cocoa/info_bubble_view.h" |
18 #import "chrome/browser/ui/cocoa/info_bubble_window.h" | 18 #import "chrome/browser/ui/cocoa/info_bubble_window.h" |
19 #include "grit/generated_resources.h" | 19 #include "grit/generated_resources.h" |
20 #include "grit/theme_resources.h" | 20 #include "grit/theme_resources.h" |
21 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTw
eaker.h" | 21 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTw
eaker.h" |
22 #import "ui/base/cocoa/controls/hyperlink_button_cell.h" | 22 #import "ui/base/cocoa/controls/hyperlink_button_cell.h" |
23 #import "ui/base/cocoa/cocoa_base_utils.h" | 23 #import "ui/base/cocoa/cocoa_base_utils.h" |
24 #include "ui/base/l10n/l10n_util_mac.h" | 24 #include "ui/base/l10n/l10n_util_mac.h" |
25 #include "ui/base/resource/resource_bundle.h" | 25 #include "ui/base/resource/resource_bundle.h" |
26 #include "ui/gfx/image/image.h" | 26 #include "ui/gfx/image/image.h" |
27 | 27 |
28 @interface AvatarMenuBubbleController (Private) | 28 @interface AvatarMenuBubbleController (Private) |
29 - (AvatarMenu*)menu; | 29 - (AvatarMenu*)menu; |
30 - (NSView*)configureManagedUserInformation:(CGFloat)width; | 30 - (NSView*)configureSupervisedUserInformation:(CGFloat)width; |
31 - (NSButton*)configureNewUserButton:(CGFloat)yOffset | 31 - (NSButton*)configureNewUserButton:(CGFloat)yOffset |
32 updateWidthAdjust:(CGFloat*)widthAdjust; | 32 updateWidthAdjust:(CGFloat*)widthAdjust; |
33 - (NSButton*)configureSwitchUserButton:(CGFloat)yOffset | 33 - (NSButton*)configureSwitchUserButton:(CGFloat)yOffset |
34 updateWidthAdjust:(CGFloat*)widthAdjust; | 34 updateWidthAdjust:(CGFloat*)widthAdjust; |
35 - (AvatarMenuItemController*)initAvatarItem:(int)itemIndex | 35 - (AvatarMenuItemController*)initAvatarItem:(int)itemIndex |
36 updateWidthAdjust:(CGFloat*)widthAdjust | 36 updateWidthAdjust:(CGFloat*)widthAdjust |
37 setYOffset:(CGFloat)yOffset; | 37 setYOffset:(CGFloat)yOffset; |
38 - (void)setWindowFrame:(CGFloat)yOffset widthAdjust:(CGFloat)width; | 38 - (void)setWindowFrame:(CGFloat)yOffset widthAdjust:(CGFloat)width; |
39 - (void)initMenuContents; | 39 - (void)initMenuContents; |
40 - (void)initManagedUserContents; | 40 - (void)initSupervisedUserContents; |
41 - (void)keyDown:(NSEvent*)theEvent; | 41 - (void)keyDown:(NSEvent*)theEvent; |
42 - (void)moveDown:(id)sender; | 42 - (void)moveDown:(id)sender; |
43 - (void)moveUp:(id)sender; | 43 - (void)moveUp:(id)sender; |
44 - (void)insertNewline:(id)sender; | 44 - (void)insertNewline:(id)sender; |
45 - (void)highlightNextItemByDelta:(NSInteger)delta; | 45 - (void)highlightNextItemByDelta:(NSInteger)delta; |
46 - (void)highlightItem:(AvatarMenuItemController*)newItem; | 46 - (void)highlightItem:(AvatarMenuItemController*)newItem; |
47 @end | 47 @end |
48 | 48 |
49 namespace { | 49 namespace { |
50 | 50 |
51 // Constants taken from the Windows/Views implementation at: | 51 // Constants taken from the Windows/Views implementation at: |
52 // chrome/browser/ui/views/avatar_menu_bubble_view.cc | 52 // chrome/browser/ui/views/avatar_menu_bubble_view.cc |
53 const CGFloat kBubbleMinWidth = 175; | 53 const CGFloat kBubbleMinWidth = 175; |
54 const CGFloat kBubbleMaxWidth = 800; | 54 const CGFloat kBubbleMaxWidth = 800; |
55 const CGFloat kMaxItemTextWidth = 200; | 55 const CGFloat kMaxItemTextWidth = 200; |
56 | 56 |
57 // Values derived from the XIB. | 57 // Values derived from the XIB. |
58 const CGFloat kVerticalSpacing = 10.0; | 58 const CGFloat kVerticalSpacing = 10.0; |
59 const CGFloat kLinkSpacing = 15.0; | 59 const CGFloat kLinkSpacing = 15.0; |
60 const CGFloat kLabelInset = 49.0; | 60 const CGFloat kLabelInset = 49.0; |
61 | 61 |
62 // The offset of the managed user information label and the "switch user" link. | 62 // The offset of the supervised user information label and the "switch user" |
63 const CGFloat kManagedUserSpacing = 26.0; | 63 // link. |
| 64 const CGFloat kSupervisedUserSpacing = 26.0; |
64 | 65 |
65 } // namespace | 66 } // namespace |
66 | 67 |
67 @implementation AvatarMenuBubbleController | 68 @implementation AvatarMenuBubbleController |
68 | 69 |
69 - (id)initWithBrowser:(Browser*)parentBrowser | 70 - (id)initWithBrowser:(Browser*)parentBrowser |
70 anchoredAt:(NSPoint)point { | 71 anchoredAt:(NSPoint)point { |
71 | 72 |
72 // Pass in a NULL observer. Rebuilding while the bubble is open will cause it | 73 // Pass in a NULL observer. Rebuilding while the bubble is open will cause it |
73 // to be positioned incorrectly. Since the bubble will be dismissed on losing | 74 // to be positioned incorrectly. Since the bubble will be dismissed on losing |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
188 [[itemView view] setFrameOrigin:NSMakePoint(0, yOffset)]; | 189 [[itemView view] setFrameOrigin:NSMakePoint(0, yOffset)]; |
189 | 190 |
190 // Keep track of the view controller. | 191 // Keep track of the view controller. |
191 [items_ addObject:itemView]; | 192 [items_ addObject:itemView]; |
192 return itemView; | 193 return itemView; |
193 } | 194 } |
194 | 195 |
195 - (void)setWindowFrame:(CGFloat)yOffset widthAdjust:(CGFloat)width { | 196 - (void)setWindowFrame:(CGFloat)yOffset widthAdjust:(CGFloat)width { |
196 // Set the window frame, clamping the width at a sensible max. | 197 // Set the window frame, clamping the width at a sensible max. |
197 NSRect frame = [[self window] frame]; | 198 NSRect frame = [[self window] frame]; |
198 // Adjust the origin after we have switched from the managed user menu to the | 199 // Adjust the origin after we have switched from the supervised user menu to |
199 // regular menu. | 200 // the regular menu. |
200 CGFloat newWidth = std::min(kBubbleMinWidth + width, kBubbleMaxWidth); | 201 CGFloat newWidth = std::min(kBubbleMinWidth + width, kBubbleMaxWidth); |
201 if (expanded_) { | 202 if (expanded_) { |
202 frame.origin.x += frame.size.width - newWidth; | 203 frame.origin.x += frame.size.width - newWidth; |
203 frame.origin.y += frame.size.height - yOffset; | 204 frame.origin.y += frame.size.height - yOffset; |
204 } | 205 } |
205 frame.size.height = yOffset; | 206 frame.size.height = yOffset; |
206 frame.size.width = newWidth; | 207 frame.size.width = newWidth; |
207 [[self window] setFrame:frame display:YES]; | 208 [[self window] setFrame:frame display:YES]; |
208 } | 209 } |
209 | 210 |
(...skipping 29 matching lines...) Expand all Loading... |
239 updateWidthAdjust:&widthAdjust | 240 updateWidthAdjust:&widthAdjust |
240 setYOffset:yOffset]; | 241 setYOffset:yOffset]; |
241 [contentView addSubview:[itemView view]]; | 242 [contentView addSubview:[itemView view]]; |
242 yOffset += NSHeight([[itemView view] frame]); | 243 yOffset += NSHeight([[itemView view] frame]); |
243 } | 244 } |
244 | 245 |
245 yOffset += kVerticalSpacing * 1.5; | 246 yOffset += kVerticalSpacing * 1.5; |
246 [self setWindowFrame:yOffset widthAdjust:widthAdjust]; | 247 [self setWindowFrame:yOffset widthAdjust:widthAdjust]; |
247 } | 248 } |
248 | 249 |
249 - (void)initManagedUserContents { | 250 - (void)initSupervisedUserContents { |
250 NSView* contentView = [[self window] contentView]; | 251 NSView* contentView = [[self window] contentView]; |
251 | 252 |
252 // |yOffset| is the next position at which to draw in contentView coordinates. | 253 // |yOffset| is the next position at which to draw in contentView coordinates. |
253 // Use a little more vertical spacing because the items have padding built- | 254 // Use a little more vertical spacing because the items have padding built- |
254 // into the xib, and this gives a little more space to visually match. | 255 // into the xib, and this gives a little more space to visually match. |
255 CGFloat yOffset = kLinkSpacing; | 256 CGFloat yOffset = kLinkSpacing; |
256 CGFloat widthAdjust = 0; | 257 CGFloat widthAdjust = 0; |
257 | 258 |
258 // Since drawing happens bottom-up, start with the "Switch User" link. | 259 // Since drawing happens bottom-up, start with the "Switch User" link. |
259 NSButton* newButton = | 260 NSButton* newButton = |
260 [self configureSwitchUserButton:yOffset updateWidthAdjust:&widthAdjust]; | 261 [self configureSwitchUserButton:yOffset updateWidthAdjust:&widthAdjust]; |
261 [contentView addSubview:newButton]; | 262 [contentView addSubview:newButton]; |
262 yOffset += NSHeight([newButton frame]) + kVerticalSpacing; | 263 yOffset += NSHeight([newButton frame]) + kVerticalSpacing; |
263 | 264 |
264 NSBox* separator = [self separatorWithFrame: | 265 NSBox* separator = [self separatorWithFrame: |
265 NSMakeRect(10, yOffset, NSWidth([contentView frame]) - 20, 0)]; | 266 NSMakeRect(10, yOffset, NSWidth([contentView frame]) - 20, 0)]; |
266 [separator setAutoresizingMask:NSViewWidthSizable]; | 267 [separator setAutoresizingMask:NSViewWidthSizable]; |
267 [contentView addSubview:separator]; | 268 [contentView addSubview:separator]; |
268 | 269 |
269 yOffset += NSHeight([separator frame]) + kVerticalSpacing; | 270 yOffset += NSHeight([separator frame]) + kVerticalSpacing; |
270 | 271 |
271 // First init the active profile in order to determine the required width. We | 272 // First init the active profile in order to determine the required width. We |
272 // will have to adjust its frame later after adding general information about | 273 // will have to adjust its frame later after adding general information about |
273 // managed users. | 274 // supervised users. |
274 AvatarMenuItemController* itemView = | 275 AvatarMenuItemController* itemView = |
275 [self initAvatarItem:menu_->GetActiveProfileIndex() | 276 [self initAvatarItem:menu_->GetActiveProfileIndex() |
276 updateWidthAdjust:&widthAdjust | 277 updateWidthAdjust:&widthAdjust |
277 setYOffset:yOffset]; | 278 setYOffset:yOffset]; |
278 | 279 |
279 // Don't increase the width too much (the total size should be at most | 280 // Don't increase the width too much (the total size should be at most |
280 // |kBubbleMaxWidth|). | 281 // |kBubbleMaxWidth|). |
281 widthAdjust = std::min(widthAdjust, kBubbleMaxWidth - kBubbleMinWidth); | 282 widthAdjust = std::min(widthAdjust, kBubbleMaxWidth - kBubbleMinWidth); |
282 CGFloat newWidth = kBubbleMinWidth + widthAdjust; | 283 CGFloat newWidth = kBubbleMinWidth + widthAdjust; |
283 | 284 |
284 // Add general information about managed users. | 285 // Add general information about supervised users. |
285 NSView* info = [self configureManagedUserInformation:newWidth]; | 286 NSView* info = [self configureSupervisedUserInformation:newWidth]; |
286 [info setFrameOrigin:NSMakePoint(0, yOffset)]; | 287 [info setFrameOrigin:NSMakePoint(0, yOffset)]; |
287 [contentView addSubview:info]; | 288 [contentView addSubview:info]; |
288 yOffset += NSHeight([info frame]) + kVerticalSpacing; | 289 yOffset += NSHeight([info frame]) + kVerticalSpacing; |
289 | 290 |
290 separator = [self separatorWithFrame: | 291 separator = [self separatorWithFrame: |
291 NSMakeRect(10, yOffset, NSWidth([contentView frame]) - 20, 0)]; | 292 NSMakeRect(10, yOffset, NSWidth([contentView frame]) - 20, 0)]; |
292 [separator setAutoresizingMask:NSViewWidthSizable]; | 293 [separator setAutoresizingMask:NSViewWidthSizable]; |
293 [contentView addSubview:separator]; | 294 [contentView addSubview:separator]; |
294 | 295 |
295 yOffset += NSHeight([separator frame]); | 296 yOffset += NSHeight([separator frame]); |
296 | 297 |
297 // Now update the frame of the active profile and add it. | 298 // Now update the frame of the active profile and add it. |
298 NSRect frame = [[itemView view] frame]; | 299 NSRect frame = [[itemView view] frame]; |
299 frame.origin.y = yOffset; | 300 frame.origin.y = yOffset; |
300 [[itemView view] setFrame:frame]; | 301 [[itemView view] setFrame:frame]; |
301 [contentView addSubview:[itemView view]]; | 302 [contentView addSubview:[itemView view]]; |
302 | 303 |
303 yOffset += NSHeight(frame) + kVerticalSpacing * 1.5; | 304 yOffset += NSHeight(frame) + kVerticalSpacing * 1.5; |
304 [self setWindowFrame:yOffset widthAdjust:widthAdjust]; | 305 [self setWindowFrame:yOffset widthAdjust:widthAdjust]; |
305 } | 306 } |
306 | 307 |
307 - (void)performLayout { | 308 - (void)performLayout { |
308 NSView* contentView = [[self window] contentView]; | 309 NSView* contentView = [[self window] contentView]; |
309 | 310 |
310 // Reset the array of controllers and remove all the views. | 311 // Reset the array of controllers and remove all the views. |
311 items_.reset([[NSMutableArray alloc] init]); | 312 items_.reset([[NSMutableArray alloc] init]); |
312 [contentView setSubviews:[NSArray array]]; | 313 [contentView setSubviews:[NSArray array]]; |
313 | 314 |
314 if (menu_->GetManagedUserInformation().empty() || expanded_) | 315 if (menu_->GetSupervisedUserInformation().empty() || expanded_) |
315 [self initMenuContents]; | 316 [self initMenuContents]; |
316 else | 317 else |
317 [self initManagedUserContents]; | 318 [self initSupervisedUserContents]; |
318 } | 319 } |
319 | 320 |
320 - (NSView*)configureManagedUserInformation:(CGFloat)width { | 321 - (NSView*)configureSupervisedUserInformation:(CGFloat)width { |
321 base::scoped_nsobject<NSView> container( | 322 base::scoped_nsobject<NSView> container( |
322 [[NSView alloc] initWithFrame:NSZeroRect]); | 323 [[NSView alloc] initWithFrame:NSZeroRect]); |
323 | 324 |
324 // Add the limited user icon on the left side of the information TextView. | 325 // Add the limited user icon on the left side of the information TextView. |
325 base::scoped_nsobject<NSImageView> iconView( | 326 base::scoped_nsobject<NSImageView> iconView( |
326 [[NSImageView alloc] initWithFrame:NSMakeRect(5, 0, 16, 16)]); | 327 [[NSImageView alloc] initWithFrame:NSMakeRect(5, 0, 16, 16)]); |
327 [iconView setImage:menu_->GetManagedUserIcon().ToNSImage()]; | 328 [iconView setImage:menu_->GetSupervisedUserIcon().ToNSImage()]; |
328 [container addSubview:iconView]; | 329 [container addSubview:iconView]; |
329 | 330 |
330 NSString* info = | 331 NSString* info = |
331 base::SysUTF16ToNSString(menu_->GetManagedUserInformation()); | 332 base::SysUTF16ToNSString(menu_->GetSupervisedUserInformation()); |
332 NSDictionary* attributes = | 333 NSDictionary* attributes = |
333 @{ NSFontAttributeName : [NSFont labelFontOfSize:12] }; | 334 @{ NSFontAttributeName : [NSFont labelFontOfSize:12] }; |
334 base::scoped_nsobject<NSAttributedString> attrString( | 335 base::scoped_nsobject<NSAttributedString> attrString( |
335 [[NSAttributedString alloc] initWithString:info attributes:attributes]); | 336 [[NSAttributedString alloc] initWithString:info attributes:attributes]); |
336 base::scoped_nsobject<NSTextView> label( | 337 base::scoped_nsobject<NSTextView> label( |
337 [[NSTextView alloc] initWithFrame:NSMakeRect( | 338 [[NSTextView alloc] initWithFrame:NSMakeRect( |
338 kManagedUserSpacing, 0, width - kManagedUserSpacing - 5, 0)]); | 339 kSupervisedUserSpacing, 0, width - kSupervisedUserSpacing - 5, 0)]); |
339 [[label textStorage] setAttributedString:attrString]; | 340 [[label textStorage] setAttributedString:attrString]; |
340 [label setHorizontallyResizable:NO]; | 341 [label setHorizontallyResizable:NO]; |
341 [label setEditable:NO]; | 342 [label setEditable:NO]; |
342 [label sizeToFit]; | 343 [label sizeToFit]; |
343 [container addSubview:label]; | 344 [container addSubview:label]; |
344 [container setFrameSize:NSMakeSize(width, NSHeight([label frame]))]; | 345 [container setFrameSize:NSMakeSize(width, NSHeight([label frame]))]; |
345 | 346 |
346 // Reposition the limited user icon so that it is on top. | 347 // Reposition the limited user icon so that it is on top. |
347 [iconView setFrameOrigin:NSMakePoint(5, NSHeight([label frame]) - 16)]; | 348 [iconView setFrameOrigin:NSMakePoint(5, NSHeight([label frame]) - 16)]; |
348 return container.autorelease(); | 349 return container.autorelease(); |
(...skipping 14 matching lines...) Expand all Loading... |
363 NSSize delta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:newButton]; | 364 NSSize delta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:newButton]; |
364 if (delta.width > 0) | 365 if (delta.width > 0) |
365 *widthAdjust = std::max(*widthAdjust, delta.width); | 366 *widthAdjust = std::max(*widthAdjust, delta.width); |
366 return newButton.autorelease(); | 367 return newButton.autorelease(); |
367 } | 368 } |
368 | 369 |
369 - (NSButton*)configureSwitchUserButton:(CGFloat)yOffset | 370 - (NSButton*)configureSwitchUserButton:(CGFloat)yOffset |
370 updateWidthAdjust:(CGFloat*)widthAdjust { | 371 updateWidthAdjust:(CGFloat*)widthAdjust { |
371 base::scoped_nsobject<NSButton> newButton( | 372 base::scoped_nsobject<NSButton> newButton( |
372 [[NSButton alloc] initWithFrame:NSMakeRect( | 373 [[NSButton alloc] initWithFrame:NSMakeRect( |
373 kManagedUserSpacing, yOffset, kBubbleMinWidth - kLabelInset, 16)]); | 374 kSupervisedUserSpacing, yOffset, kBubbleMinWidth - kLabelInset, 16)]); |
374 base::scoped_nsobject<HyperlinkButtonCell> buttonCell( | 375 base::scoped_nsobject<HyperlinkButtonCell> buttonCell( |
375 [[HyperlinkButtonCell alloc] initTextCell: | 376 [[HyperlinkButtonCell alloc] initTextCell: |
376 l10n_util::GetNSString(IDS_PROFILES_SWITCH_PROFILE_LINK)]); | 377 l10n_util::GetNSString(IDS_PROFILES_SWITCH_PROFILE_LINK)]); |
377 [newButton setCell:buttonCell.get()]; | 378 [newButton setCell:buttonCell.get()]; |
378 [newButton setFont:[NSFont labelFontOfSize:12.0]]; | 379 [newButton setFont:[NSFont labelFontOfSize:12.0]]; |
379 [newButton setBezelStyle:NSRegularSquareBezelStyle]; | 380 [newButton setBezelStyle:NSRegularSquareBezelStyle]; |
380 [newButton setTarget:self]; | 381 [newButton setTarget:self]; |
381 [newButton setAction:@selector(switchProfile:)]; | 382 [newButton setAction:@selector(switchProfile:)]; |
382 NSSize delta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:newButton]; | 383 NSSize delta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:newButton]; |
383 if (delta.width > 0) | 384 if (delta.width > 0) |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
710 - (BOOL)accessibilityIsIgnored { | 711 - (BOOL)accessibilityIsIgnored { |
711 return YES; | 712 return YES; |
712 } | 713 } |
713 @end | 714 @end |
714 | 715 |
715 @implementation AccessibilityIgnoredTextFieldCell | 716 @implementation AccessibilityIgnoredTextFieldCell |
716 - (BOOL)accessibilityIsIgnored { | 717 - (BOOL)accessibilityIsIgnored { |
717 return YES; | 718 return YES; |
718 } | 719 } |
719 @end | 720 @end |
OLD | NEW |