diff --git a/atom/browser/api/lib/dialog.coffee b/atom/browser/api/lib/dialog.coffee index b95ff4d96a30..9f51419dbde7 100644 --- a/atom/browser/api/lib/dialog.coffee +++ b/atom/browser/api/lib/dialog.coffee @@ -3,7 +3,10 @@ v8Util = process.atomBinding 'v8_util' BrowserWindow = require 'browser-window' fileDialogProperties = - openFile: 1, openDirectory: 2, multiSelections: 4, createDirectory: 8 + openFile: 1 << 0 + openDirectory: 1 << 1 + multiSelections: 1 << 2 + createDirectory: 1 << 3 messageBoxTypes = ['none', 'info', 'warning'] diff --git a/atom/browser/ui/file_dialog.h b/atom/browser/ui/file_dialog.h index 861ec14c06e8..70189c1f0580 100644 --- a/atom/browser/ui/file_dialog.h +++ b/atom/browser/ui/file_dialog.h @@ -23,10 +23,10 @@ typedef std::pair > Filter; typedef std::vector Filters; enum FileDialogProperty { - FILE_DIALOG_OPEN_FILE = 1, - FILE_DIALOG_OPEN_DIRECTORY = 2, - FILE_DIALOG_MULTI_SELECTIONS = 4, - FILE_DIALOG_CREATE_DIRECTORY = 8, + FILE_DIALOG_OPEN_FILE = 1 << 0, + FILE_DIALOG_OPEN_DIRECTORY = 1 << 1, + FILE_DIALOG_MULTI_SELECTIONS = 1 << 2, + FILE_DIALOG_CREATE_DIRECTORY = 1 << 3, }; typedef base::Callback 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 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 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;