GuiFileSelect.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /* GuiFileSelect.cpp
  2. *
  3. * Copyright (C) 2010-2012,2013,2014,2015,2016,2017 Paul Boersma, 2013 Tom Naughton
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. * See the GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "GuiP.h"
  19. #include <locale.h>
  20. #if motif
  21. #include <Shlobj.h>
  22. #endif
  23. autoStringSet GuiFileSelect_getInfileNames (GuiWindow parent, conststring32 title, bool allowMultipleFiles) {
  24. structMelderDir saveDir { };
  25. Melder_getDefaultDir (& saveDir);
  26. autoStringSet me = StringSet_create ();
  27. #if gtk
  28. (void) parent;
  29. static structMelderDir dir { };
  30. GuiObject dialog = gtk_file_chooser_dialog_new (Melder_peek32to8 (title), nullptr, GTK_FILE_CHOOSER_ACTION_OPEN,
  31. GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, nullptr);
  32. gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), allowMultipleFiles);
  33. if (MelderDir_isNull (& dir)) // first time?
  34. Melder_getDefaultDir (& dir);
  35. gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), Melder_peek32to8 (Melder_dirToPath (& dir)));
  36. if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
  37. char *infolderName_utf8 = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
  38. if (infolderName_utf8) {
  39. conststring32 infolderName = Melder_peek8to32 (infolderName_utf8); // dangle
  40. Melder_pathToDir (infolderName, & dir);
  41. g_free (infolderName_utf8);
  42. }
  43. GSList *infileNames_list = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (dialog));
  44. for (GSList *element = infileNames_list; element != nullptr; element = g_slist_next (element)) {
  45. char *infileName_utf8 = (char *) element -> data;
  46. my addString_copy (Melder_peek8to32 (infileName_utf8));
  47. g_free (infileName_utf8);
  48. }
  49. g_slist_free (infileNames_list);
  50. }
  51. gtk_widget_destroy (GTK_WIDGET (dialog));
  52. setlocale (LC_ALL, "C");
  53. #elif motif
  54. static OPENFILENAMEW openFileName, dummy;
  55. static WCHAR fullFileNameW [3000+2];
  56. ZeroMemory (& openFileName, sizeof (OPENFILENAMEW));
  57. openFileName. lStructSize = sizeof (OPENFILENAMEW);
  58. openFileName. hwndOwner = parent && parent -> d_xmShell ? (HWND) XtWindow (parent -> d_xmShell) : nullptr;
  59. openFileName. hInstance = nullptr;
  60. openFileName. lpstrFilter = L"All Files\0*.*\0";
  61. ZeroMemory (fullFileNameW, (3000+2) * sizeof (WCHAR));
  62. openFileName. lpstrCustomFilter = nullptr;
  63. openFileName. nMaxCustFilter = 0;
  64. openFileName. lpstrFile = fullFileNameW;
  65. openFileName. nMaxFile = 3000;
  66. openFileName. lpstrFileTitle = nullptr;
  67. openFileName. nMaxFileTitle = 0;
  68. openFileName. lpstrInitialDir = nullptr;
  69. openFileName. lpstrTitle = Melder_peek32toW (title);
  70. openFileName. Flags = OFN_EXPLORER | OFN_LONGNAMES | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY
  71. | (allowMultipleFiles ? OFN_ALLOWMULTISELECT : 0);
  72. openFileName. lpstrDefExt = nullptr;
  73. openFileName. lpfnHook = nullptr;
  74. openFileName. lpTemplateName = nullptr;
  75. openFileName. pvReserved = nullptr;
  76. openFileName. dwReserved = 0;
  77. openFileName. FlagsEx = 0;
  78. OSVERSIONINFO osVersionInfo;
  79. ZeroMemory (& osVersionInfo, sizeof (OSVERSIONINFO));
  80. osVersionInfo. dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
  81. GetVersionEx (& osVersionInfo);
  82. if (GetOpenFileNameW (& openFileName)) {
  83. int firstFileNameLength = wcslen (fullFileNameW);
  84. if (fullFileNameW [firstFileNameLength + 1] == L'\0') {
  85. /*
  86. * The user selected one file.
  87. */
  88. my addString_copy (Melder_peekWto32 (fullFileNameW));
  89. } else {
  90. /*
  91. * The user selected multiple files.
  92. * 'fullFileNameW' is a directory name; the file names follow.
  93. */
  94. structMelderDir dir { };
  95. Melder_pathToDir (Melder_peekWto32 (fullFileNameW), & dir);
  96. for (const WCHAR *p = & fullFileNameW [firstFileNameLength + 1]; *p != L'\0'; p += wcslen (p) + 1) {
  97. structMelderFile file { };
  98. MelderDir_getFile (& dir, Melder_peekWto32 (p), & file);
  99. my addString_copy (Melder_fileToPath (& file));
  100. }
  101. }
  102. }
  103. setlocale (LC_ALL, "C");
  104. #elif cocoa
  105. (void) parent;
  106. NSOpenPanel *openPanel = [NSOpenPanel openPanel];
  107. [openPanel setTitle: [NSString stringWithUTF8String: Melder_peek32to8 (title)]];
  108. [openPanel setAllowsMultipleSelection: allowMultipleFiles];
  109. [openPanel setCanChooseDirectories: NO];
  110. if ([openPanel runModal] == NSFileHandlingPanelOKButton) {
  111. for (NSURL *url in [openPanel URLs]) {
  112. structMelderFile file { };
  113. Melder_8bitFileRepresentationToStr32_inplace ([[url path] UTF8String], file. path); // BUG: unsafe buffer
  114. my addString_copy (file. path);
  115. }
  116. }
  117. setlocale (LC_ALL, "en_US");
  118. #endif
  119. Melder_setDefaultDir (& saveDir);
  120. return me;
  121. }
  122. autostring32 GuiFileSelect_getOutfileName (GuiWindow parent, conststring32 title, conststring32 defaultName) {
  123. structMelderDir saveDir { };
  124. Melder_getDefaultDir (& saveDir);
  125. autostring32 outfileName;
  126. #if gtk
  127. (void) parent;
  128. static structMelderFile file;
  129. GuiObject dialog = gtk_file_chooser_dialog_new (Melder_peek32to8 (title), nullptr, GTK_FILE_CHOOSER_ACTION_SAVE,
  130. GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, nullptr);
  131. gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), true);
  132. if (file. path [0] != U'\0') {
  133. gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog), Melder_peek32to8 (file. path));
  134. }
  135. gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), Melder_peek32to8 (defaultName));
  136. if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
  137. char *outfileName_utf8 = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
  138. outfileName = Melder_8to32 (outfileName_utf8);
  139. g_free (outfileName_utf8);
  140. Melder_pathToFile (outfileName.get(), & file);
  141. }
  142. gtk_widget_destroy (GTK_WIDGET (dialog));
  143. setlocale (LC_ALL, "C");
  144. #elif motif
  145. OPENFILENAMEW openFileName;
  146. static WCHAR customFilter [100+2];
  147. static WCHAR fullFileNameW [300+2];
  148. wcsncpy (fullFileNameW, Melder_peek32toW (defaultName), 300+2);
  149. fullFileNameW [300+1] = L'\0';
  150. openFileName. lStructSize = sizeof (OPENFILENAMEW);
  151. openFileName. hwndOwner = parent && parent -> d_xmShell ? (HWND) XtWindow (parent -> d_xmShell) : nullptr;
  152. openFileName. lpstrFilter = nullptr; // like *.txt
  153. openFileName. lpstrCustomFilter = customFilter;
  154. openFileName. nMaxCustFilter = 100;
  155. openFileName. lpstrFile = fullFileNameW;
  156. openFileName. nMaxFile = 300;
  157. openFileName. lpstrFileTitle = nullptr;
  158. openFileName. lpstrInitialDir = nullptr;
  159. openFileName. lpstrTitle = Melder_peek32toW (title);
  160. openFileName. Flags = OFN_LONGNAMES | OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_HIDEREADONLY;
  161. openFileName. lpstrDefExt = nullptr;
  162. if (GetSaveFileNameW (& openFileName))
  163. outfileName = Melder_Wto32 (fullFileNameW);
  164. setlocale (LC_ALL, "C");
  165. #elif cocoa
  166. (void) parent;
  167. NSSavePanel *savePanel = [NSSavePanel savePanel];
  168. [savePanel setTitle: [NSString stringWithUTF8String: Melder_peek32to8 (title)]];
  169. [savePanel setNameFieldStringValue: [NSString stringWithUTF8String: Melder_peek32to8 (defaultName)]];
  170. if ([savePanel runModal] == NSFileHandlingPanelOKButton) {
  171. NSString *path = [[savePanel URL] path];
  172. if (path == nil)
  173. Melder_throw (U"Don't understand where you want to save (1).");
  174. const char *outfileName_utf8 = [path UTF8String];
  175. if (! outfileName_utf8)
  176. Melder_throw (U"Don't understand where you want to save (2).");
  177. structMelderFile file { };
  178. Melder_8bitFileRepresentationToStr32_inplace (outfileName_utf8, file. path); // BUG: unsafe buffer
  179. outfileName = Melder_dup (file. path);
  180. }
  181. setlocale (LC_ALL, "en_US");
  182. #endif
  183. Melder_setDefaultDir (& saveDir);
  184. return outfileName;
  185. }
  186. autostring32 GuiFileSelect_getDirectoryName (GuiWindow parent, conststring32 title) {
  187. structMelderDir saveDir { };
  188. Melder_getDefaultDir (& saveDir);
  189. autostring32 directoryName;
  190. #if gtk
  191. (void) parent;
  192. static structMelderFile file;
  193. GuiObject dialog = gtk_file_chooser_dialog_new (Melder_peek32to8 (title), nullptr, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
  194. GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, "Choose", GTK_RESPONSE_ACCEPT, nullptr);
  195. if (file. path [0] != U'\0') {
  196. gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog), Melder_peek32to8 (file. path));
  197. }
  198. if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
  199. char *directoryName_utf8 = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
  200. directoryName = Melder_8to32 (directoryName_utf8);
  201. g_free (directoryName_utf8);
  202. Melder_pathToFile (directoryName.get(), & file);
  203. }
  204. gtk_widget_destroy (GTK_WIDGET (dialog));
  205. setlocale (LC_ALL, "C");
  206. #elif motif
  207. static WCHAR fullFileNameW [3000+2];
  208. static bool comInited = false;
  209. if (! comInited) {
  210. CoInitializeEx (nullptr, COINIT_APARTMENTTHREADED);
  211. comInited = true;
  212. }
  213. static BROWSEINFO info;
  214. info. hwndOwner = parent && parent -> d_xmShell ? (HWND) XtWindow (parent -> d_xmShell) : nullptr;
  215. info. ulFlags = BIF_USENEWUI;
  216. info. pidlRoot = nullptr; // everything on the computer should be browsable
  217. info. pszDisplayName = nullptr; // this would only give the bare directory name, not the full path
  218. info. lpszTitle = Melder_peek32toW (title);
  219. LPITEMIDLIST idList = SHBrowseForFolder (& info);
  220. SHGetPathFromIDList (idList, fullFileNameW);
  221. CoTaskMemFree (idList);
  222. directoryName = Melder_Wto32 (fullFileNameW);
  223. setlocale (LC_ALL, "C");
  224. #elif cocoa
  225. (void) parent;
  226. NSOpenPanel *openPanel = [NSOpenPanel openPanel];
  227. [openPanel setTitle: [NSString stringWithUTF8String: Melder_peek32to8 (title)]];
  228. [openPanel setAllowsMultipleSelection: NO];
  229. [openPanel setCanChooseDirectories: YES];
  230. [openPanel setCanChooseFiles: NO];
  231. [openPanel setPrompt: @"Choose"];
  232. if ([openPanel runModal] == NSFileHandlingPanelOKButton) {
  233. for (NSURL *url in [openPanel URLs]) {
  234. const char *directoryName_utf8 = [[url path] UTF8String];
  235. structMelderDir dir { };
  236. Melder_8bitFileRepresentationToStr32_inplace (directoryName_utf8, dir. path); // BUG: unsafe buffer
  237. directoryName = Melder_dup (dir. path);
  238. }
  239. }
  240. setlocale (LC_ALL, "en_US");
  241. #endif
  242. Melder_setDefaultDir (& saveDir);
  243. return directoryName;
  244. }
  245. /* End of file GuiFileSelect.cpp */