Index: chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm |
=================================================================== |
--- chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm (revision 99418) |
+++ chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm (working copy) |
@@ -5,6 +5,7 @@ |
#import "chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h" |
#include "base/mac/mac_util.h" |
+#include "base/memory/scoped_nsobject.h" |
#include "base/string_util.h" |
#include "base/sys_string_conversions.h" |
#include "base/utf_string_conversions.h" |
@@ -18,8 +19,17 @@ |
#include "ui/base/l10n/l10n_util.h" |
#include "ui/base/l10n/l10n_util_mac.h" |
+@interface ExtensionInstallDialogController () |
+- (bool)isInlineInstall; |
+- (void)appendRatingStar:(const SkBitmap*)skiaImage; |
+@end |
+ |
namespace { |
+// Padding above the warnings separator, we must also subtract this when hiding |
+// it. |
+const CGFloat kWarningsSeparatorPadding = 14; |
+ |
// Maximum height we will adjust controls to when trying to accomodate their |
// contents. |
const CGFloat kMaxControlHeight = 400; |
@@ -45,17 +55,25 @@ |
[control setFrameOrigin:origin]; |
} |
+void AppendRatingStarsShim(const SkBitmap* skiaImage, |
+ ExtensionInstallDialogController* controller) { |
+ [controller appendRatingStar:skiaImage]; |
} |
+} |
+ |
@implementation ExtensionInstallDialogController |
@synthesize iconView = iconView_; |
@synthesize titleField = titleField_; |
@synthesize subtitleField = subtitleField_; |
@synthesize warningsField = warningsField_; |
-@synthesize warningsBox= warningsBox_; |
@synthesize cancelButton = cancelButton_; |
@synthesize okButton = okButton_; |
+@synthesize warningsSeparator = warningsSeparator_; |
+@synthesize ratingStars = ratingStars_; |
+@synthesize ratingCountField = ratingCountField_; |
+@synthesize userCountField = userCountField_; |
- (id)initWithParentWindow:(NSWindow*)window |
profile:(Profile*)profile |
@@ -63,12 +81,18 @@ |
delegate:(ExtensionInstallUI::Delegate*)delegate |
icon:(SkBitmap*)icon |
prompt:(const ExtensionInstallUI::Prompt&)prompt { |
+ prompt_.reset(new ExtensionInstallUI::Prompt(prompt)); |
Nico
2011/09/05 22:59:17
You shouldn't write member variables before "self
Mihai Parparita -not on Chrome
2011/09/06 00:54:11
Moved initialization of prompt_ to be after the [s
|
NSString* nibpath = nil; |
- // We use a different XIB in the case of no permission warnings, that is a |
- // little bit more nicely laid out. |
- if (prompt.GetPermissionCount() == 0) { |
+ // We use a different XIB in the case of inline installs or no permission |
+ // warnings, that respectively show webstore ratings data and are a more |
+ // nicely laid out. |
+ if ([self isInlineInstall]) { |
nibpath = [base::mac::MainAppBundle() |
+ pathForResource:@"ExtensionInstallPromptInline" |
+ ofType:@"nib"]; |
+ } else if (prompt.GetPermissionCount() == 0) { |
+ nibpath = [base::mac::MainAppBundle() |
pathForResource:@"ExtensionInstallPromptNoWarnings" |
ofType:@"nib"]; |
} else { |
@@ -82,32 +106,7 @@ |
profile_ = profile; |
icon_ = *icon; |
delegate_ = delegate; |
- |
- title_.reset([base::SysUTF16ToNSString( |
- prompt.GetHeading(extension->name())) retain]); |
- subtitle_.reset([base::SysUTF16ToNSString( |
- prompt.GetPermissionsHeader()) retain]); |
- button_.reset([base::SysUTF16ToNSString( |
- prompt.GetAcceptButtonLabel()) retain]); |
- NSString* cancel_button_label = prompt.HasAbortButtonLabel() ? |
- base::SysUTF16ToNSString(prompt.GetAbortButtonLabel()) : |
- l10n_util::GetNSString(IDS_CANCEL); |
- cancel_button_.reset([cancel_button_label retain]); |
- |
- // We display the permission warnings as a simple text string, separated by |
- // newlines. |
- if (prompt.GetPermissionCount()) { |
- string16 joined_warnings; |
- for (size_t i = 0; i < prompt.GetPermissionCount(); ++i) { |
- if (i > 0) |
- joined_warnings += UTF8ToUTF16("\n\n"); |
- |
- joined_warnings += prompt.GetPermission(i); |
- } |
- |
- warnings_.reset( |
- [base::SysUTF16ToNSString(joined_warnings) retain]); |
- } |
+ extension_ = extension; |
} |
return self; |
} |
@@ -120,6 +119,16 @@ |
contextInfo:nil]; |
} |
+- (IBAction)storeLinkClicked:(id)sender { |
+ GURL store_url( |
+ extension_urls::GetWebstoreItemDetailURLPrefix() + extension_->id()); |
+ BrowserList::GetLastActiveWithProfile(profile_)-> |
+ OpenURL(store_url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK); |
+ |
+ delegate_->InstallUIAbort(true); |
Nico
2011/09/05 22:59:17
nit: Make it more clear what "true" means here, ei
Mihai Parparita -not on Chrome
2011/09/06 00:54:11
Done.
|
+ [NSApp endSheet:[self window]]; |
Nico
2011/09/05 22:59:17
Window-modal sheets are not cool. Have you thought
Mihai Parparita -not on Chrome
2011/09/06 00:54:11
Tab-modal dialogs sound like a good idea for a fol
Nico
2011/09/06 01:04:00
Yes. Thanks. (Maybe file a bug and add the bug #
Mihai Parparita -not on Chrome
2011/09/06 01:25:59
Filed http://crbug.com/95455
|
+} |
+ |
- (IBAction)cancel:(id)sender { |
delegate_->InstallUIAbort(true); |
[NSApp endSheet:[self window]]; |
@@ -131,15 +140,33 @@ |
} |
- (void)awakeFromNib { |
- [titleField_ setStringValue:title_.get()]; |
- [subtitleField_ setStringValue:subtitle_.get()]; |
- [okButton_ setTitle:button_.get()]; |
- [cancelButton_ setTitle:cancel_button_.get()]; |
+ // Make sure we're the window's delegate as set in the nib. |
+ DCHECK_EQ(self, static_cast<ExtensionInstallDialogController*>( |
+ [[self window] delegate])); |
+ // Set control labels |
Nico
2011/09/05 22:59:17
nit: trailing period.
Mihai Parparita -not on Chrome
2011/09/06 00:54:11
Done.
|
+ [titleField_ setStringValue:base::SysUTF16ToNSString( |
+ prompt_->GetHeading(extension_->name()))]; |
+ [okButton_ setTitle:base::SysUTF16ToNSString( |
+ prompt_->GetAcceptButtonLabel())]; |
+ [cancelButton_ setTitle:prompt_->HasAbortButtonLabel() ? |
+ base::SysUTF16ToNSString(prompt_->GetAbortButtonLabel()) : |
+ l10n_util::GetNSString(IDS_CANCEL)]; |
Nico
2011/09/05 22:59:17
Do you need to resize the controls to make them ad
Mihai Parparita -not on Chrome
2011/09/06 00:54:11
It looks like there's no autosizing going on (e.g.
Nico
2011/09/06 01:04:00
This is sometimes doable all in the xib file witho
Mihai Parparita -not on Chrome
2011/09/06 01:25:59
Yeah, I looked into that, but since I set the butt
|
+ if ([self isInlineInstall]) { |
+ prompt_->AppendRatingStars( |
+ reinterpret_cast<ExtensionInstallUI::Prompt::StarAppender>( |
+ AppendRatingStarsShim), |
Nico
2011/09/05 22:59:17
You need this cast because AppendRatingStarsShim d
Mihai Parparita -not on Chrome
2011/09/06 00:54:11
Done.
|
+ self); |
+ [ratingCountField_ setStringValue:base::SysUTF16ToNSString( |
+ prompt_->GetRatingCount())]; |
+ [userCountField_ setStringValue:base::SysUTF16ToNSString( |
+ prompt_->GetUserCount())]; |
+ } |
+ |
NSImage* image = gfx::SkBitmapToNSImage(icon_); |
[iconView_ setImage:image]; |
- // Reisze |titleField_| to fit title |
+ // Resize |titleField_| to fit title |
CGFloat originalTitleWidth = [titleField_ frame].size.width; |
[titleField_ sizeToFit]; |
CGFloat newTitleWidth = [titleField_ frame].size.width; |
@@ -149,48 +176,72 @@ |
[[self window] setFrame:frame display:NO]; |
} |
- // Make sure we're the window's delegate as set in the nib. |
- DCHECK_EQ(self, static_cast<ExtensionInstallDialogController*>( |
- [[self window] delegate])); |
- |
+ CGFloat totalOffset = 0.0; |
// If there are any warnings, then we have to do some special layout. |
- if ([warnings_.get() length] > 0) { |
- [warningsField_ setStringValue:warnings_.get()]; |
+ if (prompt_->GetPermissionCount() > 0) { |
+ [subtitleField_ setStringValue:base::SysUTF16ToNSString( |
+ prompt_->GetPermissionsHeader())]; |
+ // We display the permission warnings as a simple text string, separated by |
+ // newlines. |
+ string16 joined_warnings; |
Nico
2011/09/05 22:59:17
nit: variables objc methods have camelCaps names (
Mihai Parparita -not on Chrome
2011/09/06 00:54:11
Leftover from past version of the file, fixed.
|
+ for (size_t i = 0; i < prompt_->GetPermissionCount(); ++i) { |
+ if (i > 0) |
+ joined_warnings += UTF8ToUTF16("\n"); |
Nico
2011/09/05 22:59:17
nit: You could go from utf8 to nsstring directly (
Mihai Parparita -not on Chrome
2011/09/06 00:54:11
Done.
|
+ |
+ joined_warnings += prompt_->GetPermission(i); |
+ } |
+ [warningsField_ setStringValue:base::SysUTF16ToNSString(joined_warnings)]; |
+ |
// The dialog is laid out in the NIB exactly how we want it assuming that |
// each label fits on one line. However, for each label, we want to allow |
// wrapping onto multiple lines. So we accumulate an offset by measuring how |
- // big each label wants to be, and comparing it to how bit it actually is. |
+ // big each label wants to be, and comparing it to how big it actually is. |
// Then we shift each label down and resize by the appropriate amount, then |
// finally resize the window. |
- CGFloat totalOffset = 0.0; |
- // Text fields. |
- totalOffset += AdjustControlHeightToFitContent(titleField_); |
- OffsetControlVertically(titleField_, -totalOffset); |
+ // Additionally, in the store version of the dialog the icon extends past |
+ // the one-line version of the permission field. Therefore when increasing |
+ // the window size for multi-line permissions we don't have to add the full |
+ // |
Nico
2011/09/05 22:59:17
you accidentally the rest of the comment
Nico
2011/09/06 01:04:00
still missing
Mihai Parparita -not on Chrome
2011/09/06 01:25:59
Done.
|
+ CGFloat warningsGrowthSlack = 0; |
+ if ([warningsField_ frame].origin.y > [iconView_ frame].origin.y) { |
+ warningsGrowthSlack = |
+ [warningsField_ frame].origin.y - [iconView_ frame].origin.y; |
+ } |
totalOffset += AdjustControlHeightToFitContent(subtitleField_); |
OffsetControlVertically(subtitleField_, -totalOffset); |
- CGFloat warningsOffset = AdjustControlHeightToFitContent(warningsField_); |
- OffsetControlVertically(warningsField_, -warningsOffset); |
- totalOffset += warningsOffset; |
+ totalOffset += AdjustControlHeightToFitContent(warningsField_); |
+ OffsetControlVertically(warningsField_, -totalOffset); |
+ totalOffset = MAX(totalOffset - warningsGrowthSlack, 0); |
+ } else if ([self isInlineInstall]) { |
+ // Inline installs that don't have a permissions section need to hide |
+ // controls related to that and shrink the window by the space they take |
+ // up. |
+ NSRect hiddenRect = NSUnionRect([warningsSeparator_ frame], |
+ [subtitleField_ frame]); |
+ hiddenRect = NSUnionRect(hiddenRect, [warningsField_ frame]); |
+ [warningsSeparator_ setHidden:YES]; |
+ [subtitleField_ setHidden:YES]; |
+ [warningsField_ setHidden:YES]; |
+ totalOffset -= hiddenRect.size.height + kWarningsSeparatorPadding; |
+ } |
- NSRect warningsBoxRect = [warningsBox_ frame]; |
- warningsBoxRect.origin.y -= totalOffset; |
- warningsBoxRect.size.height += warningsOffset; |
- [warningsBox_ setFrame:warningsBoxRect]; |
- |
- // buttons are positioned automatically in the XIB. |
- |
- // Finally, adjust the window size. |
+ // If necessary, adjust the window size. |
+ if (totalOffset) { |
NSRect currentRect = [[self window] frame]; |
[[self window] setFrame:NSMakeRect(currentRect.origin.x, |
currentRect.origin.y - totalOffset, |
currentRect.size.width, |
currentRect.size.height + totalOffset) |
- display:NO]; |
+ display:NO]; |
} |
+ |
+ // Focus the cancel button, otherwise the store link gets the default focus |
+ // for inline installs. |
+ [[self window] makeFirstResponder:cancelButton_]; |
Nico
2011/09/05 22:59:17
I think you can set the first responder in the nib
Mihai Parparita -not on Chrome
2011/09/06 00:54:11
I selected the window in Interface Builder and the
|
} |
- (void)didEndSheet:(NSWindow*)sheet |
@@ -203,6 +254,28 @@ |
[self autorelease]; |
} |
+- (bool)isInlineInstall { |
+ return prompt_->type() == ExtensionInstallUI::INLINE_INSTALL_PROMPT; |
+} |
+ |
+- (void)appendRatingStar:(const SkBitmap*)skiaImage { |
+ NSImage* image = gfx::SkBitmapToNSImageWithColorSpace( |
+ *skiaImage, base::mac::GetSystemColorSpace()); |
+ NSRect frame = NSMakeRect(0, 0, skiaImage->width(), skiaImage->height()); |
+ NSImageView* view = [[[NSImageView alloc] initWithFrame:frame] autorelease]; |
Nico
2011/09/05 22:59:17
nit: I think we generally prefer scoped_nsobject o
Mihai Parparita -not on Chrome
2011/09/06 00:54:11
Done.
|
+ [view setImage:image]; |
+ |
+ // Add this star after all the other ones |
+ CGFloat maxStarRight = 0; |
+ if ([[ratingStars_ subviews] count]) { |
+ maxStarRight = NSMaxX([[[ratingStars_ subviews] lastObject] frame]); |
+ } |
+ NSRect starBounds = NSMakeRect(maxStarRight, 0, |
+ skiaImage->width(), skiaImage->height()); |
+ [view setFrame:starBounds]; |
+ [ratingStars_ addSubview:view]; |
+} |
+ |
@end // ExtensionInstallDialogController |
void ShowExtensionInstallDialog( |