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

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: " 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..b3509b1d05cc794f785bc96ab158de4ca6658d1a 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
@@ -4,6 +4,7 @@
#import "chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h"
+#include "base/auto_reset.h"
#include "base/i18n/rtl.h"
#include "base/mac/bundle_locations.h"
#include "base/mac/mac_util.h"
@@ -29,6 +30,12 @@ using extensions::BundleInstaller;
- (BOOL)isBundleInstall;
- (BOOL)isInlineInstall;
- (void)appendRatingStar:(const gfx::ImageSkia*)skiaImage;
+- (void)onOutlineViewRowCountDidChange;
+- (NSDictionary*)buildItemWithTitle:(NSString*)title
+ isGroupItem:(BOOL)isGroupItem
+ children:(NSArray*)children;
+- (NSDictionary*)buildIssue:(const IssueAdviceInfoEntry&)issue;
+- (NSArray*)buildWarnings:(const ExtensionInstallPrompt::Prompt&)prompt;
@end
namespace {
@@ -41,6 +48,11 @@ const CGFloat kWarningsSeparatorPadding = 14;
// contents.
const CGFloat kMaxControlHeight = 400;
+NSString* const kTitleKey = @"title";
+NSString* const kIsGroupItemKey = @"isGroupItem";
+NSString* const kChildrenKey = @"children";
+NSString* const 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.
@@ -51,10 +63,10 @@ void OffsetControlVerticallyToFitContent(NSControl* control,
NSRect fitRect = currentRect;
fitRect.size.height = kMaxControlHeight;
CGFloat desiredHeight = [[control cell] cellSizeForBounds:fitRect].height;
- CGFloat offset = desiredHeight - currentRect.size.height;
+ CGFloat offset = desiredHeight - NSHeight(currentRect);
- [control setFrameSize:NSMakeSize(currentRect.size.width,
- currentRect.size.height + offset)];
+ [control setFrameSize:NSMakeSize(NSWidth(currentRect),
+ NSHeight(currentRect) + offset)];
*totalOffset += offset;
@@ -64,12 +76,48 @@ 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 += NSHeight([outlineView rectOfRow:i]);
+ return height;
+}
+
+void OffsetOutlineViewVerticallyToFitContent(NSOutlineView* outlineView,
+ CGFloat* totalOffset) {
+ NSScrollView* scrollView = [outlineView enclosingScrollView];
+ NSRect frame = [scrollView frame];
+ CGFloat desiredHeight = GetDesiredOutlineViewHeight(outlineView);
+ CGFloat offset = desiredHeight - NSHeight(frame);
+ 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];
}
+void DrawBulletInFrame(NSRect frame) {
+ NSRect rect;
+ rect.size.width = std::min(NSWidth(frame), NSHeight(frame)) * 0.38;
+ rect.size.height = NSWidth(rect);
+ rect.origin.x = frame.origin.x + (NSWidth(frame) - NSWidth(rect)) / 2.0;
+ rect.origin.y = frame.origin.y + (NSHeight(frame) - NSHeight(rect)) / 2.0;
+ rect = NSIntegralRect(rect);
+
+ [[NSColor colorWithCalibratedWhite:0.0 alpha:0.42] set];
+ [[NSBezierPath bezierPathWithOvalInRect:rect] fill];
+}
+
}
@implementation ExtensionInstallDialogController
@@ -77,10 +125,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 +138,7 @@ void AppendRatingStarsShim(const gfx::ImageSkia* skiaImage, void* data) {
delegate:(ExtensionInstallPrompt::Delegate*)delegate
prompt:(const ExtensionInstallPrompt::Prompt&)prompt {
NSString* nibpath = nil;
+ warnings_.reset([[self 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 +151,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 +249,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,49 +267,29 @@ 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];
- totalOffset -= hiddenRect.size.height + kWarningsSeparatorPadding;
+ [[outlineView_ enclosingScrollView] setHidden:YES];
+ totalOffset -= NSHeight(hiddenRect) + kWarningsSeparatorPadding;
}
// If necessary, adjust the window size.
@@ -271,8 +297,8 @@ void AppendRatingStarsShim(const gfx::ImageSkia* skiaImage, void* data) {
NSRect currentRect = [[self window] frame];
[[self window] setFrame:NSMakeRect(currentRect.origin.x,
currentRect.origin.y - totalOffset,
- currentRect.size.width,
- currentRect.size.height + totalOffset)
+ NSWidth(currentRect),
+ NSHeight(currentRect) + totalOffset)
display:NO];
}
}
@@ -313,6 +339,198 @@ 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];
+ currentRect.origin.y -= totalOffset;
+ currentRect.size.height += totalOffset;
+ [[self window] setFrame:currentRect
+ 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 {
+ return [item objectForKey:kTitleKey];
+}
+
+- (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;
+ AutoReset<BOOL> reset(&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 = NSWidth([outlineView_ frameOfCellAtColumn:0 row:row]);
+ bounds.size.height = kMaxControlHeight;
+
+ 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];
+ }
+}
+
+- (BOOL)outlineView:(NSOutlineView *)outlineView
+ shouldSelectItem:(id)item {
+ return false;
+}
+
+- (NSDictionary*)buildItemWithTitle:(NSString*)title
+ isGroupItem:(BOOL)isGroupItem
+ children:(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 = NO;
+ }
+
+ 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 [self buildItemWithTitle:SysUTF16ToNSString(issue.description)
+ isGroupItem:NO
+ children:nil];
+ }
+
+ NSMutableArray* details = [NSMutableArray array];
+ for (size_t j = 0; j < issue.details.size(); ++j) {
+ [details addObject:
+ [self buildItemWithTitle:SysUTF16ToNSString(issue.details[j])
+ isGroupItem:NO
+ children:nil]];
+ }
+ return [self buildItemWithTitle:SysUTF16ToNSString(issue.description)
+ isGroupItem:NO
+ children: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:
+ [self buildItemWithTitle:SysUTF16ToNSString(prompt.GetPermission(i))
+ isGroupItem:NO
+ children:nil]];
+ }
+ [warnings addObject:[self
+ buildItemWithTitle:SysUTF16ToNSString(prompt.GetPermissionsHeading())
+ isGroupItem:YES
+ children:children]];
+ }
+
+ if (prompt.GetOAuthIssueCount() > 0) {
+ NSMutableArray* children = [NSMutableArray array];
+ for (size_t i = 0; i < prompt.GetOAuthIssueCount(); ++i)
+ [children addObject:[self buildIssue:prompt.GetOAuthIssue(i)]];
+ [warnings addObject:
+ [self buildItemWithTitle:SysUTF16ToNSString(prompt.GetOAuthHeading())
+ isGroupItem:YES
+ children:children]];
+ }
+
+ return warnings;
+}
+
+
@end // ExtensionInstallDialogController
void ShowExtensionInstallDialogImpl(

Powered by Google App Engine
This is Rietveld 408576698