avatar_base_controller.mm revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
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. 4 5#import "chrome/browser/ui/cocoa/profiles/avatar_base_controller.h" 6 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 "chrome/common/profile_management_switches.h" 21#include "ui/base/resource/resource_bundle.h" 22 23// Space between the avatar icon and the avatar menu bubble. 24const CGFloat kMenuYOffsetAdjust = 1.0; 25 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; 34@end 35 36class ProfileInfoUpdateObserver : public ProfileInfoCacheObserver { 37 public: 38 ProfileInfoUpdateObserver(AvatarBaseController* avatarButton) 39 : avatarButton_(avatarButton) { 40 g_browser_process->profile_manager()-> 41 GetProfileInfoCache().AddObserver(this); 42 } 43 44 virtual ~ProfileInfoUpdateObserver() { 45 g_browser_process->profile_manager()-> 46 GetProfileInfoCache().RemoveObserver(this); 47 } 48 49 // ProfileInfoCacheObserver: 50 virtual void OnProfileAdded(const base::FilePath& profile_path) OVERRIDE { 51 [avatarButton_ updateAvatarButtonAndLayoutParent:YES]; 52 } 53 54 virtual void OnProfileWasRemoved( 55 const base::FilePath& profile_path, 56 const base::string16& profile_name) OVERRIDE { 57 [avatarButton_ updateAvatarButtonAndLayoutParent:YES]; 58 } 59 60 virtual void OnProfileNameChanged( 61 const base::FilePath& profile_path, 62 const base::string16& old_profile_name) OVERRIDE { 63 [avatarButton_ updateAvatarButtonAndLayoutParent:YES]; 64 } 65 66 virtual void OnProfileAvatarChanged( 67 const base::FilePath& profile_path) OVERRIDE { 68 [avatarButton_ updateAvatarButtonAndLayoutParent:YES]; 69 } 70 71 private: 72 AvatarBaseController* avatarButton_; // Weak; owns this. 73 74 DISALLOW_COPY_AND_ASSIGN(ProfileInfoUpdateObserver); 75}; 76 77@implementation AvatarBaseController 78 79- (id)initWithBrowser:(Browser*)browser { 80 if ((self = [super init])) { 81 browser_ = browser; 82 profileInfoObserver_.reset(new ProfileInfoUpdateObserver(self)); 83 } 84 return self; 85} 86 87- (void)dealloc { 88 [[NSNotificationCenter defaultCenter] 89 removeObserver:self 90 name:NSWindowWillCloseNotification 91 object:[menuController_ window]]; 92 [super dealloc]; 93} 94 95- (NSButton*)buttonView { 96 CHECK(button_.get()); // Subclasses must set this. 97 return button_.get(); 98} 99 100- (void)showAvatarBubble:(NSView*)anchor 101 withMode:(BrowserWindow::AvatarBubbleMode)mode { 102 if (menuController_) 103 return; 104 105 DCHECK(chrome::IsCommandEnabled(browser_, IDC_SHOW_AVATAR_MENU)); 106 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]; 112 } 113 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::IsNewProfileManagement() ? 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]; 122 123 // |menuController_| will automatically release itself on close. 124 if (switches::IsNewProfileManagement()) { 125 BubbleViewMode viewMode = 126 mode == BrowserWindow::AVATAR_BUBBLE_MODE_DEFAULT ? 127 BUBBLE_VIEW_MODE_PROFILE_CHOOSER : 128 BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT; 129 menuController_ = 130 [[ProfileChooserController alloc] initWithBrowser:browser_ 131 anchoredAt:point 132 withMode:viewMode]; 133 } else { 134 menuController_ = 135 [[AvatarMenuBubbleController alloc] initWithBrowser:browser_ 136 anchoredAt:point]; 137 } 138 139 [[NSNotificationCenter defaultCenter] 140 addObserver:self 141 selector:@selector(bubbleWillClose:) 142 name:NSWindowWillCloseNotification 143 object:[menuController_ window]]; 144 [menuController_ showWindow:self]; 145 146 ProfileMetrics::LogProfileOpenMethod(ProfileMetrics::ICON_AVATAR_BUBBLE); 147} 148 149- (IBAction)buttonClicked:(id)sender { 150 DCHECK_EQ(sender, button_.get()); 151 [self showAvatarBubble:button_ 152 withMode:BrowserWindow::AVATAR_BUBBLE_MODE_DEFAULT]; 153} 154 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]; 161 } 162 menuController_ = nil; 163} 164 165- (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent { 166 NOTREACHED(); 167} 168 169- (BaseBubbleController*)menuController { 170 return menuController_; 171} 172 173@end 174