Chromium Code Reviews| 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..97d1f147fc51fc3791545077a4ed6efbe5d64ee9 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,101 @@ 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) { |
| + int installedListHeight = |
|
Robert Sesek
2012/02/27 18:59:20
For the code you're adding, use NSInteger instead
jstritar
2012/03/05 18:05:08
Done.
|
| + [self addExtensionList:installedHeadingMsg_ |
| + itemsMsg:installedItemsMsg_ |
| + state:BundleInstaller::Item::STATE_INSTALLED]; |
| + |
| + int 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; |
| } |
| +- (int)addExtensionList:(NSTextField*)headingMsg |
| + itemsMsg:(NSTextField*)itemsMsg |
| + state:(BundleInstaller::Item::State)state { |
| + string16 heading = bundle_->GetHeadingTextFor(state); |
| + BOOL hidden = heading.empty(); |
|
Robert Sesek
2012/02/27 18:59:20
C++ bool instead of ObjC bool.
jstritar
2012/03/05 18:05:08
Done.
|
| + [headingMsg setHidden:hidden]; |
| + [itemsMsg setHidden:hidden]; |
| + if (hidden) |
| + return 0; |
| + |
| + [headingMsg setStringValue:base::SysUTF16ToNSString(heading)]; |
| + [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:headingMsg]; |
| + |
| + NSMutableString* joinedItems = [NSMutableString string]; |
|
Robert Sesek
2012/02/27 18:59:20
This code is very similar with that of the other f
jstritar
2012/03/05 18:05:08
These classes use slightly different approaches fo
Robert Sesek
2012/03/05 18:30:13
SGTM
|
| + 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_ }; |
| + int offsetFromBottom = 0; |
| + BOOL is_first_visible = YES; |
| + for (size_t i = 0; i < arraysize(msgs); ++i) { |
| + if ([msgs[i] isHidden]) |
| + continue; |
| + |
| + NSRect frame = [msgs[i] frame]; |
| + int margin = is_first_visible ? |
| + extension_installed_bubble::kOuterVerticalMargin : |
| + extension_installed_bubble::kInnerVerticalMargin; |
| + |
| + frame.origin.y = offsetFromBottom + margin; |
| + [msgs[i] setFrame:frame]; |
| + offsetFromBottom += frame.size.height + margin; |
| + |
| + is_first_visible = NO; |
| + } |
| + |
| + // Move the close button a bit to vertically align it with the heading. |
| + int 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]; |