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

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

Issue 9581041: Make web intents picker work as constrained dialog instead of InfoBubble (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Removed unneeded code Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View 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_bubble_controller.h"
6
7 #include "base/memory/scoped_nsobject.h"
8 #include "base/sys_string_conversions.h"
9 #include "chrome/browser/ui/browser_list.h"
10 #import "chrome/browser/ui/cocoa/hyperlink_button_cell.h"
11 #import "chrome/browser/ui/cocoa/info_bubble_view.h"
12 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
13 #include "chrome/browser/ui/cocoa/web_intent_picker_cocoa.h"
14 #include "chrome/browser/ui/intents/web_intent_picker_delegate.h"
15 #include "chrome/browser/ui/intents/web_intent_picker_model.h"
16 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
17 #include "content/public/browser/web_contents_view.h"
18 #include "content/public/browser/web_contents.h"
19 #include "grit/generated_resources.h"
20 #include "grit/locale_settings.h"
21 #include "grit/theme_resources.h"
22 #include "grit/ui_resources.h"
23 #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/base/l10n/l10n_util_mac.h"
26 #include "ui/base/resource/resource_bundle.h"
27 #include "ui/gfx/image/image.h"
28
29 using content::OpenURLParams;
30 using content::Referrer;
31
32 namespace {
33
34 // The width of the window, in view coordinates. The height will be
35 // determined by the content.
36 const CGFloat kWindowWidth = 380;
37
38 // The width of a service button, in view coordinates.
39 const CGFloat kServiceButtonWidth = 300;
40
41 // Padding along on the X-axis between the window frame and content.
42 const CGFloat kFramePadding = 10;
43
44 // Spacing in between sections.
45 const CGFloat kVerticalSpacing = 10;
46
47 // Square size of the image.
48 const CGFloat kImageSize = 32;
49
50 // Spacing between the image and the text.
51 const CGFloat kImageSpacing = 10;
52
53 // Spacing between icons.
54 const CGFloat kImagePadding = 6;
55
56 // Width of the text fields.
57 const CGFloat kTextWidth = kWindowWidth - (kImageSize + kImageSpacing +
58 kFramePadding * 2);
59
60 } // namespace
61
62 // This simple NSView subclass is used as the single subview of the page info
63 // bubble's window's contentView. Drawing is flipped so that layout of the
64 // sections is easier. Apple recommends flipping the coordinate origin when
65 // doing a lot of text layout because it's more natural.
66 @interface WebIntentsContentView : NSView
67 @end
68 @implementation WebIntentsContentView
69 - (BOOL)isFlipped {
70 return YES;
71 }
72 @end
73
74 @implementation WebIntentBubbleController;
75
76 - (id)initWithPicker:(WebIntentPickerCocoa*)picker
77 parentWindow:(NSWindow*)parent
78 anchoredAt:(NSPoint)point {
79 // Use an arbitrary height because it will reflect the size of the content.
80 NSRect contentRect = NSMakeRect(0, 0, kWindowWidth, kVerticalSpacing);
81 // Create an empty window into which content is placed.
82 scoped_nsobject<InfoBubbleWindow> window(
83 [[InfoBubbleWindow alloc] initWithContentRect:contentRect
84 styleMask:NSBorderlessWindowMask
85 backing:NSBackingStoreBuffered
86 defer:NO]);
87 if ((self = [super initWithWindow:window.get()
88 parentWindow:parent
89 anchoredAt:point])) {
90 picker_ = picker;
91
92 [[self bubble] setArrowLocation:info_bubble::kTopLeft];
93 [self performLayoutWithModel:NULL];
94 [self showWindow:nil];
95 picker_->set_controller(self);
96 }
97
98 return self;
99 }
100
101 - (void)setInlineDispositionTabContents:(TabContentsWrapper*)wrapper {
102 contents_ = wrapper;
103 }
104
105 // We need to watch for window closing so we can notify up via |picker_|.
106 - (void)windowWillClose:(NSNotification*)notification {
107 if (picker_) {
108 WebIntentPickerCocoa* temp = picker_;
109 picker_ = NULL; // Abandon picker, we are done with it.
110 temp->OnCancelled();
111 }
112 [super windowWillClose:notification];
113 }
114
115 // Pop up a new tab with the Chrome Web Store.
116 - (IBAction)showChromeWebStore:(id)sender {
117 GURL url(l10n_util::GetStringUTF8(IDS_WEBSTORE_URL));
118 Browser* browser = BrowserList::GetLastActive();
119 OpenURLParams params(
120 url, Referrer(), NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK,
121 false);
122 browser->OpenURL(params);
123 }
124
125 // A picker button has been pressed - invoke corresponding service.
126 - (IBAction)invokeService:(id)sender {
127 if (picker_)
128 picker_->OnServiceChosen([sender tag]);
129 }
130
131 // Sets proprties on the given |field| to act as the title or description labels
132 // in the bubble.
133 - (void)configureTextFieldAsLabel:(NSTextField*)field {
134 [field setEditable:NO];
135 [field setSelectable:YES];
136 [field setDrawsBackground:NO];
137 [field setBezeled:NO];
138 }
139
140 // Adds a link to the Chrome Web Store, to obtain further intent handlers.
141 // Returns the y position delta for the next offset.
142 - (CGFloat)addCwsButtonToSubviews:(NSMutableArray*)subviews
143 atOffset:(CGFloat)offset {
144 NSRect frame = NSMakeRect(kFramePadding, offset, 100, 10);
145 scoped_nsobject<NSButton> button([[NSButton alloc] initWithFrame:frame]);
146 NSString* string =
147 l10n_util::GetNSStringWithFixup(IDS_FIND_MORE_INTENT_HANDLER_MESSAGE);
148 scoped_nsobject<HyperlinkButtonCell> cell(
149 [[HyperlinkButtonCell alloc] initTextCell:string]);
150 [cell setControlSize:NSSmallControlSize];
151 [button setCell:cell.get()];
152 [button setButtonType:NSMomentaryPushInButton];
153 [button setBezelStyle:NSRegularSquareBezelStyle];
154 [button setTarget:self];
155 [button setAction:@selector(showChromeWebStore:)];
156 [subviews addObject:button.get()];
157
158 // Call size-to-fit to fixup for the localized string.
159 [GTMUILocalizerAndLayoutTweaker sizeToFitView:button.get()];
160
161 return NSHeight([button frame]);
162 }
163
164 // Adds a header (icon and explanatory text) to picker bubble.
165 // Returns the y position delta for the next offset.
166 - (CGFloat)addHeaderToSubviews:(NSMutableArray*)subviews
167 atOffset:(CGFloat)offset {
168 NSRect imageFrame = NSMakeRect(kFramePadding, offset, kImageSize, kImageSize);
169
170 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
171 NSImage* nsImage = rb.GetNativeImageNamed(IDR_PAGEINFO_INFO);
172
173 scoped_nsobject<NSImageView> imageView(
174 [[NSImageView alloc] initWithFrame:imageFrame]);
175 [imageView setImage:nsImage];
176 [imageView setImageFrameStyle:NSImageFrameNone];
177
178 NSRect textFrame = NSMakeRect(kFramePadding + kImageSize + kImageSpacing,
179 offset, kTextWidth, 1);
180 scoped_nsobject<NSTextField> textField(
181 [[NSTextField alloc] initWithFrame:textFrame]);
182 [self configureTextFieldAsLabel:textField.get()];
183
184 NSString* nsString =
185 l10n_util::GetNSStringWithFixup(IDS_CHOOSE_INTENT_HANDLER_MESSAGE);
186 [textField setStringValue:nsString];
187 textFrame.size.height +=
188 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:
189 textField];
190
191 // Adjust view height to fit elements, center-align elements.
192 CGFloat maxHeight = std::max(imageFrame.size.height,textFrame.size.height);
193 if (maxHeight > textFrame.size.height)
194 textFrame.origin.y += (maxHeight - textFrame.size.height) / 2;
195 else
196 imageFrame.origin.y += maxHeight / 2;
197 [textField setFrame:textFrame];
198 [imageView setFrame:imageFrame];
199
200 [subviews addObject:textField.get()];
201 [subviews addObject:imageView.get()];
202 return NSHeight([imageView frame]);
203 }
204
205 - (CGFloat)addInlineHtmlToSubviews:(NSMutableArray*)subviews
206 atOffset:(CGFloat)offset {
207 if (!contents_)
208 return 0;
209
210 // Determine a good size for the inline disposition window.
211 gfx::Size size = WebIntentPicker::GetDefaultInlineDispositionSize(
212 contents_->web_contents());
213 NSRect frame = NSMakeRect(kFramePadding, offset, size.width(), size.height());
214
215 [contents_->web_contents()->GetNativeView() setFrame:frame];
216 [subviews addObject:contents_->web_contents()->GetNativeView()];
217
218 return NSHeight(frame);
219 }
220
221 // Add a single button for a specific service
222 -(CGFloat)addServiceButton:(NSString*)title
223 withImage:(NSImage*)image
224 index:(NSUInteger)index
225 toSubviews:(NSMutableArray*)subviews
226 atOffset:(CGFloat)offset {
227 NSRect frame = NSMakeRect(kFramePadding, offset, kServiceButtonWidth, 45);
228 scoped_nsobject<NSButton> button([[NSButton alloc] initWithFrame:frame]);
229
230 if (image) {
231 [button setImage:image];
232 [button setImagePosition:NSImageLeft];
233 }
234 [button setButtonType:NSMomentaryPushInButton];
235 [button setBezelStyle:NSRegularSquareBezelStyle];
236 [button setTarget:self];
237 [button setTitle:title];
238 [button setTag:index];
239 [button setAction:@selector(invokeService:)];
240 [subviews addObject:button.get()];
241
242 // Call size-to-fit to fixup size.
243 [GTMUILocalizerAndLayoutTweaker sizeToFitView:button.get()];
244
245 // But make sure we're limited to a fixed size.
246 frame = [button frame];
247 frame.size.width = kServiceButtonWidth;
248 [button setFrame:frame];
249
250 return NSHeight([button frame]);
251 }
252
253 // Layout the contents of the picker bubble.
254 - (void)performLayoutWithModel:(WebIntentPickerModel*)model {
255 // |offset| is the Y position that should be drawn at next.
256 CGFloat offset = kFramePadding + info_bubble::kBubbleArrowHeight;
257
258 // Keep the new subviews in an array that gets replaced at the end.
259 NSMutableArray* subviews = [NSMutableArray array];
260
261 if (contents_) {
262 offset += [self addInlineHtmlToSubviews:subviews atOffset:offset];
263 } else {
264 offset += [self addHeaderToSubviews:subviews atOffset:offset];
265 if (model) {
266 for (NSUInteger i = 0; i < model->GetInstalledServiceCount(); ++i) {
267 const WebIntentPickerModel::InstalledService& service =
268 model->GetInstalledServiceAt(i);
269 offset += [self addServiceButton:base::SysUTF16ToNSString(service.title)
270 withImage:service.favicon.ToNSImage()
271 index:i
272 toSubviews:subviews
273 atOffset:offset];
274 }
275 }
276 offset += [self addCwsButtonToSubviews:subviews atOffset:offset];
277 }
278
279 // Add the bottom padding.
280 offset += kVerticalSpacing;
281
282 // Create the dummy view that uses flipped coordinates.
283 NSRect contentFrame = NSMakeRect(0, 0, kWindowWidth, offset);
284 scoped_nsobject<WebIntentsContentView> contentView(
285 [[WebIntentsContentView alloc] initWithFrame:contentFrame]);
286 [contentView setSubviews:subviews];
287 [contentView setAutoresizingMask:NSViewMinYMargin];
288
289 // Adjust frame to fit all elements.
290 NSRect windowFrame = NSMakeRect(0, 0, kWindowWidth, offset);
291 windowFrame.size = [[[self window] contentView] convertSize:windowFrame.size
292 toView:nil];
293 // Adjust the origin by the difference in height.
294 windowFrame.origin = [[self window] frame].origin;
295 windowFrame.origin.y -= NSHeight(windowFrame) -
296 NSHeight([[self window] frame]);
297
298 [[self window] setFrame:windowFrame display:YES animate:YES];
299
300 // Replace the window's content.
301 [[[self window] contentView] setSubviews:
302 [NSArray arrayWithObject:contentView]];
303 }
304
305 @end // WebIntentBubbleController
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698