The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

273 lines
8.6KB

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