Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(828)

Unified Diff: chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm

Issue 10829170: Cocoa: Show OAuth issues in extension install dialog (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: test Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
index a13a2d94bc3400e29ee3687f714763b4f6a4b92a..113bbc4e50bb1709b95b4705dfe781537cfe66a4 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
@@ -29,6 +29,7 @@ using extensions::BundleInstaller;
- (BOOL)isBundleInstall;
- (BOOL)isInlineInstall;
- (void)appendRatingStar:(const gfx::ImageSkia*)skiaImage;
+- (void)onOutlineViewRowCountDidChange;
@end
namespace {
@@ -41,6 +42,11 @@ const CGFloat kWarningsSeparatorPadding = 14;
// contents.
const CGFloat kMaxControlHeight = 400;
+const NSString* kTitleKey = @"title";
+const NSString* kIsGroupItemKey = @"isGroupItem";
+const NSString* kChildrenKey = @"children";
+const NSString* kCanExpandKey = @"canExpand";
+
// Adjust the |control|'s height so that its content is not clipped.
// This also adds the change in height to the |totalOffset| and shifts the
// control down by that amount.
@@ -64,12 +70,104 @@ void OffsetControlVerticallyToFitContent(NSControl* control,
[control setFrameOrigin:origin];
}
+// Gets the desired height of |outlineView|. Simply using the view's frame
+// doesn't work if an animation is pending.
+CGFloat GetDesiredOutlineViewHeight(NSOutlineView* outlineView) {
+ CGFloat height = 0;
+ for (NSInteger i = 0; i < [outlineView numberOfRows]; ++i)
+ height += [outlineView rectOfRow:i].size.height;
+ return height;
+}
+
+void OffsetOutlineViewVerticallyToFitContent(NSOutlineView* outlineView,
+ CGFloat* totalOffset) {
+ NSScrollView* scrollView = [outlineView enclosingScrollView];
+ NSRect frame = [scrollView frame];
+ CGFloat desiredHeight = GetDesiredOutlineViewHeight(outlineView);
+ CGFloat offset = desiredHeight - frame.size.height;
+ frame.size.height += offset;
+
+ *totalOffset += offset;
+
+ // Move the control vertically by the new total offset.
+ frame.origin.y -= *totalOffset;
+ [scrollView setFrame:frame];
+}
+
void AppendRatingStarsShim(const gfx::ImageSkia* skiaImage, void* data) {
ExtensionInstallDialogController* controller =
static_cast<ExtensionInstallDialogController*>(data);
[controller appendRatingStar:skiaImage];
}
+NSDictionary* BuildItem(NSString* title, BOOL isGroupItem, NSArray* children) {
+ BOOL canExpand = YES;
+ if (!children) {
+ // Add a dummy child even though this is a leaf node. This will cause
+ // the outline view to show a disclosure triangle for this item.
+ // This is later overriden in willDisplayOutlineCell: to draw a bullet
+ // instead. (The bullet could be placed in the title instead but then
+ // the bullet wouldn't line up with disclosure triangles of sibling nodes.)
+ children = [NSArray arrayWithObject:[NSDictionary dictionary]];
+ canExpand = false;
+ }
+
+ return [NSDictionary dictionaryWithObjectsAndKeys:
+ title, kTitleKey,
+ [NSNumber numberWithBool:isGroupItem], kIsGroupItemKey,
+ children, kChildrenKey,
+ [NSNumber numberWithBool:canExpand], kCanExpandKey,
+ nil];
+}
+
+NSDictionary* BuildIssue(const IssueAdviceInfoEntry& issue) {
+ if (issue.details.empty())
+ return BuildItem(SysUTF16ToNSString(issue.description), NO, nil);
+
+ NSMutableArray* details = [NSMutableArray array];
+ for (size_t j = 0; j < issue.details.size(); ++j) {
+ [details addObject:BuildItem(
+ SysUTF16ToNSString(issue.details[j]), NO, nil)];
+ }
+ return BuildItem(SysUTF16ToNSString(issue.description), NO, details);
+}
+
+NSArray* BuildWarnings(const ExtensionInstallPrompt::Prompt& prompt) {
+ NSMutableArray* warnings = [NSMutableArray array];
+
+ if (prompt.GetPermissionCount() > 0) {
+ NSMutableArray* children = [NSMutableArray array];
+ for (size_t i = 0; i < prompt.GetPermissionCount(); ++i) {
+ [children addObject:BuildItem(
+ SysUTF16ToNSString(prompt.GetPermission(i)), NO, nil)];
+ }
+ [warnings addObject:BuildItem(
+ SysUTF16ToNSString(prompt.GetPermissionsHeading()), YES, children)];
+ }
+
+ if (prompt.GetOAuthIssueCount() > 0) {
+ NSMutableArray* children = [NSMutableArray array];
+ for (size_t i = 0; i < prompt.GetOAuthIssueCount(); ++i)
+ [children addObject:BuildIssue(prompt.GetOAuthIssue(i))];
+ [warnings addObject:BuildItem(
+ SysUTF16ToNSString(prompt.GetOAuthHeading()), YES, children)];
+ }
+
+ return warnings;
+}
+
+void DrawBulletInFrame(NSRect frame) {
+ NSRect rect;
+ rect.size.width = std::min(frame.size.width, frame.size.height) * 0.38;
+ rect.size.height = rect.size.width;
+ rect.origin.x = frame.origin.x + (frame.size.width - rect.size.width) / 2.0;
+ rect.origin.y = frame.origin.y + (frame.size.height - rect.size.height) / 2.0;
+ rect = NSIntegralRect(rect);
+
+ [[NSColor colorWithCalibratedWhite:0.0 alpha:0.42] set];
+ [[NSBezierPath bezierPathWithOvalInRect:rect] fill];
+}
+
}
@implementation ExtensionInstallDialogController
@@ -77,10 +175,9 @@ void AppendRatingStarsShim(const gfx::ImageSkia* skiaImage, void* data) {
@synthesize iconView = iconView_;
@synthesize titleField = titleField_;
@synthesize itemsField = itemsField_;
-@synthesize subtitleField = subtitleField_;
-@synthesize warningsField = warningsField_;
@synthesize cancelButton = cancelButton_;
@synthesize okButton = okButton_;
+@synthesize outlineView = outlineView_;
@synthesize warningsSeparator = warningsSeparator_;
@synthesize ratingStars = ratingStars_;
@synthesize ratingCountField = ratingCountField_;
@@ -91,6 +188,7 @@ void AppendRatingStarsShim(const gfx::ImageSkia* skiaImage, void* data) {
delegate:(ExtensionInstallPrompt::Delegate*)delegate
prompt:(const ExtensionInstallPrompt::Prompt&)prompt {
NSString* nibpath = nil;
+ warnings_.reset([BuildWarnings(prompt) retain]);
// We use a different XIB in the case of bundle installs, inline installs or
// no permission warnings. These are laid out nicely for the data they
@@ -103,7 +201,8 @@ void AppendRatingStarsShim(const gfx::ImageSkia* skiaImage, void* data) {
nibpath = [base::mac::FrameworkBundle()
pathForResource:@"ExtensionInstallPromptInline"
ofType:@"nib"];
- } else if (prompt.GetPermissionCount() == 0) {
+ } else if (prompt.GetPermissionCount() == 0 &&
+ prompt.GetOAuthIssueCount() == 0) {
nibpath = [base::mac::FrameworkBundle()
pathForResource:@"ExtensionInstallPromptNoWarnings"
ofType:@"nib"];
@@ -200,9 +299,6 @@ void AppendRatingStarsShim(const gfx::ImageSkia* skiaImage, void* data) {
}
if ([self isBundleInstall]) {
- [subtitleField_ setStringValue:base::SysUTF16ToNSString(
- prompt_->GetPermissionsHeading())];
-
// We display the list of extension names as a simple text string, seperated
// by newlines.
BundleInstaller::ItemList items = prompt_->bundle()->GetItemsWithState(
@@ -221,48 +317,28 @@ void AppendRatingStarsShim(const gfx::ImageSkia* skiaImage, void* data) {
OffsetControlVerticallyToFitContent(itemsField_, &totalOffset);
}
- // If there are any warnings, then we have to do some special layout.
- if (prompt_->GetPermissionCount() > 0) {
- [subtitleField_ setStringValue:base::SysUTF16ToNSString(
- prompt_->GetPermissionsHeading())];
-
- // We display the permission warnings as a simple text string, separated by
- // newlines.
- NSMutableString* joinedWarnings = [NSMutableString string];
- for (size_t i = 0; i < prompt_->GetPermissionCount(); ++i) {
- if (i > 0)
- [joinedWarnings appendString:@"\n"];
- [joinedWarnings appendString:base::SysUTF16ToNSString(
- prompt_->GetPermission(i))];
+ // If there are any warnings or OAuth issues, then we have to do some special
+ // layout.
+ if (prompt_->GetPermissionCount() > 0 || prompt_->GetOAuthIssueCount() > 0) {
+ NSSize spacing = [outlineView_ intercellSpacing];
+ spacing.width += 2;
+ spacing.height += 2;
+ [outlineView_ setIntercellSpacing:spacing];
+ [[[[outlineView_ tableColumns] objectAtIndex:0] dataCell] setWraps:YES];
+ for (id item in warnings_.get()) {
+ if ([[item objectForKey:kIsGroupItemKey] boolValue])
+ [outlineView_ expandItem:item expandChildren:NO];
}
- [warningsField_ setStringValue:joinedWarnings];
-
- // 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 offset,
- // only the part that extends past the icon.
- CGFloat warningsGrowthSlack = 0;
- if (![self isBundleInstall] &&
- [warningsField_ frame].origin.y > [iconView_ frame].origin.y) {
- warningsGrowthSlack =
- [warningsField_ frame].origin.y - [iconView_ frame].origin.y;
- }
-
- // Adjust the controls to fit the permission warnings.
- OffsetControlVerticallyToFitContent(subtitleField_, &totalOffset);
- OffsetControlVerticallyToFitContent(warningsField_, &totalOffset);
-
- totalOffset = MAX(totalOffset - warningsGrowthSlack, 0);
+ // Adjust the outline view to fit the warnings.
+ OffsetOutlineViewVerticallyToFitContent(outlineView_, &totalOffset);
} else if ([self isInlineInstall] || [self isBundleInstall]) {
// Inline and bundle 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]);
+ [[outlineView_ enclosingScrollView] frame]);
[warningsSeparator_ setHidden:YES];
- [subtitleField_ setHidden:YES];
- [warningsField_ setHidden:YES];
+ [[outlineView_ enclosingScrollView] setHidden:YES];
totalOffset -= hiddenRect.size.height + kWarningsSeparatorPadding;
}
@@ -313,6 +389,127 @@ void AppendRatingStarsShim(const gfx::ImageSkia* skiaImage, void* data) {
[ratingStars_ addSubview:view];
}
+- (void)onOutlineViewRowCountDidChange {
+ // Force the outline view to update.
+ [outlineView_ reloadData];
+
+ CGFloat totalOffset = 0.0;
+ OffsetOutlineViewVerticallyToFitContent(outlineView_, &totalOffset);
+ 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:YES];
+ }
+}
+
+- (id)outlineView:(NSOutlineView*)outlineView
+ child:(NSInteger)index
+ ofItem:(id)item {
+ if (!item)
+ return [warnings_ objectAtIndex:index];
+ if ([item isKindOfClass:[NSDictionary class]])
+ return [[item objectForKey:kChildrenKey] objectAtIndex:index];
+ NOTREACHED();
+ return nil;
+}
+
+- (BOOL)outlineView:(NSOutlineView*)outlineView
+ isItemExpandable:(id)item {
+ return [self outlineView:outlineView numberOfChildrenOfItem:item] > 0;
+}
+
+- (NSInteger)outlineView:(NSOutlineView*)outlineView
+ numberOfChildrenOfItem:(id)item {
+ if (!item)
+ return [warnings_ count];
+ if ([item isKindOfClass:[NSDictionary class]])
+ return [[item objectForKey:kChildrenKey] count];
+ NOTREACHED();
+ return 0;
+}
+
+- (id)outlineView:(NSOutlineView*)outlineView
+ objectValueForTableColumn:(NSTableColumn *)tableColumn
+ byItem:(id)item {
+ if ([item isKindOfClass:[NSDictionary class]])
+ return [item objectForKey:kTitleKey];
+ NOTREACHED();
+ return nil;
+}
+
+- (BOOL)outlineView:(NSOutlineView *)outlineView
+ shouldExpandItem:(id)item {
+ return [[item objectForKey:kCanExpandKey] boolValue];
+}
+
+- (void)outlineViewItemDidExpand:sender {
+ // Call via run loop to avoid animation glitches.
+ [self performSelector:@selector(onOutlineViewRowCountDidChange)
+ withObject:nil
+ afterDelay:0];
+}
+
+- (void)outlineViewItemDidCollapse:sender {
+ // Call via run loop to avoid animation glitches.
+ [self performSelector:@selector(onOutlineViewRowCountDidChange)
+ withObject:nil
+ afterDelay:0];
+}
+
+- (CGFloat)outlineView:(NSOutlineView *)outlineView
+ heightOfRowByItem:(id)item {
+ // Prevent reentrancy due to the frameOfCellAtColumn:row: call below.
+ if (isComputingRowHeight)
+ return 1;
+ isComputingRowHeight = YES;
+
+ NSCell* cell = [[[outlineView_ tableColumns] objectAtIndex:0] dataCell];
+ [cell setStringValue:[item objectForKey:kTitleKey]];
+ NSRect bounds = NSZeroRect;
+ NSInteger row = [outlineView_ rowForItem:item];
+ bounds.size.width = [outlineView_ frameOfCellAtColumn:0
+ row:row].size.width;
+ bounds.size.height = kMaxControlHeight;
+
+ isComputingRowHeight = NO;
+ return [cell cellSizeForBounds:bounds].height;
+}
+
+- (BOOL)outlineView:(NSOutlineView*)outlineView
+ shouldShowOutlineCellForItem:(id)item {
+ // The top most group header items are always expanded so hide their
+ // disclosure trianggles.
+ return ![[item objectForKey:kIsGroupItemKey] boolValue];
+}
+
+- (void)outlineView:(NSOutlineView*)outlineView
+ willDisplayCell:(id)cell
+ forTableColumn:(NSTableColumn *)tableColumn
+ item:(id)item {
+ if ([[item objectForKey:kIsGroupItemKey] boolValue])
+ [cell setFont:[NSFont boldSystemFontOfSize:11.0]];
+ else
+ [cell setFont:[NSFont systemFontOfSize:11.0]];
+}
+
+- (void)outlineView:(NSOutlineView *)outlineView
+ willDisplayOutlineCell:(id)cell
+ forTableColumn:(NSTableColumn *)tableColumn
+ item:(id)item {
+ // Replace disclosure triangles with bullet lists for leaf nodes.
+ if (![[item objectForKey:kCanExpandKey] boolValue]) {
+ [cell setImagePosition:NSNoImage];
+ DrawBulletInFrame([outlineView_ frameOfOutlineCellAtRow:
+ [outlineView_ rowForItem:item]]);
+ } else {
+ // Reset image to default value.
+ [cell setImagePosition:NSImageOverlaps];
+ }
+}
+
@end // ExtensionInstallDialogController
void ShowExtensionInstallDialogImpl(

Powered by Google App Engine
This is Rietveld 408576698