| Index: chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm
|
| diff --git a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm
|
| index 888b58cf7c63adcc10cfcedb9a20bdc023487dfd..34f6227f409557f2fd821e7ba2a88ab20c35eeca 100644
|
| --- a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm
|
| +++ b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm
|
| @@ -9,6 +9,7 @@
|
| #include "base/mac/mac_util.h"
|
| #include "base/sys_string_conversions.h"
|
| #include "base/utf_string_conversions.h"
|
| +#include "chrome/browser/extensions/bundle_installer.h"
|
| #include "chrome/browser/ui/browser.h"
|
| #include "chrome/browser/ui/browser_window.h"
|
| #include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
|
| @@ -31,6 +32,7 @@
|
| #include "ui/base/l10n/l10n_util.h"
|
|
|
| using content::BrowserThread;
|
| +using extensions::BundleInstaller;
|
|
|
| // C++ class that receives EXTENSION_LOADED notifications and proxies them back
|
| // to |controller|.
|
| @@ -80,26 +82,31 @@ class ExtensionLoadedNotificationObserver
|
| @implementation ExtensionInstalledBubbleController
|
|
|
| @synthesize extension = extension_;
|
| +@synthesize bundle = bundle_;
|
| @synthesize pageActionRemoved = pageActionRemoved_; // Exposed for unit test.
|
|
|
| - (id)initWithParentWindow:(NSWindow*)parentWindow
|
| extension:(const Extension*)extension
|
| + bundle:(const BundleInstaller*)bundle
|
| browser:(Browser*)browser
|
| icon:(SkBitmap)icon {
|
| - NSString* nibPath =
|
| - [base::mac::FrameworkBundle() pathForResource:@"ExtensionInstalledBubble"
|
| - ofType:@"nib"];
|
| + NSString* nibName = bundle ? @"ExtensionInstalledBubbleBundle" :
|
| + @"ExtensionInstalledBubble";
|
| + NSString* nibPath = [base::mac::FrameworkBundle() pathForResource:nibName
|
| + ofType:@"nib"];
|
| if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
|
| DCHECK(parentWindow);
|
| parentWindow_ = parentWindow;
|
| - DCHECK(extension);
|
| extension_ = extension;
|
| + bundle_ = bundle;
|
| DCHECK(browser);
|
| browser_ = browser;
|
| icon_.reset([gfx::SkBitmapToNSImage(icon) retain]);
|
| pageActionRemoved_ = NO;
|
|
|
| - if (!extension->omnibox_keyword().empty()) {
|
| + if (bundle_) {
|
| + type_ = extension_installed_bubble::kBundle;
|
| + } else if (!extension->omnibox_keyword().empty()) {
|
| type_ = extension_installed_bubble::kOmniboxKeyword;
|
| } else if (extension->browser_action()) {
|
| type_ = extension_installed_bubble::kBrowserAction;
|
| @@ -110,9 +117,13 @@ class ExtensionLoadedNotificationObserver
|
| NOTREACHED(); // kGeneric installs handled in the extension_install_ui.
|
| }
|
|
|
| - // Start showing window only after extension has fully loaded.
|
| - extensionObserver_.reset(new ExtensionLoadedNotificationObserver(
|
| - self, browser->profile()));
|
| + if (type_ == extension_installed_bubble::kBundle) {
|
| + [self showWindow:self];
|
| + } else {
|
| + // Start showing window only after extension has fully loaded.
|
| + extensionObserver_.reset(new ExtensionLoadedNotificationObserver(
|
| + self, browser->profile()));
|
| + }
|
|
|
| // Watch to see if the parent window closes, and if so, close this one.
|
| NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
|
| @@ -224,6 +235,14 @@ class ExtensionLoadedNotificationObserver
|
| locationBarView->GetPageActionBubblePoint(extension_->page_action());
|
| break;
|
| }
|
| + case extension_installed_bubble::kBundle: {
|
| + NSView* wrenchButton =
|
| + [[window->cocoa_controller() toolbarController] wrenchButton];
|
| + const NSRect bounds = [wrenchButton bounds];
|
| + NSPoint anchor = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
|
| + arrowPoint = [wrenchButton convertPoint:anchor toView:nil];
|
| + break;
|
| + }
|
| default: {
|
| NOTREACHED() << "Generic extension type not allowed in install bubble.";
|
| }
|
| @@ -284,6 +303,9 @@ class ExtensionLoadedNotificationObserver
|
| [infoBubbleView_ setArrowLocation:info_bubble::kTopRight];
|
| }
|
|
|
| + if (type_ == extension_installed_bubble::kBundle)
|
| + return window;
|
| +
|
| // Set appropriate icon, resizing if necessary.
|
| if ([icon_ size].width > extension_installed_bubble::kIconSize) {
|
| [icon_ setSize:NSMakeSize(extension_installed_bubble::kIconSize,
|
| @@ -292,7 +314,7 @@ class ExtensionLoadedNotificationObserver
|
| [iconImage_ setImage:icon_];
|
| [iconImage_ setNeedsDisplay:YES];
|
| return window;
|
| - }
|
| +}
|
|
|
| // Calculate the height of each install message, resizing messages in their
|
| // frames to fit window width. Return the new window height, based on the
|
| @@ -303,14 +325,16 @@ class ExtensionLoadedNotificationObserver
|
| int newWindowHeight = 2 * extension_installed_bubble::kOuterVerticalMargin;
|
|
|
| // First part of extension installed message.
|
| - string16 extension_name = UTF8ToUTF16(extension_->name().c_str());
|
| - base::i18n::AdjustStringForLocaleDirection(&extension_name);
|
| - [extensionInstalledMsg_ setStringValue:l10n_util::GetNSStringF(
|
| - IDS_EXTENSION_INSTALLED_HEADING, extension_name)];
|
| - [GTMUILocalizerAndLayoutTweaker
|
| + if (type_ != extension_installed_bubble::kBundle) {
|
| + string16 extension_name = UTF8ToUTF16(extension_->name().c_str());
|
| + base::i18n::AdjustStringForLocaleDirection(&extension_name);
|
| + [extensionInstalledMsg_ setStringValue:l10n_util::GetNSStringF(
|
| + IDS_EXTENSION_INSTALLED_HEADING, extension_name)];
|
| + [GTMUILocalizerAndLayoutTweaker
|
| sizeToFitFixedWidthTextField:extensionInstalledMsg_];
|
| - newWindowHeight += [extensionInstalledMsg_ frame].size.height +
|
| - extension_installed_bubble::kInnerVerticalMargin;
|
| + newWindowHeight += [extensionInstalledMsg_ frame].size.height +
|
| + extension_installed_bubble::kInnerVerticalMargin;
|
| + }
|
|
|
| // If type is page action, include a special message about page actions.
|
| if (type_ == extension_installed_bubble::kPageAction) {
|
| @@ -337,19 +361,100 @@ class ExtensionLoadedNotificationObserver
|
| extension_installed_bubble::kInnerVerticalMargin;
|
| }
|
|
|
| - // Second part of extension installed message.
|
| - [[extensionInstalledInfoMsg_ cell]
|
| - setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
|
| - [GTMUILocalizerAndLayoutTweaker
|
| - sizeToFitFixedWidthTextField:extensionInstalledInfoMsg_];
|
| - newWindowHeight += [extensionInstalledInfoMsg_ frame].size.height;
|
| + // If type is bundle, list the extensions that were installed and those that
|
| + // failed.
|
| + if (type_ == extension_installed_bubble::kBundle) {
|
| + NSInteger installedListHeight =
|
| + [self addExtensionList:installedHeadingMsg_
|
| + itemsMsg:installedItemsMsg_
|
| + state:BundleInstaller::Item::STATE_INSTALLED];
|
| +
|
| + NSInteger failedListHeight =
|
| + [self addExtensionList:failedHeadingMsg_
|
| + itemsMsg:failedItemsMsg_
|
| + state:BundleInstaller::Item::STATE_FAILED];
|
| +
|
| + newWindowHeight += installedListHeight + failedListHeight;
|
| +
|
| + // Put some space between the lists if both are present.
|
| + if (installedListHeight > 0 && failedListHeight > 0)
|
| + newWindowHeight += extension_installed_bubble::kInnerVerticalMargin;
|
| + } else {
|
| + // Second part of extension installed message.
|
| + [[extensionInstalledInfoMsg_ cell]
|
| + setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
|
| + [GTMUILocalizerAndLayoutTweaker
|
| + sizeToFitFixedWidthTextField:extensionInstalledInfoMsg_];
|
| + newWindowHeight += [extensionInstalledInfoMsg_ frame].size.height;
|
| + }
|
|
|
| return newWindowHeight;
|
| }
|
|
|
| +- (NSInteger)addExtensionList:(NSTextField*)headingMsg
|
| + itemsMsg:(NSTextField*)itemsMsg
|
| + state:(BundleInstaller::Item::State)state {
|
| + string16 heading = bundle_->GetHeadingTextFor(state);
|
| + bool hidden = heading.empty();
|
| + [headingMsg setHidden:hidden];
|
| + [itemsMsg setHidden:hidden];
|
| + if (hidden)
|
| + return 0;
|
| +
|
| + [headingMsg setStringValue:base::SysUTF16ToNSString(heading)];
|
| + [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:headingMsg];
|
| +
|
| + NSMutableString* joinedItems = [NSMutableString string];
|
| + BundleInstaller::ItemList items = bundle_->GetItemsWithState(state);
|
| + for (size_t i = 0; i < items.size(); ++i) {
|
| + if (i > 0)
|
| + [joinedItems appendString:@"\n"];
|
| + [joinedItems appendString:base::SysUTF16ToNSString(
|
| + items[i].GetNameForDisplay())];
|
| + }
|
| +
|
| + [itemsMsg setStringValue:joinedItems];
|
| + [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:itemsMsg];
|
| +
|
| + return [headingMsg frame].size.height +
|
| + extension_installed_bubble::kInnerVerticalMargin +
|
| + [itemsMsg frame].size.height;
|
| +}
|
| +
|
| // Adjust y-position of messages to sit properly in new window height.
|
| - (void)setMessageFrames:(int)newWindowHeight {
|
| - // The extension messages will always be shown.
|
| + if (type_ == extension_installed_bubble::kBundle) {
|
| + // Layout the messages from the bottom up.
|
| + NSTextField* msgs[] = { failedItemsMsg_, failedHeadingMsg_,
|
| + installedItemsMsg_, installedHeadingMsg_ };
|
| + NSInteger offsetFromBottom = 0;
|
| + BOOL isFirstVisible = YES;
|
| + for (size_t i = 0; i < arraysize(msgs); ++i) {
|
| + if ([msgs[i] isHidden])
|
| + continue;
|
| +
|
| + NSRect frame = [msgs[i] frame];
|
| + NSInteger margin = isFirstVisible ?
|
| + extension_installed_bubble::kOuterVerticalMargin :
|
| + extension_installed_bubble::kInnerVerticalMargin;
|
| +
|
| + frame.origin.y = offsetFromBottom + margin;
|
| + [msgs[i] setFrame:frame];
|
| + offsetFromBottom += frame.size.height + margin;
|
| +
|
| + isFirstVisible = NO;
|
| + }
|
| +
|
| + // Move the close button a bit to vertically align it with the heading.
|
| + NSInteger closeButtonFudge = 1;
|
| + NSRect frame = [closeButton_ frame];
|
| + frame.origin.y = newWindowHeight - (frame.size.height + closeButtonFudge +
|
| + extension_installed_bubble::kOuterVerticalMargin);
|
| + [closeButton_ setFrame:frame];
|
| +
|
| + return;
|
| + }
|
| +
|
| NSRect extensionMessageFrame1 = [extensionInstalledMsg_ frame];
|
| NSRect extensionMessageFrame2 = [extensionInstalledInfoMsg_ frame];
|
|
|
|
|