Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / media_picker / desktop_media_picker_controller.mm
blobc6a2a6e41916c46611fe0f55dc843a7f4c38c6d7
1 // Copyright 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.
5 #import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller.h"
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 "chrome/grit/generated_resources.h"
12 #include "content/public/browser/browser_thread.h"
13 #import "third_party/google_toolbox_for_mac/src/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"
19 namespace {
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;
30 }  // namespace
32 @interface DesktopMediaPickerController (Private)
34 // Populate the window with controls and views.
35 - (void)initializeContentsWithAppName:(const base::string16&)appName;
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;
42 // Create a button with |title|, with size adjusted to fit.
43 - (NSButton*)createButtonWithTitle:(NSString*)title;
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;
49 // Action handlers.
50 - (void)sharePressed:(id)sender;
51 - (void)cancelPressed:(id)sender;
53 @end
55 @implementation DesktopMediaPickerController
57 - (id)initWithMediaList:(scoped_ptr<DesktopMediaList>)media_list
58                  parent:(NSWindow*)parent
59                callback:(const DesktopMediaPicker::DoneCallback&)callback
60                 appName:(const base::string16&)appName
61              targetName:(const base::string16&)targetName {
62   const NSUInteger kStyleMask =
63       NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask;
64   base::scoped_nsobject<NSWindow> window(
65       [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater
66                                   styleMask:kStyleMask
67                                     backing:NSBackingStoreBuffered
68                                       defer:NO]);
70   if ((self = [super initWithWindow:window])) {
71     [parent addChildWindow:window ordered:NSWindowAbove];
72     [window setDelegate:self];
73     [self initializeContentsWithAppName:appName targetName:targetName];
74     media_list_ = media_list.Pass();
75     media_list_->SetViewDialogWindowId([window windowNumber]);
76     doneCallback_ = callback;
77     items_.reset([[NSMutableArray alloc] init]);
78     bridge_.reset(new DesktopMediaPickerBridge(self));
79   }
80   return self;
83 - (void)dealloc {
84   [shareButton_ setTarget:nil];
85   [cancelButton_ setTarget:nil];
86   [sourceBrowser_ setDelegate:nil];
87   [sourceBrowser_ setDataSource:nil];
88   [[self window] close];
89   [super dealloc];
92 - (void)initializeContentsWithAppName:(const base::string16&)appName
93                            targetName:(const base::string16&)targetName {
94   // Use flipped coordinates to facilitate manual layout.
95   const CGFloat kPaddedWidth = kInitialContentWidth - (kFramePadding * 2);
96   base::scoped_nsobject<FlippedView> content(
97       [[FlippedView alloc] initWithFrame:NSZeroRect]);
98   [[self window] setContentView:content];
99   NSPoint origin = NSMakePoint(kFramePadding, kFramePadding);
101   // Set the dialog's title.
102   NSString* titleText = l10n_util::GetNSStringF(
103       IDS_DESKTOP_MEDIA_PICKER_TITLE, appName);
104   [[self window] setTitle:titleText];
106   // Set the dialog's description.
107   NSString* descriptionText;
108   if (appName == targetName) {
109     descriptionText = l10n_util::GetNSStringF(
110         IDS_DESKTOP_MEDIA_PICKER_TEXT, appName);
111   } else {
112     descriptionText = l10n_util::GetNSStringF(
113         IDS_DESKTOP_MEDIA_PICKER_TEXT_DELEGATED, appName, targetName);
114   }
115   NSTextField* description = [self createTextFieldWithText:descriptionText
116                                                 frameWidth:kPaddedWidth];
117   [description setFrameOrigin:origin];
118   [content addSubview:description];
119   origin.y += NSHeight([description frame]) + kControlSpacing;
121   // Create the image browser.
122   sourceBrowser_.reset([[IKImageBrowserView alloc] initWithFrame:NSZeroRect]);
123   NSUInteger cellStyle = IKCellsStyleShadowed | IKCellsStyleTitled;
124   [sourceBrowser_ setDelegate:self];
125   [sourceBrowser_ setDataSource:self];
126   [sourceBrowser_ setCellsStyleMask:cellStyle];
127   [sourceBrowser_ setCellSize:NSMakeSize(kThumbnailWidth, kThumbnailHeight)];
129   // Create a scroll view to host the image browser.
130   NSRect imageBrowserScrollFrame = NSMakeRect(
131       origin.x, origin.y, kPaddedWidth, 350);
132   base::scoped_nsobject<NSScrollView> imageBrowserScroll(
133       [[NSScrollView alloc] initWithFrame:imageBrowserScrollFrame]);
134   [imageBrowserScroll setHasVerticalScroller:YES];
135   [imageBrowserScroll setDocumentView:sourceBrowser_];
136   [imageBrowserScroll setBorderType:NSBezelBorder];
137   [imageBrowserScroll setAutoresizingMask:
138       NSViewWidthSizable | NSViewHeightSizable];
139   [content addSubview:imageBrowserScroll];
140   origin.y += NSHeight(imageBrowserScrollFrame) + kControlSpacing;
142   // Create the share button.
143   shareButton_ = [self createButtonWithTitle:l10n_util::GetNSString(
144       IDS_DESKTOP_MEDIA_PICKER_SHARE)];
145   origin.x = kInitialContentWidth - kFramePadding -
146       (NSWidth([shareButton_ frame]) - kExcessButtonPadding);
147   [shareButton_ setEnabled:NO];
148   [shareButton_ setFrameOrigin:origin];
149   [shareButton_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
150   [shareButton_ setTarget:self];
151   [shareButton_ setAction:@selector(sharePressed:)];
152   [content addSubview:shareButton_];
154   // Create the cancel button.
155   cancelButton_ =
156       [self createButtonWithTitle:l10n_util::GetNSString(IDS_CANCEL)];
157   origin.x -= kControlSpacing +
158       (NSWidth([cancelButton_ frame]) - (kExcessButtonPadding * 2));
159   [cancelButton_ setFrameOrigin:origin];
160   [cancelButton_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
161   [cancelButton_ setTarget:self];
162   [cancelButton_ setAction:@selector(cancelPressed:)];
163   [content addSubview:cancelButton_];
164   origin.y += kFramePadding +
165       (NSHeight([cancelButton_ frame]) - kExcessButtonPadding);
167   // Resize window to fit.
168   [[[self window] contentView] setAutoresizesSubviews:NO];
169   [[self window] setContentSize:NSMakeSize(kInitialContentWidth, origin.y)];
170   [[self window] setContentMinSize:
171       NSMakeSize(kMinimumContentWidth, kMinimumContentHeight)];
172   [[[self window] contentView] setAutoresizesSubviews:YES];
175 - (void)showWindow:(id)sender {
176   // Signal the media_list to start sending thumbnails. |bridge_| is used as the
177   // observer, and will forward notifications to this object.
178   media_list_->SetThumbnailSize(gfx::Size(kThumbnailWidth, kThumbnailHeight));
179   media_list_->StartUpdating(bridge_.get());
181   [self.window center];
182   [super showWindow:sender];
185 - (void)reportResult:(content::DesktopMediaID)sourceID {
186   if (doneCallback_.is_null()) {
187     return;
188   }
190   // Notify the |callback_| asynchronously because it may release the
191   // controller.
192   content::BrowserThread::PostTask(
193       content::BrowserThread::UI, FROM_HERE,
194       base::Bind(doneCallback_, sourceID));
195   doneCallback_.Reset();
198 - (void)sharePressed:(id)sender {
199   NSIndexSet* indexes = [sourceBrowser_ selectionIndexes];
200   NSUInteger selectedIndex = [indexes firstIndex];
201   DesktopMediaPickerItem* item =
202       [items_ objectAtIndex:selectedIndex];
203   [self reportResult:[item sourceID]];
204   [self close];
207 - (void)cancelPressed:(id)sender {
208   [self reportResult:content::DesktopMediaID()];
209   [self close];
212 - (NSTextField*)createTextFieldWithText:(NSString*)text
213                              frameWidth:(CGFloat)width {
214   NSRect frame = NSMakeRect(0, 0, width, 1);
215   base::scoped_nsobject<NSTextField> textField(
216       [[NSTextField alloc] initWithFrame:frame]);
217   [textField setEditable:NO];
218   [textField setSelectable:YES];
219   [textField setDrawsBackground:NO];
220   [textField setBezeled:NO];
221   [textField setStringValue:text];
222   [textField setFont:[NSFont systemFontOfSize:13]];
223   [textField setAutoresizingMask:NSViewWidthSizable];
224   [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:textField];
225   return textField.autorelease();
228 - (NSButton*)createButtonWithTitle:(NSString*)title {
229   base::scoped_nsobject<NSButton> button(
230       [[NSButton alloc] initWithFrame:NSZeroRect]);
231   [button setButtonType:NSMomentaryPushInButton];
232   [button setBezelStyle:NSRoundedBezelStyle];
233   [button setTitle:title];
234   [GTMUILocalizerAndLayoutTweaker sizeToFitView:button];
235   return button.autorelease();
238 #pragma mark NSWindowDelegate
240 - (void)windowWillClose:(NSNotification*)notification {
241   // Report the result if it hasn't been reported yet. |reportResult:| ensures
242   // that the result is only reported once.
243   [self reportResult:content::DesktopMediaID()];
245   // Remove self from the parent.
246   NSWindow* window = [self window];
247   [[window parentWindow] removeChildWindow:window];
250 #pragma mark IKImageBrowserDataSource
252 - (NSUInteger)numberOfItemsInImageBrowser:(IKImageBrowserView*)browser {
253   return [items_ count];
256 - (id)imageBrowser:(IKImageBrowserView *)browser
257        itemAtIndex:(NSUInteger)index {
258   return [items_ objectAtIndex:index];
261 #pragma mark IKImageBrowserDelegate
263 - (void)imageBrowser:(IKImageBrowserView *)browser
264       cellWasDoubleClickedAtIndex:(NSUInteger)index {
265   DesktopMediaPickerItem* item = [items_ objectAtIndex:index];
266   [self reportResult:[item sourceID]];
267   [self close];
270 - (void)imageBrowserSelectionDidChange:(IKImageBrowserView*) aBrowser {
271   // Enable or disable the OK button based on whether we have a selection.
272   [shareButton_ setEnabled:([[sourceBrowser_ selectionIndexes] count] > 0)];
275 #pragma mark DesktopMediaPickerObserver
277 - (void)sourceAddedAtIndex:(int)index {
278   const DesktopMediaList::Source& source = media_list_->GetSource(index);
279   NSString* imageTitle = base::SysUTF16ToNSString(source.name);
280   base::scoped_nsobject<DesktopMediaPickerItem> item(
281       [[DesktopMediaPickerItem alloc] initWithSourceId:source.id
282                                               imageUID:++lastImageUID_
283                                             imageTitle:imageTitle]);
284   [items_ insertObject:item atIndex:index];
285   [sourceBrowser_ reloadData];
288 - (void)sourceRemovedAtIndex:(int)index {
289   if ([[sourceBrowser_ selectionIndexes] containsIndex:index]) {
290     // Selected item was removed. Clear selection.
291     [sourceBrowser_ setSelectionIndexes:[NSIndexSet indexSet]
292                       byExtendingSelection:FALSE];
293   }
294   [items_ removeObjectAtIndex:index];
295   [sourceBrowser_ reloadData];
298 - (void)sourceMovedFrom:(int)oldIndex to:(int)newIndex {
299   base::scoped_nsobject<DesktopMediaPickerItem> item(
300       [[items_ objectAtIndex:oldIndex] retain]);
301   [items_ removeObjectAtIndex:oldIndex];
302   [items_ insertObject:item atIndex:newIndex];
303   [sourceBrowser_ reloadData];
306 - (void)sourceNameChangedAtIndex:(int)index {
307   DesktopMediaPickerItem* item = [items_ objectAtIndex:index];
308   const DesktopMediaList::Source& source = media_list_->GetSource(index);
309   [item setImageTitle:base::SysUTF16ToNSString(source.name)];
310   [sourceBrowser_ reloadData];
313 - (void)sourceThumbnailChangedAtIndex:(int)index {
314   const DesktopMediaList::Source& source = media_list_->GetSource(index);
315   NSImage* image = gfx::NSImageFromImageSkia(source.thumbnail);
317   DesktopMediaPickerItem* item = [items_ objectAtIndex:index];
318   [item setImageRepresentation:image];
319   [sourceBrowser_ reloadData];
322 @end  // @interface DesktopMediaPickerController