Commit 56b7e39e authored by sail@chromium.org's avatar sail@chromium.org

Cocoa: Implement media gallery dialog

This is the cocoa version of the media galleries permission dialog. The dialog is implemented as an NSAlert displayed as a constrained window. The gallery checkboxes are added inside a accessory view.

The views and GTK versions are here:
http://codereview.chromium.org/10828166/
https://chromiumcodereview.appspot.com/10826129

Screenshots: http://i.imgur.com/fedm0.png

BUG=134929
TBR=mihaip@chromium.org

Review URL: https://chromiumcodereview.appspot.com/10834242

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@152128 0039d316-1c4b-4281-b951-d872f2087c98
parent 7038f72a
......@@ -12,6 +12,7 @@
#include "base/platform_file.h"
#include "base/values.h"
#include "chrome/browser/media_gallery/media_file_system_registry.h"
#include "chrome/browser/media_gallery/media_galleries_dialog_controller.h"
#include "chrome/browser/ui/tab_contents/tab_contents.h"
#include "chrome/common/extensions/api/experimental_media_galleries.h"
#include "content/public/browser/child_process_security_policy.h"
......@@ -23,10 +24,6 @@
#include "base/sys_string_conversions.h"
#endif
#if !defined(OS_MACOSX)
#include "chrome/browser/media_gallery/media_galleries_dialog_controller.h"
#endif
using content::WebContents;
namespace extensions {
......@@ -112,16 +109,11 @@ void MediaGalleriesGetMediaFileSystemsFunction::ShowDialog() {
return;
}
#if !defined(OS_MACOSX)
// Controller will delete itself.
new chrome::MediaGalleriesDialogController(
tab_contents, *GetExtension(),
base::Bind(&MediaGalleriesGetMediaFileSystemsFunction::ReturnGalleries,
this));
#else
// TODO(estade): implement dialog on Views and Cocoa.
ReturnGalleries();
#endif
}
// MediaGalleriesAssembleMediaFileFunction -------------------------------------
......
......@@ -44,13 +44,13 @@ MediaGalleriesDialogController::~MediaGalleriesDialogController() {
select_folder_dialog_->ListenerDestroyed();
}
string16 MediaGalleriesDialogController::GetHeader() {
string16 MediaGalleriesDialogController::GetHeader() const {
std::string extension_name(extension_ ? extension_->name() : "");
return l10n_util::GetStringFUTF16(IDS_MEDIA_GALLERIES_DIALOG_HEADER,
UTF8ToUTF16(extension_name));
}
string16 MediaGalleriesDialogController::GetSubtext() {
string16 MediaGalleriesDialogController::GetSubtext() const {
if (extension_ && extension_->HasAPIPermission(
extensions::APIPermission::kMediaGalleriesRead)) {
return l10n_util::GetStringFUTF16(IDS_MEDIA_GALLERIES_DIALOG_READ_SUBTEXT,
......@@ -60,6 +60,15 @@ string16 MediaGalleriesDialogController::GetSubtext() {
return string16();
}
bool MediaGalleriesDialogController::HasPermittedGalleries() const {
for (KnownGalleryPermissions::const_iterator iter = permissions().begin();
iter != permissions().end(); iter++) {
if (iter->second.allowed)
return true;
}
return false;
}
void MediaGalleriesDialogController::OnAddFolderClicked() {
FilePath user_data_dir;
PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
......@@ -75,7 +84,7 @@ void MediaGalleriesDialogController::OnAddFolderClicked() {
NULL);
}
void MediaGalleriesDialogController::GalleryToggled(
void MediaGalleriesDialogController::DidToggleGallery(
const MediaGalleryPrefInfo* gallery,
bool enabled) {
// Check known galleries.
......
......@@ -66,11 +66,12 @@ class MediaGalleriesDialogController : public ui::SelectFileDialog::Listener {
const base::Callback<void(void)>& on_finish);
// Called by the view.
string16 GetHeader();
string16 GetSubtext();
string16 GetHeader() const;
string16 GetSubtext() const;
bool HasPermittedGalleries() const;
void OnAddFolderClicked();
virtual void GalleryToggled(const MediaGalleryPrefInfo* pref_info,
bool enabled);
virtual void DidToggleGallery(const MediaGalleryPrefInfo* pref_info,
bool enabled);
virtual void DialogFinished(bool accepted);
// SelectFileDialog::Listener implementation:
......
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_COCOA_EXTENSIONS_MEDIA_GALLERIES_DIALOG_COCOA_H_
#define CHROME_BROWSER_UI_COCOA_EXTENSIONS_MEDIA_GALLERIES_DIALOG_COCOA_H_
#import <Cocoa/Cocoa.h>
#include "chrome/browser/media_gallery/media_galleries_dialog_controller.h"
#import "chrome/browser/ui/cocoa/constrained_window_mac.h"
@class MediaGalleriesCocoaController;
namespace chrome {
// This class displays an alert that can be used to grant permission for
// extensions to access a gallery (media folders).
class MediaGalleriesDialogCocoa :
public ConstrainedWindowMacDelegateSystemSheet,
public MediaGalleriesDialog {
public:
MediaGalleriesDialogCocoa(
MediaGalleriesDialogController* controller,
MediaGalleriesCocoaController* delegate);
virtual ~MediaGalleriesDialogCocoa();
// Called when the user clicks the Add Gallery button.
void OnAddFolderClicked();
// Called when the user toggles a gallery checkbox.
void OnCheckboxToggled(NSButton* checkbox);
// Called when the alert closes.
void SheetDidEnd(NSInteger result);
// MediaGalleriesDialog implementation:
virtual void UpdateGallery(const MediaGalleryPrefInfo* gallery,
bool permitted) OVERRIDE;
// ConstrainedWindowMacDelegateSystemSheet implementation.
virtual void DeleteDelegate() OVERRIDE;
private:
void UpdateGalleryCheckbox(NSButton* checkbox,
const MediaGalleryPrefInfo* gallery,
bool permitted);
void UpdateCheckboxContainerFrame();
MediaGalleriesDialogController* controller_; // weak
ConstrainedWindow* window_; // weak
// True if the user has pressed accept.
bool accepted_;
// List of checkboxes ordered from bottom to top.
scoped_nsobject<NSMutableArray> checkboxes_;
// Container view for checkboxes.
scoped_nsobject<NSView> checkbox_container_;
// The alert that the dialog is being displayed as.
scoped_nsobject<NSAlert> alert_;
// An Objective-C class to route callbacks from Cocoa code.
scoped_nsobject<MediaGalleriesCocoaController> cocoa_controller_;
DISALLOW_COPY_AND_ASSIGN(MediaGalleriesDialogCocoa);
};
} // namespace chrome
#endif // CHROME_BROWSER_UI_COCOA_EXTENSIONS_MEDIA_GALLERIES_DIALOG_COCOA_H_
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.h"
#include "base/sys_string_conversions.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
const CGFloat kCheckboxMargin = 5;
const CGFloat kCheckboxMaxWidth = 350;
@interface MediaGalleriesCocoaController : NSObject {
@private
chrome::MediaGalleriesDialogCocoa* dialog_;
}
@property(nonatomic, assign) chrome::MediaGalleriesDialogCocoa* dialog;
@end
@implementation MediaGalleriesCocoaController
@synthesize dialog = dialog_;
- (void)onAddFolderClicked:(id)sender {
DCHECK(dialog_);
dialog_->OnAddFolderClicked();
}
- (void)onCheckboxToggled:(id)sender {
DCHECK(dialog_);
dialog_->OnCheckboxToggled(sender);
}
- (void)sheetDidEnd:(NSWindow*)parent
returnCode:(NSInteger)returnCode
context:(void*)context {
DCHECK(dialog_);
dialog_->SheetDidEnd(returnCode);
}
@end
namespace chrome {
MediaGalleriesDialogCocoa::MediaGalleriesDialogCocoa(
MediaGalleriesDialogController* controller,
MediaGalleriesCocoaController* cocoa_controller)
: ConstrainedWindowMacDelegateSystemSheet(
cocoa_controller, @selector(sheetDidEnd:returnCode:context:)),
controller_(controller),
window_(NULL),
accepted_(false),
cocoa_controller_([cocoa_controller retain]) {
[cocoa_controller_ setDialog:this];
alert_.reset([[NSAlert alloc] init]);
[alert_ setMessageText:base::SysUTF16ToNSString(controller_->GetHeader())];
[alert_ setInformativeText:SysUTF16ToNSString(controller_->GetSubtext())];
[alert_ addButtonWithTitle:l10n_util::GetNSString(
IDS_MEDIA_GALLERIES_DIALOG_CONFIRM)];
[alert_ addButtonWithTitle:l10n_util::GetNSString(
IDS_MEDIA_GALLERIES_DIALOG_CANCEL)];
[alert_ addButtonWithTitle:l10n_util::GetNSString(
IDS_MEDIA_GALLERIES_DIALOG_ADD_GALLERY)];
// Override the add button click handler to prevent the alert from closing.
NSButton* add_button = [[alert_ buttons] objectAtIndex:2];
[add_button setTarget:cocoa_controller_];
[add_button setAction:@selector(onAddFolderClicked:)];
// Add gallery permission checkboxes inside an accessory view.
checkbox_container_.reset([[NSView alloc] initWithFrame:NSZeroRect]);
checkboxes_.reset([[NSMutableArray alloc] init]);
const MediaGalleriesDialogController::KnownGalleryPermissions& permissions =
controller_->permissions();
for (MediaGalleriesDialogController::KnownGalleryPermissions::
const_reverse_iterator iter = permissions.rbegin();
iter != permissions.rend(); iter++) {
const MediaGalleriesDialogController::GalleryPermission& permission =
iter->second;
UpdateGalleryCheckbox(nil, &permission.pref_info, permission.allowed);
}
UpdateCheckboxContainerFrame();
[alert_ setAccessoryView:checkbox_container_];
// As a safeguard against the user skipping reading over the dialog and just
// confirming, the button will be unavailable for dialogs without any checks
// until the user toggles something.
[[[alert_ buttons] objectAtIndex:0] setEnabled:
controller_->HasPermittedGalleries()];
set_sheet(alert_);
window_ = new ConstrainedWindowMac(controller->tab_contents(), this);
}
MediaGalleriesDialogCocoa::~MediaGalleriesDialogCocoa() {
}
void MediaGalleriesDialogCocoa::OnAddFolderClicked() {
controller_->OnAddFolderClicked();
}
void MediaGalleriesDialogCocoa::OnCheckboxToggled(NSButton* checkbox) {
const MediaGalleriesDialogController::KnownGalleryPermissions& permissions =
controller_->permissions();
[[[alert_ buttons] objectAtIndex:0] setEnabled:YES];
for (MediaGalleriesDialogController::KnownGalleryPermissions::
const_reverse_iterator iter = permissions.rbegin();
iter != permissions.rend(); iter++) {
const MediaGalleryPrefInfo* gallery = &iter->second.pref_info;
NSString* device_id = base::SysUTF8ToNSString(gallery->device_id);
if ([[[checkbox cell] representedObject] isEqual:device_id]) {
controller_->DidToggleGallery(gallery, [checkbox state] == NSOnState);
break;
}
}
}
void MediaGalleriesDialogCocoa::SheetDidEnd(NSInteger result) {
switch (result) {
case NSAlertFirstButtonReturn:
accepted_ = true;
window_->CloseConstrainedWindow();
break;
case NSAlertSecondButtonReturn:
window_->CloseConstrainedWindow();
break;
default:
NOTREACHED();
break;
}
}
void MediaGalleriesDialogCocoa::UpdateGalleryCheckbox(
NSButton* checkbox,
const MediaGalleryPrefInfo* gallery,
bool permitted) {
CGFloat y_pos = 0;
if (checkbox) {
y_pos = NSMinY([checkbox frame]);
} else {
if ([checkboxes_ count] > 0)
y_pos = NSMaxY([[checkboxes_ lastObject] frame]) + kCheckboxMargin;
scoped_nsobject<NSButton> new_checkbox(
[[NSButton alloc] initWithFrame:NSZeroRect]);
NSString* device_id = base::SysUTF8ToNSString(gallery->device_id);
[[new_checkbox cell] setRepresentedObject:device_id];
[[new_checkbox cell] setLineBreakMode:NSLineBreakByTruncatingMiddle];
[new_checkbox setButtonType:NSSwitchButton];
[new_checkbox setTarget:cocoa_controller_];
[new_checkbox setAction:@selector(onCheckboxToggled:)];
[checkbox_container_ addSubview:new_checkbox];
[checkboxes_ addObject:new_checkbox];
checkbox = new_checkbox.get();
}
[checkbox setTitle:base::SysUTF16ToNSString(gallery->display_name)];
[checkbox setToolTip:
base::SysUTF16ToNSString(gallery->path.LossyDisplayName())];
[checkbox setState:permitted ? NSOnState : NSOffState];
[checkbox sizeToFit];
NSRect rect = [checkbox bounds];
rect.origin.y = y_pos;
rect.size.width = std::min(NSWidth(rect), kCheckboxMaxWidth);
[checkbox setFrame:rect];
}
void MediaGalleriesDialogCocoa::UpdateCheckboxContainerFrame() {
NSRect rect = NSMakeRect(
0, 0, kCheckboxMaxWidth, NSMaxY([[checkboxes_ lastObject] frame]));
[checkbox_container_ setFrame:rect];
}
void MediaGalleriesDialogCocoa::UpdateGallery(
const MediaGalleryPrefInfo* gallery,
bool permitted) {
NSButton* checkbox = nil;
NSString* device_id = base::SysUTF8ToNSString(gallery->device_id);
for (NSButton* button in checkboxes_.get()) {
if ([[[button cell] representedObject] isEqual:device_id]) {
checkbox = button;
break;
}
}
UpdateGalleryCheckbox(checkbox, gallery, permitted);
UpdateCheckboxContainerFrame();
[alert_ layout];
}
void MediaGalleriesDialogCocoa::DeleteDelegate() {
// As required by ConstrainedWindowMacDelegate, close the sheet if
// it's still open.
if (is_sheet_open())
[NSApp endSheet:sheet()];
controller_->DialogFinished(accepted_);
}
// static
MediaGalleriesDialog* MediaGalleriesDialog::Create(
MediaGalleriesDialogController* controller) {
scoped_nsobject<MediaGalleriesCocoaController> cocoa_controller(
[[MediaGalleriesCocoaController alloc] init]);
return new MediaGalleriesDialogCocoa(controller, cocoa_controller);
}
} // namespace chrome
......@@ -52,14 +52,9 @@ void MediaGalleriesDialogGtk::InitWidgets() {
gtk_box_pack_start(GTK_BOX(contents_.get()), checkbox_container_,
FALSE, FALSE, 0);
// As a safeguard against the user skipping reading over the dialog and just
// confirming, the button will be unavailable for dialogs without any checks
// until the user toggles something.
bool confirm_available = false;
const GalleryPermissions& permissions = controller_->permissions();
for (GalleryPermissions::const_iterator iter = permissions.begin();
iter != permissions.end(); iter++) {
confirm_available = confirm_available || iter->second.allowed;
UpdateGallery(&iter->second.pref_info, iter->second.allowed);
}
......@@ -90,7 +85,10 @@ void MediaGalleriesDialogGtk::InitWidgets() {
g_signal_connect(cancel, "clicked", G_CALLBACK(OnCancelThunk), this);
gtk_box_pack_end(GTK_BOX(bottom_area), cancel, FALSE, FALSE, 0);
gtk_widget_set_sensitive(confirm_, confirm_available);
// As a safeguard against the user skipping reading over the dialog and just
// confirming, the button will be unavailable for dialogs without any checks
// until the user toggles something.
gtk_widget_set_sensitive(confirm_, controller_->HasPermittedGalleries());
}
void MediaGalleriesDialogGtk::UpdateGallery(
......@@ -136,7 +134,7 @@ void MediaGalleriesDialogGtk::OnToggled(GtkWidget* widget) {
for (CheckboxMap::iterator iter = checkbox_map_.begin();
iter != checkbox_map_.end(); ++iter) {
if (iter->second == widget) {
controller_->GalleryToggled(
controller_->DidToggleGallery(
iter->first, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
return;
}
......
......@@ -15,10 +15,10 @@ class MediaGalleriesDialogTest : public testing::Test,
virtual ~MediaGalleriesDialogTest() {}
virtual void DialogFinished(bool accepted) OVERRIDE {}
virtual void GalleryToggled(const MediaGalleryPrefInfo* pref_info,
bool enabled) OVERRIDE {
virtual void DidToggleGallery(const MediaGalleryPrefInfo* pref_info,
bool enabled) OVERRIDE {
toggles_++;
MediaGalleriesDialogController::GalleryToggled(pref_info, enabled);
MediaGalleriesDialogController::DidToggleGallery(pref_info, enabled);
}
protected:
......
......@@ -93,9 +93,8 @@ void MediaGalleriesDialogViews::InitChildViews() {
for (GalleryPermissions::const_iterator iter = permissions.begin();
iter != permissions.end(); ++iter) {
AddOrUpdateGallery(&iter->second.pref_info, iter->second.allowed);
if (iter->second.allowed)
confirm_available_ = true;
}
confirm_available_ = controller_->HasPermittedGalleries();
// Add Gallery button.
add_gallery_ = new views::NativeTextButton(
......@@ -182,7 +181,7 @@ void MediaGalleriesDialogViews::ButtonPressed(views::Button* sender,
for (CheckboxMap::iterator iter = checkbox_map_.begin();
iter != checkbox_map_.end(); ++iter) {
if (sender == iter->second) {
controller_->GalleryToggled(
controller_->DidToggleGallery(
iter->first, static_cast<views::Checkbox*>(sender)->checked());
return;
}
......
......@@ -2765,6 +2765,8 @@
'browser/ui/cocoa/extensions/extension_uninstall_dialog_cocoa.mm',
'browser/ui/cocoa/extensions/extension_view_mac.h',
'browser/ui/cocoa/extensions/extension_view_mac.mm',
'browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.h',
'browser/ui/cocoa/extensions/media_galleries_dialog_cocoa.mm',
'browser/ui/cocoa/extensions/shell_window_cocoa.h',
'browser/ui/cocoa/extensions/shell_window_cocoa.mm',
'browser/ui/cocoa/external_protocol_dialog.h',
......@@ -5083,7 +5085,6 @@
'browser/importer/nss_decryptor_system_nss.h',
'browser/jankometer.cc',
'browser/lifetime/application_lifetime_stub.cc',
'browser/media_gallery/media_galleries_dialog_controller.cc',
'browser/password_manager/encryptor_posix.cc',
'browser/password_manager/login_database_posix.cc',
'browser/tab_contents/spellchecker_submenu_observer_hunspell.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment