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

Side by Side Diff: chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller.mm

Issue 23944003: Implement Desktop Media Picker (Mac version) for Desktop Capture API (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Clearing delegate/dataSource on dealloc. Fixes 10.6 tests. Created 7 years, 3 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) 2013 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/media_picker/desktop_media_picker_controller.h"
6
7 #include "base/bind.h"
8 #import "base/mac/bundle_locations.h"
9 #include "base/strings/sys_string_conversions.h"
10 #import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_item.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "grit/generated_resources.h"
13 #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
14 #import "ui/base/cocoa/flipped_view.h"
15 #import "ui/base/cocoa/window_size_constants.h"
16 #include "ui/base/l10n/l10n_util.h"
17 #include "ui/gfx/image/image_skia_util_mac.h"
18
19 namespace {
20
21 const int kInitialContentWidth = 620;
22 const int kMinimumContentWidth = 500;
23 const int kMinimumContentHeight = 390;
24 const int kThumbnailWidth = 150;
25 const int kThumbnailHeight = 150;
26 const int kFramePadding = 20;
27 const int kControlSpacing = 10;
28 const int kExcessButtonPadding = 6;
29
30 } // namespace
31
32 @interface DesktopMediaPickerController (Private)
33
34 // Populate the window with controls and views.
35 - (void)initializeContentsWithAppName:(const string16&)appName;
36
37 // Create a |NSTextField| with label traits given |width|. Frame height is
38 // automatically adjusted to fit.
39 - (NSTextField*)createTextFieldWithText:(NSString*)text
40 frameWidth:(CGFloat)width;
41
42 // Create a button with |title|, with size adjusted to fit.
43 - (NSButton*)createButtonWithTitle:(NSString*)title;
44
45 // Report result by invoking |doneCallback_|. The callback is invoked only on
46 // the first call to |reportResult:|. Subsequent calls will be no-ops.
47 - (void)reportResult:(content::DesktopMediaID)sourceID;
48
49 // Action handlers.
50 - (void)okPressed:(id)sender;
51 - (void)cancelPressed:(id)sender;
52
53 @end
54
55 @implementation DesktopMediaPickerController
56
57 - (id)initWithModel:(scoped_ptr<DesktopMediaPickerModel>)model
58 callback:(const DesktopMediaPicker::DoneCallback&)callback
59 appName:(const string16&)appName {
60 const NSUInteger kStyleMask =
61 NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask;
62 base::scoped_nsobject<NSWindow> window(
63 [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater
64 styleMask:kStyleMask
65 backing:NSBackingStoreBuffered
66 defer:NO]);
67
68 if ((self = [super initWithWindow:window])) {
69 [window setDelegate:self];
70 [self initializeContentsWithAppName:appName];
71 model_ = model.Pass();
72 doneCallback_ = callback;
73 items_.reset([[NSMutableArray alloc] init]);
74 bridge_.reset(new DesktopMediaPickerBridge(self));
75 }
76 return self;
77 }
78
79 - (void)dealloc {
80 [sourceBrowser_ setDelegate:nil];
81 [sourceBrowser_ setDataSource:nil];
82 [super dealloc];
83 }
84
85 - (void)initializeContentsWithAppName:(const string16&)appName {
86 // Use flipped coordinates to facilitate manual layout.
87 const CGFloat kPaddedWidth = kInitialContentWidth - (kFramePadding * 2);
88 base::scoped_nsobject<FlippedView> content(
89 [[FlippedView alloc] initWithFrame:NSZeroRect]);
90 [[self window] setContentView:content];
91 NSPoint origin = NSMakePoint(kFramePadding, kFramePadding);
92
93 // Set the dialog's title.
94 NSString* titleText = l10n_util::GetNSStringF(
95 IDS_DESKTOP_MEDIA_PICKER_TITLE, appName);
96 [[self window] setTitle:titleText];
97
98 // Set the dialog's description.
99 NSString* descriptionText = l10n_util::GetNSStringF(
100 IDS_DESKTOP_MEDIA_PICKER_TEXT, appName);
101 NSTextField* description = [self createTextFieldWithText:descriptionText
102 frameWidth:kPaddedWidth];
103 [description setFrameOrigin:origin];
104 [content addSubview:description];
105 origin.y += NSHeight([description frame]) + kControlSpacing;
106
107 // Create the image browser.
108 sourceBrowser_.reset([[IKImageBrowserView alloc] initWithFrame:NSZeroRect]);
109 NSUInteger cellStyle = IKCellsStyleShadowed | IKCellsStyleTitled;
110 [sourceBrowser_ setDelegate:self];
111 [sourceBrowser_ setDataSource:self];
112 [sourceBrowser_ setCellsStyleMask:cellStyle];
113 [sourceBrowser_ setCellSize:NSMakeSize(kThumbnailWidth, kThumbnailHeight)];
114
115 // Create a scroll view to host the image browser.
116 NSRect imageBrowserScrollFrame = NSMakeRect(
117 origin.x, origin.y, kPaddedWidth, 350);
118 base::scoped_nsobject<NSScrollView> imageBrowserScroll(
119 [[NSScrollView alloc] initWithFrame:imageBrowserScrollFrame]);
120 [imageBrowserScroll setHasVerticalScroller:YES];
121 [imageBrowserScroll setDocumentView:sourceBrowser_];
122 [imageBrowserScroll setBorderType:NSBezelBorder];
123 [imageBrowserScroll setAutoresizingMask:
124 NSViewWidthSizable | NSViewHeightSizable];
125 [content addSubview:imageBrowserScroll];
126 origin.y += NSHeight(imageBrowserScrollFrame) + kControlSpacing;
127
128 // Create the cancel button.
129 cancelButton_ =
130 [self createButtonWithTitle:l10n_util::GetNSString(IDS_CANCEL)];
131 origin.x = kInitialContentWidth - kFramePadding -
132 (NSWidth([cancelButton_ frame]) - kExcessButtonPadding);
133 [cancelButton_ setFrameOrigin:origin];
134 [cancelButton_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
135 [cancelButton_ setTarget:self];
136 [cancelButton_ setAction:@selector(cancelPressed:)];
137 [content addSubview:cancelButton_];
138
139 // Create the OK button.
140 okButton_ = [self createButtonWithTitle:l10n_util::GetNSString(IDS_OK)];
141 origin.x -= kControlSpacing +
142 (NSWidth([okButton_ frame]) - (kExcessButtonPadding * 2));
143 [okButton_ setEnabled:NO];
144 [okButton_ setFrameOrigin:origin];
145 [okButton_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
146 [okButton_ setTarget:self];
147 [okButton_ setAction:@selector(okPressed:)];
148 [content addSubview:okButton_];
149 origin.y += kFramePadding +
150 (NSHeight([okButton_ frame]) - kExcessButtonPadding);
151
152 // Resize window to fit.
153 [[[self window] contentView] setAutoresizesSubviews:NO];
154 [[self window] setContentSize:NSMakeSize(kInitialContentWidth, origin.y)];
155 [[self window] setContentMinSize:
156 NSMakeSize(kMinimumContentWidth, kMinimumContentHeight)];
157 [[[self window] contentView] setAutoresizesSubviews:YES];
158 }
159
160 - (void)showWindow:(id)sender {
161 // Signal the model to start sending thumbnails. |bridge_| is used as the
162 // observer, and will forward notifications to this object.
163 model_->SetThumbnailSize(gfx::Size(kThumbnailWidth, kThumbnailHeight));
164 model_->StartUpdating(bridge_.get());
165
166 [self.window center];
167 [super showWindow:sender];
168 }
169
170 - (void)reportResult:(content::DesktopMediaID)sourceID {
171 if (doneCallback_.is_null()) {
172 return;
173 }
174
175 // Notify the |callback_| asynchronously because it may release the
176 // controller.
177 content::BrowserThread::PostTask(
178 content::BrowserThread::UI, FROM_HERE,
179 base::Bind(doneCallback_, sourceID));
180 doneCallback_.Reset();
181 }
182
183 - (void)okPressed:(id)sender {
184 NSIndexSet* indexes = [sourceBrowser_ selectionIndexes];
185 NSUInteger selectedIndex = [indexes firstIndex];
186 DesktopMediaPickerItem* item =
187 [items_ objectAtIndex:selectedIndex];
188 [self reportResult:[item sourceID]];
189 [self close];
190 }
191
192 - (void)cancelPressed:(id)sender {
193 [self reportResult:content::DesktopMediaID()];
194 [self close];
195 }
196
197 - (NSTextField*)createTextFieldWithText:(NSString*)text
198 frameWidth:(CGFloat)width {
199 NSRect frame = NSMakeRect(0, 0, width, 1);
200 base::scoped_nsobject<NSTextField> textField(
201 [[NSTextField alloc] initWithFrame:frame]);
202 [textField setEditable:NO];
203 [textField setSelectable:YES];
204 [textField setDrawsBackground:NO];
205 [textField setBezeled:NO];
206 [textField setStringValue:text];
207 [textField setFont:[NSFont systemFontOfSize:13]];
208 [textField setAutoresizingMask:NSViewWidthSizable];
209 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:textField];
210 return textField.autorelease();
211 }
212
213 - (NSButton*)createButtonWithTitle:(NSString*)title {
214 base::scoped_nsobject<NSButton> button(
215 [[NSButton alloc] initWithFrame:NSZeroRect]);
216 [button setButtonType:NSMomentaryPushInButton];
217 [button setBezelStyle:NSRoundedBezelStyle];
218 [button setTitle:title];
219 [GTMUILocalizerAndLayoutTweaker sizeToFitView:button];
220 return button.autorelease();
221 }
222
223 #pragma mark NSWindowDelegate
224
225 - (void)windowWillClose:(NSNotification*)notification {
226 // Report the result if it hasn't been reported yet. |reportResult:| ensures
227 // that the result is only reported once.
228 [self reportResult:content::DesktopMediaID()];
229 }
230
231 #pragma mark IKImageBrowserDataSource
232
233 - (NSUInteger)numberOfItemsInImageBrowser:(IKImageBrowserView*)browser {
234 return [items_ count];
235 }
236
237 - (id)imageBrowser:(IKImageBrowserView *)browser
238 itemAtIndex:(NSUInteger)index {
239 return [items_ objectAtIndex:index];
240 }
241
242 #pragma mark IKImageBrowserDelegate
243
244 - (void)imageBrowser:(IKImageBrowserView *)browser
245 cellWasDoubleClickedAtIndex:(NSUInteger)index {
246 DesktopMediaPickerItem* item = [items_ objectAtIndex:index];
247 [self reportResult:[item sourceID]];
248 [self close];
249 }
250
251 - (void)imageBrowserSelectionDidChange:(IKImageBrowserView*) aBrowser {
252 // Enable or disable the OK button based on whether we have a selection.
253 [okButton_ setEnabled:([[sourceBrowser_ selectionIndexes] count] > 0)];
254 }
255
256 #pragma mark DesktopMediaPickerObserver
257
258 - (void)sourceAddedAtIndex:(int)index {
259 const DesktopMediaPickerModel::Source& source = model_->source(index);
260 NSString* imageTitle = base::SysUTF16ToNSString(source.name);
261 base::scoped_nsobject<DesktopMediaPickerItem> item(
262 [[DesktopMediaPickerItem alloc] initWithSourceId:source.id
263 imageUID:++lastImageUID_
264 imageTitle:imageTitle]);
265 [items_ insertObject:item atIndex:index];
266 [sourceBrowser_ reloadData];
267 }
268
269 - (void)sourceRemovedAtIndex:(int)index {
270 if ([[sourceBrowser_ selectionIndexes] containsIndex:index]) {
271 // Selected item was removed. Clear selection.
272 [sourceBrowser_ setSelectionIndexes:[NSIndexSet indexSet]
273 byExtendingSelection:FALSE];
274 }
275 [items_ removeObjectAtIndex:index];
276 [sourceBrowser_ reloadData];
277 }
278
279 - (void)sourceNameChangedAtIndex:(int)index {
280 DesktopMediaPickerItem* item = [items_ objectAtIndex:index];
281 const DesktopMediaPickerModel::Source& source = model_->source(index);
282 [item setImageTitle:base::SysUTF16ToNSString(source.name)];
283 [sourceBrowser_ reloadData];
284 }
285
286 - (void)sourceThumbnailChangedAtIndex:(int)index {
287 const DesktopMediaPickerModel::Source& source = model_->source(index);
288 NSImage* image = gfx::NSImageFromImageSkia(source.thumbnail);
289
290 DesktopMediaPickerItem* item = [items_ objectAtIndex:index];
291 [item setImageRepresentation:image];
292 [sourceBrowser_ reloadData];
293 }
294
295 @end // @interface DesktopMediaPickerController
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698