nfd_cocoa.m 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*
  2. Native File Dialog
  3. http://www.frogtoss.com/labs
  4. */
  5. #include <AppKit/AppKit.h>
  6. #include "nfd.h"
  7. #include "nfd_common.h"
  8. static NSArray *BuildAllowedFileTypes( const char *filterList )
  9. {
  10. // Commas and semicolons are the same thing on this platform
  11. NSMutableArray *buildFilterList = [[NSMutableArray alloc] init];
  12. char typebuf[NFD_MAX_STRLEN] = {0};
  13. size_t filterListLen = strlen(filterList);
  14. char *p_typebuf = typebuf;
  15. for ( size_t i = 0; i < filterListLen+1; ++i )
  16. {
  17. if ( filterList[i] == ',' || filterList[i] == ';' || filterList[i] == '\0' )
  18. {
  19. if (filterList[i] != '\0')
  20. ++p_typebuf;
  21. *p_typebuf = '\0';
  22. NSString *thisType = [NSString stringWithUTF8String: typebuf];
  23. [buildFilterList addObject:thisType];
  24. p_typebuf = typebuf;
  25. *p_typebuf = '\0';
  26. }
  27. else
  28. {
  29. *p_typebuf = filterList[i];
  30. ++p_typebuf;
  31. }
  32. }
  33. NSArray *returnArray = [NSArray arrayWithArray:buildFilterList];
  34. [buildFilterList release];
  35. return returnArray;
  36. }
  37. static void AddFilterListToDialog( NSSavePanel *dialog, const char *filterList )
  38. {
  39. if ( !filterList || strlen(filterList) == 0 )
  40. return;
  41. NSArray *allowedFileTypes = BuildAllowedFileTypes( filterList );
  42. if ( [allowedFileTypes count] != 0 )
  43. {
  44. [dialog setAllowedFileTypes:allowedFileTypes];
  45. }
  46. }
  47. static void SetDefaultPath( NSSavePanel *dialog, const nfdchar_t *defaultPath )
  48. {
  49. if ( !defaultPath || strlen(defaultPath) == 0 )
  50. return;
  51. NSString *defaultPathString = [NSString stringWithUTF8String: defaultPath];
  52. NSURL *url = [NSURL fileURLWithPath:defaultPathString isDirectory:YES];
  53. [dialog setDirectoryURL:url];
  54. }
  55. /* fixme: pathset should be pathSet */
  56. static nfdresult_t AllocPathSet( NSArray *urls, nfdpathset_t *pathset )
  57. {
  58. assert(pathset);
  59. assert([urls count]);
  60. pathset->count = (size_t)[urls count];
  61. pathset->indices = NFDi_Malloc( sizeof(size_t)*pathset->count );
  62. if ( !pathset->indices )
  63. {
  64. return NFD_ERROR;
  65. }
  66. // count the total space needed for buf
  67. size_t bufsize = 0;
  68. for ( NSURL *url in urls )
  69. {
  70. NSString *path = [url path];
  71. bufsize += [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1;
  72. }
  73. pathset->buf = NFDi_Malloc( sizeof(nfdchar_t) * bufsize );
  74. if ( !pathset->buf )
  75. {
  76. return NFD_ERROR;
  77. }
  78. // fill buf
  79. nfdchar_t *p_buf = pathset->buf;
  80. size_t count = 0;
  81. for ( NSURL *url in urls )
  82. {
  83. NSString *path = [url path];
  84. const nfdchar_t *utf8Path = [path UTF8String];
  85. size_t byteLen = [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1;
  86. memcpy( p_buf, utf8Path, byteLen );
  87. ptrdiff_t index = p_buf - pathset->buf;
  88. assert( index >= 0 );
  89. pathset->indices[count] = (size_t)index;
  90. p_buf += byteLen;
  91. ++count;
  92. }
  93. return NFD_OKAY;
  94. }
  95. /* public */
  96. nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList,
  97. const nfdchar_t *defaultPath,
  98. nfdchar_t **outPath )
  99. {
  100. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  101. NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
  102. NSOpenPanel *dialog = [NSOpenPanel openPanel];
  103. [dialog setAllowsMultipleSelection:NO];
  104. // Build the filter list
  105. AddFilterListToDialog(dialog, filterList);
  106. // Set the starting directory
  107. SetDefaultPath(dialog, defaultPath);
  108. nfdresult_t nfdResult = NFD_CANCEL;
  109. if ( [dialog runModal] == NSModalResponseOK )
  110. {
  111. NSURL *url = [dialog URL];
  112. const char *utf8Path = [[url path] UTF8String];
  113. // byte count, not char count
  114. size_t len = strlen(utf8Path);//NFDi_UTF8_Strlen(utf8Path);
  115. *outPath = NFDi_Malloc( len+1 );
  116. if ( !*outPath )
  117. {
  118. [pool release];
  119. [keyWindow makeKeyAndOrderFront:nil];
  120. return NFD_ERROR;
  121. }
  122. memcpy( *outPath, utf8Path, len+1 ); /* copy null term */
  123. nfdResult = NFD_OKAY;
  124. }
  125. [pool release];
  126. [keyWindow makeKeyAndOrderFront:nil];
  127. return nfdResult;
  128. }
  129. nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList,
  130. const nfdchar_t *defaultPath,
  131. nfdpathset_t *outPaths )
  132. {
  133. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  134. NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
  135. NSOpenPanel *dialog = [NSOpenPanel openPanel];
  136. [dialog setAllowsMultipleSelection:YES];
  137. // Build the fiter list.
  138. AddFilterListToDialog(dialog, filterList);
  139. // Set the starting directory
  140. SetDefaultPath(dialog, defaultPath);
  141. nfdresult_t nfdResult = NFD_CANCEL;
  142. if ( [dialog runModal] == NSModalResponseOK )
  143. {
  144. NSArray *urls = [dialog URLs];
  145. if ( [urls count] == 0 )
  146. {
  147. [pool release];
  148. [keyWindow makeKeyAndOrderFront:nil];
  149. return NFD_CANCEL;
  150. }
  151. if ( AllocPathSet( urls, outPaths ) == NFD_ERROR )
  152. {
  153. [pool release];
  154. [keyWindow makeKeyAndOrderFront:nil];
  155. return NFD_ERROR;
  156. }
  157. nfdResult = NFD_OKAY;
  158. }
  159. [pool release];
  160. [keyWindow makeKeyAndOrderFront:nil];
  161. return nfdResult;
  162. }
  163. nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
  164. const nfdchar_t *defaultPath,
  165. nfdchar_t **outPath )
  166. {
  167. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  168. NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
  169. NSSavePanel *dialog = [NSSavePanel savePanel];
  170. [dialog setExtensionHidden:NO];
  171. // Build the filter list.
  172. AddFilterListToDialog(dialog, filterList);
  173. // Set the starting directory
  174. SetDefaultPath(dialog, defaultPath);
  175. nfdresult_t nfdResult = NFD_CANCEL;
  176. if ( [dialog runModal] == NSModalResponseOK )
  177. {
  178. NSURL *url = [dialog URL];
  179. const char *utf8Path = [[url path] UTF8String];
  180. size_t byteLen = [url.path lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1;
  181. *outPath = NFDi_Malloc( byteLen );
  182. if ( !*outPath )
  183. {
  184. [pool release];
  185. [keyWindow makeKeyAndOrderFront:nil];
  186. return NFD_ERROR;
  187. }
  188. memcpy( *outPath, utf8Path, byteLen );
  189. nfdResult = NFD_OKAY;
  190. }
  191. [pool release];
  192. [keyWindow makeKeyAndOrderFront:nil];
  193. return nfdResult;
  194. }
  195. nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath,
  196. nfdchar_t **outPath)
  197. {
  198. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  199. NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
  200. NSOpenPanel *dialog = [NSOpenPanel openPanel];
  201. [dialog setAllowsMultipleSelection:NO];
  202. [dialog setCanChooseDirectories:YES];
  203. [dialog setCanCreateDirectories:YES];
  204. [dialog setCanChooseFiles:NO];
  205. // Set the starting directory
  206. SetDefaultPath(dialog, defaultPath);
  207. nfdresult_t nfdResult = NFD_CANCEL;
  208. if ( [dialog runModal] == NSModalResponseOK )
  209. {
  210. NSURL *url = [dialog URL];
  211. const char *utf8Path = [[url path] UTF8String];
  212. // byte count, not char count
  213. size_t len = strlen(utf8Path);//NFDi_UTF8_Strlen(utf8Path);
  214. *outPath = NFDi_Malloc( len+1 );
  215. if ( !*outPath )
  216. {
  217. [pool release];
  218. [keyWindow makeKeyAndOrderFront:nil];
  219. return NFD_ERROR;
  220. }
  221. memcpy( *outPath, utf8Path, len+1 ); /* copy null term */
  222. nfdResult = NFD_OKAY;
  223. }
  224. [pool release];
  225. [keyWindow makeKeyAndOrderFront:nil];
  226. return nfdResult;
  227. }