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

Side by Side Diff: chrome/browser/ui/cocoa/web_intent_sheet_controller.mm

Issue 11414153: Remove legacy constrained window dialogs (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #import "chrome/browser/ui/cocoa/web_intent_sheet_controller.h"
6
7 #include "base/memory/scoped_nsobject.h"
8 #include "base/sys_string_conversions.h"
9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/ui/browser_list.h"
11 #import "chrome/browser/ui/cocoa/event_utils.h"
12 #import "chrome/browser/ui/cocoa/hover_close_button.h"
13 #import "chrome/browser/ui/cocoa/hyperlink_button_cell.h"
14 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
15 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
16 #include "chrome/browser/ui/cocoa/web_intent_picker_cocoa.h"
17 #include "chrome/browser/ui/constrained_window.h"
18 #include "chrome/browser/ui/constrained_window_constants.h"
19 #include "chrome/browser/ui/intents/web_intent_picker_delegate.h"
20 #include "chrome/browser/ui/intents/web_intent_picker_model.h"
21 #import "chrome/browser/ui/cocoa/tabs/throbber_view.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/browser/web_contents_view.h"
24 #include "grit/generated_resources.h"
25 #include "grit/google_chrome_strings.h"
26 #include "grit/locale_settings.h"
27 #include "grit/theme_resources.h"
28 #include "grit/ui_resources.h"
29 #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
30 #include "ui/base/l10n/l10n_util.h"
31 #include "ui/base/l10n/l10n_util_mac.h"
32 #include "ui/base/resource/resource_bundle.h"
33 #include "ui/base/text/text_elider.h"
34 #include "ui/gfx/font.h"
35 #include "ui/gfx/image/image.h"
36
37 using content::OpenURLParams;
38 using content::Referrer;
39
40 @interface HyperlinkButtonCell (Private)
41 - (void)customizeButtonCell;
42 @end
43
44 @interface CustomLinkButtonCell : HyperlinkButtonCell
45 @end
46
47 namespace {
48
49 // The width of a service button, in view coordinates.
50 const CGFloat kServiceButtonWidth = 300;
51
52 // Spacing in between sections.
53 const CGFloat kVerticalSpacing = 18;
54
55 // Square size of the close button.
56 const CGFloat kCloseButtonSize = 16;
57
58 // Width of the text fields.
59 const CGFloat kTextWidth = WebIntentPicker::kWindowMinWidth -
60 (WebIntentPicker::kContentAreaBorder * 2.0 + kCloseButtonSize);
61
62 // Maximum number of intents (suggested and installed) displayed.
63 const int kMaxIntentRows = 4;
64
65 // Sets properties on the given |field| to act as title or description labels.
66 void ConfigureTextFieldAsLabel(NSTextField* field) {
67 [field setEditable:NO];
68 [field setSelectable:YES];
69 [field setDrawsBackground:NO];
70 [field setBezeled:NO];
71 }
72
73 NSButton* CreateHyperlinkButton(NSString* title, const NSRect& frame) {
74 NSButton* button = [[NSButton alloc] initWithFrame:frame];
75 scoped_nsobject<CustomLinkButtonCell> cell(
76 [[CustomLinkButtonCell alloc] initTextCell:title]);
77 [cell setControlSize:NSSmallControlSize];
78 [button setCell:cell.get()];
79 [button setButtonType:NSMomentaryPushInButton];
80 [button setBezelStyle:NSRegularSquareBezelStyle];
81
82 return button;
83 }
84
85 } // namespace
86
87
88 // Provide custom link format for intent picker. Removes underline attribute,
89 // since UX direction is "look like WebUI".
90 @implementation CustomLinkButtonCell
91 - (void)customizeButtonCell {
92 [super customizeButtonCell];
93 [self setTextColor:[NSColor colorWithDeviceRed:0x11/255.0
94 green:0x55/255.0
95 blue:0xcc/255.0
96 alpha:0xff/255.0]];
97 }
98
99 - (NSDictionary*)linkAttributes {
100 scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
101 [[NSParagraphStyle defaultParagraphStyle] mutableCopy]);
102 [paragraphStyle setAlignment:[self alignment]];
103
104 return @{
105 NSForegroundColorAttributeName: [self textColor],
106 NSFontAttributeName: [self font],
107 NSCursorAttributeName: [NSCursor pointingHandCursor],
108 NSParagraphStyleAttributeName: paragraphStyle.get()
109 };
110 }
111 @end
112
113 // This simple NSView subclass is used as the single subview of the page info
114 // bubble's window's contentView. Drawing is flipped so that layout of the
115 // sections is easier. Apple recommends flipping the coordinate origin when
116 // doing a lot of text layout because it's more natural.
117 @interface WebIntentsContentView : NSView
118 @end
119 @implementation WebIntentsContentView
120 - (BOOL)isFlipped {
121 return YES;
122 }
123
124 - (void)drawRect:(NSRect)rect {
125 [[NSColor colorWithCalibratedWhite:1.0 alpha:1.0] set];
126 NSRectFill(rect);
127 }
128 @end
129
130 // NSImageView subclassed to allow fading the alpha value of the image to
131 // indicate an inactive/disabled extension.
132 @interface DimmableImageView : NSImageView {
133 @private
134 CGFloat alpha;
135 }
136
137 - (void)setEnabled:(BOOL)enabled;
138
139 // NSView override
140 - (void)drawRect:(NSRect)rect;
141 @end
142
143 @implementation DimmableImageView
144 - (void)drawRect:(NSRect)rect {
145 NSImage* image = [self image];
146
147 NSRect sourceRect, destinationRect;
148 sourceRect.origin = NSZeroPoint;
149 sourceRect.size = [image size];
150
151 destinationRect.origin = NSZeroPoint;
152 destinationRect.size = [self frame].size;
153
154 // If the source image is smaller than the destination, center it.
155 if (destinationRect.size.width > sourceRect.size.width) {
156 destinationRect.origin.x =
157 (destinationRect.size.width - sourceRect.size.width) / 2.0;
158 destinationRect.size.width = sourceRect.size.width;
159 }
160 if (destinationRect.size.height > sourceRect.size.height) {
161 destinationRect.origin.y =
162 (destinationRect.size.height - sourceRect.size.height) / 2.0;
163 destinationRect.size.height = sourceRect.size.height;
164 }
165
166 [image drawInRect:destinationRect
167 fromRect:sourceRect
168 operation:NSCompositeSourceOver
169 fraction:alpha];
170 }
171
172 - (void)setEnabled:(BOOL)enabled {
173 if (enabled)
174 alpha = 1.0;
175 else
176 alpha = 0.5;
177 [self setNeedsDisplay:YES];
178 }
179 @end
180
181 @interface WaitingView : NSView {
182 @private
183 scoped_nsobject<NSTextField> text_;
184 scoped_nsobject<ThrobberView> throbber_;
185 }
186 @end
187
188 @implementation WaitingView
189 - (id)init {
190 NSRect frame = NSMakeRect(WebIntentPicker::kContentAreaBorder, 0,
191 kTextWidth, 140);
192
193 if (self = [super initWithFrame:frame]) {
194 const CGFloat kTopMargin = 35.0;
195 const CGFloat kBottomMargin = 25.0;
196 const CGFloat kVerticalSpacing = 18.0;
197 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
198
199 frame.origin = NSMakePoint(WebIntentPicker::kContentAreaBorder,
200 kBottomMargin);
201 frame.size.width = kTextWidth;
202 text_.reset([[NSTextField alloc] initWithFrame:frame]);
203 ConfigureTextFieldAsLabel(text_);
204 [text_ setAlignment:NSCenterTextAlignment];
205 [text_ setFont:[NSFont boldSystemFontOfSize:[NSFont systemFontSize]]];
206 [text_ setStringValue:
207 l10n_util::GetNSStringWithFixup(IDS_INTENT_PICKER_WAIT_FOR_CWS)];
208 frame.size.height +=
209 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
210 text_];
211 [text_ setFrame:frame];
212
213 frame.origin.y += NSHeight(frame) + kVerticalSpacing;
214
215 // The sprite image consists of all the animation frames put together in one
216 // horizontal/wide image. Each animation frame is square in shape within the
217 // sprite.
218 NSImage* iconImage =
219 rb.GetNativeImageNamed(IDR_SPEECH_INPUT_SPINNER).ToNSImage();
220 frame.size = [iconImage size];
221 frame.size.width = NSHeight(frame);
222 frame.origin.x = (WebIntentPicker::kWindowMinWidth - NSWidth(frame))/2.0;
223 throbber_.reset([ThrobberView filmstripThrobberViewWithFrame:frame
224 image:iconImage]);
225
226 frame.size = NSMakeSize(WebIntentPicker::kWindowMinWidth,
227 NSMaxY(frame) + kTopMargin);
228 frame.origin = NSMakePoint(0, 0);
229 [self setSubviews:@[throbber_, text_]];
230 [self setFrame:frame];
231 }
232 return self;
233 }
234 @end
235
236 // An NSView subclass to display ratings stars.
237 @interface RatingsView : NSView
238 // Mark RatingsView as disabled/enabled.
239 - (void)setEnabled:(BOOL)enabled;
240 @end
241
242 @implementation RatingsView
243 - (void)setEnabled:(BOOL)enabled {
244 for (DimmableImageView* imageView in [self subviews])
245 [imageView setEnabled:enabled];
246 }
247 @end
248
249 // NSView for the header of the box.
250 @interface HeaderView : NSView {
251 @private
252 // Used to forward button clicks. Weak reference.
253 scoped_nsobject<NSTextField> titleField_;
254 scoped_nsobject<NSTextField> subtitleField_;
255 scoped_nsobject<NSBox> spacer_;
256 }
257
258 - (id)init;
259 @end
260
261 @implementation HeaderView
262 - (id)init {
263 NSRect contentFrame = NSMakeRect(0, 0, WebIntentPicker::kWindowMinWidth, 1);
264 if (self = [super initWithFrame:contentFrame]) {
265 NSRect frame = NSMakeRect(WebIntentPicker::kContentAreaBorder, 0,
266 kTextWidth, 1);
267
268 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
269 titleField_.reset([[NSTextField alloc] initWithFrame:frame]);
270 ConfigureTextFieldAsLabel(titleField_);
271 gfx::Font titleFont = rb.GetFont(
272 ConstrainedWindowConstants::kTitleFontStyle);
273 titleFont = titleFont.DeriveFont(0, gfx::Font::BOLD);
274 [titleField_ setFont:titleFont.GetNativeFont()];
275
276 frame = NSMakeRect(WebIntentPicker::kContentAreaBorder, 0,
277 kTextWidth, 1);
278 subtitleField_.reset([[NSTextField alloc] initWithFrame:frame]);
279 ConfigureTextFieldAsLabel(subtitleField_);
280 gfx::Font textFont = rb.GetFont(ConstrainedWindowConstants::kTextFontStyle);
281 [subtitleField_ setFont:textFont.GetNativeFont()];
282
283 frame = NSMakeRect(0, 0, WebIntentPicker::kWindowMinWidth, 1.0);
284 spacer_.reset([[NSBox alloc] initWithFrame:frame]);
285 [spacer_ setBoxType:NSBoxSeparator];
286 [spacer_ setBorderColor:[NSColor blackColor]];
287 [spacer_ setAlphaValue:0.2];
288
289 NSArray* subviews = @[titleField_, subtitleField_, spacer_];
290 [self setSubviews:subviews];
291 }
292 return self;
293 }
294
295 - (void)setTitle:(NSString*)title {
296 NSRect frame = [titleField_ frame];
297 [titleField_ setStringValue:title];
298 frame.size.height +=
299 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
300 titleField_];
301 [titleField_ setFrame:frame];
302 }
303
304 - (void)setSubtitle:(NSString*)subtitle {
305 if (subtitle && [subtitle length]) {
306 NSRect frame = [subtitleField_ frame];
307
308 [subtitleField_ setHidden:FALSE];
309 [subtitleField_ setStringValue:subtitle];
310 frame.size.height +=
311 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
312 subtitleField_];
313 [subtitleField_ setFrame:frame];
314 } else {
315 [subtitleField_ setHidden:TRUE];
316 }
317 }
318
319 - (void)performLayout {
320 CGFloat offset = kVerticalSpacing;
321
322 NSRect frame = [spacer_ frame];
323 frame.origin.y = offset;
324 [spacer_ setFrame:frame];
325 offset += NSHeight(frame);
326
327 offset += kVerticalSpacing;
328
329 if (![subtitleField_ isHidden]) {
330 frame = [subtitleField_ frame];
331 frame.origin.y = offset;
332 [subtitleField_ setFrame:frame];
333 offset += NSHeight(frame);
334 }
335
336 frame = [titleField_ frame];
337 frame.origin.y = offset;
338 [titleField_ setFrame:frame];
339 offset += NSHeight(frame);
340
341 // No kContentAreaBorder here, since that is currently handled elsewhere.
342 frame = [self frame];
343 frame.size.height = offset;
344 [self setFrame:frame];
345 }
346 @end
347
348 // NSView for a single row in the intents view.
349 @interface IntentRowView : NSView {
350 @private
351 scoped_nsobject<NSProgressIndicator> throbber_;
352 scoped_nsobject<NSButton> cwsButton_;
353 scoped_nsobject<RatingsView> ratingsWidget_;
354 scoped_nsobject<NSButton> installButton_;
355 scoped_nsobject<DimmableImageView> iconView_;
356 scoped_nsobject<NSTextField> label_;
357 }
358
359 - (id)initWithExtension:
360 (const WebIntentPickerModel::SuggestedExtension*)extension
361 withIndex:(size_t)index
362 forController:(WebIntentPickerSheetController*)controller;
363 - (void)startThrobber;
364 - (void)setEnabled:(BOOL)enabled;
365 - (void)stopThrobber;
366 - (NSInteger)tag;
367 @end
368
369 @implementation IntentRowView
370 const CGFloat kMaxHeight = 34.0;
371 const CGFloat kTitleX = 20.0;
372 const CGFloat kMinAddButtonHeight = 28.0;
373 const CGFloat kAddButtonX = 245;
374 const CGFloat kAddButtonWidth = 128.0;
375
376 + (RatingsView*)createStarWidgetWithRating:(CGFloat)rating {
377 const int kStarSpacing = 1; // Spacing between stars in pixels.
378 const CGFloat kStarSize = 16.0; // Size of the star in pixels.
379
380 NSMutableArray* subviews = [NSMutableArray array];
381
382 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
383 NSRect imageFrame = NSMakeRect(0, 0, kStarSize, kStarSize);
384
385 for (int i = 0; i < 5; ++i) {
386 NSImage* nsImage = rb.GetNativeImageNamed(
387 WebIntentPicker::GetNthStarImageIdFromCWSRating(rating, i)).ToNSImage();
388
389 scoped_nsobject<DimmableImageView> imageView(
390 [[DimmableImageView alloc] initWithFrame:imageFrame]);
391 [imageView setImage:nsImage];
392 [imageView setImageFrameStyle:NSImageFrameNone];
393 [imageView setFrame:imageFrame];
394 [imageView setEnabled:YES];
395 [subviews addObject:imageView];
396 imageFrame.origin.x += kStarSize + kStarSpacing;
397 }
398
399 NSRect frame = NSMakeRect(0, 0, (kStarSize + kStarSpacing) * 5, kStarSize);
400 RatingsView* widget = [[RatingsView alloc] initWithFrame:frame];
401 [widget setSubviews:subviews];
402 return widget;
403 }
404
405
406 - (void)setIcon:(NSImage*)icon {
407 NSRect imageFrame = NSZeroRect;
408
409 iconView_.reset(
410 [[DimmableImageView alloc] initWithFrame:imageFrame]);
411 [iconView_ setImage:icon];
412 [iconView_ setImageFrameStyle:NSImageFrameNone];
413 [iconView_ setEnabled:YES];
414
415 imageFrame.size = [icon size];
416 imageFrame.size.height = std::min(NSHeight(imageFrame), kMaxHeight);
417 imageFrame.origin.y += (kMaxHeight - NSHeight(imageFrame)) / 2.0;
418 [iconView_ setFrame:imageFrame];
419 }
420
421 - (void)setActionButton:(NSString*)title
422 withSelector:(SEL)selector
423 forController:(WebIntentPickerSheetController*)controller {
424
425 NSRect frame = NSMakeRect(kAddButtonX, 0, kAddButtonWidth, 0);
426 installButton_.reset([[NSButton alloc] initWithFrame:frame]);
427 [installButton_ setAlignment:NSCenterTextAlignment];
428 [installButton_ setButtonType:NSMomentaryPushInButton];
429 [installButton_ setBezelStyle:NSRegularSquareBezelStyle];
430 [installButton_ setTitle:title];
431 frame.size.height = std::min(kMinAddButtonHeight, kMaxHeight);
432 frame.origin.y += (kMaxHeight - NSHeight(frame)) / 2.0;
433 [installButton_ setFrame:frame];
434
435 [installButton_ setTarget:controller];
436 [installButton_ setAction:selector];
437 }
438
439 - (id)init {
440 // Build the main view.
441 NSRect contentFrame = NSMakeRect(
442 0, 0, WebIntentPicker::kWindowMinWidth, kMaxHeight);
443 if (self = [super initWithFrame:contentFrame]) {
444 NSMutableArray* subviews = [NSMutableArray array];
445 if (iconView_) [subviews addObject:iconView_];
446 if (label_) [subviews addObject:label_];
447 if (cwsButton_) [subviews addObject:cwsButton_];
448 if (ratingsWidget_) [subviews addObject:ratingsWidget_];
449 if (installButton_) [subviews addObject:installButton_];
450 if (throbber_) [subviews addObject:throbber_];
451 [self setSubviews:subviews];
452 }
453 return self;
454 }
455
456 - (id)initWithExtension:
457 (const WebIntentPickerModel::SuggestedExtension*)extension
458 withIndex:(size_t)index
459 forController:(WebIntentPickerSheetController*)controller {
460 // Add the extension icon.
461 [self setIcon:extension->icon.ToNSImage()];
462
463 // Add the extension title.
464 NSRect frame = NSMakeRect(kTitleX, 0, 0, 0);
465 const string16 elidedTitle = ui::ElideText(
466 extension->title, gfx::Font(), WebIntentPicker::kTitleLinkMaxWidth,
467 ui::ELIDE_AT_END);
468 NSString* string = base::SysUTF16ToNSString(elidedTitle);
469 cwsButton_.reset(CreateHyperlinkButton(string, frame));
470 [cwsButton_ setAlignment:NSCenterTextAlignment];
471 [cwsButton_ setTarget:controller];
472 [cwsButton_ setAction:@selector(openExtensionLink:)];
473 [cwsButton_ setTag:index];
474 [cwsButton_ sizeToFit];
475
476 frame = [cwsButton_ frame];
477 frame.size.height = std::min([[cwsButton_ cell] cellSize].height,
478 kMaxHeight);
479 frame.origin.y = (kMaxHeight - NSHeight(frame)) / 2.0;
480 [cwsButton_ setFrame:frame];
481
482 // Add the star rating
483 CGFloat offsetX = frame.origin.x + NSWidth(frame) +
484 WebIntentPicker::kContentAreaBorder;
485 ratingsWidget_.reset(
486 [IntentRowView
487 createStarWidgetWithRating:extension->average_rating]);
488 frame = [ratingsWidget_ frame];
489 frame.origin.y += (kMaxHeight - NSHeight(frame)) / 2.0;
490 frame.origin.x = offsetX;
491 [ratingsWidget_ setFrame:frame];
492
493 // Add an "add to chromium" button.
494 string = l10n_util::GetNSStringWithFixup(
495 IDS_INTENT_PICKER_INSTALL_EXTENSION);
496 [self setActionButton:string
497 withSelector:@selector(installExtension:)
498 forController:controller];
499 [installButton_ setTag:index];
500
501 // Keep a throbber handy.
502 frame = [installButton_ frame];
503 frame.origin.x += (NSWidth(frame) - 16) / 2;
504 frame.origin.y += (NSHeight(frame) - 16) /2;
505 frame.size = NSMakeSize(16, 16);
506 throbber_.reset([[NSProgressIndicator alloc] initWithFrame:frame]);
507 [throbber_ setHidden:YES];
508 [throbber_ setStyle:NSProgressIndicatorSpinningStyle];
509
510 return [self init];
511 }
512
513 - (id)initWithService:
514 (const WebIntentPickerModel::InstalledService*)service
515 withIndex:(size_t)index
516 forController:(WebIntentPickerSheetController*)controller {
517
518 // Add the extension icon.
519 [self setIcon:service->favicon.ToNSImage()];
520
521 // Add the extension title.
522 NSRect frame = NSMakeRect(
523 kTitleX, 0, WebIntentPicker::kTitleLinkMaxWidth, 10);
524
525 const string16 elidedTitle = ui::ElideText(
526 service->title, gfx::Font(),
527 WebIntentPicker::kTitleLinkMaxWidth, ui::ELIDE_AT_END);
528 NSString* string = base::SysUTF16ToNSString(elidedTitle);
529
530 label_.reset([[NSTextField alloc] initWithFrame:frame]);
531 ConfigureTextFieldAsLabel(label_);
532 [label_ setStringValue:string];
533 frame.size.height +=
534 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
535 label_];
536 frame.origin.y = (kMaxHeight - NSHeight(frame)) / 2.0;
537 [label_ setFrame:frame];
538
539 string = l10n_util::GetNSStringWithFixup(
540 IDS_INTENT_PICKER_SELECT_INTENT);
541 [self setActionButton:string
542 withSelector:@selector(invokeService:)
543 forController:controller];
544 [installButton_ setTag:index];
545 return [self init];
546 }
547
548 - (NSInteger)tag {
549 return [installButton_ tag];
550 }
551
552 - (void)startThrobber {
553 [installButton_ setHidden:YES];
554 [throbber_ setHidden:NO];
555 [throbber_ startAnimation:self];
556 [iconView_ setEnabled:YES];
557 [ratingsWidget_ setEnabled:NO];
558 }
559
560 - (void)setEnabled:(BOOL) enabled {
561 [installButton_ setEnabled:enabled];
562 [cwsButton_ setEnabled:enabled];
563 [iconView_ setEnabled:enabled];
564 [ratingsWidget_ setEnabled:enabled];
565 }
566
567 - (void)stopThrobber {
568 if (throbber_.get()) {
569 [throbber_ setHidden:YES];
570 [throbber_ stopAnimation:self];
571 }
572 [installButton_ setHidden:NO];
573 }
574
575 - (void)adjustButtonSize:(CGFloat)newWidth {
576 CGFloat increase = std::max(kAddButtonWidth, newWidth) - kAddButtonWidth;
577 NSRect frame = [self frame];
578 frame.size.width += increase;
579 [self setFrame:frame];
580
581 frame = [installButton_ frame];
582 frame.size.width += increase;
583 [installButton_ setFrame:frame];
584 }
585
586 @end
587
588 @interface IntentView : NSView {
589 @private
590 // Used to forward button clicks. Weak reference.
591 WebIntentPickerSheetController* controller_;
592 }
593
594 - (id)initWithModel:(WebIntentPickerModel*)model
595 forController:(WebIntentPickerSheetController*)controller;
596 - (void)startThrobberForRow:(NSInteger)index;
597 - (void)stopThrobber;
598 @end
599
600 @implementation IntentView
601 - (id)initWithModel:(WebIntentPickerModel*)model
602 forController:(WebIntentPickerSheetController*)controller {
603 if (self = [super initWithFrame:NSZeroRect]) {
604 const CGFloat kYMargin = 16.0;
605 int availableSpots = kMaxIntentRows;
606
607 CGFloat offset = kYMargin;
608 NSMutableArray* subviews = [NSMutableArray array];
609 NSMutableArray* rows = [NSMutableArray array];
610
611 for (size_t i = 0; i < model->GetInstalledServiceCount() && availableSpots;
612 ++i, --availableSpots) {
613 const WebIntentPickerModel::InstalledService& svc =
614 model->GetInstalledServiceAt(i);
615 scoped_nsobject<NSView> suggestView(
616 [[IntentRowView alloc] initWithService:&svc
617 withIndex:i
618 forController:controller]);
619
620 [rows addObject:suggestView];
621 }
622
623 // Special case for the empty view.
624 size_t count = model->GetSuggestedExtensionCount();
625 if (count == 0 && availableSpots == kMaxIntentRows)
626 return nil;
627
628 for (size_t i = count; i > 0 && availableSpots; --i, --availableSpots) {
629 const WebIntentPickerModel::SuggestedExtension& ext =
630 model->GetSuggestedExtensionAt(i - 1);
631 scoped_nsobject<NSView> suggestView(
632 [[IntentRowView alloc] initWithExtension:&ext
633 withIndex:i-1
634 forController:controller]);
635 [rows addObject:suggestView];
636 }
637
638 // Determine optimal width for buttons given localized texts.
639 scoped_nsobject<NSButton> sizeHelper(
640 [[NSButton alloc] initWithFrame:NSZeroRect]);
641 [sizeHelper setAlignment:NSCenterTextAlignment];
642 [sizeHelper setButtonType:NSMomentaryPushInButton];
643 [sizeHelper setBezelStyle:NSRegularSquareBezelStyle];
644
645 [sizeHelper setTitle:
646 l10n_util::GetNSStringWithFixup(IDS_INTENT_PICKER_INSTALL_EXTENSION)];
647 [sizeHelper sizeToFit];
648 CGFloat buttonWidth = NSWidth([sizeHelper frame]);
649
650 [sizeHelper setTitle:
651 l10n_util::GetNSStringWithFixup(IDS_INTENT_PICKER_SELECT_INTENT)];
652 [sizeHelper sizeToFit];
653 buttonWidth = std::max(buttonWidth, NSWidth([sizeHelper frame]));
654
655 for (IntentRowView* row in [rows reverseObjectEnumerator]) {
656 [row adjustButtonSize:buttonWidth];
657 offset += [self addStackedView:row
658 toSubviews:subviews
659 atOffset:offset];
660 }
661
662 [self setSubviews:subviews];
663 NSRect contentFrame = NSMakeRect(WebIntentPicker::kContentAreaBorder, 0,
664 WebIntentPicker::kWindowMinWidth, offset);
665 [self setFrame:contentFrame];
666 controller_ = controller;
667 }
668 return self;
669 }
670
671 - (void)startThrobberForRow:(NSInteger)index {
672 for (IntentRowView* row in [self subviews]) {
673 if ([row isMemberOfClass:[IntentRowView class]]) {
674 [row setEnabled:NO];
675 if ([row tag] == index) {
676 [row startThrobber];
677 }
678 }
679 }
680 }
681
682 - (void)stopThrobber {
683 for (IntentRowView* row in [self subviews]) {
684 if ([row isMemberOfClass:[IntentRowView class]]) {
685 [row stopThrobber];
686 [row setEnabled:YES];
687 }
688 }
689 }
690
691 - (IBAction)installExtension:(id)sender {
692 [controller_ installExtension:sender];
693 }
694
695 - (CGFloat)addStackedView:(NSView*)view
696 toSubviews:(NSMutableArray*)subviews
697 atOffset:(CGFloat)offset {
698 if (view == nil)
699 return 0.0;
700
701 NSPoint frameOrigin = [view frame].origin;
702 frameOrigin.y = offset;
703 [view setFrameOrigin:frameOrigin];
704 [subviews addObject:view];
705
706 return NSHeight([view frame]);
707 }
708 @end
709
710 @implementation WebIntentPickerSheetController
711
712 - (id)initWithPicker:(WebIntentPickerCocoa*)picker {
713 // Use an arbitrary height because it will reflect the size of the content.
714 NSRect contentRect = NSMakeRect(
715 0, 0, WebIntentPicker::kWindowMinWidth, kVerticalSpacing);
716
717 // |window| is retained by the ConstrainedWindowMacDelegateCustomSheet when
718 // the sheet is initialized.
719 scoped_nsobject<NSWindow> window(
720 [[NSWindow alloc] initWithContentRect:contentRect
721 styleMask:NSTitledWindowMask
722 backing:NSBackingStoreBuffered
723 defer:YES]);
724 if ((self = [super initWithWindow:window.get()])) {
725 picker_ = picker;
726 if (picker)
727 model_ = picker->model();
728
729 inlineDispositionTitleField_.reset([[NSTextField alloc] init]);
730 ConfigureTextFieldAsLabel(inlineDispositionTitleField_);
731 [inlineDispositionTitleField_ setFont:
732 [NSFont boldSystemFontOfSize:[NSFont systemFontSize]]];
733 flipView_.reset([[WebIntentsContentView alloc] init]);
734 [flipView_ setAutoresizingMask:NSViewMinYMargin];
735 [[[self window] contentView] setSubviews:@[flipView_]];
736
737 [self performLayoutWithModel:model_];
738 }
739 return self;
740 }
741
742 // Handle default OSX dialog cancel mechanisms. (Cmd-.)
743 - (void)cancelOperation:(id)sender {
744 if (picker_)
745 picker_->OnCancelled();
746 [self closeSheet];
747 }
748
749 - (void)chooseAnotherService:(id)sender {
750 if (picker_)
751 picker_->OnChooseAnotherService();
752 }
753
754 - (void)sheetDidEnd:(NSWindow*)sheet
755 returnCode:(int)returnCode
756 contextInfo:(void*)contextInfo {
757 if (picker_)
758 picker_->OnSheetDidEnd(sheet);
759 }
760
761 - (void)setInlineDispositionWebContents:(content::WebContents*)webContents {
762 webContents_ = webContents;
763 }
764
765 - (void)setInlineDispositionFrameSize:(NSSize)inlineContentSize {
766 DCHECK(webContents_);
767
768 NSView* webContentView = webContents_->GetNativeView();
769
770 // Make sure inline content size is never shrunk.
771 inlineContentSize = NSMakeSize(
772 std::max(NSWidth([webContentView frame]), inlineContentSize.width),
773 std::max(NSHeight([webContentView frame]), inlineContentSize.height));
774
775 // Compute container size to fit all elements, including padding.
776 NSSize containerSize = inlineContentSize;
777 containerSize.height +=
778 [webContentView frame].origin.y + WebIntentPicker::kContentAreaBorder;
779 containerSize.width += 2 * WebIntentPicker::kContentAreaBorder;
780
781 // Ensure minimum container width.
782 containerSize.width =
783 std::max(CGFloat(WebIntentPicker::kWindowMinWidth), containerSize.width);
784
785 // Resize web contents.
786 [webContentView setFrameSize:inlineContentSize];
787 [self setContainerSize:containerSize];
788 }
789
790 - (void)setContainerSize:(NSSize)containerSize {
791 // Resize container views
792 NSRect frame = NSMakeRect(0, 0, 0, 0);
793 frame.size = containerSize;
794 [[[self window] contentView] setFrame:frame];
795 [flipView_ setFrame:frame];
796
797 // Resize and reposition dialog window.
798 frame.size = [[[self window] contentView] convertSize:containerSize
799 toView:nil];
800 frame = [[self window] frameRectForContentRect:frame];
801
802 // Readjust window position to keep top in place and center horizontally.
803 NSRect windowFrame = [[self window] frame];
804 windowFrame.origin.x -= (NSWidth(frame) - NSWidth(windowFrame)) / 2.0;
805 windowFrame.origin.y -= (NSHeight(frame) - NSHeight(windowFrame));
806 windowFrame.size = frame.size;
807 [[self window] setFrame:windowFrame display:YES animate:NO];
808 }
809
810 // Pop up a new tab with the Chrome Web Store.
811 - (IBAction)showChromeWebStore:(id)sender {
812 DCHECK(picker_);
813 picker_->OnSuggestionsLinkClicked(
814 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]));
815 }
816
817 // A picker button has been pressed - invoke corresponding service.
818 - (IBAction)invokeService:(id)sender {
819 DCHECK(picker_);
820 picker_->OnServiceChosen([sender tag]);
821 }
822
823 - (IBAction)openExtensionLink:(id)sender {
824 DCHECK(model_);
825 DCHECK(picker_);
826 const WebIntentPickerModel::SuggestedExtension& extension =
827 model_->GetSuggestedExtensionAt([sender tag]);
828
829 picker_->OnExtensionLinkClicked(extension.id,
830 event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]));
831 }
832
833 - (IBAction)installExtension:(id)sender {
834 DCHECK(model_);
835 DCHECK(picker_);
836 const WebIntentPickerModel::SuggestedExtension& extension =
837 model_->GetSuggestedExtensionAt([sender tag]);
838 if (picker_) {
839 [intentView_ startThrobberForRow:[sender tag]];
840 [closeButton_ setEnabled:NO];
841 picker_->OnExtensionInstallRequested(extension.id);
842 }
843 }
844
845 - (CGFloat)addStackedView:(NSView*)view
846 toSubviews:(NSMutableArray*)subviews
847 atOffset:(CGFloat)offset {
848 if (view == nil)
849 return 0.0;
850
851 NSPoint frameOrigin = [view frame].origin;
852 frameOrigin.y = offset;
853 [view setFrameOrigin:frameOrigin];
854 [subviews addObject:view];
855
856 return NSHeight([view frame]);
857 }
858
859 // Adds a link to the Chrome Web Store, to obtain further intent handlers.
860 // Returns the y position delta for the next offset.
861 - (CGFloat)addCwsButtonToSubviews:(NSMutableArray*)subviews
862 atOffset:(CGFloat)offset {
863 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
864 NSImage* iconImage = rb.GetNativeImageNamed(IDR_WEBSTORE_ICON_16).ToNSImage();
865 NSRect imageFrame;
866 imageFrame.origin = NSMakePoint(WebIntentPicker::kContentAreaBorder, offset);
867 imageFrame.size = [iconImage size];
868 scoped_nsobject<NSImageView> iconView(
869 [[NSImageView alloc] initWithFrame:imageFrame]);
870 [iconView setImage:iconImage];
871 [iconView setImageFrameStyle:NSImageFrameNone];
872
873 const CGFloat kCWSIconPadding = 4.0; // Same spacing as for service options.
874 NSRect frame = NSMakeRect(WebIntentPicker::kContentAreaBorder +
875 NSWidth(imageFrame) + kCWSIconPadding,
876 offset, 100, 10);
877 NSString* string = l10n_util::GetNSStringWithFixup(
878 IDS_FIND_MORE_INTENT_HANDLER_MESSAGE);
879 scoped_nsobject<NSButton> button(CreateHyperlinkButton(string, frame));
880 [button setTarget:self];
881 [button setAction:@selector(showChromeWebStore:)];
882 [subviews addObjectsFromArray:@[iconView, button]];
883
884 // Call size-to-fit to fixup for the localized string.
885 [GTMUILocalizerAndLayoutTweaker sizeToFitView:button];
886
887 return NSHeight([button frame]);
888 }
889
890 - (void)addCloseButtonToSubviews:(NSMutableArray*)subviews {
891 const CGFloat kButtonPadding = 4.0; // whitespace inside button frame.
892 if (!closeButton_.get()) {
893 NSRect buttonFrame = NSMakeRect(
894 WebIntentPicker::kContentAreaBorder + kTextWidth + kButtonPadding,
895 WebIntentPicker::kContentAreaBorder - kButtonPadding,
896 kCloseButtonSize, kCloseButtonSize);
897 closeButton_.reset(
898 [[HoverCloseButton alloc] initWithFrame:buttonFrame]);
899 // Anchor close button to upper right.
900 // (NSViewMaxYMargin since parent view is flipped.)
901 [closeButton_ setAutoresizingMask:NSViewMaxYMargin|NSViewMinXMargin];
902 [closeButton_ setTarget:self];
903 [closeButton_ setAction:@selector(cancelOperation:)];
904 [[closeButton_ cell] setKeyEquivalent:@"\e"];
905 }
906 [subviews addObject:closeButton_];
907 }
908
909 // Adds a header (icon and explanatory text) to picker bubble.
910 // Returns the y position delta for the next offset.
911 - (CGFloat)addHeaderToSubviews:(NSMutableArray*)subviews
912 atOffset:(CGFloat)offset {
913 // Create a new text field if we don't have one yet.
914 // TODO(groby): This should not be necessary since the controller sends this
915 // string.
916 if (!actionTextField_.get()) {
917 NSString* nsString =
918 l10n_util::GetNSStringWithFixup(IDS_CHOOSE_INTENT_HANDLER_MESSAGE);
919 [self setActionString:nsString];
920 }
921
922 scoped_nsobject<HeaderView> header([[HeaderView alloc] init]);
923
924 [header setTitle:[actionTextField_ stringValue]];
925 string16 labelText;
926 if (model_ && model_->GetInstalledServiceCount() == 0)
927 labelText = model_->GetSuggestionsLinkText();
928 [header setSubtitle:base::SysUTF16ToNSString(labelText)];
929 [header performLayout];
930
931 NSRect frame = [header frame];
932 frame.origin.y = offset;
933 [header setFrame:frame];
934 [subviews addObject:header];
935
936 return NSHeight(frame);
937 }
938
939 - (CGFloat)addInlineHtmlToSubviews:(NSMutableArray*)subviews
940 atOffset:(CGFloat)offset {
941 if (!webContents_)
942 return 0;
943
944 // Determine a good size for the inline disposition window.
945
946 gfx::Size size = picker_->GetMinInlineDispositionSize();
947 NSView* webContentView = webContents_->GetNativeView();
948 NSRect contentFrame = NSMakeRect(
949 WebIntentPicker::kContentAreaBorder,
950 offset,
951 std::max(NSWidth([webContentView frame]),CGFloat(size.width())),
952 std::max(NSHeight([webContentView frame]),CGFloat(size.height())));
953
954 [webContentView setFrame:contentFrame];
955 [subviews addObject:webContentView];
956
957 return NSHeight(contentFrame);
958 }
959
960 - (CGFloat)addAnotherServiceLinkToSubviews:(NSMutableArray*)subviews
961 atOffset:(CGFloat)offset {
962 DCHECK(model_);
963 DCHECK(model_->IsInlineDisposition());
964 GURL url = model_->inline_disposition_url();
965
966 const WebIntentPickerModel::InstalledService* service =
967 model_->GetInstalledServiceWithURL(url);
968 DCHECK(service);
969
970 CGFloat originalOffset = offset;
971
972 // Icon for current service.
973 scoped_nsobject<NSImageView> icon;
974 NSRect imageFrame = NSMakeRect(WebIntentPicker::kContentAreaBorder, offset,
975 0, 0);
976 icon.reset([[NSImageView alloc] initWithFrame:imageFrame]);
977 [icon setImage:service->favicon.ToNSImage()];
978 [icon setImageFrameStyle:NSImageFrameNone];
979 [icon setEnabled:YES];
980
981 imageFrame.size = [service->favicon.ToNSImage() size];
982 [icon setFrame:imageFrame];
983
984 [subviews addObject:icon];
985
986 // Resize control to fit text
987 NSRect textFrame =
988 NSMakeRect(NSMaxX(imageFrame) + 4,
989 offset,
990 WebIntentPicker::kTitleLinkMaxWidth, 1);
991 [inlineDispositionTitleField_ setFrame:textFrame];
992 [subviews addObject:inlineDispositionTitleField_];
993 [GTMUILocalizerAndLayoutTweaker sizeToFitView:inlineDispositionTitleField_];
994 textFrame = [inlineDispositionTitleField_ frame];
995
996 // Add link for "choose another service" if other suggestions are available
997 // or if more than one (the current) service is installed.
998 if (model_->show_use_another_service() &&
999 (model_->GetInstalledServiceCount() > 1 ||
1000 model_->GetSuggestedExtensionCount())) {
1001 NSRect frame = NSMakeRect(
1002 NSMaxX(textFrame) + WebIntentPicker::kContentAreaBorder, offset,
1003 1, 1);
1004 NSString* string = l10n_util::GetNSStringWithFixup(
1005 IDS_INTENT_PICKER_USE_ALTERNATE_SERVICE);
1006 scoped_nsobject<NSButton> button(CreateHyperlinkButton(string, frame));
1007 [[button cell] setControlSize:NSRegularControlSize];
1008 [[button cell] setFont:
1009 [NSFont controlContentFontOfSize:[NSFont systemFontSize]]];
1010 [button setTarget:self];
1011 [button setAction:@selector(chooseAnotherService:)];
1012 [subviews addObject:button];
1013
1014 // Call size-to-fit to fixup for the localized string.
1015 [GTMUILocalizerAndLayoutTweaker sizeToFitView:button];
1016
1017 // Right-align the "use another service" button.
1018 frame = [button frame];
1019 frame.origin.x = WebIntentPicker::kWindowMinWidth - NSWidth(frame) -
1020 2 * WebIntentPicker::kContentAreaBorder - kCloseButtonSize;
1021 [button setFrame:frame];
1022 [button setAutoresizingMask:NSViewMinXMargin];
1023
1024 // And finally, make sure the link and the title are horizontally centered.
1025 frame = [button frame];
1026 CGFloat height = std::max(NSHeight(textFrame), NSHeight(frame));
1027 frame.origin.y += (height - NSHeight(frame)) / 2.0;
1028 frame.size.height = height;
1029 textFrame.origin.y += (height - NSHeight(textFrame)) / 2.0;
1030 textFrame.size.height = height;
1031 [button setFrame:frame];
1032 [inlineDispositionTitleField_ setFrame:textFrame];
1033 }
1034
1035 offset += NSHeight(textFrame) + kVerticalSpacing;
1036
1037 scoped_nsobject<NSBox> spacer;
1038
1039 NSRect frame = NSMakeRect(0, offset, WebIntentPicker::kWindowMinWidth, 1.0);
1040 spacer.reset([[NSBox alloc] initWithFrame:frame]);
1041 [spacer setBoxType:NSBoxSeparator];
1042 [spacer setAlphaValue:0.2];
1043 [spacer setAutoresizingMask:NSViewWidthSizable];
1044 [subviews addObject: spacer];
1045
1046 return offset + kVerticalSpacing - originalOffset;
1047 }
1048
1049 - (NSView*)createEmptyView {
1050 NSRect titleFrame = NSMakeRect(WebIntentPicker::kContentAreaBorder,
1051 WebIntentPicker::kContentAreaBorder,
1052 kTextWidth, 1);
1053 scoped_nsobject<NSTextField> title(
1054 [[NSTextField alloc] initWithFrame:titleFrame]);
1055 ConfigureTextFieldAsLabel(title);
1056 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
1057 gfx::Font titleFont = rb.GetFont(ConstrainedWindowConstants::kTitleFontStyle);
1058 titleFont = titleFont.DeriveFont(0, gfx::Font::BOLD);
1059 [title setFont:titleFont.GetNativeFont()];
1060 [title setStringValue:
1061 l10n_util::GetNSStringWithFixup(IDS_INTENT_PICKER_NO_SERVICES_TITLE)];
1062 titleFrame.size.height +=
1063 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:title];
1064
1065 NSRect bodyFrame = titleFrame;
1066 bodyFrame.origin.y +=
1067 NSHeight(titleFrame) + WebIntentPicker::kContentAreaBorder;
1068
1069 scoped_nsobject<NSTextField> body(
1070 [[NSTextField alloc] initWithFrame:bodyFrame]);
1071 ConfigureTextFieldAsLabel(body);
1072 [body setStringValue:
1073 l10n_util::GetNSStringWithFixup(IDS_INTENT_PICKER_NO_SERVICES)];
1074 bodyFrame.size.height +=
1075 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:body];
1076 NSRect viewFrame = NSMakeRect(
1077 0,
1078 WebIntentPicker::kContentAreaBorder,
1079 std::max(NSWidth(bodyFrame), NSWidth(titleFrame)) +
1080 2 * WebIntentPicker::kContentAreaBorder,
1081 NSHeight(titleFrame) + NSHeight(bodyFrame) + kVerticalSpacing);
1082
1083 titleFrame.origin.y = NSHeight(viewFrame) - NSHeight(titleFrame);
1084 bodyFrame.origin.y = 0;
1085
1086 [title setFrame:titleFrame];
1087 [body setFrame:bodyFrame];
1088
1089 NSView* view = [[NSView alloc] initWithFrame:viewFrame];
1090 [view setSubviews:@[title, body]];
1091
1092 return view;
1093 }
1094
1095 - (void)performLayoutWithModel:(WebIntentPickerModel*)model {
1096 model_ = model;
1097
1098 // |offset| is the Y position that should be drawn at next.
1099 CGFloat offset = WebIntentPicker::kContentAreaBorder;
1100
1101 // Keep the new subviews in an array that gets replaced at the end.
1102 NSMutableArray* subviews = [NSMutableArray array];
1103
1104 // Indicator that we have neither suggested nor installed services,
1105 // and we're not in the wait stage any more either.
1106 BOOL isEmpty = model_ &&
1107 !model_->IsWaitingForSuggestions() &&
1108 !model_->GetInstalledServiceCount() &&
1109 !model_->GetSuggestedExtensionCount();
1110
1111 if (model_ && model_->IsWaitingForSuggestions()) {
1112 if (!waitingView_.get())
1113 waitingView_.reset([[WaitingView alloc] init]);
1114 [subviews addObject:waitingView_];
1115 offset += NSHeight([waitingView_ frame]);
1116 } else if (isEmpty) {
1117 scoped_nsobject<NSView> emptyView([self createEmptyView]);
1118 [subviews addObject:emptyView];
1119 offset += NSHeight([emptyView frame]);
1120 } else if (webContents_) {
1121 offset += [self addAnotherServiceLinkToSubviews:subviews
1122 atOffset:offset];
1123 offset += [self addInlineHtmlToSubviews:subviews atOffset:offset];
1124 } else {
1125 offset += [self addHeaderToSubviews:subviews atOffset:offset];
1126
1127 if (model) {
1128 intentView_.reset(
1129 [[IntentView alloc] initWithModel:model forController:self]);
1130 offset += [self addStackedView:intentView_
1131 toSubviews:subviews
1132 atOffset:offset];
1133 }
1134 offset += [self addCwsButtonToSubviews:subviews atOffset:offset];
1135 }
1136
1137 // Add the bottom padding.
1138 offset += WebIntentPicker::kContentAreaBorder;
1139
1140 // Resize to fit.
1141 [self setContainerSize:NSMakeSize(WebIntentPicker::kWindowMinWidth, offset)];
1142
1143 [self addCloseButtonToSubviews:subviews];
1144
1145 // Replace the window's content.
1146 [flipView_ setSubviews:subviews];
1147 }
1148
1149 - (void)setActionString:(NSString*)actionString {
1150 NSRect textFrame;
1151 if (!actionTextField_.get()) {
1152 textFrame = NSMakeRect(WebIntentPicker::kContentAreaBorder, 0,
1153 kTextWidth, 1);
1154
1155 actionTextField_.reset([[NSTextField alloc] initWithFrame:textFrame]);
1156 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
1157 ConfigureTextFieldAsLabel(actionTextField_);
1158 gfx::Font titleFont = rb.GetFont(
1159 ConstrainedWindowConstants::kTitleFontStyle);
1160 titleFont = titleFont.DeriveFont(0, gfx::Font::BOLD);
1161 [actionTextField_ setFont:titleFont.GetNativeFont()];
1162 } else {
1163 textFrame = [actionTextField_ frame];
1164 }
1165
1166 [actionTextField_ setStringValue:actionString];
1167 textFrame.size.height +=
1168 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
1169 actionTextField_];
1170 [actionTextField_ setFrame:textFrame];
1171 }
1172
1173 - (void)setInlineDispositionTitle:(NSString*)title {
1174 NSFont* nsfont = [inlineDispositionTitleField_ font];
1175 gfx::Font font(
1176 base::SysNSStringToUTF8([nsfont fontName]), [nsfont pointSize]);
1177 NSString* elidedTitle = base::SysUTF16ToNSString(ui::ElideText(
1178 base::SysNSStringToUTF16(title),
1179 font, WebIntentPicker::kTitleLinkMaxWidth, ui::ELIDE_AT_END));
1180 [inlineDispositionTitleField_ setStringValue:elidedTitle];
1181 }
1182
1183 - (void)stopThrobber {
1184 [closeButton_ setEnabled:YES];
1185 [intentView_ stopThrobber];
1186 }
1187
1188 - (void)closeSheet {
1189 [NSApp endSheet:[self window]];
1190 }
1191
1192 @end // WebIntentPickerSheetController
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698