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.

278 lines
8.9KB

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