Browse Source

mac: Implement the filters option.

Cheng Zhao 10 years ago
parent
commit
0721b34847

+ 4 - 1
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']
 

+ 4 - 4
atom/browser/ui/file_dialog.h

@@ -23,10 +23,10 @@ typedef std::pair<std::string, std::vector<std::string> > Filter;
 typedef std::vector<Filter> 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<void(

+ 39 - 6
atom/browser/ui/file_dialog_mac.mm

@@ -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;