Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

juce_FileChooser.h 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. //==============================================================================
  21. /**
  22. Creates a dialog box to choose a file or directory to load or save.
  23. To use a FileChooser:
  24. - create one (as a local stack variable is the neatest way)
  25. - call one of its browseFor.. methods
  26. - if this returns true, the user has selected a file, so you can retrieve it
  27. with the getResult() method.
  28. e.g. @code
  29. void loadMooseFile()
  30. {
  31. FileChooser myChooser ("Please select the moose you want to load...",
  32. File::getSpecialLocation (File::userHomeDirectory),
  33. "*.moose");
  34. if (myChooser.browseForFileToOpen())
  35. {
  36. File mooseFile (myChooser.getResult());
  37. loadMoose (mooseFile);
  38. }
  39. }
  40. @endcode
  41. @tags{GUI}
  42. */
  43. class JUCE_API FileChooser
  44. {
  45. public:
  46. //==============================================================================
  47. /** Creates a FileChooser.
  48. After creating one of these, use one of the browseFor... methods to display it.
  49. @param dialogBoxTitle a text string to display in the dialog box to
  50. tell the user what's going on
  51. @param initialFileOrDirectory the file or directory that should be selected
  52. when the dialog box opens. If this parameter is
  53. set to File(), a sensible default directory will
  54. be used instead. When using native dialogs, not
  55. all platforms will actually select the file. For
  56. example, on macOS, when initialFileOrDirectory is
  57. a file, only the parent directory of
  58. initialFileOrDirectory will be used as the initial
  59. directory of the native file chooser.
  60. Note: On iOS when saving a file, a user will not
  61. be able to change a file name, so it may be a good
  62. idea to include at least a valid file name in
  63. initialFileOrDirectory. When no filename is found,
  64. "Untitled" will be used.
  65. Also, if you pass an already existing file on iOS,
  66. that file will be automatically copied to the
  67. destination chosen by user and if it can be previewed,
  68. its preview will be presented in the dialog too. You
  69. will still be able to write into this file copy, since
  70. its URL will be returned by getURLResult(). This can be
  71. useful when you want to save e.g. an image, so that
  72. you can pass a (temporary) file with low quality
  73. preview and after the user picks the destination,
  74. you can write a high quality image into the copied
  75. file. If you create such a temporary file, you need
  76. to delete it yourself, once it is not needed anymore.
  77. @param filePatternsAllowed a set of file patterns to specify which files can be
  78. selected - each pattern should be separated by a comma or
  79. semi-colon, e.g. "*" or "*.jpg;*.gif". The native MacOS
  80. file browser only supports wildcard that specify
  81. extensions, so "*.jpg" is OK but "myfilename*" will not
  82. work. An empty string means that all files are allowed
  83. @param useOSNativeDialogBox if true, then a native dialog box will be used
  84. if possible; if false, then a Juce-based
  85. browser dialog box will always be used
  86. @param treatFilePackagesAsDirectories if true, then the file chooser will allow the
  87. selection of files inside packages when
  88. invoked on OS X and when using native dialog
  89. boxes.
  90. @param parentComponent An optional component which should be the parent
  91. for the file chooser. If this is a nullptr then the
  92. FileChooser will be a top-level window. AUv3s on iOS
  93. must specify this parameter as opening a top-level window
  94. in an AUv3 is forbidden due to sandbox restrictions.
  95. @see browseForFileToOpen, browseForFileToSave, browseForDirectory
  96. */
  97. FileChooser (const String& dialogBoxTitle,
  98. const File& initialFileOrDirectory = File(),
  99. const String& filePatternsAllowed = String(),
  100. bool useOSNativeDialogBox = true,
  101. bool treatFilePackagesAsDirectories = false,
  102. Component* parentComponent = nullptr);
  103. /** Destructor. */
  104. ~FileChooser();
  105. //==============================================================================
  106. /** Shows a dialog box to choose a file to open.
  107. This will display the dialog box modally, using an "open file" mode, so that
  108. it won't allow non-existent files or directories to be chosen.
  109. @param previewComponent an optional component to display inside the dialog
  110. box to show special info about the files that the user
  111. is browsing. The component will not be deleted by this
  112. object, so the caller must take care of it.
  113. @returns true if the user selected a file, in which case, use the getResult()
  114. method to find out what it was. Returns false if they cancelled instead.
  115. @see browseForFileToSave, browseForDirectory
  116. */
  117. bool browseForFileToOpen (FilePreviewComponent* previewComponent = nullptr);
  118. /** Same as browseForFileToOpen, but allows the user to select multiple files.
  119. The files that are returned can be obtained by calling getResults(). See
  120. browseForFileToOpen() for more info about the behaviour of this method.
  121. */
  122. bool browseForMultipleFilesToOpen (FilePreviewComponent* previewComponent = nullptr);
  123. /** Shows a dialog box to choose a file to save.
  124. This will display the dialog box modally, using an "save file" mode, so it
  125. will allow non-existent files to be chosen, but not directories.
  126. @param warnAboutOverwritingExistingFiles if true, the dialog box will ask
  127. the user if they're sure they want to overwrite a file that already
  128. exists
  129. @returns true if the user chose a file and pressed 'ok', in which case, use
  130. the getResult() method to find out what the file was. Returns false
  131. if they cancelled instead.
  132. @see browseForFileToOpen, browseForDirectory
  133. */
  134. bool browseForFileToSave (bool warnAboutOverwritingExistingFiles);
  135. /** Shows a dialog box to choose a directory.
  136. This will display the dialog box modally, using an "open directory" mode, so it
  137. will only allow directories to be returned, not files.
  138. @returns true if the user chose a directory and pressed 'ok', in which case, use
  139. the getResult() method to find out what they chose. Returns false
  140. if they cancelled instead.
  141. @see browseForFileToOpen, browseForFileToSave
  142. */
  143. bool browseForDirectory();
  144. /** Same as browseForFileToOpen, but allows the user to select multiple files and directories.
  145. The files that are returned can be obtained by calling getResults(). See
  146. browseForFileToOpen() for more info about the behaviour of this method.
  147. */
  148. bool browseForMultipleFilesOrDirectories (FilePreviewComponent* previewComponent = nullptr);
  149. //==============================================================================
  150. /** Runs a dialog box for the given set of option flags.
  151. The flag values used are those in FileBrowserComponent::FileChooserFlags.
  152. @returns true if the user chose a directory and pressed 'ok', in which case, use
  153. the getResult() method to find out what they chose. Returns false
  154. if they cancelled instead.
  155. @see FileBrowserComponent::FileChooserFlags
  156. */
  157. bool showDialog (int flags, FilePreviewComponent* previewComponent);
  158. /** Use this method to launch the file browser window asynchronously.
  159. This will create a file browser dialog based on the settings in this
  160. structure and will launch it modally, returning immediately.
  161. You must specify a callback which is called when the file browser is
  162. canceled or a file is selected. To abort the file selection, simply
  163. delete the FileChooser object.
  164. You can use the ModalCallbackFunction::create method to wrap a lambda
  165. into a modal Callback object.
  166. You must ensure that the lifetime of the callback object is longer than
  167. the lifetime of the file-chooser.
  168. */
  169. void launchAsync (int flags,
  170. std::function<void (const FileChooser&)>,
  171. FilePreviewComponent* previewComponent = nullptr);
  172. //==============================================================================
  173. /** Returns the last file that was chosen by one of the browseFor methods.
  174. After calling the appropriate browseFor... method, this method lets you
  175. find out what file or directory they chose.
  176. Note that the file returned is only valid if the browse method returned true (i.e.
  177. if the user pressed 'ok' rather than cancelling).
  178. On mobile platforms, the file browser may return a URL instead of a local file.
  179. Therefore, on mobile platforms, you should call getURLResult() instead.
  180. If you're using a multiple-file select, then use the getResults() method instead,
  181. to obtain the list of all files chosen.
  182. @see getURLResult, getResults
  183. */
  184. File getResult() const;
  185. /** Returns a list of all the files that were chosen during the last call to a
  186. browse method.
  187. On mobile platforms, the file browser may return a URL instead of a local file.
  188. Therefore, on mobile platforms, you should call getURLResults() instead.
  189. This array may be empty if no files were chosen, or can contain multiple entries
  190. if multiple files were chosen.
  191. @see getURLResults, getResult
  192. */
  193. Array<File> getResults() const noexcept;
  194. //==============================================================================
  195. /** Returns the last document that was chosen by one of the browseFor methods.
  196. Use this method if you are using the FileChooser on a mobile platform which
  197. may return a URL to a remote document. If a local file is chosen then you can
  198. convert this file to a JUCE File class via the URL::getLocalFile method.
  199. Note: On iOS you must use the returned URL object directly (you are also
  200. allowed to copy- or move-construct another URL from the returned URL), rather
  201. than just storing the path as a String and then creating a new URL from that
  202. String. This is because the returned URL contains internally a security
  203. bookmark that is required to access the files pointed by it. Then, once you stop
  204. dealing with the file pointed by the URL, you should dispose that URL object,
  205. so that the security bookmark can be released by the system (only a limited
  206. number of such URLs is allowed).
  207. @see getResult, URL::getLocalFile
  208. */
  209. URL getURLResult() const;
  210. /** Returns a list of all the files that were chosen during the last call to a
  211. browse method.
  212. Use this method if you are using the FileChooser on a mobile platform which
  213. may return a URL to a remote document. If a local file is chosen then you can
  214. convert this file to a JUCE File class via the URL::getLocalFile method.
  215. This array may be empty if no files were chosen, or can contain multiple entries
  216. if multiple files were chosen.
  217. Note: On iOS you must use the returned URL object directly (you are also
  218. allowed to copy- or move-construct another URL from the returned URL), rather
  219. than just storing the path as a String and then creating a new URL from that
  220. String. This is because the returned URL contains internally a security
  221. bookmark that is required to access the files pointed by it. Then, once you stop
  222. dealing with the file pointed by the URL, you should dispose that URL object,
  223. so that the security bookmark can be released by the system (only a limited
  224. number of such URLs is allowed).
  225. @see getResults, URL::getLocalFile
  226. */
  227. const Array<URL>& getURLResults() const noexcept { return results; }
  228. //==============================================================================
  229. /** Returns if a native filechooser is currently available on this platform.
  230. Note: On iOS this will only return true if you have iCloud permissions
  231. and code-signing enabled in the Projucer and have added iCloud containers
  232. to your app in Apple's online developer portal. Additionally, the user must
  233. have installed the iCloud app on their device and used the app at least once.
  234. */
  235. static bool isPlatformDialogAvailable();
  236. //==============================================================================
  237. #ifndef DOXYGEN
  238. class Native;
  239. #endif
  240. private:
  241. //==============================================================================
  242. String title, filters;
  243. File startingFile;
  244. Component* parent;
  245. Array<URL> results;
  246. const bool useNativeDialogBox;
  247. const bool treatFilePackagesAsDirs;
  248. std::function<void (const FileChooser&)> asyncCallback;
  249. //==============================================================================
  250. void finished (const Array<URL>&);
  251. //==============================================================================
  252. struct Pimpl
  253. {
  254. virtual ~Pimpl() = default;
  255. virtual void launch() = 0;
  256. virtual void runModally() = 0;
  257. };
  258. std::unique_ptr<Pimpl> pimpl;
  259. //==============================================================================
  260. Pimpl* createPimpl (int, FilePreviewComponent*);
  261. static Pimpl* showPlatformDialog (FileChooser&, int,
  262. FilePreviewComponent*);
  263. class NonNative;
  264. friend class NonNative;
  265. friend class Native;
  266. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileChooser)
  267. };
  268. } // namespace juce