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.

270 lines
8.5KB

  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, browserComponent.findColour (AlertWindow::backgroundColourId))
  33. {}
  34. ~NonNative()
  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. : title (chooserBoxTitle),
  77. filters (fileFilters),
  78. startingFile (currentFileOrDirectory),
  79. useNativeDialogBox (useNativeBox && isPlatformDialogAvailable()),
  80. treatFilePackagesAsDirs (treatFilePackagesAsDirectories)
  81. {
  82. #ifndef JUCE_MAC
  83. ignoreUnused (treatFilePackagesAsDirs);
  84. #endif
  85. if (! fileFilters.containsNonWhitespaceChars())
  86. filters = "*";
  87. }
  88. FileChooser::~FileChooser()
  89. {
  90. asyncCallback = nullptr;
  91. }
  92. #if JUCE_MODAL_LOOPS_PERMITTED
  93. bool FileChooser::browseForFileToOpen (FilePreviewComponent* previewComp)
  94. {
  95. return showDialog (FileBrowserComponent::openMode
  96. | FileBrowserComponent::canSelectFiles,
  97. previewComp);
  98. }
  99. bool FileChooser::browseForMultipleFilesToOpen (FilePreviewComponent* previewComp)
  100. {
  101. return showDialog (FileBrowserComponent::openMode
  102. | FileBrowserComponent::canSelectFiles
  103. | FileBrowserComponent::canSelectMultipleItems,
  104. previewComp);
  105. }
  106. bool FileChooser::browseForMultipleFilesOrDirectories (FilePreviewComponent* previewComp)
  107. {
  108. return showDialog (FileBrowserComponent::openMode
  109. | FileBrowserComponent::canSelectFiles
  110. | FileBrowserComponent::canSelectDirectories
  111. | FileBrowserComponent::canSelectMultipleItems,
  112. previewComp);
  113. }
  114. bool FileChooser::browseForFileToSave (const bool warnAboutOverwrite)
  115. {
  116. return showDialog (FileBrowserComponent::saveMode
  117. | FileBrowserComponent::canSelectFiles
  118. | (warnAboutOverwrite ? FileBrowserComponent::warnAboutOverwriting : 0),
  119. nullptr);
  120. }
  121. bool FileChooser::browseForDirectory()
  122. {
  123. return showDialog (FileBrowserComponent::openMode
  124. | FileBrowserComponent::canSelectDirectories,
  125. nullptr);
  126. }
  127. bool FileChooser::showDialog (const int flags, FilePreviewComponent* const previewComp)
  128. {
  129. FocusRestorer focusRestorer;
  130. pimpl.reset (createPimpl (flags, previewComp));
  131. pimpl->runModally();
  132. // ensure that the finished function was invoked
  133. jassert (pimpl == nullptr);
  134. return (results.size() > 0);
  135. }
  136. #endif
  137. void FileChooser::launchAsync (int flags, std::function<void (const FileChooser&)> callback,
  138. FilePreviewComponent* previewComp)
  139. {
  140. // You must specify a callback when using launchAsync
  141. jassert (callback);
  142. // you cannot run two file chooser dialog boxes at the same time
  143. jassert (asyncCallback == nullptr);
  144. asyncCallback = static_cast<std::function<void (const FileChooser&)>&&> (callback);
  145. pimpl.reset (createPimpl (flags, previewComp));
  146. pimpl->launch();
  147. }
  148. FileChooser::Pimpl* FileChooser::createPimpl (int flags, FilePreviewComponent* previewComp)
  149. {
  150. results.clear();
  151. // the preview component needs to be the right size before you pass it in here..
  152. jassert (previewComp == nullptr || (previewComp->getWidth() > 10
  153. && previewComp->getHeight() > 10));
  154. if (pimpl != nullptr)
  155. {
  156. // you cannot run two file chooser dialog boxes at the same time
  157. jassertfalse;
  158. pimpl.reset();
  159. }
  160. // You've set the flags for both saveMode and openMode!
  161. jassert (! (((flags & FileBrowserComponent::saveMode) != 0)
  162. && ((flags & FileBrowserComponent::openMode) != 0)));
  163. #if JUCE_WINDOWS
  164. const bool selectsFiles = (flags & FileBrowserComponent::canSelectFiles) != 0;
  165. const bool selectsDirectories = (flags & FileBrowserComponent::canSelectDirectories) != 0;
  166. if (useNativeDialogBox && ! (selectsFiles && selectsDirectories))
  167. #else
  168. if (useNativeDialogBox)
  169. #endif
  170. {
  171. return showPlatformDialog (*this, flags, previewComp);
  172. }
  173. else
  174. {
  175. return new NonNative (*this, flags, previewComp);
  176. }
  177. }
  178. Array<File> FileChooser::getResults() const noexcept
  179. {
  180. Array<File> files;
  181. for (auto url : getURLResults())
  182. if (url.isLocalFile())
  183. files.add (url.getLocalFile());
  184. return files;
  185. }
  186. File FileChooser::getResult() const
  187. {
  188. auto fileResults = getResults();
  189. // if you've used a multiple-file select, you should use the getResults() method
  190. // to retrieve all the files that were chosen.
  191. jassert (fileResults.size() <= 1);
  192. return fileResults.getFirst();
  193. }
  194. URL FileChooser::getURLResult() const
  195. {
  196. // if you've used a multiple-file select, you should use the getResults() method
  197. // to retrieve all the files that were chosen.
  198. jassert (results.size() <= 1);
  199. return results.getFirst();
  200. }
  201. void FileChooser::finished (const Array<URL>& asyncResults)
  202. {
  203. std::function<void (const FileChooser&)> callback;
  204. std::swap (callback, asyncCallback);
  205. results = asyncResults;
  206. pimpl.reset();
  207. if (callback)
  208. callback (*this);
  209. }
  210. //==============================================================================
  211. FilePreviewComponent::FilePreviewComponent() {}
  212. FilePreviewComponent::~FilePreviewComponent() {}
  213. } // namespace juce