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