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
3 // found in the LICENSE file.
5 #import "chrome/browser/ui/cocoa/profiles/avatar_base_controller.h"
7 #include "chrome/app/chrome_command_ids.h"
8 #include "chrome/browser/browser_process.h"
9 #include "chrome/browser/profiles/profile_info_cache_observer.h"
10 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
11 #include "chrome/browser/profiles/profile_manager.h"
12 #include "chrome/browser/profiles/profile_metrics.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/browser_commands.h"
15 #include "chrome/browser/ui/browser_window.h"
16 #import "chrome/browser/ui/cocoa/base_bubble_controller.h"
17 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
18 #import "chrome/browser/ui/cocoa/profiles/avatar_menu_bubble_controller.h"
19 #import "chrome/browser/ui/cocoa/profiles/profile_chooser_controller.h"
20 #include "components/signin/core/common/profile_management_switches.h"
21 #include "ui/base/resource/resource_bundle.h"
23 // Space between the avatar icon and the avatar menu bubble.
24 const CGFloat kMenuYOffsetAdjust = 1.0;
26 @interface AvatarBaseController (Private)
27 // Shows the avatar bubble.
28 - (IBAction)buttonClicked:(id)sender;
29 - (void)bubbleWillClose:(NSNotification*)notif;
30 // Updates the profile name displayed by the avatar button. If |layoutParent| is
31 // yes, then the BrowserWindowController is notified to relayout the subviews,
32 // as the button needs to be repositioned.
33 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent;
36 class ProfileInfoUpdateObserver : public ProfileInfoCacheObserver {
38 ProfileInfoUpdateObserver(AvatarBaseController* avatarButton)
39 : avatarButton_(avatarButton) {
40 g_browser_process->profile_manager()->
41 GetProfileInfoCache().AddObserver(this);
44 virtual ~ProfileInfoUpdateObserver() {
45 g_browser_process->profile_manager()->
46 GetProfileInfoCache().RemoveObserver(this);
49 // ProfileInfoCacheObserver:
50 virtual void OnProfileAdded(const base::FilePath& profile_path) OVERRIDE {
51 [avatarButton_ updateAvatarButtonAndLayoutParent:YES];
54 virtual void OnProfileWasRemoved(
55 const base::FilePath& profile_path,
56 const base::string16& profile_name) OVERRIDE {
57 [avatarButton_ updateAvatarButtonAndLayoutParent:YES];
60 virtual void OnProfileNameChanged(
61 const base::FilePath& profile_path,
62 const base::string16& old_profile_name) OVERRIDE {
63 [avatarButton_ updateAvatarButtonAndLayoutParent:YES];
66 virtual void OnProfileAvatarChanged(
67 const base::FilePath& profile_path) OVERRIDE {
68 [avatarButton_ updateAvatarButtonAndLayoutParent:YES];
72 AvatarBaseController* avatarButton_; // Weak; owns this.
74 DISALLOW_COPY_AND_ASSIGN(ProfileInfoUpdateObserver);
77 @implementation AvatarBaseController
79 - (id)initWithBrowser:(Browser*)browser {
80 if ((self = [super init])) {
82 profileInfoObserver_.reset(new ProfileInfoUpdateObserver(self));
88 [[NSNotificationCenter defaultCenter]
90 name:NSWindowWillCloseNotification
91 object:[menuController_ window]];
95 - (NSButton*)buttonView {
96 CHECK(button_.get()); // Subclasses must set this.
100 - (void)showAvatarBubble:(NSView*)anchor
101 withMode:(BrowserWindow::AvatarBubbleMode)mode {
105 DCHECK(chrome::IsCommandEnabled(browser_, IDC_SHOW_AVATAR_MENU));
107 NSWindowController* wc =
108 [browser_->window()->GetNativeWindow() windowController];
109 if ([wc isKindOfClass:[BrowserWindowController class]]) {
110 [static_cast<BrowserWindowController*>(wc)
111 lockBarVisibilityForOwner:self withAnimation:NO delay:NO];
114 // The new avatar bubble does not have an arrow, and it should be anchored
115 // to the edge of the avatar button.
116 int anchorX = switches::IsNewAvatarMenu() ? NSMaxX([anchor bounds]) :
117 NSMidX([anchor bounds]);
118 NSPoint point = NSMakePoint(anchorX,
119 NSMaxY([anchor bounds]) - kMenuYOffsetAdjust);
120 point = [anchor convertPoint:point toView:nil];
121 point = [[anchor window] convertBaseToScreen:point];
123 // |menuController_| will automatically release itself on close.
124 if (switches::IsNewAvatarMenu()) {
125 BubbleViewMode viewMode =
126 mode == BrowserWindow::AVATAR_BUBBLE_MODE_DEFAULT ?
127 BUBBLE_VIEW_MODE_PROFILE_CHOOSER :
128 BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT;
130 [[ProfileChooserController alloc] initWithBrowser:browser_
135 [[AvatarMenuBubbleController alloc] initWithBrowser:browser_
139 [[NSNotificationCenter defaultCenter]
141 selector:@selector(bubbleWillClose:)
142 name:NSWindowWillCloseNotification
143 object:[menuController_ window]];
144 [menuController_ showWindow:self];
146 ProfileMetrics::LogProfileOpenMethod(ProfileMetrics::ICON_AVATAR_BUBBLE);
149 - (IBAction)buttonClicked:(id)sender {
150 DCHECK_EQ(sender, button_.get());
151 [self showAvatarBubble:button_
152 withMode:BrowserWindow::AVATAR_BUBBLE_MODE_DEFAULT];
155 - (void)bubbleWillClose:(NSNotification*)notif {
156 NSWindowController* wc =
157 [browser_->window()->GetNativeWindow() windowController];
158 if ([wc isKindOfClass:[BrowserWindowController class]]) {
159 [static_cast<BrowserWindowController*>(wc)
160 releaseBarVisibilityForOwner:self withAnimation:YES delay:NO];
162 menuController_ = nil;
165 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent {
169 - (BaseBubbleController*)menuController {
170 return menuController_;