|
@@ -9,15 +9,45 @@
|
|
|
|
|
|
#include "atom/browser/native_window.h"
|
|
|
#include "base/file_util.h"
|
|
|
+#include "base/mac/mac_util.h"
|
|
|
+#include "base/mac/scoped_cftyperef.h"
|
|
|
#include "base/strings/sys_string_conversions.h"
|
|
|
|
|
|
namespace file_dialog {
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
+CFStringRef CreateUTIFromExtension(const std::string& ext) {
|
|
|
+ base::ScopedCFTypeRef<CFStringRef> ext_cf(base::SysUTF8ToCFStringRef(ext));
|
|
|
+ return UTTypeCreatePreferredIdentifierForTag(
|
|
|
+ kUTTagClassFilenameExtension, ext_cf.get(), NULL);
|
|
|
+}
|
|
|
+
|
|
|
+void SetAllowedFileTypes(NSSavePanel* dialog, const Filters& filters) {
|
|
|
+ NSMutableSet* file_type_set = [NSMutableSet set];
|
|
|
+ for (size_t i = 0; i < filters.size(); ++i) {
|
|
|
+ const Filter& filter = filters[i];
|
|
|
+ for (size_t j = 0; j < filter.second.size(); ++j) {
|
|
|
+ base::ScopedCFTypeRef<CFStringRef> uti(
|
|
|
+ CreateUTIFromExtension(filter.second[j]));
|
|
|
+ [file_type_set addObject:base::mac::CFToNSCast(uti.get())];
|
|
|
+
|
|
|
+ // Always allow the extension itself, in case the UTI doesn't map
|
|
|
+ // back to the original extension correctly. This occurs with dynamic
|
|
|
+ // UTIs on 10.7 and 10.8.
|
|
|
+ // See http://crbug.com/148840, http://openradar.me/12316273
|
|
|
+ base::ScopedCFTypeRef<CFStringRef> ext_cf(
|
|
|
+ base::SysUTF8ToCFStringRef(filter.second[j]));
|
|
|
+ [file_type_set addObject:base::mac::CFToNSCast(ext_cf.get())];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ [dialog setAllowedFileTypes:[file_type_set allObjects]];
|
|
|
+}
|
|
|
+
|
|
|
void SetupDialog(NSSavePanel* dialog,
|
|
|
const std::string& title,
|
|
|
- const base::FilePath& default_path) {
|
|
|
+ const base::FilePath& default_path,
|
|
|
+ const Filters& filters) {
|
|
|
if (!title.empty())
|
|
|
[dialog setTitle:base::SysUTF8ToNSString(title)];
|
|
|
|
|
@@ -39,7 +69,10 @@ void SetupDialog(NSSavePanel* dialog,
|
|
|
[dialog setNameFieldStringValue:default_filename];
|
|
|
|
|
|
[dialog setCanSelectHiddenExtension:YES];
|
|
|
- [dialog setAllowsOtherFileTypes:YES];
|
|
|
+ if (filters.empty())
|
|
|
+ [dialog setAllowsOtherFileTypes:YES];
|
|
|
+ else
|
|
|
+ SetAllowedFileTypes(dialog, filters);
|
|
|
}
|
|
|
|
|
|
void SetupDialogForProperties(NSOpenPanel* dialog, int properties) {
|
|
@@ -89,7 +122,7 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
|
|
DCHECK(paths);
|
|
|
NSOpenPanel* dialog = [NSOpenPanel openPanel];
|
|
|
|
|
|
- SetupDialog(dialog, title, default_path);
|
|
|
+ SetupDialog(dialog, title, default_path, filters);
|
|
|
SetupDialogForProperties(dialog, properties);
|
|
|
|
|
|
int chosen = RunModalDialog(dialog, parent_window);
|
|
@@ -108,7 +141,7 @@ void ShowOpenDialog(atom::NativeWindow* parent_window,
|
|
|
const OpenDialogCallback& c) {
|
|
|
NSOpenPanel* dialog = [NSOpenPanel openPanel];
|
|
|
|
|
|
- SetupDialog(dialog, title, default_path);
|
|
|
+ SetupDialog(dialog, title, default_path, filters);
|
|
|
SetupDialogForProperties(dialog, properties);
|
|
|
|
|
|
// Duplicate the callback object here since c is a reference and gcd would
|
|
@@ -136,7 +169,7 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
|
|
DCHECK(path);
|
|
|
NSSavePanel* dialog = [NSSavePanel savePanel];
|
|
|
|
|
|
- SetupDialog(dialog, title, default_path);
|
|
|
+ SetupDialog(dialog, title, default_path, filters);
|
|
|
|
|
|
int chosen = RunModalDialog(dialog, parent_window);
|
|
|
if (chosen == NSFileHandlingPanelCancelButton || ![[dialog URL] isFileURL])
|
|
@@ -153,7 +186,7 @@ void ShowSaveDialog(atom::NativeWindow* parent_window,
|
|
|
const SaveDialogCallback& c) {
|
|
|
NSSavePanel* dialog = [NSSavePanel savePanel];
|
|
|
|
|
|
- SetupDialog(dialog, title, default_path);
|
|
|
+ SetupDialog(dialog, title, default_path, filters);
|
|
|
|
|
|
__block SaveDialogCallback callback = c;
|
|
|
|