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 @@ ...@@ -12,6 +12,7 @@
#include "base/platform_file.h" #include "base/platform_file.h"
#include "base/values.h" #include "base/values.h"
#include "chrome/browser/media_gallery/media_file_system_registry.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/browser/ui/tab_contents/tab_contents.h"
#include "chrome/common/extensions/api/experimental_media_galleries.h" #include "chrome/common/extensions/api/experimental_media_galleries.h"
#include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/child_process_security_policy.h"
...@@ -23,10 +24,6 @@ ...@@ -23,10 +24,6 @@
#include "base/sys_string_conversions.h" #include "base/sys_string_conversions.h"
#endif #endif
#if !defined(OS_MACOSX)
#include "chrome/browser/media_gallery/media_galleries_dialog_controller.h"
#endif
using content::WebContents; using content::WebContents;
namespace extensions { namespace extensions {
...@@ -112,16 +109,11 @@ void MediaGalleriesGetMediaFileSystemsFunction::ShowDialog() { ...@@ -112,16 +109,11 @@ void MediaGalleriesGetMediaFileSystemsFunction::ShowDialog() {
return; return;
} }
#if !defined(OS_MACOSX)
// Controller will delete itself. // Controller will delete itself.
new chrome::MediaGalleriesDialogController( new chrome::MediaGalleriesDialogController(
tab_contents, *GetExtension(), tab_contents, *GetExtension(),
base::Bind(&MediaGalleriesGetMediaFileSystemsFunction::ReturnGalleries, base::Bind(&MediaGalleriesGetMediaFileSystemsFunction::ReturnGalleries,
this)); this));
#else
// TODO(estade): implement dialog on Views and Cocoa.
ReturnGalleries();
#endif
} }
// MediaGalleriesAssembleMediaFileFunction ------------------------------------- // MediaGalleriesAssembleMediaFileFunction -------------------------------------
......
...@@ -44,13 +44,13 @@ MediaGalleriesDialogController::~MediaGalleriesDialogController() { ...@@ -44,13 +44,13 @@ MediaGalleriesDialogController::~MediaGalleriesDialogController() {
select_folder_dialog_->ListenerDestroyed(); select_folder_dialog_->ListenerDestroyed();
} }
string16 MediaGalleriesDialogController::GetHeader() { string16 MediaGalleriesDialogController::GetHeader() const {
std::string extension_name(extension_ ? extension_->name() : ""); std::string extension_name(extension_ ? extension_->name() : "");
return l10n_util::GetStringFUTF16(IDS_MEDIA_GALLERIES_DIALOG_HEADER, return l10n_util::GetStringFUTF16(IDS_MEDIA_GALLERIES_DIALOG_HEADER,
UTF8ToUTF16(extension_name)); UTF8ToUTF16(extension_name));
} }
string16 MediaGalleriesDialogController::GetSubtext() { string16 MediaGalleriesDialogController::GetSubtext() const {
if (extension_ && extension_->HasAPIPermission( if (extension_ && extension_->HasAPIPermission(
extensions::APIPermission::kMediaGalleriesRead)) { extensions::APIPermission::kMediaGalleriesRead)) {
return l10n_util::GetStringFUTF16(IDS_MEDIA_GALLERIES_DIALOG_READ_SUBTEXT, return l10n_util::GetStringFUTF16(IDS_MEDIA_GALLERIES_DIALOG_READ_SUBTEXT,
...@@ -60,6 +60,15 @@ string16 MediaGalleriesDialogController::GetSubtext() { ...@@ -60,6 +60,15 @@ string16 MediaGalleriesDialogController::GetSubtext() {
return string16(); 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() { void MediaGalleriesDialogController::OnAddFolderClicked() {
FilePath user_data_dir; FilePath user_data_dir;
PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
...@@ -75,7 +84,7 @@ void MediaGalleriesDialogController::OnAddFolderClicked() { ...@@ -75,7 +84,7 @@ void MediaGalleriesDialogController::OnAddFolderClicked() {
NULL); NULL);
} }
void MediaGalleriesDialogController::GalleryToggled( void MediaGalleriesDialogController::DidToggleGallery(
const MediaGalleryPrefInfo* gallery, const MediaGalleryPrefInfo* gallery,
bool enabled) { bool enabled) {
// Check known galleries. // Check known galleries.
......
...@@ -66,10 +66,11 @@ class MediaGalleriesDialogController : public ui::SelectFileDialog::Listener { ...@@ -66,10 +66,11 @@ class MediaGalleriesDialogController : public ui::SelectFileDialog::Listener {
const base::Callback<void(void)>& on_finish); const base::Callback<void(void)>& on_finish);
// Called by the view. // Called by the view.
string16 GetHeader(); string16 GetHeader() const;
string16 GetSubtext(); string16 GetSubtext() const;
bool HasPermittedGalleries() const;
void OnAddFolderClicked(); void OnAddFolderClicked();
virtual void GalleryToggled(const MediaGalleryPrefInfo* pref_info, virtual void DidToggleGallery(const MediaGalleryPrefInfo* pref_info,
bool enabled); bool enabled);
virtual void DialogFinished(bool accepted); virtual void DialogFinished(bool accepted);
......
// 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() { ...@@ -52,14 +52,9 @@ void MediaGalleriesDialogGtk::InitWidgets() {
gtk_box_pack_start(GTK_BOX(contents_.get()), checkbox_container_, gtk_box_pack_start(GTK_BOX(contents_.get()), checkbox_container_,
FALSE, FALSE, 0); 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(); const GalleryPermissions& permissions = controller_->permissions();
for (GalleryPermissions::const_iterator iter = permissions.begin(); for (GalleryPermissions::const_iterator iter = permissions.begin();
iter != permissions.end(); iter++) { iter != permissions.end(); iter++) {
confirm_available = confirm_available || iter->second.allowed;
UpdateGallery(&iter->second.pref_info, iter->second.allowed); UpdateGallery(&iter->second.pref_info, iter->second.allowed);
} }
...@@ -90,7 +85,10 @@ void MediaGalleriesDialogGtk::InitWidgets() { ...@@ -90,7 +85,10 @@ void MediaGalleriesDialogGtk::InitWidgets() {
g_signal_connect(cancel, "clicked", G_CALLBACK(OnCancelThunk), this); g_signal_connect(cancel, "clicked", G_CALLBACK(OnCancelThunk), this);
gtk_box_pack_end(GTK_BOX(bottom_area), cancel, FALSE, FALSE, 0); 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( void MediaGalleriesDialogGtk::UpdateGallery(
...@@ -136,7 +134,7 @@ void MediaGalleriesDialogGtk::OnToggled(GtkWidget* widget) { ...@@ -136,7 +134,7 @@ void MediaGalleriesDialogGtk::OnToggled(GtkWidget* widget) {
for (CheckboxMap::iterator iter = checkbox_map_.begin(); for (CheckboxMap::iterator iter = checkbox_map_.begin();
iter != checkbox_map_.end(); ++iter) { iter != checkbox_map_.end(); ++iter) {
if (iter->second == widget) { if (iter->second == widget) {
controller_->GalleryToggled( controller_->DidToggleGallery(
iter->first, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); iter->first, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
return; return;
} }
......
...@@ -15,10 +15,10 @@ class MediaGalleriesDialogTest : public testing::Test, ...@@ -15,10 +15,10 @@ class MediaGalleriesDialogTest : public testing::Test,
virtual ~MediaGalleriesDialogTest() {} virtual ~MediaGalleriesDialogTest() {}
virtual void DialogFinished(bool accepted) OVERRIDE {} virtual void DialogFinished(bool accepted) OVERRIDE {}
virtual void GalleryToggled(const MediaGalleryPrefInfo* pref_info, virtual void DidToggleGallery(const MediaGalleryPrefInfo* pref_info,
bool enabled) OVERRIDE { bool enabled) OVERRIDE {
toggles_++; toggles_++;
MediaGalleriesDialogController::GalleryToggled(pref_info, enabled); MediaGalleriesDialogController::DidToggleGallery(pref_info, enabled);
} }
protected: protected:
......
...@@ -93,9 +93,8 @@ void MediaGalleriesDialogViews::InitChildViews() { ...@@ -93,9 +93,8 @@ void MediaGalleriesDialogViews::InitChildViews() {
for (GalleryPermissions::const_iterator iter = permissions.begin(); for (GalleryPermissions::const_iterator iter = permissions.begin();
iter != permissions.end(); ++iter) { iter != permissions.end(); ++iter) {
AddOrUpdateGallery(&iter->second.pref_info, iter->second.allowed); AddOrUpdateGallery(&iter->second.pref_info, iter->second.allowed);
if (iter->second.allowed)
confirm_available_ = true;
} }
confirm_available_ = controller_->HasPermittedGalleries();
// Add Gallery button. // Add Gallery button.
add_gallery_ = new views::NativeTextButton( add_gallery_ = new views::NativeTextButton(
...@@ -182,7 +181,7 @@ void MediaGalleriesDialogViews::ButtonPressed(views::Button* sender, ...@@ -182,7 +181,7 @@ void MediaGalleriesDialogViews::ButtonPressed(views::Button* sender,
for (CheckboxMap::iterator iter = checkbox_map_.begin(); for (CheckboxMap::iterator iter = checkbox_map_.begin();
iter != checkbox_map_.end(); ++iter) { iter != checkbox_map_.end(); ++iter) {
if (sender == iter->second) { if (sender == iter->second) {
controller_->GalleryToggled( controller_->DidToggleGallery(
iter->first, static_cast<views::Checkbox*>(sender)->checked()); iter->first, static_cast<views::Checkbox*>(sender)->checked());
return; return;
} }
......
...@@ -2765,6 +2765,8 @@ ...@@ -2765,6 +2765,8 @@
'browser/ui/cocoa/extensions/extension_uninstall_dialog_cocoa.mm', 'browser/ui/cocoa/extensions/extension_uninstall_dialog_cocoa.mm',
'browser/ui/cocoa/extensions/extension_view_mac.h', 'browser/ui/cocoa/extensions/extension_view_mac.h',
'browser/ui/cocoa/extensions/extension_view_mac.mm', '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.h',
'browser/ui/cocoa/extensions/shell_window_cocoa.mm', 'browser/ui/cocoa/extensions/shell_window_cocoa.mm',
'browser/ui/cocoa/external_protocol_dialog.h', 'browser/ui/cocoa/external_protocol_dialog.h',
...@@ -5083,7 +5085,6 @@ ...@@ -5083,7 +5085,6 @@
'browser/importer/nss_decryptor_system_nss.h', 'browser/importer/nss_decryptor_system_nss.h',
'browser/jankometer.cc', 'browser/jankometer.cc',
'browser/lifetime/application_lifetime_stub.cc', 'browser/lifetime/application_lifetime_stub.cc',
'browser/media_gallery/media_galleries_dialog_controller.cc',
'browser/password_manager/encryptor_posix.cc', 'browser/password_manager/encryptor_posix.cc',
'browser/password_manager/login_database_posix.cc', 'browser/password_manager/login_database_posix.cc',
'browser/tab_contents/spellchecker_submenu_observer_hunspell.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