OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.
h" | 5 #import "chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.
h" |
6 | 6 |
7 #include "base/i18n/rtl.h" | 7 #include "base/i18n/rtl.h" |
8 #include "base/mac/bundle_locations.h" | 8 #include "base/mac/bundle_locations.h" |
9 #include "base/mac/mac_util.h" | 9 #include "base/mac/mac_util.h" |
10 #include "base/memory/scoped_nsobject.h" | 10 #include "base/memory/scoped_nsobject.h" |
(...skipping 11 matching lines...) Expand all Loading... |
22 #include "ui/base/l10n/l10n_util_mac.h" | 22 #include "ui/base/l10n/l10n_util_mac.h" |
23 | 23 |
24 using content::OpenURLParams; | 24 using content::OpenURLParams; |
25 using content::Referrer; | 25 using content::Referrer; |
26 using extensions::BundleInstaller; | 26 using extensions::BundleInstaller; |
27 | 27 |
28 @interface ExtensionInstallDialogController () | 28 @interface ExtensionInstallDialogController () |
29 - (BOOL)isBundleInstall; | 29 - (BOOL)isBundleInstall; |
30 - (BOOL)isInlineInstall; | 30 - (BOOL)isInlineInstall; |
31 - (void)appendRatingStar:(const gfx::ImageSkia*)skiaImage; | 31 - (void)appendRatingStar:(const gfx::ImageSkia*)skiaImage; |
| 32 - (void)onOutlineViewRowCountDidChange; |
32 @end | 33 @end |
33 | 34 |
34 namespace { | 35 namespace { |
35 | 36 |
36 // Padding above the warnings separator, we must also subtract this when hiding | 37 // Padding above the warnings separator, we must also subtract this when hiding |
37 // it. | 38 // it. |
38 const CGFloat kWarningsSeparatorPadding = 14; | 39 const CGFloat kWarningsSeparatorPadding = 14; |
39 | 40 |
40 // Maximum height we will adjust controls to when trying to accomodate their | 41 // Maximum height we will adjust controls to when trying to accomodate their |
41 // contents. | 42 // contents. |
42 const CGFloat kMaxControlHeight = 400; | 43 const CGFloat kMaxControlHeight = 400; |
43 | 44 |
| 45 const NSString* kTitleKey = @"title"; |
| 46 const NSString* kIsGroupItemKey = @"isGroupItem"; |
| 47 const NSString* kChildrenKey = @"children"; |
| 48 const NSString* kCanExpandKey = @"canExpand"; |
| 49 |
44 // Adjust the |control|'s height so that its content is not clipped. | 50 // Adjust the |control|'s height so that its content is not clipped. |
45 // This also adds the change in height to the |totalOffset| and shifts the | 51 // This also adds the change in height to the |totalOffset| and shifts the |
46 // control down by that amount. | 52 // control down by that amount. |
47 void OffsetControlVerticallyToFitContent(NSControl* control, | 53 void OffsetControlVerticallyToFitContent(NSControl* control, |
48 CGFloat* totalOffset) { | 54 CGFloat* totalOffset) { |
49 // Adjust the control's height so that its content is not clipped. | 55 // Adjust the control's height so that its content is not clipped. |
50 NSRect currentRect = [control frame]; | 56 NSRect currentRect = [control frame]; |
51 NSRect fitRect = currentRect; | 57 NSRect fitRect = currentRect; |
52 fitRect.size.height = kMaxControlHeight; | 58 fitRect.size.height = kMaxControlHeight; |
53 CGFloat desiredHeight = [[control cell] cellSizeForBounds:fitRect].height; | 59 CGFloat desiredHeight = [[control cell] cellSizeForBounds:fitRect].height; |
54 CGFloat offset = desiredHeight - currentRect.size.height; | 60 CGFloat offset = desiredHeight - currentRect.size.height; |
55 | 61 |
56 [control setFrameSize:NSMakeSize(currentRect.size.width, | 62 [control setFrameSize:NSMakeSize(currentRect.size.width, |
57 currentRect.size.height + offset)]; | 63 currentRect.size.height + offset)]; |
58 | 64 |
59 *totalOffset += offset; | 65 *totalOffset += offset; |
60 | 66 |
61 // Move the control vertically by the new total offset. | 67 // Move the control vertically by the new total offset. |
62 NSPoint origin = [control frame].origin; | 68 NSPoint origin = [control frame].origin; |
63 origin.y -= *totalOffset; | 69 origin.y -= *totalOffset; |
64 [control setFrameOrigin:origin]; | 70 [control setFrameOrigin:origin]; |
65 } | 71 } |
66 | 72 |
| 73 // Gets the desired height of |outlineView|. Simply using the view's frame |
| 74 // doesn't work if an animation is pending. |
| 75 CGFloat GetDesiredOutlineViewHeight(NSOutlineView* outlineView) { |
| 76 CGFloat height = 0; |
| 77 for (NSInteger i = 0; i < [outlineView numberOfRows]; ++i) |
| 78 height += [outlineView rectOfRow:i].size.height; |
| 79 return height; |
| 80 } |
| 81 |
| 82 void OffsetOutlineViewVerticallyToFitContent(NSOutlineView* outlineView, |
| 83 CGFloat* totalOffset) { |
| 84 NSScrollView* scrollView = [outlineView enclosingScrollView]; |
| 85 NSRect frame = [scrollView frame]; |
| 86 CGFloat desiredHeight = GetDesiredOutlineViewHeight(outlineView); |
| 87 CGFloat offset = desiredHeight - frame.size.height; |
| 88 frame.size.height += offset; |
| 89 |
| 90 *totalOffset += offset; |
| 91 |
| 92 // Move the control vertically by the new total offset. |
| 93 frame.origin.y -= *totalOffset; |
| 94 [scrollView setFrame:frame]; |
| 95 } |
| 96 |
67 void AppendRatingStarsShim(const gfx::ImageSkia* skiaImage, void* data) { | 97 void AppendRatingStarsShim(const gfx::ImageSkia* skiaImage, void* data) { |
68 ExtensionInstallDialogController* controller = | 98 ExtensionInstallDialogController* controller = |
69 static_cast<ExtensionInstallDialogController*>(data); | 99 static_cast<ExtensionInstallDialogController*>(data); |
70 [controller appendRatingStar:skiaImage]; | 100 [controller appendRatingStar:skiaImage]; |
71 } | 101 } |
72 | 102 |
| 103 NSDictionary* BuildItem(NSString* title, BOOL isGroupItem, NSArray* children) { |
| 104 BOOL canExpand = YES; |
| 105 if (!children) { |
| 106 // Add a dummy child even though this is a leaf node. This will cause |
| 107 // the outline view to show a disclosure triangle for this item. |
| 108 // This is later overriden in willDisplayOutlineCell: to draw a bullet |
| 109 // instead. (The bullet could be placed in the title instead but then |
| 110 // the bullet wouldn't line up with disclosure triangles of sibling nodes.) |
| 111 children = [NSArray arrayWithObject:[NSDictionary dictionary]]; |
| 112 canExpand = false; |
| 113 } |
| 114 |
| 115 return [NSDictionary dictionaryWithObjectsAndKeys: |
| 116 title, kTitleKey, |
| 117 [NSNumber numberWithBool:isGroupItem], kIsGroupItemKey, |
| 118 children, kChildrenKey, |
| 119 [NSNumber numberWithBool:canExpand], kCanExpandKey, |
| 120 nil]; |
| 121 } |
| 122 |
| 123 NSDictionary* BuildIssue(const IssueAdviceInfoEntry& issue) { |
| 124 if (issue.details.empty()) |
| 125 return BuildItem(SysUTF16ToNSString(issue.description), NO, nil); |
| 126 |
| 127 NSMutableArray* details = [NSMutableArray array]; |
| 128 for (size_t j = 0; j < issue.details.size(); ++j) { |
| 129 [details addObject:BuildItem( |
| 130 SysUTF16ToNSString(issue.details[j]), NO, nil)]; |
| 131 } |
| 132 return BuildItem(SysUTF16ToNSString(issue.description), NO, details); |
| 133 } |
| 134 |
| 135 NSArray* BuildWarnings(const ExtensionInstallPrompt::Prompt& prompt) { |
| 136 NSMutableArray* warnings = [NSMutableArray array]; |
| 137 |
| 138 if (prompt.GetPermissionCount() > 0) { |
| 139 NSMutableArray* children = [NSMutableArray array]; |
| 140 for (size_t i = 0; i < prompt.GetPermissionCount(); ++i) { |
| 141 [children addObject:BuildItem( |
| 142 SysUTF16ToNSString(prompt.GetPermission(i)), NO, nil)]; |
| 143 } |
| 144 [warnings addObject:BuildItem( |
| 145 SysUTF16ToNSString(prompt.GetPermissionsHeading()), YES, children)]; |
| 146 } |
| 147 |
| 148 if (prompt.GetOAuthIssueCount() > 0) { |
| 149 NSMutableArray* children = [NSMutableArray array]; |
| 150 for (size_t i = 0; i < prompt.GetOAuthIssueCount(); ++i) |
| 151 [children addObject:BuildIssue(prompt.GetOAuthIssue(i))]; |
| 152 [warnings addObject:BuildItem( |
| 153 SysUTF16ToNSString(prompt.GetOAuthHeading()), YES, children)]; |
| 154 } |
| 155 |
| 156 return warnings; |
| 157 } |
| 158 |
| 159 void DrawBulletInFrame(NSRect frame) { |
| 160 NSRect rect; |
| 161 rect.size.width = std::min(frame.size.width, frame.size.height) * 0.38; |
| 162 rect.size.height = rect.size.width; |
| 163 rect.origin.x = frame.origin.x + (frame.size.width - rect.size.width) / 2.0; |
| 164 rect.origin.y = frame.origin.y + (frame.size.height - rect.size.height) / 2.0; |
| 165 rect = NSIntegralRect(rect); |
| 166 |
| 167 [[NSColor colorWithCalibratedWhite:0.0 alpha:0.42] set]; |
| 168 [[NSBezierPath bezierPathWithOvalInRect:rect] fill]; |
| 169 } |
| 170 |
73 } | 171 } |
74 | 172 |
75 @implementation ExtensionInstallDialogController | 173 @implementation ExtensionInstallDialogController |
76 | 174 |
77 @synthesize iconView = iconView_; | 175 @synthesize iconView = iconView_; |
78 @synthesize titleField = titleField_; | 176 @synthesize titleField = titleField_; |
79 @synthesize itemsField = itemsField_; | 177 @synthesize itemsField = itemsField_; |
80 @synthesize subtitleField = subtitleField_; | |
81 @synthesize warningsField = warningsField_; | |
82 @synthesize cancelButton = cancelButton_; | 178 @synthesize cancelButton = cancelButton_; |
83 @synthesize okButton = okButton_; | 179 @synthesize okButton = okButton_; |
| 180 @synthesize outlineView = outlineView_; |
84 @synthesize warningsSeparator = warningsSeparator_; | 181 @synthesize warningsSeparator = warningsSeparator_; |
85 @synthesize ratingStars = ratingStars_; | 182 @synthesize ratingStars = ratingStars_; |
86 @synthesize ratingCountField = ratingCountField_; | 183 @synthesize ratingCountField = ratingCountField_; |
87 @synthesize userCountField = userCountField_; | 184 @synthesize userCountField = userCountField_; |
88 | 185 |
89 - (id)initWithParentWindow:(NSWindow*)window | 186 - (id)initWithParentWindow:(NSWindow*)window |
90 navigator:(content::PageNavigator*)navigator | 187 navigator:(content::PageNavigator*)navigator |
91 delegate:(ExtensionInstallPrompt::Delegate*)delegate | 188 delegate:(ExtensionInstallPrompt::Delegate*)delegate |
92 prompt:(const ExtensionInstallPrompt::Prompt&)prompt { | 189 prompt:(const ExtensionInstallPrompt::Prompt&)prompt { |
93 NSString* nibpath = nil; | 190 NSString* nibpath = nil; |
| 191 warnings_.reset([BuildWarnings(prompt) retain]); |
94 | 192 |
95 // We use a different XIB in the case of bundle installs, inline installs or | 193 // We use a different XIB in the case of bundle installs, inline installs or |
96 // no permission warnings. These are laid out nicely for the data they | 194 // no permission warnings. These are laid out nicely for the data they |
97 // display. | 195 // display. |
98 if (prompt.type() == ExtensionInstallPrompt::BUNDLE_INSTALL_PROMPT) { | 196 if (prompt.type() == ExtensionInstallPrompt::BUNDLE_INSTALL_PROMPT) { |
99 nibpath = [base::mac::FrameworkBundle() | 197 nibpath = [base::mac::FrameworkBundle() |
100 pathForResource:@"ExtensionInstallPromptBundle" | 198 pathForResource:@"ExtensionInstallPromptBundle" |
101 ofType:@"nib"]; | 199 ofType:@"nib"]; |
102 } else if (prompt.type() == ExtensionInstallPrompt::INLINE_INSTALL_PROMPT) { | 200 } else if (prompt.type() == ExtensionInstallPrompt::INLINE_INSTALL_PROMPT) { |
103 nibpath = [base::mac::FrameworkBundle() | 201 nibpath = [base::mac::FrameworkBundle() |
104 pathForResource:@"ExtensionInstallPromptInline" | 202 pathForResource:@"ExtensionInstallPromptInline" |
105 ofType:@"nib"]; | 203 ofType:@"nib"]; |
106 } else if (prompt.GetPermissionCount() == 0) { | 204 } else if (prompt.GetPermissionCount() == 0 && |
| 205 prompt.GetOAuthIssueCount() == 0) { |
107 nibpath = [base::mac::FrameworkBundle() | 206 nibpath = [base::mac::FrameworkBundle() |
108 pathForResource:@"ExtensionInstallPromptNoWarnings" | 207 pathForResource:@"ExtensionInstallPromptNoWarnings" |
109 ofType:@"nib"]; | 208 ofType:@"nib"]; |
110 } else { | 209 } else { |
111 nibpath = [base::mac::FrameworkBundle() | 210 nibpath = [base::mac::FrameworkBundle() |
112 pathForResource:@"ExtensionInstallPrompt" | 211 pathForResource:@"ExtensionInstallPrompt" |
113 ofType:@"nib"]; | 212 ofType:@"nib"]; |
114 } | 213 } |
115 | 214 |
116 if ((self = [super initWithWindowNibPath:nibpath owner:self])) { | 215 if ((self = [super initWithWindowNibPath:nibpath owner:self])) { |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 [cancelButton_ setFrame:NSOffsetRect([cancelButton_ frame], | 292 [cancelButton_ setFrame:NSOffsetRect([cancelButton_ frame], |
194 -buttonDelta.width, 0)]; | 293 -buttonDelta.width, 0)]; |
195 } | 294 } |
196 buttonDelta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:cancelButton_]; | 295 buttonDelta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:cancelButton_]; |
197 if (buttonDelta.width) { | 296 if (buttonDelta.width) { |
198 [cancelButton_ setFrame:NSOffsetRect([cancelButton_ frame], | 297 [cancelButton_ setFrame:NSOffsetRect([cancelButton_ frame], |
199 -buttonDelta.width, 0)]; | 298 -buttonDelta.width, 0)]; |
200 } | 299 } |
201 | 300 |
202 if ([self isBundleInstall]) { | 301 if ([self isBundleInstall]) { |
203 [subtitleField_ setStringValue:base::SysUTF16ToNSString( | |
204 prompt_->GetPermissionsHeading())]; | |
205 | |
206 // We display the list of extension names as a simple text string, seperated | 302 // We display the list of extension names as a simple text string, seperated |
207 // by newlines. | 303 // by newlines. |
208 BundleInstaller::ItemList items = prompt_->bundle()->GetItemsWithState( | 304 BundleInstaller::ItemList items = prompt_->bundle()->GetItemsWithState( |
209 BundleInstaller::Item::STATE_PENDING); | 305 BundleInstaller::Item::STATE_PENDING); |
210 | 306 |
211 NSMutableString* joinedItems = [NSMutableString string]; | 307 NSMutableString* joinedItems = [NSMutableString string]; |
212 for (size_t i = 0; i < items.size(); ++i) { | 308 for (size_t i = 0; i < items.size(); ++i) { |
213 if (i > 0) | 309 if (i > 0) |
214 [joinedItems appendString:@"\n"]; | 310 [joinedItems appendString:@"\n"]; |
215 [joinedItems appendString:base::SysUTF16ToNSString( | 311 [joinedItems appendString:base::SysUTF16ToNSString( |
216 items[i].GetNameForDisplay())]; | 312 items[i].GetNameForDisplay())]; |
217 } | 313 } |
218 [itemsField_ setStringValue:joinedItems]; | 314 [itemsField_ setStringValue:joinedItems]; |
219 | 315 |
220 // Adjust the controls to fit the list of extensions. | 316 // Adjust the controls to fit the list of extensions. |
221 OffsetControlVerticallyToFitContent(itemsField_, &totalOffset); | 317 OffsetControlVerticallyToFitContent(itemsField_, &totalOffset); |
222 } | 318 } |
223 | 319 |
224 // If there are any warnings, then we have to do some special layout. | 320 // If there are any warnings or OAuth issues, then we have to do some special |
225 if (prompt_->GetPermissionCount() > 0) { | 321 // layout. |
226 [subtitleField_ setStringValue:base::SysUTF16ToNSString( | 322 if (prompt_->GetPermissionCount() > 0 || prompt_->GetOAuthIssueCount() > 0) { |
227 prompt_->GetPermissionsHeading())]; | 323 NSSize spacing = [outlineView_ intercellSpacing]; |
228 | 324 spacing.width += 2; |
229 // We display the permission warnings as a simple text string, separated by | 325 spacing.height += 2; |
230 // newlines. | 326 [outlineView_ setIntercellSpacing:spacing]; |
231 NSMutableString* joinedWarnings = [NSMutableString string]; | 327 [[[[outlineView_ tableColumns] objectAtIndex:0] dataCell] setWraps:YES]; |
232 for (size_t i = 0; i < prompt_->GetPermissionCount(); ++i) { | 328 for (id item in warnings_.get()) { |
233 if (i > 0) | 329 if ([[item objectForKey:kIsGroupItemKey] boolValue]) |
234 [joinedWarnings appendString:@"\n"]; | 330 [outlineView_ expandItem:item expandChildren:NO]; |
235 [joinedWarnings appendString:base::SysUTF16ToNSString( | |
236 prompt_->GetPermission(i))]; | |
237 } | 331 } |
238 [warningsField_ setStringValue:joinedWarnings]; | 332 // Adjust the outline view to fit the warnings. |
239 | 333 OffsetOutlineViewVerticallyToFitContent(outlineView_, &totalOffset); |
240 // In the store version of the dialog the icon extends past the one-line | |
241 // version of the permission field. Therefore when increasing the window | |
242 // size for multi-line permissions we don't have to add the full offset, | |
243 // only the part that extends past the icon. | |
244 CGFloat warningsGrowthSlack = 0; | |
245 if (![self isBundleInstall] && | |
246 [warningsField_ frame].origin.y > [iconView_ frame].origin.y) { | |
247 warningsGrowthSlack = | |
248 [warningsField_ frame].origin.y - [iconView_ frame].origin.y; | |
249 } | |
250 | |
251 // Adjust the controls to fit the permission warnings. | |
252 OffsetControlVerticallyToFitContent(subtitleField_, &totalOffset); | |
253 OffsetControlVerticallyToFitContent(warningsField_, &totalOffset); | |
254 | |
255 totalOffset = MAX(totalOffset - warningsGrowthSlack, 0); | |
256 } else if ([self isInlineInstall] || [self isBundleInstall]) { | 334 } else if ([self isInlineInstall] || [self isBundleInstall]) { |
257 // Inline and bundle installs that don't have a permissions section need to | 335 // Inline and bundle installs that don't have a permissions section need to |
258 // hide controls related to that and shrink the window by the space they | 336 // hide controls related to that and shrink the window by the space they |
259 // take up. | 337 // take up. |
260 NSRect hiddenRect = NSUnionRect([warningsSeparator_ frame], | 338 NSRect hiddenRect = NSUnionRect([warningsSeparator_ frame], |
261 [subtitleField_ frame]); | 339 [[outlineView_ enclosingScrollView] frame]); |
262 hiddenRect = NSUnionRect(hiddenRect, [warningsField_ frame]); | |
263 [warningsSeparator_ setHidden:YES]; | 340 [warningsSeparator_ setHidden:YES]; |
264 [subtitleField_ setHidden:YES]; | 341 [[outlineView_ enclosingScrollView] setHidden:YES]; |
265 [warningsField_ setHidden:YES]; | |
266 totalOffset -= hiddenRect.size.height + kWarningsSeparatorPadding; | 342 totalOffset -= hiddenRect.size.height + kWarningsSeparatorPadding; |
267 } | 343 } |
268 | 344 |
269 // If necessary, adjust the window size. | 345 // If necessary, adjust the window size. |
270 if (totalOffset) { | 346 if (totalOffset) { |
271 NSRect currentRect = [[self window] frame]; | 347 NSRect currentRect = [[self window] frame]; |
272 [[self window] setFrame:NSMakeRect(currentRect.origin.x, | 348 [[self window] setFrame:NSMakeRect(currentRect.origin.x, |
273 currentRect.origin.y - totalOffset, | 349 currentRect.origin.y - totalOffset, |
274 currentRect.size.width, | 350 currentRect.size.width, |
275 currentRect.size.height + totalOffset) | 351 currentRect.size.height + totalOffset) |
(...skipping 30 matching lines...) Expand all Loading... |
306 CGFloat maxStarRight = 0; | 382 CGFloat maxStarRight = 0; |
307 if ([[ratingStars_ subviews] count]) { | 383 if ([[ratingStars_ subviews] count]) { |
308 maxStarRight = NSMaxX([[[ratingStars_ subviews] lastObject] frame]); | 384 maxStarRight = NSMaxX([[[ratingStars_ subviews] lastObject] frame]); |
309 } | 385 } |
310 NSRect starBounds = NSMakeRect(maxStarRight, 0, | 386 NSRect starBounds = NSMakeRect(maxStarRight, 0, |
311 skiaImage->width(), skiaImage->height()); | 387 skiaImage->width(), skiaImage->height()); |
312 [view setFrame:starBounds]; | 388 [view setFrame:starBounds]; |
313 [ratingStars_ addSubview:view]; | 389 [ratingStars_ addSubview:view]; |
314 } | 390 } |
315 | 391 |
| 392 - (void)onOutlineViewRowCountDidChange { |
| 393 // Force the outline view to update. |
| 394 [outlineView_ reloadData]; |
| 395 |
| 396 CGFloat totalOffset = 0.0; |
| 397 OffsetOutlineViewVerticallyToFitContent(outlineView_, &totalOffset); |
| 398 if (totalOffset) { |
| 399 NSRect currentRect = [[self window] frame]; |
| 400 [[self window] setFrame:NSMakeRect(currentRect.origin.x, |
| 401 currentRect.origin.y - totalOffset, |
| 402 currentRect.size.width, |
| 403 currentRect.size.height + totalOffset) |
| 404 display:YES]; |
| 405 } |
| 406 } |
| 407 |
| 408 - (id)outlineView:(NSOutlineView*)outlineView |
| 409 child:(NSInteger)index |
| 410 ofItem:(id)item { |
| 411 if (!item) |
| 412 return [warnings_ objectAtIndex:index]; |
| 413 if ([item isKindOfClass:[NSDictionary class]]) |
| 414 return [[item objectForKey:kChildrenKey] objectAtIndex:index]; |
| 415 NOTREACHED(); |
| 416 return nil; |
| 417 } |
| 418 |
| 419 - (BOOL)outlineView:(NSOutlineView*)outlineView |
| 420 isItemExpandable:(id)item { |
| 421 return [self outlineView:outlineView numberOfChildrenOfItem:item] > 0; |
| 422 } |
| 423 |
| 424 - (NSInteger)outlineView:(NSOutlineView*)outlineView |
| 425 numberOfChildrenOfItem:(id)item { |
| 426 if (!item) |
| 427 return [warnings_ count]; |
| 428 if ([item isKindOfClass:[NSDictionary class]]) |
| 429 return [[item objectForKey:kChildrenKey] count]; |
| 430 NOTREACHED(); |
| 431 return 0; |
| 432 } |
| 433 |
| 434 - (id)outlineView:(NSOutlineView*)outlineView |
| 435 objectValueForTableColumn:(NSTableColumn *)tableColumn |
| 436 byItem:(id)item { |
| 437 if ([item isKindOfClass:[NSDictionary class]]) |
| 438 return [item objectForKey:kTitleKey]; |
| 439 NOTREACHED(); |
| 440 return nil; |
| 441 } |
| 442 |
| 443 - (BOOL)outlineView:(NSOutlineView *)outlineView |
| 444 shouldExpandItem:(id)item { |
| 445 return [[item objectForKey:kCanExpandKey] boolValue]; |
| 446 } |
| 447 |
| 448 - (void)outlineViewItemDidExpand:sender { |
| 449 // Call via run loop to avoid animation glitches. |
| 450 [self performSelector:@selector(onOutlineViewRowCountDidChange) |
| 451 withObject:nil |
| 452 afterDelay:0]; |
| 453 } |
| 454 |
| 455 - (void)outlineViewItemDidCollapse:sender { |
| 456 // Call via run loop to avoid animation glitches. |
| 457 [self performSelector:@selector(onOutlineViewRowCountDidChange) |
| 458 withObject:nil |
| 459 afterDelay:0]; |
| 460 } |
| 461 |
| 462 - (CGFloat)outlineView:(NSOutlineView *)outlineView |
| 463 heightOfRowByItem:(id)item { |
| 464 // Prevent reentrancy due to the frameOfCellAtColumn:row: call below. |
| 465 if (isComputingRowHeight) |
| 466 return 1; |
| 467 isComputingRowHeight = YES; |
| 468 |
| 469 NSCell* cell = [[[outlineView_ tableColumns] objectAtIndex:0] dataCell]; |
| 470 [cell setStringValue:[item objectForKey:kTitleKey]]; |
| 471 NSRect bounds = NSZeroRect; |
| 472 NSInteger row = [outlineView_ rowForItem:item]; |
| 473 bounds.size.width = [outlineView_ frameOfCellAtColumn:0 |
| 474 row:row].size.width; |
| 475 bounds.size.height = kMaxControlHeight; |
| 476 |
| 477 isComputingRowHeight = NO; |
| 478 return [cell cellSizeForBounds:bounds].height; |
| 479 } |
| 480 |
| 481 - (BOOL)outlineView:(NSOutlineView*)outlineView |
| 482 shouldShowOutlineCellForItem:(id)item { |
| 483 // The top most group header items are always expanded so hide their |
| 484 // disclosure trianggles. |
| 485 return ![[item objectForKey:kIsGroupItemKey] boolValue]; |
| 486 } |
| 487 |
| 488 - (void)outlineView:(NSOutlineView*)outlineView |
| 489 willDisplayCell:(id)cell |
| 490 forTableColumn:(NSTableColumn *)tableColumn |
| 491 item:(id)item { |
| 492 if ([[item objectForKey:kIsGroupItemKey] boolValue]) |
| 493 [cell setFont:[NSFont boldSystemFontOfSize:11.0]]; |
| 494 else |
| 495 [cell setFont:[NSFont systemFontOfSize:11.0]]; |
| 496 } |
| 497 |
| 498 - (void)outlineView:(NSOutlineView *)outlineView |
| 499 willDisplayOutlineCell:(id)cell |
| 500 forTableColumn:(NSTableColumn *)tableColumn |
| 501 item:(id)item { |
| 502 // Replace disclosure triangles with bullet lists for leaf nodes. |
| 503 if (![[item objectForKey:kCanExpandKey] boolValue]) { |
| 504 [cell setImagePosition:NSNoImage]; |
| 505 DrawBulletInFrame([outlineView_ frameOfOutlineCellAtRow: |
| 506 [outlineView_ rowForItem:item]]); |
| 507 } else { |
| 508 // Reset image to default value. |
| 509 [cell setImagePosition:NSImageOverlaps]; |
| 510 } |
| 511 } |
| 512 |
316 @end // ExtensionInstallDialogController | 513 @end // ExtensionInstallDialogController |
317 | 514 |
318 void ShowExtensionInstallDialogImpl( | 515 void ShowExtensionInstallDialogImpl( |
319 gfx::NativeWindow parent, | 516 gfx::NativeWindow parent, |
320 content::PageNavigator* navigator, | 517 content::PageNavigator* navigator, |
321 ExtensionInstallPrompt::Delegate* delegate, | 518 ExtensionInstallPrompt::Delegate* delegate, |
322 const ExtensionInstallPrompt::Prompt& prompt) { | 519 const ExtensionInstallPrompt::Prompt& prompt) { |
323 ExtensionInstallDialogController* controller = | 520 ExtensionInstallDialogController* controller = |
324 [[ExtensionInstallDialogController alloc] | 521 [[ExtensionInstallDialogController alloc] |
325 initWithParentWindow:parent | 522 initWithParentWindow:parent |
326 navigator:navigator | 523 navigator:navigator |
327 delegate:delegate | 524 delegate:delegate |
328 prompt:prompt]; | 525 prompt:prompt]; |
329 | 526 |
330 // TODO(mihaip): Switch this to be tab-modal (http://crbug.com/95455) | 527 // TODO(mihaip): Switch this to be tab-modal (http://crbug.com/95455) |
331 [controller runAsModalSheet]; | 528 [controller runAsModalSheet]; |
332 } | 529 } |
OLD | NEW |