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.cpp 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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. class FileChooser::NonNative : public FileChooser::Pimpl
  22. {
  23. public:
  24. NonNative (FileChooser& fileChooser, int flags, FilePreviewComponent* preview)
  25. : owner (fileChooser),
  26. selectsDirectories ((flags & FileBrowserComponent::canSelectDirectories) != 0),
  27. selectsFiles ((flags & FileBrowserComponent::canSelectFiles) != 0),
  28. warnAboutOverwrite ((flags & FileBrowserComponent::warnAboutOverwriting) != 0),
  29. filter (selectsFiles ? owner.filters : String(), selectsDirectories ? "*" : String(), {}),
  30. browserComponent (flags, owner.startingFile, &filter, preview),
  31. dialogBox (owner.title, {}, browserComponent, warnAboutOverwrite,
  32. browserComponent.findColour (AlertWindow::backgroundColourId), owner.parent)
  33. {}
  34. ~NonNative() override
  35. {
  36. dialogBox.exitModalState (0);
  37. }
  38. void launch() override
  39. {
  40. dialogBox.centreWithDefaultSize (nullptr);
  41. dialogBox.enterModalState (true, ModalCallbackFunction::create ([this] (int r) { modalStateFinished (r); }), true);
  42. }
  43. void runModally() override
  44. {
  45. #if JUCE_MODAL_LOOPS_PERMITTED
  46. modalStateFinished (dialogBox.show() ? 1 : 0);
  47. #else
  48. jassertfalse;
  49. #endif
  50. }
  51. private:
  52. void modalStateFinished (int returnValue)
  53. {
  54. Array<URL> result;
  55. if (returnValue != 0)
  56. {
  57. for (int i = 0; i < browserComponent.getNumSelectedFiles(); ++i)
  58. result.add (URL (browserComponent.getSelectedFile (i)));
  59. }
  60. owner.finished (result);
  61. }
  62. //==============================================================================
  63. FileChooser& owner;
  64. bool selectsDirectories, selectsFiles, warnAboutOverwrite;
  65. WildcardFileFilter filter;
  66. FileBrowserComponent browserComponent;
  67. FileChooserDialogBox dialogBox;
  68. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NonNative)
  69. };
  70. //==============================================================================
  71. FileChooser::FileChooser (const String& chooserBoxTitle,
  72. const File& currentFileOrDirectory,
  73. const String& fileFilters,
  74. const bool useNativeBox,
  75. const bool treatFilePackagesAsDirectories,
  76. Component* parentComponentToUse)
  77. : title (chooserBoxTitle),
  78. filters (fileFilters),
  79. startingFile (currentFileOrDirectory),
  80. parent (parentComponentToUse),
  81. useNativeDialogBox (useNativeBox && isPlatformDialogAvailable()),
  82. treatFilePackagesAsDirs (treatFilePackagesAsDirectories)
  83. {
  84. #ifndef JUCE_MAC
  85. ignoreUnused (treatFilePackagesAsDirs);
  86. #endif
  87. if (! fileFilters.containsNonWhitespaceChars())
  88. filters = "*";
  89. }
  90. FileChooser::~FileChooser()
  91. {
  92. asyncCallback = nullptr;
  93. }
  94. #if JUCE_MODAL_LOOPS_PERMITTED
  95. bool FileChooser::browseForFileToOpen (FilePreviewComponent* previewComp)
  96. {
  97. return showDialog (FileBrowserComponent::openMode
  98. | FileBrowserComponent::canSelectFiles,
  99. previewComp);
  100. }
  101. bool FileChooser::browseForMultipleFilesToOpen (FilePreviewComponent* previewComp)
  102. {
  103. return showDialog (FileBrowserComponent::openMode
  104. | FileBrowserComponent::canSelectFiles
  105. | FileBrowserComponent::canSelectMultipleItems,
  106. previewComp);
  107. }
  108. bool FileChooser::browseForMultipleFilesOrDirectories (FilePreviewComponent* previewComp)
  109. {
  110. return showDialog (FileBrowserComponent::openMode
  111. | FileBrowserComponent::canSelectFiles
  112. | FileBrowserComponent::canSelectDirectories
  113. | FileBrowserComponent::canSelectMultipleItems,
  114. previewComp);
  115. }
  116. bool FileChooser::browseForFileToSave (const bool warnAboutOverwrite)
  117. {
  118. return showDialog (FileBrowserComponent::saveMode
  119. | FileBrowserComponent::canSelectFiles
  120. | (warnAboutOverwrite ? FileBrowserComponent::warnAboutOverwriting : 0),
  121. nullptr);
  122. }
  123. bool FileChooser::browseForDirectory()
  124. {
  125. return showDialog (FileBrowserComponent::openMode
  126. | FileBrowserComponent::canSelectDirectories,
  127. nullptr);
  128. }
  129. bool FileChooser::showDialog (const int flags, FilePreviewComponent* const previewComp)
  130. {
  131. FocusRestorer focusRestorer;
  132. pimpl.reset (createPimpl (flags, previewComp));
  133. pimpl->runModally();
  134. // ensure that the finished function was invoked
  135. jassert (pimpl == nullptr);
  136. return (results.size() > 0);
  137. }
  138. #endif
  139. void FileChooser::launchAsync (int flags, std::function<void (const FileChooser&)> callback,
  140. FilePreviewComponent* previewComp)
  141. {
  142. // You must specify a callback when using launchAsync
  143. jassert (callback);
  144. // you cannot run two file chooser dialog boxes at the same time
  145. jassert (asyncCallback == nullptr);
  146. asyncCallback = std::move (callback);
  147. pimpl.reset (createPimpl (flags, previewComp));
  148. pimpl->launch();
  149. }
  150. FileChooser::Pimpl* FileChooser::createPimpl (int flags, FilePreviewComponent* previewComp)
  151. {
  152. results.clear();
  153. // the preview component needs to be the right size before you pass it in here..
  154. jassert (previewComp == nullptr || (previewComp->getWidth() > 10
  155. && previewComp->getHeight() > 10));
  156. if (pimpl != nullptr)
  157. {
  158. // you cannot run two file chooser dialog boxes at the same time
  159. jassertfalse;
  160. pimpl.reset();
  161. }
  162. // You've set the flags for both saveMode and openMode!
  163. jassert (! (((flags & FileBrowserComponent::saveMode) != 0)
  164. && ((flags & FileBrowserComponent::openMode) != 0)));
  165. #if JUCE_WINDOWS
  166. const bool selectsFiles = (flags & FileBrowserComponent::canSelectFiles) != 0;
  167. const bool selectsDirectories = (flags & FileBrowserComponent::canSelectDirectories) != 0;
  168. if (useNativeDialogBox && ! (selectsFiles && selectsDirectories))
  169. #else
  170. if (useNativeDialogBox)
  171. #endif
  172. {
  173. return showPlatformDialog (*this, flags, previewComp);
  174. }
  175. else
  176. {
  177. return new NonNative (*this, flags, previewComp);
  178. }
  179. }
  180. Array<File> FileChooser::getResults() const noexcept
  181. {
  182. Array<File> files;
  183. for (auto url : getURLResults())
  184. if (url.isLocalFile())
  185. files.add (url.getLocalFile());
  186. return files;
  187. }
  188. File FileChooser::getResult() const
  189. {
  190. auto fileResults = getResults();
  191. // if you've used a multiple-file select, you should use the getResults() method
  192. // to retrieve all the files that were chosen.
  193. jassert (fileResults.size() <= 1);
  194. return fileResults.getFirst();
  195. }
  196. URL FileChooser::getURLResult() const
  197. {
  198. // if you've used a multiple-file select, you should use the getResults() method
  199. // to retrieve all the files that were chosen.
  200. jassert (results.size() <= 1);
  201. return results.getFirst();
  202. }
  203. void FileChooser::finished (const Array<URL>& asyncResults)
  204. {
  205. std::function<void (const FileChooser&)> callback;
  206. std::swap (callback, asyncCallback);
  207. results = asyncResults;
  208. pimpl.reset();
  209. if (callback)
  210. callback (*this);
  211. }
  212. //==============================================================================
  213. FilePreviewComponent::FilePreviewComponent() {}
  214. FilePreviewComponent::~FilePreviewComponent() {}
  215. } // namespace juce