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.

271 lines
8.6KB

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