summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/ui/cocoa/browser/avatar_button.h47
-rw-r--r--chrome/browser/ui/cocoa/browser/avatar_button_controller.h44
-rw-r--r--chrome/browser/ui/cocoa/browser/avatar_button_controller.mm (renamed from chrome/browser/ui/cocoa/browser/avatar_button.mm)93
-rw-r--r--chrome/browser/ui/cocoa/browser/avatar_button_controller_unittest.mm51
-rw-r--r--chrome/browser/ui/cocoa/browser_window_controller.h10
-rw-r--r--chrome/browser/ui/cocoa/browser_window_controller.mm24
-rw-r--r--chrome/browser/ui/cocoa/browser_window_controller_private.mm24
-rw-r--r--chrome/chrome_browser.gypi4
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/test/base/testing_profile_manager.cc6
10 files changed, 189 insertions, 115 deletions
diff --git a/chrome/browser/ui/cocoa/browser/avatar_button.h b/chrome/browser/ui/cocoa/browser/avatar_button.h
deleted file mode 100644
index dd9dfa8..0000000
--- a/chrome/browser/ui/cocoa/browser/avatar_button.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2011 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.
-
-#ifndef CHROME_BROWSER_UI_COCOA_BROWSER_AVATAR_BUTTON_H_
-#define CHROME_BROWSER_UI_COCOA_BROWSER_AVATAR_BUTTON_H_
-#pragma once
-
-#import <AppKit/AppKit.h>
-
-#include "base/memory/scoped_nsobject.h"
-#include "base/memory/scoped_ptr.h"
-
-class Browser;
-
-namespace AvatarButtonInternal {
-class Observer;
-}
-
-// The AvatarButton sits in the top of the window frame when using multi-
-// profiles. It shows the current profile's avatar, or, when in Incognito, the
-// spy dude. With multi-profiles, clicking will open the profile menu; in
-// Incognito, clicking will do nothing.
-@interface AvatarButton : NSView {
- @private
- Browser* browser_;
-
- // The button child view of this view.
- scoped_nsobject<NSButton> button_;
-
- // Notification bridge for profile info updates.
- scoped_ptr<AvatarButtonInternal::Observer> observer_;
-}
-
-// Designated initializer.
-- (id)initWithBrowser:(Browser*)browser;
-
-// Whether or not to open the menu when clicked.
-- (void)setOpenMenuOnClick:(BOOL)flag;
-
-// Sets the image to be used as the avatar. This will have a drop shadow applied
-// and will be resized to the frame of the button.
-- (void)setImage:(NSImage*)image;
-
-@end
-
-#endif // CHROME_BROWSER_UI_COCOA_BROWSER_AVATAR_BUTTON_H_
diff --git a/chrome/browser/ui/cocoa/browser/avatar_button_controller.h b/chrome/browser/ui/cocoa/browser/avatar_button_controller.h
new file mode 100644
index 0000000..e0d35de
--- /dev/null
+++ b/chrome/browser/ui/cocoa/browser/avatar_button_controller.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 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.
+
+#ifndef CHROME_BROWSER_UI_COCOA_BROWSER_AVATAR_BUTTON_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_BROWSER_AVATAR_BUTTON_CONTROLLER_H_
+#pragma once
+
+#import <AppKit/AppKit.h>
+
+#include "base/memory/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
+
+class Browser;
+
+namespace AvatarButtonControllerInternal {
+class Observer;
+}
+
+// This view controller manages the button/image that sits in the top of the
+// window frame when using multi-profiles. It shows the current profile's
+// avatar, or, when in Incognito, the spy dude. With multi-profiles, clicking
+// will open the profile menu; in Incognito, clicking will do nothing.
+@interface AvatarButtonController : NSViewController {
+ @private
+ Browser* browser_;
+
+ // Notification bridge for profile info updates.
+ scoped_ptr<AvatarButtonControllerInternal::Observer> observer_;
+}
+
+// The view cast to a button.
+@property (readonly, nonatomic) NSButton* buttonView;
+
+// Designated initializer.
+- (id)initWithBrowser:(Browser*)browser;
+
+// Sets the image to be used as the avatar. This will have a drop shadow applied
+// and will be resized to the frame of the button.
+- (void)setImage:(NSImage*)image;
+
+@end
+
+#endif // CHROME_BROWSER_UI_COCOA_BROWSER_AVATAR_BUTTON_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/browser/avatar_button.mm b/chrome/browser/ui/cocoa/browser/avatar_button_controller.mm
index e2ab217..0df960f 100644
--- a/chrome/browser/ui/cocoa/browser/avatar_button.mm
+++ b/chrome/browser/ui/cocoa/browser/avatar_button_controller.mm
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#import "chrome/browser/ui/cocoa/browser/avatar_button.h"
+#import "chrome/browser/ui/cocoa/browser/avatar_button_controller.h"
#include "base/sys_string_conversions.h"
#include "chrome/browser/browser_process.h"
@@ -10,6 +10,7 @@
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
#import "chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.h"
#import "chrome/browser/ui/cocoa/browser_window_controller.h"
#import "chrome/browser/ui/cocoa/image_utils.h"
@@ -22,17 +23,19 @@
#include "ui/gfx/mac/nsimage_cache.h"
#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
-@interface AvatarButton (Private)
+@interface AvatarButtonController (Private)
+- (void)setOpenMenuOnClick:(BOOL)flag;
- (IBAction)buttonClicked:(id)sender;
- (NSImage*)compositeImageWithShadow:(NSImage*)image;
- (void)updateAvatar;
+- (void)addOrRemoveButtonIfNecessary;
@end
-namespace AvatarButtonInternal {
+namespace AvatarButtonControllerInternal {
class Observer : public NotificationObserver {
public:
- Observer(AvatarButton* button) : button_(button) {
+ Observer(AvatarButtonController* button) : button_(button) {
registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
NotificationService::AllSources());
}
@@ -44,6 +47,7 @@ class Observer : public NotificationObserver {
switch (type) {
case chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED:
[button_ updateAvatar];
+ [button_ addOrRemoveButtonIfNecessary];
break;
default:
NOTREACHED();
@@ -54,20 +58,20 @@ class Observer : public NotificationObserver {
private:
NotificationRegistrar registrar_;
- AvatarButton* button_; // Weak; owns this.
+ AvatarButtonController* button_; // Weak; owns this.
};
-} // namespace AvatarButtonInternal
+} // namespace AvatarButtonControllerInternal
namespace {
-const CGFloat kMenuYOffsetAdjust = 5.0;
+const CGFloat kMenuYOffsetAdjust = 1.0;
} // namespace
////////////////////////////////////////////////////////////////////////////////
-@implementation AvatarButton
+@implementation AvatarButtonController
- (id)initWithBrowser:(Browser*)browser {
if ((self = [super init])) {
@@ -76,50 +80,56 @@ const CGFloat kMenuYOffsetAdjust = 5.0;
// This view's single child view is a button with the same size and width as
// the parent. Set it to automatically resize to the size of this view and
// to scale the image.
- button_.reset([[NSButton alloc] initWithFrame:[self bounds]]);
- [button_ setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
- [button_ setButtonType:NSMomentaryLightButton];
- [button_ setImagePosition:NSImageOnly];
- [[button_ cell] setImageScaling:NSImageScaleProportionallyDown];
- [[button_ cell] setImagePosition:NSImageBelow];
+ scoped_nsobject<NSButton> button(
+ [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 20, 20)]);
+ [button setButtonType:NSMomentaryLightButton];
+ [button setImagePosition:NSImageOnly];
+ [[button cell] setImageScaling:NSImageScaleProportionallyDown];
+ [[button cell] setImagePosition:NSImageBelow];
// AppKit sets a title for some reason when using |-setImagePosition:|.
- [button_ setTitle:nil];
- [[button_ cell] setImageDimsWhenDisabled:NO];
- [[button_ cell] setHighlightsBy:NSContentsCellMask];
- [[button_ cell] setShowsStateBy:NSContentsCellMask];
- [button_ setBordered:NO];
- [button_ setTarget:self];
- [button_ setAction:@selector(buttonClicked:)];
- [self addSubview:button_];
- [self setOpenMenuOnClick:YES];
+ [button setTitle:nil];
+ [[button cell] setImageDimsWhenDisabled:NO];
+ [[button cell] setHighlightsBy:NSContentsCellMask];
+ [[button cell] setShowsStateBy:NSContentsCellMask];
+ [button setBordered:NO];
+ [button setTarget:self];
+ [button setAction:@selector(buttonClicked:)];
+ [self setView:button];
if (browser_->profile()->IsOffTheRecord()) {
[self setImage:gfx::GetCachedImageWithName(@"otr_icon.pdf")];
+ [self setOpenMenuOnClick:NO];
} else {
- observer_.reset(new AvatarButtonInternal::Observer(self));
+ observer_.reset(new AvatarButtonControllerInternal::Observer(self));
+ [self setOpenMenuOnClick:YES];
[self updateAvatar];
}
}
return self;
}
-- (void)setOpenMenuOnClick:(BOOL)flag {
- [button_ setEnabled:flag];
+- (NSButton*)buttonView {
+ return static_cast<NSButton*>(self.view);
}
- (void)setImage:(NSImage*)image {
- [button_ setImage:[self compositeImageWithShadow:image]];
+ [self.buttonView setImage:[self compositeImageWithShadow:image]];
}
// Private /////////////////////////////////////////////////////////////////////
+- (void)setOpenMenuOnClick:(BOOL)flag {
+ [self.buttonView setEnabled:flag];
+}
+
- (IBAction)buttonClicked:(id)sender {
- DCHECK_EQ(button_.get(), sender);
+ DCHECK_EQ(self.buttonView, sender);
- NSPoint point = NSMakePoint(NSMidX([self bounds]),
- NSMinY([self bounds]) + kMenuYOffsetAdjust);
- point = [self convertPoint:point toView:nil];
- point = [[self window] convertBaseToScreen:point];
+ NSView* view = self.view;
+ NSPoint point = NSMakePoint(NSMidX([view bounds]),
+ NSMaxY([view bounds]) - kMenuYOffsetAdjust);
+ point = [view convertPoint:point toView:nil];
+ point = [[view window] convertBaseToScreen:point];
// |menu| will automatically release itself on close.
AvatarMenuBubbleController* menu =
@@ -167,8 +177,25 @@ const CGFloat kMenuYOffsetAdjust = 5.0;
if (index != std::string::npos) {
[self setImage:cache.GetAvatarIconOfProfileAtIndex(index).ToNSImage()];
const string16& name = cache.GetNameOfProfileAtIndex(index);
- [button_ setToolTip:base::SysUTF16ToNSString(name)];
+ [self.view setToolTip:base::SysUTF16ToNSString(name)];
}
}
+// If the second-to-last profile was removed or a second profile was added,
+// show or hide the avatar button from the window frame.
+- (void)addOrRemoveButtonIfNecessary {
+ if (browser_->profile()->IsOffTheRecord())
+ return;
+
+ NSWindowController* wc =
+ [browser_->window()->GetNativeHandle() windowController];
+ if (![wc isKindOfClass:[BrowserWindowController class]])
+ return;
+
+ size_t count = g_browser_process->profile_manager()->GetNumberOfProfiles();
+ [self.view setHidden:count < 2];
+
+ [static_cast<BrowserWindowController*>(wc) layoutSubviews];
+}
+
@end
diff --git a/chrome/browser/ui/cocoa/browser/avatar_button_controller_unittest.mm b/chrome/browser/ui/cocoa/browser/avatar_button_controller_unittest.mm
new file mode 100644
index 0000000..3213d7e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/browser/avatar_button_controller_unittest.mm
@@ -0,0 +1,51 @@
+// Copyright (c) 2011 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 "chrome/browser/ui/cocoa/browser/avatar_button_controller.h"
+
+#include "base/memory/scoped_nsobject.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
+#include "chrome/browser/ui/cocoa/run_loop_testing.h"
+
+class AvatarButtonControllerTest : public CocoaProfileTest {
+ public:
+ virtual void SetUp() {
+ CocoaProfileTest::SetUp();
+ ASSERT_TRUE(browser());
+ browser()->InitBrowserWindow();
+
+ controller_.reset(
+ [[AvatarButtonController alloc] initWithBrowser:browser()]);
+ [[controller_ view] setHidden:YES];
+ }
+
+ virtual void TearDown() {
+ browser()->window()->Close();
+ CocoaProfileTest::TearDown();
+ }
+
+ NSButton* button() { return [controller_ buttonView]; }
+
+ private:
+ scoped_nsobject<AvatarButtonController> controller_;
+};
+
+TEST_F(AvatarButtonControllerTest, AddRemoveProfiles) {
+ EXPECT_TRUE([button() isHidden]);
+
+ testing_profile_manager()->CreateTestingProfile("one");
+
+ EXPECT_FALSE([button() isHidden]);
+
+ testing_profile_manager()->CreateTestingProfile("two");
+ EXPECT_FALSE([button() isHidden]);
+
+ testing_profile_manager()->DeleteTestingProfile("one");
+ EXPECT_FALSE([button() isHidden]);
+
+ testing_profile_manager()->DeleteTestingProfile("two");
+ EXPECT_TRUE([button() isHidden]);
+}
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h
index a856017..fa2bd91 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.h
+++ b/chrome/browser/ui/cocoa/browser_window_controller.h
@@ -28,7 +28,7 @@
#import "chrome/browser/ui/cocoa/view_resizer.h"
#include "ui/gfx/rect.h"
-@class AvatarButton;
+@class AvatarButtonController;
class Browser;
class BrowserWindow;
class BrowserWindowCocoa;
@@ -110,10 +110,10 @@ class TabContents;
CGFloat totalMagnifyGestureAmount_;
NSInteger currentZoomStepDelta_;
- // The view that shows the incognito badge or the multi-profile avatar icon.
- // Nil if neither is present. Needed to access the view to move it to/from the
- // fullscreen window.
- scoped_nsobject<AvatarButton> avatarButton_;
+ // The view controller that manages the incognito badge or the multi-profile
+ // avatar icon. The view is always in the view hierarchy, but will be hidden
+ // unless it's appropriate to show it.
+ scoped_nsobject<AvatarButtonController> avatarButtonController_;
// The view that shows the presentation mode toggle when in Lion fullscreen
// mode. Nil if not in fullscreen mode or not on Lion.
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index 21b475f..2db44e0 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -30,7 +30,7 @@
#import "chrome/browser/ui/cocoa/background_gradient_view.h"
#import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
#import "chrome/browser/ui/cocoa/bookmarks/bookmark_editor_controller.h"
-#import "chrome/browser/ui/cocoa/browser/avatar_button.h"
+#import "chrome/browser/ui/cocoa/browser/avatar_button_controller.h"
#import "chrome/browser/ui/cocoa/browser_window_cocoa.h"
#import "chrome/browser/ui/cocoa/browser_window_controller_private.h"
#import "chrome/browser/ui/cocoa/browser_window_utils.h"
@@ -1637,21 +1637,17 @@ enum {
// view to decorate the window at the upper right. Use the same base y
// coordinate as the tab strip.
- (void)installAvatar {
- // Only install if this browser window is OTR and has a tab strip.
- if (![self shouldShowAvatar])
- return;
-
- // Install the image into the badge view. Hide it for now; positioning,
- // sizing, and showing will be done by the layout code. The AvatarButton will
- // choose which image to display based on the browser.
- avatarButton_.reset([[AvatarButton alloc] initWithBrowser:browser_.get()]);
- [avatarButton_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
- [avatarButton_ setHidden:YES];
- // The button shouldn't do anything in incognito.
- [avatarButton_ setOpenMenuOnClick:!browser_->profile()->IsOffTheRecord()];
+ // Install the image into the badge view. Hide it for now; positioning and
+ // sizing will be done by the layout code. The AvatarButton will choose which
+ // image to display based on the browser.
+ avatarButtonController_.reset(
+ [[AvatarButtonController alloc] initWithBrowser:browser_.get()]);
+ NSView* view = [avatarButtonController_ view];
+ [view setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
+ [view setHidden:![self shouldShowAvatar]];
// Install the view.
- [[[[self window] contentView] superview] addSubview:avatarButton_];
+ [[[[self window] contentView] superview] addSubview:view];
}
// Documented in 10.6+, but present starting in 10.5. Called when we get a
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
index 35a8ebb..8ecabb2 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -14,7 +14,7 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
#include "chrome/browser/ui/browser_list.h"
-#import "chrome/browser/ui/cocoa/browser/avatar_button.h"
+#import "chrome/browser/ui/cocoa/browser/avatar_button_controller.h"
#import "chrome/browser/ui/cocoa/fast_resize_view.h"
#import "chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.h"
#import "chrome/browser/ui/cocoa/floating_bar_backing_view.h"
@@ -355,19 +355,20 @@ willPositionSheet:(NSWindow*)sheet
[tabStripController_ layoutTabsWithoutAnimation];
// Now lay out incognito badge together with the tab strip.
- if (avatarButton_.get()) {
- [avatarButton_ setFrameSize:NSMakeSize(tabStripHeight,
- tabStripHeight - 5.0)];
+ if ([self shouldShowAvatar]) {
+ NSView* avatarButton = [avatarButtonController_ view];
+ [avatarButton setFrameSize:NSMakeSize(tabStripHeight,
+ tabStripHeight - 5.0)];
// Actually place the badge *above* |maxY|, by +2 to miss the divider. On
// Lion or later, shift the badge left to move it away from the fullscreen
// button.
CGFloat badgeOffset = kAvatarRightOffset + possibleExtraShiftForLion;
NSPoint origin =
- NSMakePoint(width - NSWidth([avatarButton_ frame]) - badgeOffset,
+ NSMakePoint(width - NSWidth([avatarButton frame]) - badgeOffset,
maxY + 2);
- [avatarButton_ setFrameOrigin:origin];
- [avatarButton_ setHidden:NO]; // Make sure it's shown.
+ [avatarButton setFrameOrigin:origin];
+ [avatarButton setHidden:NO]; // Make sure it's shown.
}
return maxY;
@@ -625,10 +626,11 @@ willPositionSheet:(NSWindow*)sheet
[destWindow setContentView:contentView];
// Move the incognito badge if present.
- if (avatarButton_.get()) {
- [avatarButton_ removeFromSuperview];
- [avatarButton_ setHidden:YES]; // Will be shown in layout.
- [[[destWindow contentView] superview] addSubview:avatarButton_];
+ if ([self shouldShowAvatar]) {
+ [[avatarButtonController_ view] removeFromSuperview];
+ [[avatarButtonController_ view] setHidden:YES]; // Will be shown in layout.
+ [[[destWindow contentView] superview] addSubview:
+ [avatarButtonController_ view]];
}
// Add the tab strip after setting the content view and moving the incognito
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 2a954cc..69a9d7d 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2426,8 +2426,8 @@
'browser/ui/cocoa/bookmarks/bookmark_name_folder_controller.mm',
'browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell.h',
'browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell.mm',
- 'browser/ui/cocoa/browser/avatar_button.h',
- 'browser/ui/cocoa/browser/avatar_button.mm',
+ 'browser/ui/cocoa/browser/avatar_button_controller.h',
+ 'browser/ui/cocoa/browser/avatar_button_controller.mm',
'browser/ui/cocoa/browser/avatar_menu_bubble_controller.h',
'browser/ui/cocoa/browser/avatar_menu_bubble_controller.mm',
'browser/ui/cocoa/browser/edit_search_engine_cocoa_controller.h',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index d066286..fe03193 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1617,6 +1617,7 @@
'browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa_unittest.mm',
'browser/ui/cocoa/bookmarks/bookmark_name_folder_controller_unittest.mm',
'browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell_unittest.mm',
+ 'browser/ui/cocoa/browser/avatar_button_controller_unittest.mm',
'browser/ui/cocoa/browser/avatar_menu_bubble_controller_unittest.mm',
'browser/ui/cocoa/browser/edit_search_engine_cocoa_controller_unittest.mm',
'browser/ui/cocoa/browser_frame_view_unittest.mm',
diff --git a/chrome/test/base/testing_profile_manager.cc b/chrome/test/base/testing_profile_manager.cc
index e96f2a5..f8273ee 100644
--- a/chrome/test/base/testing_profile_manager.cc
+++ b/chrome/test/base/testing_profile_manager.cc
@@ -79,12 +79,12 @@ void TestingProfileManager::DeleteTestingProfile(const std::string& name) {
TestingProfilesMap::iterator it = testing_profiles_.find(name);
DCHECK(it != testing_profiles_.end());
- scoped_ptr<TestingProfile> profile(it->second);
-
- profile_manager_->profiles_info_.erase(profile->GetPath());
+ TestingProfile* profile = it->second;
ProfileInfoCache& cache = profile_manager_->GetProfileInfoCache();
cache.DeleteProfileFromCache(profile->GetPath());
+
+ profile_manager_->profiles_info_.erase(profile->GetPath());
}
ProfileManager* TestingProfileManager::profile_manager() {