Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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/browser/new_avatar_button_controller.h" | |
| 6 | |
| 7 #include "base/strings/sys_string_conversions.h" | |
| 8 #include "chrome/app/chrome_command_ids.h" | |
| 9 #include "chrome/browser/chrome_notification_types.h" | |
| 10 #include "chrome/browser/profiles/profile_metrics.h" | |
| 11 #include "chrome/browser/profiles/profiles_state.h" | |
| 12 #include "chrome/browser/ui/browser.h" | |
| 13 #include "chrome/browser/ui/browser_commands.h" | |
| 14 #include "chrome/browser/ui/browser_window.h" | |
| 15 #import "chrome/browser/ui/cocoa/browser/profile_chooser_controller.h" | |
| 16 #import "chrome/browser/ui/cocoa/browser_window_controller.h" | |
| 17 #include "content/public/browser/notification_service.h" | |
| 18 #include "grit/generated_resources.h" | |
| 19 #include "grit/theme_resources.h" | |
| 20 #include "ui/base/l10n/l10n_util_mac.h" | |
| 21 #include "ui/base/resource/resource_bundle.h" | |
| 22 #include "ui/gfx/text_elider.h" | |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 NSString* GetElidedProfileName(const base::string16& name) { | |
| 27 // Maximum characters the button can be before the text will get elided. | |
| 28 const int kMaxCharactersToDisplay = 15; | |
| 29 | |
| 30 gfx::FontList font_list = ui::ResourceBundle::GetSharedInstance().GetFontList( | |
| 31 ui::ResourceBundle::BaseFont); | |
| 32 return base::SysUTF16ToNSString(gfx::ElideText( | |
| 33 name, | |
| 34 font_list, | |
| 35 font_list.GetExpectedTextWidth(kMaxCharactersToDisplay), | |
| 36 gfx::ELIDE_AT_END)); | |
| 37 } | |
| 38 | |
| 39 } // namespace | |
| 40 | |
| 41 @interface NewAvatarButtonController (Private) | |
| 42 // Shows the ProfileMenuController. | |
| 43 - (IBAction)buttonClicked:(id)sender; | |
| 44 | |
| 45 - (void)bubbleWillClose:(NSNotification*)notif; | |
| 46 | |
| 47 // Updates the profile name displayed by the avatar button. If |layoutParent| is | |
| 48 // yes, then the BrowserWindowController is notified to relayout the subviews, | |
| 49 // as the button needs to be repositioned. | |
| 50 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent; | |
| 51 @end | |
| 52 | |
| 53 class ProfileInfoUpdateObserverBridge : public content::NotificationObserver { | |
|
Nico
2014/01/07 23:20:33
In general, we try to not use notifications in new
noms (inactive)
2014/01/08 15:05:31
I can also make this an AvatarMenuObserver (like t
| |
| 54 public: | |
| 55 ProfileInfoUpdateObserverBridge(NewAvatarButtonController* avatarButton) | |
| 56 : avatarButton_(avatarButton) { | |
| 57 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, | |
| 58 content::NotificationService::AllSources()); | |
| 59 } | |
| 60 | |
| 61 virtual ~ProfileInfoUpdateObserverBridge() { | |
| 62 registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, | |
| 63 content::NotificationService::AllSources()); | |
|
Nico
2014/01/07 23:20:33
Do you need to do this? I thought the point of Not
| |
| 64 } | |
| 65 | |
| 66 // content::NotificationObserver: | |
| 67 virtual void Observe(int type, | |
| 68 const content::NotificationSource& source, | |
| 69 const content::NotificationDetails& details) OVERRIDE { | |
| 70 switch (type) { | |
| 71 case chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED: | |
| 72 [avatarButton_ updateAvatarButtonAndLayoutParent:YES]; | |
| 73 break; | |
| 74 default: | |
| 75 NOTREACHED(); | |
| 76 break; | |
| 77 } | |
| 78 } | |
| 79 | |
| 80 private: | |
| 81 content::NotificationRegistrar registrar_; | |
| 82 | |
| 83 NewAvatarButtonController* avatarButton_; // Weak; owns this. | |
| 84 | |
| 85 DISALLOW_COPY_AND_ASSIGN(ProfileInfoUpdateObserverBridge); | |
| 86 }; | |
| 87 | |
| 88 @implementation NewAvatarButtonController | |
| 89 | |
| 90 - (id)initWithBrowser:(Browser*)browser { | |
| 91 if ((self = [super init])) { | |
| 92 browser_ = browser; | |
| 93 profileInfoObserver_.reset(new ProfileInfoUpdateObserverBridge(self)); | |
| 94 | |
| 95 base::scoped_nsobject<NSView> container([[NSView alloc] | |
| 96 initWithFrame:NSZeroRect]); | |
| 97 [self setView:container]; | |
| 98 | |
| 99 button_.reset([[NSButton alloc] initWithFrame:NSZeroRect]); | |
| 100 [button_ setBezelStyle:NSTexturedRoundedBezelStyle]; | |
| 101 [button_ setImage:ui::ResourceBundle::GetSharedInstance(). | |
| 102 GetNativeImageNamed(IDR_APP_DROPARROW).ToNSImage()]; | |
| 103 [button_ setImagePosition:NSImageRight]; | |
| 104 [button_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin]; | |
| 105 [button_ setTarget:self]; | |
| 106 [button_ setAction:@selector(buttonClicked:)]; | |
| 107 | |
| 108 [self updateAvatarButtonAndLayoutParent:NO]; | |
| 109 | |
| 110 [[self view] addSubview:button_]; | |
|
Nico
2014/01/07 23:20:33
Since this is the only view, can button_ just be t
noms (inactive)
2014/01/08 15:05:31
Not really. The only reason I added the container
| |
| 111 } | |
| 112 return self; | |
| 113 } | |
| 114 | |
| 115 - (void)dealloc { | |
| 116 [[NSNotificationCenter defaultCenter] | |
| 117 removeObserver:self | |
| 118 name:NSWindowWillCloseNotification | |
| 119 object:[menuController_ window]]; | |
| 120 [super dealloc]; | |
| 121 } | |
| 122 | |
| 123 - (NSButton*)buttonView { | |
| 124 return button_.get(); | |
| 125 } | |
| 126 | |
| 127 - (void)showAvatarBubble:(NSView*)anchor { | |
| 128 if (menuController_) | |
| 129 return; | |
| 130 | |
| 131 DCHECK(chrome::IsCommandEnabled(browser_, IDC_SHOW_AVATAR_MENU)); | |
| 132 | |
| 133 NSWindowController* wc = | |
| 134 [browser_->window()->GetNativeWindow() windowController]; | |
| 135 if ([wc isKindOfClass:[BrowserWindowController class]]) { | |
| 136 [static_cast<BrowserWindowController*>(wc) | |
| 137 lockBarVisibilityForOwner:self withAnimation:NO delay:NO]; | |
| 138 } | |
| 139 | |
| 140 NSPoint point = NSMakePoint(NSMidX([anchor bounds]), | |
| 141 NSMaxY([anchor bounds])); | |
| 142 point = [anchor convertPoint:point toView:nil]; | |
| 143 point = [[anchor window] convertBaseToScreen:point]; | |
| 144 | |
| 145 menuController_ = [[ProfileChooserController alloc] initWithBrowser:browser_ | |
| 146 anchoredAt:point]; | |
| 147 [[NSNotificationCenter defaultCenter] | |
| 148 addObserver:self | |
| 149 selector:@selector(bubbleWillClose:) | |
| 150 name:NSWindowWillCloseNotification | |
| 151 object:[menuController_ window]]; | |
| 152 [menuController_ showWindow:self]; | |
| 153 | |
| 154 ProfileMetrics::LogProfileOpenMethod(ProfileMetrics::ICON_AVATAR_BUBBLE); | |
| 155 } | |
| 156 | |
| 157 - (IBAction)buttonClicked:(id)sender { | |
| 158 DCHECK(sender == button_.get()); | |
| 159 [self showAvatarBubble:button_]; | |
| 160 } | |
| 161 | |
| 162 - (void)bubbleWillClose:(NSNotification*)notif { | |
| 163 NSWindowController* wc = | |
| 164 [browser_->window()->GetNativeWindow() windowController]; | |
| 165 if ([wc isKindOfClass:[BrowserWindowController class]]) { | |
| 166 [static_cast<BrowserWindowController*>(wc) | |
| 167 releaseBarVisibilityForOwner:self withAnimation:YES delay:NO]; | |
| 168 } | |
| 169 menuController_ = nil; | |
| 170 } | |
| 171 | |
| 172 - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent { | |
| 173 [button_ setTitle:GetElidedProfileName( | |
| 174 profiles::GetActiveProfileDisplayName(browser_))]; | |
| 175 [button_ sizeToFit]; | |
| 176 | |
| 177 // Resize the container. | |
| 178 [[self view] setFrameSize:[button_ frame].size]; | |
| 179 [button_ setFrameOrigin:NSMakePoint(0, 0)]; | |
| 180 | |
| 181 if (layoutParent) { | |
| 182 // Because the width of the button might have changed, the parent browser | |
| 183 // frame needs to recalculate the button bounds and redraw it. | |
| 184 [[BrowserWindowController | |
| 185 browserWindowControllerForWindow:browser_->window()->GetNativeWindow()] | |
| 186 layoutSubviews]; | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 - (ProfileChooserController*)menuController { | |
| 191 return menuController_; | |
| 192 } | |
| 193 | |
| 194 @end | |
| OLD | NEW |