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.

425 lines
19KB

  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. /**
  17. A class to take care of the logic involved with the loading/saving of some kind
  18. of document.
  19. There's quite a lot of tedious logic involved in writing all the load/save/save-as
  20. functions you need for documents that get saved to a file, so this class attempts
  21. to abstract most of the boring stuff.
  22. Your subclass should just implement all the pure virtual methods, and you can
  23. then use the higher-level public methods to do the load/save dialogs, to warn the user
  24. about overwriting files, etc.
  25. The document object keeps track of whether it has changed since it was last saved or
  26. loaded, so when you change something, call its changed() method. This will set a
  27. flag so it knows it needs saving, and will also broadcast a change message using the
  28. ChangeBroadcaster base class.
  29. @see ChangeBroadcaster
  30. @tags{GUI}
  31. */
  32. class JUCE_API FileBasedDocument : public ChangeBroadcaster
  33. {
  34. public:
  35. /** Creates a FileBasedDocument.
  36. @param fileExtension the extension to use when loading/saving files, e.g. ".doc"
  37. @param fileWildCard the wildcard to use in file dialogs, e.g. "*.doc"
  38. @param openFileDialogTitle the title to show on an open-file dialog, e.g. "Choose a file to open.."
  39. @param saveFileDialogTitle the title to show on an save-file dialog, e.g. "Choose a file to save as.."
  40. */
  41. FileBasedDocument (const String& fileExtension,
  42. const String& fileWildCard,
  43. const String& openFileDialogTitle,
  44. const String& saveFileDialogTitle);
  45. /** Destructor. */
  46. ~FileBasedDocument() override;
  47. //==============================================================================
  48. /** Returns true if the changed() method has been called since the file was
  49. last saved or loaded.
  50. @see setChangedFlag, changed
  51. */
  52. bool hasChangedSinceSaved() const;
  53. /** Called to indicate that the document has changed and needs saving.
  54. This method will also trigger a change message to be sent out using the
  55. ChangeBroadcaster base class.
  56. After calling the method, the hasChangedSinceSaved() method will return true, until
  57. it is reset either by saving to a file or using the setChangedFlag() method.
  58. @see hasChangedSinceSaved, setChangedFlag
  59. */
  60. virtual void changed();
  61. /** Sets the state of the 'changed' flag.
  62. The 'changed' flag is set to true when the changed() method is called - use this method
  63. to reset it or to set it without also broadcasting a change message.
  64. @see changed, hasChangedSinceSaved
  65. */
  66. void setChangedFlag (bool hasChanged);
  67. //==============================================================================
  68. /** Tries to open a file.
  69. If the file opens correctly the document's file (see the getFile() method) is set
  70. to this new one; if it fails, the document's file is left unchanged, and optionally
  71. a message box is shown telling the user there was an error.
  72. @returns A result indicating whether the new file loaded successfully, or the error
  73. message if it failed.
  74. @see loadDocument, loadFromUserSpecifiedFile
  75. */
  76. Result loadFrom (const File& fileToLoadFrom,
  77. bool showMessageOnFailure,
  78. bool showWaitCursor = true);
  79. /** Tries to open a file.
  80. The callback is called with the result indicating whether the new file loaded
  81. successfully, or the error message if it failed.
  82. If the file opens correctly the document's file (see the getFile() method) is set
  83. to this new one; if it fails, the document's file is left unchanged, and optionally
  84. a message box is shown telling the user there was an error.
  85. @see loadDocumentAsync, loadFromUserSpecifiedFileAsync
  86. */
  87. void loadFromAsync (const File& fileToLoadFrom,
  88. bool showMessageOnFailure,
  89. std::function<void (Result)> callback);
  90. #if JUCE_MODAL_LOOPS_PERMITTED
  91. /** Asks the user for a file and tries to load it.
  92. This will pop up a dialog box using the title, file extension and
  93. wildcard specified in the document's constructor, and asks the user
  94. for a file. If they pick one, the loadFrom() method is used to
  95. try to load it, optionally showing a message if it fails.
  96. @returns a result indicating success; This will be a failure message if the user
  97. cancelled or if they picked a file which failed to load correctly
  98. @see loadFrom
  99. */
  100. Result loadFromUserSpecifiedFile (bool showMessageOnFailure);
  101. #endif
  102. /** Asks the user for a file and tries to load it.
  103. This will pop up a dialog box using the title, file extension and
  104. wildcard specified in the document's constructor, and asks the user
  105. for a file. If they pick one, the loadFrom() method is used to
  106. try to load it, optionally showing a message if it fails. The result
  107. of the operation is provided in the callback function.
  108. @see loadFrom
  109. */
  110. void loadFromUserSpecifiedFileAsync (bool showMessageOnFailure, std::function<void (Result)> callback);
  111. //==============================================================================
  112. /** A set of possible outcomes of one of the save() methods
  113. */
  114. enum SaveResult
  115. {
  116. savedOk = 0, /**< indicates that a file was saved successfully. */
  117. userCancelledSave, /**< indicates that the user aborted the save operation. */
  118. failedToWriteToFile /**< indicates that it tried to write to a file but this failed. */
  119. };
  120. #if JUCE_MODAL_LOOPS_PERMITTED
  121. /** Tries to save the document to the last file it was saved or loaded from.
  122. This will always try to write to the file, even if the document isn't flagged as
  123. having changed.
  124. @param askUserForFileIfNotSpecified if there's no file currently specified and this is
  125. true, it will prompt the user to pick a file, as if
  126. saveAsInteractive() was called.
  127. @param showMessageOnFailure if true it will show a warning message when if the
  128. save operation fails
  129. @see saveIfNeededAndUserAgrees, saveAs, saveAsInteractive
  130. */
  131. SaveResult save (bool askUserForFileIfNotSpecified,
  132. bool showMessageOnFailure);
  133. #endif
  134. /** Tries to save the document to the last file it was saved or loaded from.
  135. This will always try to write to the file, even if the document isn't flagged as
  136. having changed.
  137. @param askUserForFileIfNotSpecified if there's no file currently specified and this is
  138. true, it will prompt the user to pick a file, as if
  139. saveAsInteractive() was called.
  140. @param showMessageOnFailure if true it will show a warning message when if the
  141. save operation fails
  142. @param callback called after the save operation with the result
  143. @see saveIfNeededAndUserAgrees, saveAs, saveAsInteractive
  144. */
  145. void saveAsync (bool askUserForFileIfNotSpecified,
  146. bool showMessageOnFailure,
  147. std::function<void (SaveResult)> callback);
  148. #if JUCE_MODAL_LOOPS_PERMITTED
  149. /** If the file needs saving, it'll ask the user if that's what they want to do, and save
  150. it if they say yes.
  151. If you've got a document open and want to close it (e.g. to quit the app), this is the
  152. method to call.
  153. If the document doesn't need saving it'll return the value savedOk so
  154. you can go ahead and delete the document.
  155. If it does need saving it'll prompt the user, and if they say "discard changes" it'll
  156. return savedOk, so again, you can safely delete the document.
  157. If the user clicks "cancel", it'll return userCancelledSave, so if you can abort the
  158. close-document operation.
  159. And if they click "save changes", it'll try to save and either return savedOk, or
  160. failedToWriteToFile if there was a problem.
  161. @see save, saveAs, saveAsInteractive
  162. */
  163. SaveResult saveIfNeededAndUserAgrees();
  164. #endif
  165. /** If the file needs saving, it'll ask the user if that's what they want to do, and save
  166. it if they say yes.
  167. If you've got a document open and want to close it (e.g. to quit the app), this is the
  168. method to call.
  169. If the document doesn't need saving the callback will be called with the value savedOk
  170. so you can go ahead and delete the document.
  171. If it does need saving it'll prompt the user, and if they say "discard changes" the
  172. callback will be called with savedOk, so again, you can safely delete the document.
  173. If the user clicks "cancel", the callback will be called with userCancelledSave, so
  174. you can abort the close-document operation.
  175. And if they click "save changes", it'll try to save and the callback will be called
  176. with either savedOk, or failedToWriteToFile if there was a problem.
  177. @see saveAsync, saveAsAsync, saveAsInteractiveAsync
  178. */
  179. void saveIfNeededAndUserAgreesAsync (std::function<void (SaveResult)> callback);
  180. #if JUCE_MODAL_LOOPS_PERMITTED
  181. /** Tries to save the document to a specified file.
  182. If this succeeds, it'll also change the document's internal file (as returned by
  183. the getFile() method). If it fails, the file will be left unchanged.
  184. @param newFile the file to try to write to
  185. @param warnAboutOverwritingExistingFiles if true and the file exists, it'll ask
  186. the user first if they want to overwrite it
  187. @param askUserForFileIfNotSpecified if the file is non-existent and this is true, it'll
  188. use the saveAsInteractive() method to ask the user for a
  189. filename
  190. @param showMessageOnFailure if true and the write operation fails, it'll show
  191. a message box to warn the user
  192. @param showWaitCursor if true, the 'wait' mouse cursor will be showin during
  193. saving
  194. @see saveIfNeededAndUserAgrees, save, saveAsInteractive
  195. */
  196. SaveResult saveAs (const File& newFile,
  197. bool warnAboutOverwritingExistingFiles,
  198. bool askUserForFileIfNotSpecified,
  199. bool showMessageOnFailure,
  200. bool showWaitCursor = true);
  201. #endif
  202. /** Tries to save the document to a specified file.
  203. If this succeeds, it'll also change the document's internal file (as returned by
  204. the getFile() method). If it fails, the file will be left unchanged.
  205. @param newFile the file to try to write to
  206. @param warnAboutOverwritingExistingFiles if true and the file exists, it'll ask the user
  207. first if they want to overwrite it
  208. @param askUserForFileIfNotSpecified if the file is non-existent and this is true, it'll
  209. use the saveAsInteractive() method to ask the user
  210. for a filename
  211. @param showMessageOnFailure if true and the write operation fails, it'll show
  212. a message box to warn the user
  213. @param callback called with the result of the save operation
  214. @see saveIfNeededAndUserAgreesAsync, saveAsync, saveAsInteractiveAsync
  215. */
  216. void saveAsAsync (const File& newFile,
  217. bool warnAboutOverwritingExistingFiles,
  218. bool askUserForFileIfNotSpecified,
  219. bool showMessageOnFailure,
  220. std::function<void (SaveResult)> callback);
  221. #if JUCE_MODAL_LOOPS_PERMITTED
  222. /** Prompts the user for a filename and tries to save to it.
  223. This will pop up a dialog box using the title, file extension and
  224. wildcard specified in the document's constructor, and asks the user
  225. for a file. If they pick one, the saveAs() method is used to try to save
  226. to this file.
  227. @param warnAboutOverwritingExistingFiles if true and the file exists, it'll ask
  228. the user first if they want to overwrite it
  229. @see saveIfNeededAndUserAgrees, save, saveAs
  230. */
  231. SaveResult saveAsInteractive (bool warnAboutOverwritingExistingFiles);
  232. #endif
  233. /** Prompts the user for a filename and tries to save to it.
  234. This will pop up a dialog box using the title, file extension and
  235. wildcard specified in the document's constructor, and asks the user
  236. for a file. If they pick one, the saveAs() method is used to try to save
  237. to this file.
  238. @param warnAboutOverwritingExistingFiles if true and the file exists, it'll ask
  239. the user first if they want to overwrite it
  240. @param callback called with the result of the save operation
  241. @see saveIfNeededAndUserAgreesAsync, saveAsync, saveAsAsync
  242. */
  243. void saveAsInteractiveAsync (bool warnAboutOverwritingExistingFiles,
  244. std::function<void (SaveResult)> callback);
  245. //==============================================================================
  246. /** Returns the file that this document was last successfully saved or loaded from.
  247. When the document object is created, this will be set to File().
  248. It is changed when one of the load or save methods is used, or when setFile()
  249. is used to explicitly set it.
  250. */
  251. const File& getFile() const;
  252. /** Sets the file that this document thinks it was loaded from.
  253. This won't actually load anything - it just changes the file stored internally.
  254. @see getFile
  255. */
  256. void setFile (const File& newFile);
  257. protected:
  258. //==============================================================================
  259. /** Overload this to return the title of the document.
  260. This is used in message boxes, filenames and file choosers, so it should be
  261. something sensible.
  262. */
  263. virtual String getDocumentTitle() = 0;
  264. /** This method should try to load your document from the given file.
  265. @returns a Result object to indicate the whether there was an error.
  266. */
  267. virtual Result loadDocument (const File& file) = 0;
  268. /** This method should try to load your document from the given file, then
  269. call the provided callback on the message thread, passing the result of the load.
  270. By default, this will synchronously call through to loadDocument.
  271. For longer-running load operations, you may wish to override this function to
  272. run the load on a background thread, and then to call the callback later on the
  273. message thread to signal that the load has completed.
  274. */
  275. virtual void loadDocumentAsync (const File& file, std::function<void (Result)> callback);
  276. /** This method should try to write your document to the given file.
  277. @returns a Result object to indicate the whether there was an error.
  278. */
  279. virtual Result saveDocument (const File& file) = 0;
  280. /** This method should try to write your document to the given file, then
  281. call the provided callback on the message thread, passing the result of the write.
  282. By default, this will synchronously call through to saveDocument.
  283. For longer-running save operations, you may wish to override this function to
  284. run the save on a background thread, and then to call the callback later on the
  285. message thread to signal that the save has completed.
  286. */
  287. virtual void saveDocumentAsync (const File& file, std::function<void (Result)> callback);
  288. /** This is used for dialog boxes to make them open at the last folder you
  289. were using.
  290. getLastDocumentOpened() and setLastDocumentOpened() are used to store
  291. the last document that was used - you might want to store this value
  292. in a static variable, or even in your application's properties. It should
  293. be a global setting rather than a property of this object.
  294. This method works very well in conjunction with a RecentlyOpenedFilesList
  295. object to manage your recent-files list.
  296. As a default value, it's ok to return File(), and the document object will
  297. use a sensible one instead.
  298. @see RecentlyOpenedFilesList
  299. */
  300. virtual File getLastDocumentOpened() = 0;
  301. /** This is used for dialog boxes to make them open at the last folder you
  302. were using.
  303. getLastDocumentOpened() and setLastDocumentOpened() are used to store
  304. the last document that was used - you might want to store this value
  305. in a static variable, or even in your application's properties. It should
  306. be a global setting rather than a property of this object.
  307. This method works very well in conjunction with a RecentlyOpenedFilesList
  308. object to manage your recent-files list.
  309. @see RecentlyOpenedFilesList
  310. */
  311. virtual void setLastDocumentOpened (const File& file) = 0;
  312. /** This is called by saveAsInteractiveAsync() to allow you to optionally customise the
  313. filename that the user is presented with in the save dialog.
  314. The defaultFile parameter is an initial suggestion based on what the class knows
  315. about the current document - you can return a variation on this file with a different
  316. extension, etc, or just return something completely different.
  317. */
  318. virtual File getSuggestedSaveAsFile (const File& defaultFile);
  319. private:
  320. //==============================================================================
  321. class Pimpl;
  322. std::unique_ptr<Pimpl> pimpl;
  323. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileBasedDocument)
  324. };
  325. } // namespace juce