Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4999)

Unified Diff: chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.mm

Issue 15932008: Add managed user avatar menu for mac. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add unit test. Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.mm
diff --git a/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.mm b/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.mm
index 071852409383bbe5f4fef87a5fcb1bd4eb3528dd..28486eee57bf033633367df5058be2a0d4f17951 100644
--- a/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.mm
@@ -26,7 +26,17 @@
@interface AvatarMenuBubbleController (Private)
- (AvatarMenuModel*)model;
-- (NSButton*)configureNewUserButton:(CGFloat)yOffset;
+- (NSTextView*)configureManagedUserInformation:(CGFloat)yOffset;
+- (NSButton*)configureNewUserButton:(CGFloat)yOffset
+ updateWidthAdjust:(CGFloat*)widthAdjust;
+- (NSButton*)configureSwitchUserButton:(CGFloat)yOffset
+ updateWidthAdjust:(CGFloat*)widthAdjust;
+- (AvatarMenuItemController*)initAvatarItem:(int)itemIndex
+ updateWidthAdjust:(CGFloat*)widthAdjust
+ setYOffset:(CGFloat)yOffset;
+- (void)setWindowFrame:(CGFloat)yOffset widthAdjust:(CGFloat)width;
+- (void)initMenuContents;
+- (void)initManagedUserContents;
- (void)keyDown:(NSEvent*)theEvent;
- (void)moveDown:(id)sender;
- (void)moveUp:(id)sender;
@@ -84,6 +94,11 @@ const CGFloat kLabelInset = 49.0;
model_->EditProfile([sender modelIndex]);
}
+- (IBAction)switchProfile:(id)sender {
+ expanded_ = YES;
+ [self performLayout];
+}
+
// Private /////////////////////////////////////////////////////////////////////
- (id)initWithModel:(AvatarMenuModel*)model
@@ -115,22 +130,77 @@ const CGFloat kLabelInset = 49.0;
return self;
}
-- (void)performLayout {
+- (AvatarMenuItemController*)initAvatarItem:(int)itemIndex
+ updateWidthAdjust:(CGFloat*)widthAdjust
+ setYOffset:(CGFloat)yOffset {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- NSView* contentView = [[self window] contentView];
+ const AvatarMenuModel::Item& item = model_->GetItemAt(itemIndex);
+ // Create the item view controller. Autorelease it because it will be owned
+ // by the |items_| array.
+ AvatarMenuItemController* itemView =
+ [[[AvatarMenuItemController alloc] initWithModelIndex:item.model_index
+ menuController:self] autorelease];
+ itemView.iconView.image = item.icon.ToNSImage();
+
+ // Adjust the name field to fit the string. If it overflows, record by how
+ // much the window needs to grow to accomodate the new size of the field.
+ NSTextField* nameField = itemView.nameField;
+ nameField.stringValue = base::SysUTF16ToNSString(item.name);
+ NSSize delta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:nameField];
+ if (delta.width > 0)
+ *widthAdjust = std::max(*widthAdjust, delta.width);
+
+ // Repeat for the sync state/email.
+ NSTextField* emailField = itemView.emailField;
+ emailField.stringValue = base::SysUTF16ToNSString(item.sync_state);
+ delta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:emailField];
+ if (delta.width > 0)
+ *widthAdjust = std::max(*widthAdjust, delta.width);
+
+ if (!item.active) {
+ // In the inactive case, hide additional UI.
+ [itemView.activeView setHidden:YES];
+ [itemView.editButton setHidden:YES];
+ } else {
+ // Otherwise, set up the edit button and its three interaction states.
+ itemView.activeView.image =
+ rb.GetImageNamed(IDR_PROFILE_SELECTED).ToNSImage();
+ }
- // Reset the array of controllers and remove all the views.
- items_.reset([[NSMutableArray alloc] init]);
- [contentView setSubviews:[NSArray array]];
+ // Add the item to the content view.
+ [[itemView view] setFrameOrigin:NSMakePoint(0, yOffset)];
+
+ // Keep track of the view controller.
+ [items_ addObject:itemView];
+ return itemView;
+}
+
+- (void)setWindowFrame:(CGFloat)yOffset widthAdjust:(CGFloat)width {
+ // Set the window frame, clamping the width at a sensible max.
+ NSRect frame = [[self window] frame];
+ // Adjust the origin after we have switched from the managed user menu to the
+ // regular menu.
+ if (expanded_)
+ frame.origin.y += frame.size.height - yOffset;
+ frame.size.height = yOffset;
+ frame.size.width = kBubbleMinWidth + width;
+ frame.size.width = std::min(NSWidth(frame), kBubbleMaxWidth);
+ [[self window] setFrame:frame display:YES];
+}
+
+- (void)initMenuContents {
+ NSView* contentView = [[self window] contentView];
// |yOffset| is the next position at which to draw in contentView coordinates.
// Use a little more vertical spacing because the items have padding built-
// into the xib, and this gives a little more space to visually match.
CGFloat yOffset = kLinkSpacing;
+ CGFloat widthAdjust = 0;
if (model_->ShouldShowAddNewProfileLink()) {
// Since drawing happens bottom-up, start with the "New User" link.
- NSButton* newButton = [self configureNewUserButton:yOffset];
+ NSButton* newButton =
+ [self configureNewUserButton:yOffset updateWidthAdjust:&widthAdjust];
[contentView addSubview:newButton];
yOffset += NSHeight([newButton frame]) + kVerticalSpacing;
@@ -145,65 +215,111 @@ const CGFloat kLabelInset = 49.0;
}
// Loop over the profiles in reverse, constructing the menu items.
- CGFloat widthAdjust = 0;
for (int i = model_->GetNumberOfItems() - 1; i >= 0; --i) {
- const AvatarMenuModel::Item& item = model_->GetItemAt(i);
-
- // Create the item view controller. Autorelease it because it will be owned
- // by the |items_| array.
- AvatarMenuItemController* itemView =
- [[[AvatarMenuItemController alloc] initWithModelIndex:item.model_index
- menuController:self] autorelease];
- itemView.iconView.image = item.icon.ToNSImage();
-
- // Adjust the name field to fit the string. If it overflows, record by how
- // much the window needs to grow to accomodate the new size of the field.
- NSTextField* nameField = itemView.nameField;
- nameField.stringValue = base::SysUTF16ToNSString(item.name);
- NSSize delta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:nameField];
- if (delta.width > 0)
- widthAdjust = std::max(widthAdjust, delta.width);
-
- // Repeat for the sync state/email.
- NSTextField* emailField = itemView.emailField;
- emailField.stringValue = base::SysUTF16ToNSString(item.sync_state);
- delta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:emailField];
- if (delta.width > 0)
- widthAdjust = std::max(widthAdjust, delta.width);
-
- if (!item.active) {
- // In the inactive case, hide additional UI.
- [itemView.activeView setHidden:YES];
- [itemView.editButton setHidden:YES];
- } else {
- // Otherwise, set up the edit button and its three interaction states.
- itemView.activeView.image =
- rb.GetImageNamed(IDR_PROFILE_SELECTED).ToNSImage();
- }
-
- // Add the item to the content view.
- [[itemView view] setFrameOrigin:NSMakePoint(0, yOffset)];
+ AvatarMenuItemController* itemView = [self initAvatarItem:i
+ updateWidthAdjust:&widthAdjust
+ setYOffset:yOffset];
[contentView addSubview:[itemView view]];
yOffset += NSHeight([[itemView view] frame]);
-
- // Keep track of the view controller.
- [items_ addObject:itemView];
}
yOffset += kVerticalSpacing * 1.5;
+ [self setWindowFrame:yOffset widthAdjust:widthAdjust];
+}
- // Set the window frame, clamping the width at a sensible max.
- NSRect frame = [[self window] frame];
- frame.size.height = yOffset;
- frame.size.width = kBubbleMinWidth + widthAdjust;
- frame.size.width = std::min(NSWidth(frame), kBubbleMaxWidth);
- [[self window] setFrame:frame display:YES];
+- (void)initManagedUserContents {
+ NSView* contentView = [[self window] contentView];
+
+ // |yOffset| is the next position at which to draw in contentView coordinates.
+ // Use a little more vertical spacing because the items have padding built-
+ // into the xib, and this gives a little more space to visually match.
+ CGFloat yOffset = kLinkSpacing;
+ CGFloat widthAdjust = 0;
+
+ // Since drawing happens bottom-up, start with the "Switch User" link.
+ NSButton* newButton =
+ [self configureSwitchUserButton:yOffset updateWidthAdjust:&widthAdjust];
+ [contentView addSubview:newButton];
+ yOffset += NSHeight([newButton frame]) + kVerticalSpacing;
+
+ NSBox* separator = [self separatorWithFrame:
+ NSMakeRect(10, yOffset, NSWidth([contentView frame]) - 20, 0)];
+ [separator setAutoresizingMask:NSViewWidthSizable];
+ [contentView addSubview:separator];
+
+ yOffset += NSHeight([separator frame]) + kVerticalSpacing;
+
+ // First init the active profile in order to determine the required width. We
+ // will have to adjust its frame later after adding general information about
+ // managed users.
+ AvatarMenuItemController* itemView =
+ [self initAvatarItem:model_->GetActiveProfileIndex()
+ updateWidthAdjust:&widthAdjust
+ setYOffset:yOffset];
+
+ // Don't increase the width too much (the total size should be at most
+ // |kBubbleMaxWidth|).
+ widthAdjust = std::min(widthAdjust, kBubbleMaxWidth - kBubbleMinWidth);
+ CGFloat newWidth = kBubbleMinWidth + widthAdjust;
+
+ // Add general information about managed users.
+ NSTextView* info = [self configureManagedUserInformation:yOffset
+ setWidth:newWidth];
+ [contentView addSubview:info];
+ yOffset += NSHeight([info frame]) + kVerticalSpacing;
+
+ separator = [self separatorWithFrame:
+ NSMakeRect(10, yOffset, NSWidth([contentView frame]) - 20, 0)];
+ [separator setAutoresizingMask:NSViewWidthSizable];
+ [contentView addSubview:separator];
+
+ yOffset += NSHeight([separator frame]);
+
+ // Now update the frame of the active profile and add it.
+ NSRect frame = [[itemView view] frame];
+ frame.origin.y = yOffset;
+ [[itemView view] setFrame:frame];
+ [contentView addSubview:[itemView view]];
+
+ yOffset += NSHeight(frame) + kVerticalSpacing * 1.5;
+ [self setWindowFrame:yOffset widthAdjust:widthAdjust];
}
-- (NSButton*)configureNewUserButton:(CGFloat)yOffset {
+- (void)performLayout {
+ NSView* contentView = [[self window] contentView];
+
+ // Reset the array of controllers and remove all the views.
+ items_.reset([[NSMutableArray alloc] init]);
+ [contentView setSubviews:[NSArray array]];
+
+ if (model_->GetManagedUserInformation().empty() || expanded_)
+ [self initMenuContents];
+ else
+ [self initManagedUserContents];
+}
+
+- (NSTextView*)configureManagedUserInformation:(CGFloat)yOffset
+ setWidth:(CGFloat)width {
+ NSString* info =
+ base::SysUTF16ToNSString(model_->GetManagedUserInformation());
+ scoped_nsobject<NSAttributedString> attrString(
+ [[NSAttributedString alloc] initWithString:info attributes:nil]);
+ NSTextView* label =
+ [[[NSTextView alloc] initWithFrame:
+ NSMakeRect(5, yOffset, width - 10, 0)] autorelease];
+ [label setFont:[NSFont labelFontOfSize:12.0]];
+ [[label textStorage] setAttributedString:attrString];
+ [label setHorizontallyResizable:NO];
+ [label setEditable:NO];
+ [label sizeToFit];
+ return label;
+}
+
+- (NSButton*)configureNewUserButton:(CGFloat)yOffset
+ updateWidthAdjust:(CGFloat*)widthAdjust {
scoped_nsobject<NSButton> newButton(
- [[NSButton alloc] initWithFrame:NSMakeRect(kLabelInset, yOffset,
- 90, 16)]);
+ [[NSButton alloc] initWithFrame:NSMakeRect(
+ kLabelInset, yOffset, kBubbleMinWidth - kLabelInset, 16)]);
scoped_nsobject<HyperlinkButtonCell> buttonCell(
[[HyperlinkButtonCell alloc] initTextCell:
l10n_util::GetNSString(IDS_PROFILES_CREATE_NEW_PROFILE_LINK)]);
@@ -212,8 +328,29 @@ const CGFloat kLabelInset = 49.0;
[newButton setBezelStyle:NSRegularSquareBezelStyle];
[newButton setTarget:self];
[newButton setAction:@selector(newProfile:)];
- [GTMUILocalizerAndLayoutTweaker sizeToFitView:newButton];
- return [newButton.release() autorelease];
+ NSSize delta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:newButton];
+ if (delta.width > 0)
+ *widthAdjust = std::max(*widthAdjust, delta.width);
+ return newButton.autorelease();
+}
+
+- (NSButton*)configureSwitchUserButton:(CGFloat)yOffset
+ updateWidthAdjust:(CGFloat*)widthAdjust {
+ scoped_nsobject<NSButton> newButton(
+ [[NSButton alloc] initWithFrame:NSMakeRect(
+ kLabelInset, yOffset, kBubbleMinWidth - kLabelInset, 16)]);
+ scoped_nsobject<HyperlinkButtonCell> buttonCell(
+ [[HyperlinkButtonCell alloc] initTextCell:
+ l10n_util::GetNSString(IDS_PROFILES_SWITCH_PROFILE_LINK)]);
+ [newButton setCell:buttonCell.get()];
+ [newButton setFont:[NSFont labelFontOfSize:12.0]];
+ [newButton setBezelStyle:NSRegularSquareBezelStyle];
+ [newButton setTarget:self];
+ [newButton setAction:@selector(switchProfile:)];
+ NSSize delta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:newButton];
+ if (delta.width > 0)
+ *widthAdjust = std::max(*widthAdjust, delta.width);
+ return newButton.autorelease();
}
- (NSMutableArray*)items {
« no previous file with comments | « chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.h ('k') | chrome/browser/ui/cocoa/browser_window_controller.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698