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

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

Issue 229163004: [Mac] Move profile related UI from cocoa/browser to cocoa/profiles (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: oops forgot a comment Created 6 years, 8 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/profile_chooser_controller.mm
diff --git a/chrome/browser/ui/cocoa/browser/profile_chooser_controller.mm b/chrome/browser/ui/cocoa/browser/profile_chooser_controller.mm
deleted file mode 100644
index 0c9e0f44e77fa4b7c913f092879c5b96e76c5ae9..0000000000000000000000000000000000000000
--- a/chrome/browser/ui/cocoa/browser/profile_chooser_controller.mm
+++ /dev/null
@@ -1,1383 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/ui/cocoa/browser/profile_chooser_controller.h"
-
-#include "base/mac/bundle_locations.h"
-#include "base/prefs/pref_service.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/lifetime/application_lifetime.h"
-#include "chrome/browser/profiles/avatar_menu.h"
-#include "chrome/browser/profiles/avatar_menu_observer.h"
-#include "chrome/browser/profiles/profile_info_cache.h"
-#include "chrome/browser/profiles/profile_info_util.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/profiles/profile_metrics.h"
-#include "chrome/browser/profiles/profile_window.h"
-#include "chrome/browser/profiles/profiles_state.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
-#include "chrome/browser/signin/signin_promo.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_dialogs.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/chrome_style.h"
-#import "chrome/browser/ui/cocoa/info_bubble_view.h"
-#import "chrome/browser/ui/cocoa/info_bubble_window.h"
-#import "chrome/browser/ui/cocoa/user_manager_mac.h"
-#include "chrome/browser/ui/singleton_tabs.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/profile_management_switches.h"
-#include "chrome/common/url_constants.h"
-#include "components/signin/core/browser/mutable_profile_oauth2_token_service.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
-#include "components/signin/core/browser/signin_manager.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
-#include "google_apis/gaia/oauth2_token_service.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-#import "ui/base/cocoa/cocoa_base_utils.h"
-#import "ui/base/cocoa/controls/blue_label_button.h"
-#import "ui/base/cocoa/controls/hyperlink_button_cell.h"
-#import "ui/base/cocoa/hover_image_button.h"
-#include "ui/base/cocoa/window_size_constants.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/text_elider.h"
-#include "ui/native_theme/native_theme.h"
-
-namespace {
-
-// Constants taken from the Windows/Views implementation at:
-// chrome/browser/ui/views/profile_chooser_view.cc
-const int kLargeImageSide = 64;
-const int kSmallImageSide = 32;
-const CGFloat kFixedMenuWidth = 250;
-
-const CGFloat kVerticalSpacing = 20.0;
-const CGFloat kSmallVerticalSpacing = 10.0;
-const CGFloat kHorizontalSpacing = 20.0;
-const CGFloat kTitleFontSize = 15.0;
-const CGFloat kTextFontSize = 12.0;
-const CGFloat kProfileButtonHeight = 30;
-const int kOverlayHeight = 20; // Height of the "Change" avatar photo overlay.
-const int kBezelThickness = 3; // Width of the bezel on an NSButton.
-const int kImageTitleSpacing = 10;
-const int kBlueButtonHeight = 30;
-
-// Fixed size for embedded sign in pages as defined in Gaia.
-const CGFloat kFixedGaiaViewWidth = 360;
-const CGFloat kFixedGaiaViewHeight = 400;
-
-// Fixed size for the account removal view.
-const CGFloat kFixedAccountRemovalViewWidth = 280;
-
-// Maximum number of times to show the tutorial in the profile avatar bubble.
-const int kProfileAvatarTutorialShowMax = 5;
-
-// The tag number for the primary account.
-const int kPrimaryProfileTag = -1;
-
-gfx::Image CreateProfileImage(const gfx::Image& icon, int imageSize) {
- return profiles::GetSizedAvatarIconWithBorder(
- icon, true /* image is a square */,
- imageSize + profiles::kAvatarIconPadding,
- imageSize + profiles::kAvatarIconPadding);
-}
-
-// Updates the window size and position.
-void SetWindowSize(NSWindow* window, NSSize size) {
- NSRect frame = [window frame];
- frame.origin.x += frame.size.width - size.width;
- frame.origin.y += frame.size.height - size.height;
- frame.size = size;
- [window setFrame:frame display:YES];
-}
-
-NSString* ElideEmail(const std::string& email, CGFloat width) {
- base::string16 elidedEmail = gfx::ElideEmail(
- base::UTF8ToUTF16(email),
- ui::ResourceBundle::GetSharedInstance().GetFontList(
- ui::ResourceBundle::BaseFont),
- width);
- return base::SysUTF16ToNSString(elidedEmail);
-}
-
-// Builds a label with the given |title| anchored at |frame_origin|. Sets the
-// text color and background color to the given colors if not null.
-NSTextField* BuildLabel(NSString* title,
- NSPoint frame_origin,
- NSColor* background_color,
- NSColor* text_color) {
- base::scoped_nsobject<NSTextField> label(
- [[NSTextField alloc] initWithFrame:NSZeroRect]);
- [label setStringValue:title];
- [label setEditable:NO];
- [label setAlignment:NSLeftTextAlignment];
- [label setBezeled:NO];
- [label setFont:[NSFont labelFontOfSize:kTextFontSize]];
- [label setFrameOrigin:frame_origin];
- [label sizeToFit];
-
- if (background_color) {
- DCHECK(text_color);
- [[label cell] setBackgroundColor:background_color];
- [[label cell] setTextColor:text_color];
- }
- return label.autorelease();
-}
-
-// Builds a title card with one back button right aligned and one label center
-// aligned.
-NSView* BuildTitleCard(NSRect frame_rect,
- int message_id,
- id back_button_target,
- SEL back_button_action) {
- base::scoped_nsobject<NSView> container(
- [[NSView alloc] initWithFrame:frame_rect]);
-
- base::scoped_nsobject<HoverImageButton> button(
- [[HoverImageButton alloc] initWithFrame:frame_rect]);
- [button setBordered:NO];
- ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
- [button setDefaultImage:rb->GetNativeImageNamed(IDR_BACK).ToNSImage()];
- [button setHoverImage:rb->GetNativeImageNamed(IDR_BACK_H).ToNSImage()];
- [button setPressedImage:rb->GetNativeImageNamed(IDR_BACK_P).ToNSImage()];
- [button setTarget:back_button_target];
- [button setAction:back_button_action];
- [button setFrameSize:NSMakeSize(kProfileButtonHeight, kProfileButtonHeight)];
- [button setFrameOrigin:NSMakePoint(kHorizontalSpacing, 0)];
-
- NSTextField* title_label =
- BuildLabel(l10n_util::GetNSString(message_id), NSZeroPoint,
- nil /* background_color */, nil /* text_color */);
- [title_label setAlignment:NSCenterTextAlignment];
- [title_label setFont:[NSFont labelFontOfSize:kTitleFontSize]];
- [title_label sizeToFit];
- CGFloat x_offset = (frame_rect.size.width - NSWidth([title_label frame])) / 2;
- [title_label setFrameOrigin:NSMakePoint(x_offset, 0)];
-
- [container addSubview:button];
- [container addSubview:title_label];
- CGFloat height = std::max(NSMaxY([title_label frame]),
- NSMaxY([button frame])) + kSmallVerticalSpacing;
- [container setFrameSize:NSMakeSize(NSWidth([container frame]), height)];
-
- return container.autorelease();
-}
-
-} // namespace
-
-// Class that listens to changes to the OAuth2Tokens for the active profile,
-// changes to the avatar menu model or browser close notifications.
-class ActiveProfileObserverBridge : public AvatarMenuObserver,
- public content::NotificationObserver,
- public OAuth2TokenService::Observer {
- public:
- ActiveProfileObserverBridge(ProfileChooserController* controller,
- Browser* browser)
- : controller_(controller),
- browser_(browser),
- token_observer_registered_(false) {
- registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSING,
- content::NotificationService::AllSources());
- if (!browser_->profile()->IsGuestSession())
- AddTokenServiceObserver();
- }
-
- virtual ~ActiveProfileObserverBridge() {
- RemoveTokenServiceObserver();
- }
-
- private:
- void AddTokenServiceObserver() {
- ProfileOAuth2TokenService* oauth2_token_service =
- ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
- DCHECK(oauth2_token_service);
- oauth2_token_service->AddObserver(this);
- token_observer_registered_ = true;
- }
-
- void RemoveTokenServiceObserver() {
- if (!token_observer_registered_)
- return;
- DCHECK(browser_->profile());
- ProfileOAuth2TokenService* oauth2_token_service =
- ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
- DCHECK(oauth2_token_service);
- oauth2_token_service->RemoveObserver(this);
- token_observer_registered_ = false;
- }
-
- // OAuth2TokenService::Observer:
- virtual void OnRefreshTokenAvailable(const std::string& account_id) OVERRIDE {
- // Tokens can only be added by adding an account through the inline flow,
- // which is started from the account management view. Refresh it to show the
- // update.
- BubbleViewMode viewMode = [controller_ viewMode];
- if (viewMode == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ||
- viewMode == BUBBLE_VIEW_MODE_GAIA_SIGNIN ||
- viewMode == BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT) {
- [controller_
- initMenuContentsWithView:BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT];
- }
- }
-
- virtual void OnRefreshTokenRevoked(const std::string& account_id) OVERRIDE {
- // Tokens can only be removed from the account management view. Refresh it
- // to show the update.
- if ([controller_ viewMode] == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT)
- [controller_
- initMenuContentsWithView:BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT];
- }
-
- // AvatarMenuObserver:
- virtual void OnAvatarMenuChanged(AvatarMenu* avatar_menu) OVERRIDE {
- // While the bubble is open, the avatar menu can only change from the
- // profile chooser view by modifying the current profile's photo or name.
- [controller_ initMenuContentsWithView:BUBBLE_VIEW_MODE_PROFILE_CHOOSER];
- }
-
- // content::NotificationObserver:
- virtual void Observe(
- int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) OVERRIDE {
- DCHECK_EQ(chrome::NOTIFICATION_BROWSER_CLOSING, type);
- if (browser_ == content::Source<Browser>(source).ptr()) {
- RemoveTokenServiceObserver();
- // Clean up the bubble's WebContents (used by the Gaia embedded view), to
- // make sure the guest profile doesn't have any dangling host renderers.
- // This can happen if Chrome is quit using Command-Q while the bubble is
- // still open, which won't give the bubble a chance to be closed and
- // clean up the WebContents itself.
- [controller_ cleanUpEmbeddedViewContents];
- }
- }
-
- ProfileChooserController* controller_; // Weak; owns this.
- Browser* browser_; // Weak.
- content::NotificationRegistrar registrar_;
-
- // The observer can be removed both when closing the browser, and by just
- // closing the avatar bubble. However, in the case of closing the browser,
- // the avatar bubble will also be closed afterwards, resulting in a second
- // attempt to remove the observer. This ensures the observer is only
- // removed once.
- bool token_observer_registered_;
-
- DISALLOW_COPY_AND_ASSIGN(ActiveProfileObserverBridge);
-};
-
-// A custom button that has a transparent backround.
-@interface TransparentBackgroundButton : NSButton
-@end
-
-@implementation TransparentBackgroundButton
-- (id)initWithFrame:(NSRect)frameRect {
- if ((self = [super initWithFrame:frameRect])) {
- [self setBordered:NO];
- [self setFont:[NSFont labelFontOfSize:kTextFontSize]];
- [self setButtonType:NSMomentaryChangeButton];
- }
- return self;
-}
-
-- (void)drawRect:(NSRect)dirtyRect {
- NSColor* backgroundColor = [NSColor colorWithCalibratedWhite:0 alpha:0.5f];
- [backgroundColor setFill];
- NSRectFillUsingOperation(dirtyRect, NSCompositeSourceAtop);
- [super drawRect:dirtyRect];
-}
-@end
-
-// A custom image control that shows a "Change" button when moused over.
-@interface EditableProfilePhoto : NSImageView {
- @private
- AvatarMenu* avatarMenu_; // Weak; Owned by ProfileChooserController.
- base::scoped_nsobject<TransparentBackgroundButton> changePhotoButton_;
- // Used to display the "Change" button on hover.
- ui::ScopedCrTrackingArea trackingArea_;
-}
-
-- (id)initWithFrame:(NSRect)frameRect
- avatarMenu:(AvatarMenu*)avatarMenu
- profileIcon:(const gfx::Image&)profileIcon
- editingAllowed:(BOOL)editingAllowed;
-
-// Called when the "Change" button is clicked.
-- (void)editPhoto:(id)sender;
-
-// When hovering over the profile photo, show the "Change" button.
-- (void)mouseEntered:(NSEvent*)event;
-
-// When hovering away from the profile photo, hide the "Change" button.
-- (void)mouseExited:(NSEvent*)event;
-@end
-
-@interface EditableProfilePhoto (Private)
-// Create the "Change" avatar photo button.
-- (TransparentBackgroundButton*)changePhotoButtonWithRect:(NSRect)rect;
-@end
-
-@implementation EditableProfilePhoto
-- (id)initWithFrame:(NSRect)frameRect
- avatarMenu:(AvatarMenu*)avatarMenu
- profileIcon:(const gfx::Image&)profileIcon
- editingAllowed:(BOOL)editingAllowed {
- if ((self = [super initWithFrame:frameRect])) {
- avatarMenu_ = avatarMenu;
- [self setImage:CreateProfileImage(
- profileIcon, kLargeImageSide).ToNSImage()];
-
- // Add a tracking area so that we can show/hide the button when hovering.
- trackingArea_.reset([[CrTrackingArea alloc]
- initWithRect:[self bounds]
- options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways
- owner:self
- userInfo:nil]);
- [self addTrackingArea:trackingArea_.get()];
-
- if (editingAllowed) {
- // The avatar photo uses a frame of width profiles::kAvatarIconPadding,
- // which we must subtract from the button's bounds.
- changePhotoButton_.reset([self changePhotoButtonWithRect:NSMakeRect(
- profiles::kAvatarIconPadding, profiles::kAvatarIconPadding,
- kLargeImageSide - 2 * profiles::kAvatarIconPadding,
- kOverlayHeight)]);
- [self addSubview:changePhotoButton_];
-
- // Hide the button until the image is hovered over.
- [changePhotoButton_ setHidden:YES];
- }
- }
- return self;
-}
-
-- (void)editPhoto:(id)sender {
- avatarMenu_->EditProfile(avatarMenu_->GetActiveProfileIndex());
-}
-
-- (void)mouseEntered:(NSEvent*)event {
- [changePhotoButton_ setHidden:NO];
-}
-
-- (void)mouseExited:(NSEvent*)event {
- [changePhotoButton_ setHidden:YES];
-}
-
-- (TransparentBackgroundButton*)changePhotoButtonWithRect:(NSRect)rect {
- TransparentBackgroundButton* button =
- [[TransparentBackgroundButton alloc] initWithFrame:rect];
-
- // The button has a centered white text and a transparent background.
- base::scoped_nsobject<NSMutableParagraphStyle> textStyle(
- [[NSMutableParagraphStyle alloc] init]);
- [textStyle setAlignment:NSCenterTextAlignment];
- NSDictionary* titleAttributes = @{
- NSParagraphStyleAttributeName : textStyle,
- NSForegroundColorAttributeName : [NSColor whiteColor]
- };
- NSString* buttonTitle = l10n_util::GetNSString(
- IDS_PROFILES_PROFILE_CHANGE_PHOTO_BUTTON);
- base::scoped_nsobject<NSAttributedString> attributedTitle(
- [[NSAttributedString alloc] initWithString:buttonTitle
- attributes:titleAttributes]);
- [button setAttributedTitle:attributedTitle];
- [button setTarget:self];
- [button setAction:@selector(editPhoto:)];
- return button;
-}
-@end
-
-// A custom text control that turns into a textfield for editing when clicked.
-@interface EditableProfileNameButton : HoverImageButton<NSTextFieldDelegate> {
- @private
- base::scoped_nsobject<NSTextField> profileNameTextField_;
- Profile* profile_; // Weak.
-}
-
-- (id)initWithFrame:(NSRect)frameRect
- profile:(Profile*)profile
- profileName:(NSString*)profileName
- editingAllowed:(BOOL)editingAllowed;
-
-// Called when the button is clicked.
-- (void)showEditableView:(id)sender;
-
-// Called when the user presses "Enter" in the textfield.
-- (void)controlTextDidEndEditing:(NSNotification *)obj;
-@end
-
-@implementation EditableProfileNameButton
-- (id)initWithFrame:(NSRect)frameRect
- profile:(Profile*)profile
- profileName:(NSString*)profileName
- editingAllowed:(BOOL)editingAllowed {
- if ((self = [super initWithFrame:frameRect])) {
- profile_ = profile;
-
- [self setBordered:NO];
- [self setFont:[NSFont labelFontOfSize:kTitleFontSize]];
- [self setAlignment:NSLeftTextAlignment];
- [[self cell] setLineBreakMode:NSLineBreakByTruncatingTail];
- [self setTitle:profileName];
-
- if (editingAllowed) {
- // Show an "edit" pencil icon when hovering over.
- ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
- [self setHoverImage:
- rb->GetNativeImageNamed(IDR_ICON_PROFILES_EDIT_HOVER).AsNSImage()];
- [self setAlternateImage:
- rb->GetNativeImageNamed(IDR_ICON_PROFILES_EDIT_PRESSED).AsNSImage()];
- [self setImagePosition:NSImageRight];
- [self setTarget:self];
- [self setAction:@selector(showEditableView:)];
-
- // We need to subtract the width of the bezel from the frame rect, so that
- // the textfield can take the exact same space as the button.
- frameRect.size.height -= 2 * kBezelThickness;
- frameRect.origin = NSMakePoint(0, kBezelThickness);
- profileNameTextField_.reset(
- [[NSTextField alloc] initWithFrame:frameRect]);
- [profileNameTextField_ setStringValue:profileName];
- [profileNameTextField_ setFont:[NSFont labelFontOfSize:kTitleFontSize]];
- [profileNameTextField_ setEditable:YES];
- [profileNameTextField_ setDrawsBackground:YES];
- [profileNameTextField_ setBezeled:YES];
- [[profileNameTextField_ cell] setWraps:NO];
- [[profileNameTextField_ cell] setLineBreakMode:
- NSLineBreakByTruncatingTail];
- [profileNameTextField_ setDelegate:self];
- [self addSubview:profileNameTextField_];
-
- // Hide the textfield until the user clicks on the button.
- [profileNameTextField_ setHidden:YES];
- }
- }
- return self;
-}
-
-// NSTextField objects send an NSNotification to a delegate if
-// it implements this method:
-- (void)controlTextDidEndEditing:(NSNotification *)obj {
- NSString* text = [profileNameTextField_ stringValue];
- // Empty profile names are not allowed, and are treated as a cancel.
- if ([text length] > 0) {
- profiles::UpdateProfileName(profile_, base::SysNSStringToUTF16(text));
- [self setTitle:text];
- }
- [profileNameTextField_ setHidden:YES];
- [profileNameTextField_ resignFirstResponder];
-}
-
-- (void)showEditableView:(id)sender {
- [profileNameTextField_ setHidden:NO];
- [profileNameTextField_ becomeFirstResponder];
-}
-
-@end
-
-// Custom button cell that adds a left padding before the button image, and
-// a custom spacing between the button image and title.
-@interface CustomPaddingImageButtonCell : NSButtonCell {
- @private
- // Padding between the left margin of the button and the cell image.
- int leftMarginSpacing_;
- // Spacing between the cell image and title.
- int imageTitleSpacing_;
-}
-
-- (id)initWithLeftMarginSpacing:(int)leftMarginSpacing
- imageTitleSpacing:(int)imageTitleSpacing;
-@end
-
-@implementation CustomPaddingImageButtonCell
-- (id)initWithLeftMarginSpacing:(int)leftMarginSpacing
- imageTitleSpacing:(int)imageTitleSpacing {
- if ((self = [super init])) {
- leftMarginSpacing_ = leftMarginSpacing;
- imageTitleSpacing_ = imageTitleSpacing;
- }
- return self;
-}
-
-- (NSRect)drawTitle:(NSAttributedString*)title
- withFrame:(NSRect)frame
- inView:(NSView*)controlView {
- // The title frame origin isn't aware of the left margin spacing added
- // in -drawImage, so it must be added when drawing the title as well.
- frame.origin.x += leftMarginSpacing_ + imageTitleSpacing_;
- frame.size.width -= (imageTitleSpacing_ + leftMarginSpacing_);
- return [super drawTitle:title withFrame:frame inView:controlView];
-}
-
-- (void)drawImage:(NSImage*)image
- withFrame:(NSRect)frame
- inView:(NSView*)controlView {
- frame.origin.x = leftMarginSpacing_;
- [super drawImage:image withFrame:frame inView:controlView];
-}
-
-- (NSSize)cellSize {
- NSSize buttonSize = [super cellSize];
- buttonSize.width += leftMarginSpacing_ + imageTitleSpacing_;
- return buttonSize;
-}
-
-@end
-
-// A custom button that allows for setting a background color when hovered over.
-@interface BackgroundColorHoverButton : HoverImageButton
-@end
-
-@implementation BackgroundColorHoverButton
-- (id)initWithFrame:(NSRect)frameRect {
- if ((self = [super initWithFrame:frameRect])) {
- [self setBordered:NO];
- [self setFont:[NSFont labelFontOfSize:kTextFontSize]];
- [self setButtonType:NSMomentaryChangeButton];
-
- base::scoped_nsobject<CustomPaddingImageButtonCell> cell(
- [[CustomPaddingImageButtonCell alloc]
- initWithLeftMarginSpacing:kHorizontalSpacing
- imageTitleSpacing:kImageTitleSpacing]);
- [cell setLineBreakMode:NSLineBreakByTruncatingTail];
- [self setCell:cell.get()];
- }
- return self;
-}
-
-- (void)setHoverState:(HoverState)state {
- [super setHoverState:state];
- bool isHighlighted = ([self hoverState] != kHoverStateNone);
-
- NSColor* backgroundColor = gfx::SkColorToCalibratedNSColor(
- ui::NativeTheme::instance()->GetSystemColor(isHighlighted?
- ui::NativeTheme::kColorId_MenuSeparatorColor :
- ui::NativeTheme::kColorId_DialogBackground));
-
- [[self cell] setBackgroundColor:backgroundColor];
-}
-
-@end
-
-// A custom view with the given background color.
-@interface BackgroundColorView : NSView {
- @private
- base::scoped_nsobject<NSColor> backgroundColor_;
-}
-@end
-
-@implementation BackgroundColorView
-- (id)initWithFrame:(NSRect)frameRect
- withColor:(NSColor*)color {
- if ((self = [super initWithFrame:frameRect]))
- backgroundColor_.reset([color retain]);
- return self;
-}
-
-- (void)drawRect:(NSRect)dirtyRect {
- [backgroundColor_ setFill];
- NSRectFill(dirtyRect);
- [super drawRect:dirtyRect];
-}
-@end
-
-@interface ProfileChooserController ()
-// Creates a tutorial card for the profile |avatar_item| if needed.
-- (NSView*)createTutorialViewIfNeeded:(const AvatarMenu::Item&)item;
-
-// Creates the main profile card for the profile |item| at the top of
-// the bubble.
-- (NSView*)createCurrentProfileView:(const AvatarMenu::Item&)item;
-
-// Creates the possible links for the main profile card with profile |item|.
-- (NSView*)createCurrentProfileLinksForItem:(const AvatarMenu::Item&)item
- withXOffset:(CGFloat)xOffset;
-
-// Creates a main profile card for the guest user.
-- (NSView*)createGuestProfileView;
-
-// Creates an item for the profile |itemIndex| that is used in the fast profile
-// switcher in the middle of the bubble.
-- (NSButton*)createOtherProfileView:(int)itemIndex;
-
-// Creates the "Not you" and Lock option buttons.
-- (NSView*)createOptionsViewWithRect:(NSRect)rect
- enableLock:(BOOL)enableLock;
-
-// Creates the account management view for the active profile.
-- (NSView*)createCurrentProfileAccountsView:(NSRect)rect;
-
-// Creates the list of accounts for the active profile.
-- (NSView*)createAccountsListWithRect:(NSRect)rect;
-
-// Creates the Gaia sign-in/add account view.
-- (NSView*)buildGaiaEmbeddedView;
-
-// Creates the account removal view.
-- (NSView*)buildAccountRemovalView;
-
-// Creates a button with |text|, an icon given by |imageResourceId| and with
-// |action|. The icon |alternateImageResourceId| is displayed in the button's
-// hovered and pressed states.
-- (NSButton*)hoverButtonWithRect:(NSRect)rect
- text:(NSString*)text
- imageResourceId:(int)imageResourceId
- alternateImageResourceId:(int)alternateImageResourceId
- action:(SEL)action;
-
-// Creates a generic link button with |title| and an |action| positioned at
-// |frameOrigin|.
-- (NSButton*)linkButtonWithTitle:(NSString*)title
- frameOrigin:(NSPoint)frameOrigin
- action:(SEL)action;
-
-// Creates an email account button with |title| and a remove icon.
-- (NSButton*)accountButtonWithRect:(NSRect)rect
- title:(const std::string&)title;
-
-@end
-
-@implementation ProfileChooserController
-- (BubbleViewMode) viewMode {
- return viewMode_;
-}
-
-- (IBAction)switchToProfile:(id)sender {
- // Check the event flags to see if a new window should be created.
- bool alwaysCreate = ui::WindowOpenDispositionFromNSEvent(
- [NSApp currentEvent]) == NEW_WINDOW;
- avatarMenu_->SwitchToProfile([sender tag], alwaysCreate,
- ProfileMetrics::SWITCH_PROFILE_ICON);
-}
-
-- (IBAction)showUserManager:(id)sender {
- // Guest users cannot appear in the User Manager, nor display a tutorial.
- profiles::ShowUserManagerMaybeWithTutorial(
- isGuestSession_ ? NULL : browser_->profile());
-}
-
-- (IBAction)showAccountManagement:(id)sender {
- [self initMenuContentsWithView:BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT];
-}
-
-- (IBAction)lockProfile:(id)sender {
- profiles::LockProfile(browser_->profile());
-}
-
-- (IBAction)showSigninPage:(id)sender {
- [self initMenuContentsWithView:BUBBLE_VIEW_MODE_GAIA_SIGNIN];
-}
-
-- (IBAction)addAccount:(id)sender {
- [self initMenuContentsWithView:BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT];
-}
-
-- (IBAction)navigateBackFromSigninPage:(id)sender {
- std::string primaryAccount = SigninManagerFactory::GetForProfile(
- browser_->profile())->GetAuthenticatedUsername();
- [self initMenuContentsWithView:primaryAccount.empty() ?
- BUBBLE_VIEW_MODE_PROFILE_CHOOSER : BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT];
-}
-
-- (IBAction)showAccountRemovalView:(id)sender {
- DCHECK(!isGuestSession_);
-
- // Tag is either |kPrimaryProfileTag| for the primary account, or equal to the
- // index in |currentProfileAccounts_| for a secondary account.
- int tag = [sender tag];
- if (tag == kPrimaryProfileTag) {
- accountIdToRemove_ = SigninManagerFactory::GetForProfile(
- browser_->profile())->GetAuthenticatedUsername();
- } else {
- DCHECK(ContainsKey(currentProfileAccounts_, tag));
- accountIdToRemove_ = currentProfileAccounts_[tag];
- }
-
- [self initMenuContentsWithView:BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL];
-}
-
-- (IBAction)removeAccountAndRelaunch:(id)sender {
- DCHECK(!accountIdToRemove_.empty());
- ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile(
- browser_->profile())->RevokeCredentials(accountIdToRemove_);
- accountIdToRemove_.clear();
- chrome::AttemptRestart();
-}
-
-- (IBAction)openTutorialLearnMoreURL:(id)sender {
- // TODO(guohui): update |learnMoreUrl| once it is decided.
- const GURL learnMoreUrl("https://support.google.com/chrome/?hl=en#to");
- chrome::NavigateParams params(browser_->profile(), learnMoreUrl,
- content::PAGE_TRANSITION_LINK);
- params.disposition = NEW_FOREGROUND_TAB;
- chrome::Navigate(&params);
-}
-
-- (IBAction)dismissTutorial:(id)sender {
- // If the user manually dismissed the tutorial, never show it again by setting
- // the number of times shown to the maximum plus 1, so that later we could
- // distinguish between the dismiss case and the case when the tutorial is
- // indeed shown for the maximum number of times.
- browser_->profile()->GetPrefs()->SetInteger(
- prefs::kProfileAvatarTutorialShown, kProfileAvatarTutorialShowMax + 1);
- [self initMenuContentsWithView:BUBBLE_VIEW_MODE_PROFILE_CHOOSER];
-}
-
-- (void)cleanUpEmbeddedViewContents {
- webContents_.reset();
-}
-
-- (id)initWithBrowser:(Browser*)browser
- anchoredAt:(NSPoint)point
- withMode:(BubbleViewMode)mode {
- base::scoped_nsobject<InfoBubbleWindow> window([[InfoBubbleWindow alloc]
- initWithContentRect:ui::kWindowSizeDeterminedLater
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:NO]);
-
- if ((self = [super initWithWindow:window
- parentWindow:browser->window()->GetNativeWindow()
- anchoredAt:point])) {
- browser_ = browser;
- viewMode_ = mode;
- tutorialShowing_ = false;
- observer_.reset(new ActiveProfileObserverBridge(self, browser_));
-
- avatarMenu_.reset(new AvatarMenu(
- &g_browser_process->profile_manager()->GetProfileInfoCache(),
- observer_.get(),
- browser_));
- avatarMenu_->RebuildMenu();
-
- // Guest profiles do not have a token service.
- isGuestSession_ = browser_->profile()->IsGuestSession();
-
- ui::NativeTheme* nativeTheme = ui::NativeTheme::instance();
- [[self bubble] setAlignment:info_bubble::kAlignRightEdgeToAnchorEdge];
- [[self bubble] setArrowLocation:info_bubble::kNoArrow];
- [[self bubble] setBackgroundColor:
- gfx::SkColorToCalibratedNSColor(nativeTheme->GetSystemColor(
- ui::NativeTheme::kColorId_DialogBackground))];
- [self initMenuContentsWithView:viewMode_];
- }
-
- return self;
-}
-
-- (void)initMenuContentsWithView:(BubbleViewMode)viewToDisplay {
- viewMode_ = viewToDisplay;
- NSView* contentView = [[self window] contentView];
- [contentView setSubviews:[NSArray array]];
-
- if (viewMode_ == BUBBLE_VIEW_MODE_GAIA_SIGNIN ||
- viewMode_ == BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT ||
- viewMode_ == BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL) {
- bool isRemovalView = viewMode_ == BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL;
- NSView* subView = isRemovalView ?
- [self buildAccountRemovalView] : [self buildGaiaEmbeddedView];
- [contentView addSubview:subView];
- SetWindowSize([self window],
- NSMakeSize(NSWidth([subView frame]), NSHeight([subView frame])));
- return;
- }
-
- NSView* tutorialView = nil;
- NSView* currentProfileView = nil;
- base::scoped_nsobject<NSMutableArray> otherProfiles(
- [[NSMutableArray alloc] init]);
- // Local and guest profiles cannot lock their profile.
- bool enableLock = false;
-
- // Loop over the profiles in reverse, so that they are sorted by their
- // y-coordinate, and separate them into active and "other" profiles.
- for (int i = avatarMenu_->GetNumberOfItems() - 1; i >= 0; --i) {
- const AvatarMenu::Item& item = avatarMenu_->GetItemAt(i);
- if (item.active) {
- if (viewMode_ == BUBBLE_VIEW_MODE_PROFILE_CHOOSER)
- tutorialView = [self createTutorialViewIfNeeded:item];
- currentProfileView = [self createCurrentProfileView:item];
- enableLock = item.signed_in;
- } else {
- [otherProfiles addObject:[self createOtherProfileView:i]];
- }
- }
- if (!currentProfileView) // Guest windows don't have an active profile.
- currentProfileView = [self createGuestProfileView];
-
- // |yOffset| is the next position at which to draw in |contentView|
- // coordinates.
- CGFloat yOffset = kSmallVerticalSpacing;
-
- // Option buttons.
- NSView* optionsView = [self createOptionsViewWithRect:
- NSMakeRect(0, yOffset, kFixedMenuWidth, 0)
- enableLock:enableLock];
- [contentView addSubview:optionsView];
- yOffset = NSMaxY([optionsView frame]) + kSmallVerticalSpacing;
-
- NSBox* separator = [self separatorWithFrame:
- NSMakeRect(0, yOffset, kFixedMenuWidth, 0)];
- [contentView addSubview:separator];
- yOffset = NSMaxY([separator frame]) + kVerticalSpacing;
-
- if (viewToDisplay == BUBBLE_VIEW_MODE_PROFILE_CHOOSER &&
- switches::IsFastUserSwitching()) {
- // Other profiles switcher. The profiles have already been sorted
- // by their y-coordinate, so they can be added in the existing order.
- for (NSView *otherProfileView in otherProfiles.get()) {
- [otherProfileView setFrameOrigin:NSMakePoint(kHorizontalSpacing,
- yOffset)];
- [contentView addSubview:otherProfileView];
- yOffset = NSMaxY([otherProfileView frame]) + kSmallVerticalSpacing;
- }
-
- // If we displayed other profiles, ensure the spacing between the last item
- // and the active profile card is the same as the spacing between the active
- // profile card and the bottom of the bubble.
- if ([otherProfiles.get() count] > 0)
- yOffset += kSmallVerticalSpacing;
- } else if (viewToDisplay == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) {
- NSView* currentProfileAccountsView = [self createCurrentProfileAccountsView:
- NSMakeRect(kHorizontalSpacing,
- yOffset,
- kFixedMenuWidth - 2 * kHorizontalSpacing,
- 0)];
- [contentView addSubview:currentProfileAccountsView];
- yOffset = NSMaxY([currentProfileAccountsView frame]) + kVerticalSpacing;
-
- NSBox* accountsSeparator = [self separatorWithFrame:
- NSMakeRect(0, yOffset, kFixedMenuWidth, 0)];
- [contentView addSubview:accountsSeparator];
- yOffset = NSMaxY([accountsSeparator frame]) + kVerticalSpacing;
- }
-
- // Active profile card.
- if (currentProfileView) {
- [currentProfileView setFrameOrigin:NSMakePoint(kHorizontalSpacing,
- yOffset)];
- [contentView addSubview:currentProfileView];
- yOffset = NSMaxY([currentProfileView frame]) + kVerticalSpacing;
- }
-
- if (tutorialView) {
- [tutorialView setFrameOrigin:NSMakePoint(0, yOffset)];
- [contentView addSubview:tutorialView];
- yOffset = NSMaxY([tutorialView frame]);
- } else {
- tutorialShowing_ = false;
- }
-
- SetWindowSize([self window], NSMakeSize(kFixedMenuWidth, yOffset));
-}
-
-- (NSView*)createTutorialViewIfNeeded:(const AvatarMenu::Item&)item {
- if (!item.signed_in)
- return nil;
-
- Profile* profile = browser_->profile();
- const int showCount = profile->GetPrefs()->GetInteger(
- prefs::kProfileAvatarTutorialShown);
- // Do not show the tutorial if user has dismissed it.
- if (showCount > kProfileAvatarTutorialShowMax)
- return nil;
-
- if (!tutorialShowing_) {
- if (showCount == kProfileAvatarTutorialShowMax)
- return nil;
- profile->GetPrefs()->SetInteger(
- prefs::kProfileAvatarTutorialShown, showCount + 1);
- tutorialShowing_ = true;
- }
-
- NSColor* tutorialBackgroundColor =
- gfx::SkColorToSRGBNSColor(profiles::kAvatarTutorialBackgroundColor);
- base::scoped_nsobject<NSView> container([[BackgroundColorView alloc]
- initWithFrame:NSMakeRect(0, 0, kFixedMenuWidth, 0)
- withColor:tutorialBackgroundColor]);
- CGFloat availableWidth = kFixedMenuWidth - 2 * kHorizontalSpacing;
- CGFloat yOffset = kVerticalSpacing;
-
- // Adds links and buttons at the bottom.
- NSButton* learnMoreLink =
- [self linkButtonWithTitle:
- l10n_util::GetNSString(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE)
- frameOrigin:NSMakePoint(kHorizontalSpacing, yOffset)
- action:@selector(openTutorialLearnMoreURL:)];
- [[learnMoreLink cell] setTextColor:[NSColor whiteColor]];
- [container addSubview:learnMoreLink];
-
- base::scoped_nsobject<NSButton> tutorialOkButton([[HoverButton alloc]
- initWithFrame:NSZeroRect]);
- [tutorialOkButton setTitle:l10n_util::GetNSString(
- IDS_PROFILES_SIGNIN_TUTORIAL_OK_BUTTON)];
- [tutorialOkButton setTarget:self];
- [tutorialOkButton setAction:@selector(dismissTutorial:)];
- [tutorialOkButton sizeToFit];
- NSSize buttonSize = [tutorialOkButton frame].size;
- const CGFloat kTopBottomTextPadding = 6;
- const CGFloat kLeftRightTextPadding = 15;
- buttonSize.width += 2 * kLeftRightTextPadding;
- buttonSize.height += 2 * kTopBottomTextPadding;
- [tutorialOkButton setFrameSize:buttonSize];
- [tutorialOkButton setAlignment:NSCenterTextAlignment];
- [tutorialOkButton setFrameOrigin:NSMakePoint(
- kFixedMenuWidth - NSWidth([tutorialOkButton frame]) - kHorizontalSpacing,
- yOffset)];
- [container addSubview:tutorialOkButton];
-
- yOffset = std::max(NSMaxY([learnMoreLink frame]),
- NSMaxY([tutorialOkButton frame])) + kVerticalSpacing;
-
- // Adds body content.
- NSTextField* contentLabel = BuildLabel(
- l10n_util::GetNSString(IDS_PROFILES_SIGNIN_TUTORIAL_CONTENT_TEXT),
- NSMakePoint(kHorizontalSpacing, yOffset),
- tutorialBackgroundColor,
- gfx::SkColorToSRGBNSColor(profiles::kAvatarTutorialContentTextColor));
- [contentLabel setFrameSize:NSMakeSize(availableWidth, 0)];
- [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:contentLabel];
- [container addSubview:contentLabel];
- yOffset = NSMaxY([contentLabel frame]) + kSmallVerticalSpacing;
-
- // Adds title.
- NSTextField* titleLabel =
- BuildLabel(
- l10n_util::GetNSString(IDS_PROFILES_SIGNIN_TUTORIAL_TITLE),
- NSMakePoint(kHorizontalSpacing, yOffset),
- tutorialBackgroundColor,
- [NSColor whiteColor] /* text_color */);
- [titleLabel setFont:[NSFont labelFontOfSize:kTitleFontSize]];
- [titleLabel sizeToFit];
- [titleLabel setFrameSize:
- NSMakeSize(availableWidth, NSHeight([titleLabel frame]))];
- [container addSubview:titleLabel];
- yOffset = NSMaxY([titleLabel frame]) + kVerticalSpacing;
-
- [container setFrameSize:NSMakeSize(kFixedMenuWidth, yOffset)];
-
- // Adds caret at the bottom.
- NSImage* caretImage = ui::ResourceBundle::GetSharedInstance().
- GetNativeImageNamed(IDR_ICON_PROFILES_MENU_CARET).AsNSImage();
- base::scoped_nsobject<NSImageView> caretView(
- [[NSImageView alloc] initWithFrame:NSMakeRect(
- kHorizontalSpacing, 0, caretImage.size.width,
- caretImage.size.height)]);
- [caretView setImage:caretImage];
-
- base::scoped_nsobject<NSView> containerWithCaret([[NSView alloc]
- initWithFrame:NSMakeRect(0, 0, kFixedMenuWidth, 0)]);
- [containerWithCaret addSubview:caretView];
-
- [container setFrameOrigin:NSMakePoint(0, caretImage.size.height)];
- [containerWithCaret addSubview:container];
-
- [containerWithCaret setFrameSize:
- NSMakeSize(kFixedMenuWidth, NSMaxY([container frame]))];
- return containerWithCaret.autorelease();
-}
-
-- (NSView*)createCurrentProfileView:(const AvatarMenu::Item&)item {
- base::scoped_nsobject<NSView> container([[NSView alloc]
- initWithFrame:NSZeroRect]);
-
- // Profile icon.
- base::scoped_nsobject<EditableProfilePhoto> iconView(
- [[EditableProfilePhoto alloc]
- initWithFrame:NSMakeRect(0, 0, kLargeImageSide, kLargeImageSide)
- avatarMenu:avatarMenu_.get()
- profileIcon:item.icon
- editingAllowed:!isGuestSession_]);
-
- [container addSubview:iconView];
-
- CGFloat xOffset = NSMaxX([iconView frame]) + kHorizontalSpacing;
- CGFloat yOffset = kVerticalSpacing;
- if (!isGuestSession_ && viewMode_ == BUBBLE_VIEW_MODE_PROFILE_CHOOSER) {
- NSView* linksContainer =
- [self createCurrentProfileLinksForItem:item withXOffset:xOffset];
- [container addSubview:linksContainer];
- yOffset = NSMaxY([linksContainer frame]);
- }
-
- // Profile name.
- CGFloat availableTextWidth =
- kFixedMenuWidth - xOffset - 2 * kHorizontalSpacing;
- base::scoped_nsobject<EditableProfileNameButton> profileName(
- [[EditableProfileNameButton alloc]
- initWithFrame:NSMakeRect(xOffset, yOffset,
- availableTextWidth,
- kProfileButtonHeight)
- profile:browser_->profile()
- profileName:base::SysUTF16ToNSString(
- profiles::GetAvatarNameForProfile(browser_->profile()))
- editingAllowed:!isGuestSession_]);
-
- [container addSubview:profileName];
- [container setFrameSize:NSMakeSize(kFixedMenuWidth,
- NSHeight([iconView frame]))];
- return container.autorelease();
-}
-
-- (NSView*)createCurrentProfileLinksForItem:(const AvatarMenu::Item&)item
- withXOffset:(CGFloat)xOffset {
- base::scoped_nsobject<NSView> container([[NSView alloc]
- initWithFrame:NSZeroRect]);
-
- NSButton* link;
- NSPoint frameOrigin = NSMakePoint(xOffset, kSmallVerticalSpacing);
- // The available links depend on the type of profile that is active.
- if (item.signed_in) {
- link = [self linkButtonWithTitle:l10n_util::GetNSString(
- IDS_PROFILES_PROFILE_MANAGE_ACCOUNTS_BUTTON)
- frameOrigin:frameOrigin
- action:@selector(showAccountManagement:)];
- } else {
- link = [self linkButtonWithTitle:l10n_util::GetNSStringFWithFixup(
- IDS_SYNC_START_SYNC_BUTTON_LABEL,
- l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME))
- frameOrigin:frameOrigin
- action:@selector(showSigninPage:)];
- }
-
- [container addSubview:link];
- [container setFrameSize:NSMakeSize(
- NSMaxX([link frame]), NSMaxY([link frame]) + kSmallVerticalSpacing)];
- return container.autorelease();
-}
-
-- (NSView*)createGuestProfileView {
- gfx::Image guestIcon =
- ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
- IDR_LOGIN_GUEST);
- AvatarMenu::Item guestItem(std::string::npos, /* menu_index, not used */
- std::string::npos, /* profile_index, not used */
- guestIcon);
- guestItem.active = true;
- guestItem.name = base::SysNSStringToUTF16(
- l10n_util::GetNSString(IDS_PROFILES_GUEST_PROFILE_NAME));
-
- return [self createCurrentProfileView:guestItem];
-}
-
-- (NSButton*)createOtherProfileView:(int)itemIndex {
- const AvatarMenu::Item& item = avatarMenu_->GetItemAt(itemIndex);
- base::scoped_nsobject<NSButton> profileButton([[NSButton alloc]
- initWithFrame:NSZeroRect]);
- base::scoped_nsobject<CustomPaddingImageButtonCell> cell(
- [[CustomPaddingImageButtonCell alloc]
- initWithLeftMarginSpacing:0
- imageTitleSpacing:kImageTitleSpacing]);
- [profileButton setCell:cell.get()];
-
- [[profileButton cell] setLineBreakMode:NSLineBreakByTruncatingTail];
- [profileButton setTitle:base::SysUTF16ToNSString(item.name)];
- [profileButton setImage:CreateProfileImage(
- item.icon, kSmallImageSide).ToNSImage()];
- [profileButton setImagePosition:NSImageLeft];
- [profileButton setAlignment:NSLeftTextAlignment];
- [profileButton setBordered:NO];
- [profileButton setFont:[NSFont labelFontOfSize:kTitleFontSize]];
- [profileButton setTag:itemIndex];
- [profileButton setTarget:self];
- [profileButton setAction:@selector(switchToProfile:)];
-
- // Since the bubble is fixed width, we need to calculate the width available
- // for the profile name, as longer names will have to be elided.
- CGFloat availableTextWidth = kFixedMenuWidth - 2 * kHorizontalSpacing;
- [profileButton sizeToFit];
- [profileButton setFrameSize:NSMakeSize(availableTextWidth,
- NSHeight([profileButton frame]))];
-
- return profileButton.autorelease();
-}
-
-- (NSView*)createOptionsViewWithRect:(NSRect)rect
- enableLock:(BOOL)enableLock {
- int widthOfLockButton = enableLock? 2 * kHorizontalSpacing + 12 : 0;
- NSRect viewRect = NSMakeRect(0, 0,
- rect.size.width - widthOfLockButton,
- kBlueButtonHeight);
- NSButton* notYouButton =
- [self hoverButtonWithRect:viewRect
- text:l10n_util::GetNSStringF(
- IDS_PROFILES_NOT_YOU_BUTTON,
- profiles::GetAvatarNameForProfile(browser_->profile()))
- imageResourceId:IDR_ICON_PROFILES_MENU_AVATAR
- alternateImageResourceId:IDR_ICON_PROFILES_MENU_AVATAR
- action:@selector(showUserManager:)];
-
- rect.size.height = NSMaxY([notYouButton frame]);
- base::scoped_nsobject<NSView> container([[NSView alloc]
- initWithFrame:rect]);
- [container addSubview:notYouButton];
-
- if (enableLock) {
- viewRect.origin.x = NSMaxX([notYouButton frame]);
- viewRect.size.width = widthOfLockButton;
- NSButton* lockButton =
- [self hoverButtonWithRect:viewRect
- text:@""
- imageResourceId:IDR_ICON_PROFILES_MENU_LOCK
- alternateImageResourceId:IDR_ICON_PROFILES_MENU_LOCK
- action:@selector(lockProfile:)];
- [container addSubview:lockButton];
- }
-
- return container.autorelease();
-}
-
-- (NSView*)createCurrentProfileAccountsView:(NSRect)rect {
- const CGFloat kAccountButtonHeight = 15;
-
- const AvatarMenu::Item& item =
- avatarMenu_->GetItemAt(avatarMenu_->GetActiveProfileIndex());
- DCHECK(item.signed_in);
-
- base::scoped_nsobject<NSView> container([[NSView alloc] initWithFrame:rect]);
-
- NSRect viewRect = NSMakeRect(0, 0, rect.size.width, kBlueButtonHeight);
- base::scoped_nsobject<NSButton> addAccountsButton([[BlueLabelButton alloc]
- initWithFrame:viewRect]);
-
- // Manually elide the button text so that the contents fit inside the bubble.
- // This is needed because the BlueLabelButton cell resets the style on
- // every call to -cellSize, which prevents setting a custom lineBreakMode.
- NSString* elidedButtonText = base::SysUTF16ToNSString(gfx::ElideText(
- l10n_util::GetStringFUTF16(
- IDS_PROFILES_PROFILE_ADD_ACCOUNT_BUTTON, item.name),
- ui::ResourceBundle::GetSharedInstance().GetFontList(
- ui::ResourceBundle::BaseFont),
- rect.size.width,
- gfx::ELIDE_AT_END));
-
- [addAccountsButton setTitle:elidedButtonText];
- [addAccountsButton setTarget:self];
- [addAccountsButton setAction:@selector(addAccount:)];
- [container addSubview:addAccountsButton];
-
- // Update the height of the email account buttons. This is needed so that the
- // all the buttons span the entire width of the bubble.
- viewRect.origin.y = NSMaxY([addAccountsButton frame]) + kVerticalSpacing;
- viewRect.size.height = kAccountButtonHeight;
-
- NSView* accountEmails = [self createAccountsListWithRect:viewRect];
- [container addSubview:accountEmails];
- [container setFrameSize:NSMakeSize(
- NSWidth([container frame]), NSMaxY([accountEmails frame]))];
- return container.autorelease();
-}
-
-- (NSView*)createAccountsListWithRect:(NSRect)rect {
- base::scoped_nsobject<NSView> container([[NSView alloc] initWithFrame:rect]);
- currentProfileAccounts_.clear();
-
- Profile* profile = browser_->profile();
- std::string primaryAccount =
- SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedUsername();
- DCHECK(!primaryAccount.empty());
- std::vector<std::string>accounts =
- profiles::GetSecondaryAccountsForProfile(profile, primaryAccount);
-
- rect.origin.y = 0;
- for (size_t i = 0; i < accounts.size(); ++i) {
- // Save the original email address, as the button text could be elided.
- currentProfileAccounts_[i] = accounts[i];
- NSButton* accountButton = [self accountButtonWithRect:rect
- title:accounts[i]];
- [accountButton setTag:i];
- [container addSubview:accountButton];
- rect.origin.y = NSMaxY([accountButton frame]) + kSmallVerticalSpacing;
- }
-
- // The primary account should always be listed first.
- NSButton* accountButton = [self accountButtonWithRect:rect
- title:primaryAccount];
- [container addSubview:accountButton];
- [container setFrameSize:NSMakeSize(NSWidth([container frame]),
- NSMaxY([accountButton frame]))];
- [accountButton setTag:kPrimaryProfileTag];
- return container.autorelease();
-}
-
-- (NSView*)buildGaiaEmbeddedView {
- base::scoped_nsobject<NSView> container(
- [[NSView alloc] initWithFrame:NSZeroRect]);
- CGFloat yOffset = 0;
-
- bool addSecondaryAccount = viewMode_ == BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT;
- signin::Source source = addSecondaryAccount ?
- signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT :
- signin::SOURCE_AVATAR_BUBBLE_SIGN_IN;
-
- webContents_.reset(content::WebContents::Create(
- content::WebContents::CreateParams(browser_->profile())));
- webContents_->GetController().LoadURL(
- signin::GetPromoURL(
- source, false /* auto_close */, true /* is_constrained */),
- content::Referrer(),
- content::PAGE_TRANSITION_AUTO_TOPLEVEL,
- std::string());
- NSView* webview = webContents_->GetView()->GetNativeView();
- [webview setFrameSize:NSMakeSize(kFixedGaiaViewWidth, kFixedGaiaViewHeight)];
- [container addSubview:webview];
- yOffset = NSMaxY([webview frame]);
-
- // Adds the title card.
- NSBox* separator = [self separatorWithFrame:
- NSMakeRect(0, yOffset, kFixedGaiaViewWidth, 0)];
- [container addSubview:separator];
- yOffset = NSMaxY([separator frame]) + kSmallVerticalSpacing;
-
- NSView* titleView = BuildTitleCard(
- NSMakeRect(0, yOffset, kFixedGaiaViewWidth,0),
- addSecondaryAccount ? IDS_PROFILES_GAIA_ADD_ACCOUNT_TITLE :
- IDS_PROFILES_GAIA_SIGNIN_TITLE,
- self /* backButtonTarget*/,
- @selector(navigateBackFromSigninPage:) /* backButtonAction */);
- [container addSubview:titleView];
- yOffset = NSMaxY([titleView frame]);
-
- [container setFrameSize:NSMakeSize(kFixedGaiaViewWidth, yOffset)];
- return container.autorelease();
-}
-
-- (NSView*)buildAccountRemovalView {
- DCHECK(!accountIdToRemove_.empty());
-
- base::scoped_nsobject<NSView> container(
- [[NSView alloc] initWithFrame:NSZeroRect]);
- CGFloat availableWidth =
- kFixedAccountRemovalViewWidth - 2 * kHorizontalSpacing;
- CGFloat yOffset = kVerticalSpacing;
-
- const std::string& primaryAccount = SigninManagerFactory::GetForProfile(
- browser_->profile())->GetAuthenticatedUsername();
- bool isPrimaryAccount = primaryAccount == accountIdToRemove_;
-
- // Adds "remove and relaunch" button at the bottom if needed.
- if (!isPrimaryAccount) {
- base::scoped_nsobject<NSButton> removeAndRelaunchButton(
- [[BlueLabelButton alloc] initWithFrame:NSZeroRect]);
- [removeAndRelaunchButton setTitle:l10n_util::GetNSString(
- IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON)];
- [removeAndRelaunchButton setTarget:self];
- [removeAndRelaunchButton setAction:@selector(removeAccountAndRelaunch:)];
- [removeAndRelaunchButton sizeToFit];
- [removeAndRelaunchButton setAlignment:NSCenterTextAlignment];
- CGFloat xOffset = (kFixedAccountRemovalViewWidth -
- NSWidth([removeAndRelaunchButton frame])) / 2;
- [removeAndRelaunchButton setFrameOrigin:NSMakePoint(xOffset, yOffset)];
- [container addSubview:removeAndRelaunchButton];
-
- yOffset = NSMaxY([removeAndRelaunchButton frame]) + kVerticalSpacing;
- }
-
- // Adds the main text.
- NSString* contentStr = isPrimaryAccount ?
- l10n_util::GetNSStringF(IDS_PROFILES_PRIMARY_ACCOUNT_REMOVAL_TEXT,
- base::UTF8ToUTF16(accountIdToRemove_)) :
- l10n_util::GetNSString(IDS_PROFILES_ACCOUNT_REMOVAL_TEXT);
- NSTextField* contentLabel =
- BuildLabel(contentStr, NSMakePoint(kHorizontalSpacing, yOffset),
- nil /* background_color */, nil /* text_color */);
- [contentLabel setFrameSize:NSMakeSize(availableWidth, 0)];
- [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:contentLabel];
- [container addSubview:contentLabel];
- yOffset = NSMaxY([contentLabel frame]) + kVerticalSpacing;
-
- // Adds the title card.
- NSBox* separator = [self separatorWithFrame:
- NSMakeRect(0, yOffset, kFixedAccountRemovalViewWidth, 0)];
- [container addSubview:separator];
- yOffset = NSMaxY([separator frame]) + kSmallVerticalSpacing;
-
- NSView* titleView = BuildTitleCard(
- NSMakeRect(0, yOffset, kFixedAccountRemovalViewWidth,0),
- IDS_PROFILES_ACCOUNT_REMOVAL_TITLE,
- self /* backButtonTarget*/,
- @selector(showAccountManagement:) /* backButtonAction */);
- [container addSubview:titleView];
- yOffset = NSMaxY([titleView frame]);
-
- [container setFrameSize:NSMakeSize(kFixedAccountRemovalViewWidth, yOffset)];
- return container.autorelease();
-}
-
-- (NSButton*)hoverButtonWithRect:(NSRect)rect
- text:(NSString*)text
- imageResourceId:(int)imageResourceId
- alternateImageResourceId:(int)alternateImageResourceId
- action:(SEL)action {
- base::scoped_nsobject<BackgroundColorHoverButton> button(
- [[BackgroundColorHoverButton alloc] initWithFrame:rect]);
-
- [button setTitle:text];
- ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
- NSImage* alternateImage = rb->GetNativeImageNamed(
- alternateImageResourceId).ToNSImage();
- [button setDefaultImage:rb->GetNativeImageNamed(imageResourceId).ToNSImage()];
- [button setHoverImage:alternateImage];
- [button setPressedImage:alternateImage];
- [button setImagePosition:NSImageLeft];
- [button setAlignment:NSLeftTextAlignment];
- [button setBordered:NO];
- [button setTarget:self];
- [button setAction:action];
-
- return button.autorelease();
-}
-
-- (NSButton*)linkButtonWithTitle:(NSString*)title
- frameOrigin:(NSPoint)frameOrigin
- action:(SEL)action {
- base::scoped_nsobject<NSButton> link(
- [[HyperlinkButtonCell buttonWithString:title] retain]);
-
- [[link cell] setShouldUnderline:NO];
- [[link cell] setTextColor:gfx::SkColorToCalibratedNSColor(
- chrome_style::GetLinkColor())];
- [link setTitle:title];
- [link setBordered:NO];
- [link setFont:[NSFont labelFontOfSize:kTextFontSize]];
- [link setTarget:self];
- [link setAction:action];
- [link setFrameOrigin:frameOrigin];
- [link sizeToFit];
-
- return link.autorelease();
-}
-
-- (NSButton*)accountButtonWithRect:(NSRect)rect
- title:(const std::string&)title {
- base::scoped_nsobject<NSButton> button([[NSButton alloc] initWithFrame:rect]);
- [button setTitle:ElideEmail(title, rect.size.width)];
- [button setAlignment:NSLeftTextAlignment];
- [button setBordered:NO];
-
- [button setImage:ui::ResourceBundle::GetSharedInstance().
- GetNativeImageNamed(IDR_CLOSE_1).ToNSImage()];
- [button setImagePosition:NSImageRight];
- [button setTarget:self];
- [button setAction:@selector(showAccountRemovalView:)];
-
- return button.autorelease();
-}
-
-@end

Powered by Google App Engine
This is Rietveld 408576698