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.

260 lines
8.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. FileBasedDocument::FileBasedDocument (const String& fileExtension_,
  18. const String& fileWildcard_,
  19. const String& openFileDialogTitle_,
  20. const String& saveFileDialogTitle_)
  21. : changedSinceSave (false),
  22. fileExtension (fileExtension_),
  23. fileWildcard (fileWildcard_),
  24. openFileDialogTitle (openFileDialogTitle_),
  25. saveFileDialogTitle (saveFileDialogTitle_)
  26. {
  27. }
  28. FileBasedDocument::~FileBasedDocument()
  29. {
  30. }
  31. //==============================================================================
  32. void FileBasedDocument::setChangedFlag (const bool hasChanged)
  33. {
  34. if (changedSinceSave != hasChanged)
  35. {
  36. changedSinceSave = hasChanged;
  37. sendChangeMessage();
  38. }
  39. }
  40. void FileBasedDocument::changed()
  41. {
  42. changedSinceSave = true;
  43. sendChangeMessage();
  44. }
  45. //==============================================================================
  46. void FileBasedDocument::setFile (const File& newFile)
  47. {
  48. if (documentFile != newFile)
  49. {
  50. documentFile = newFile;
  51. changed();
  52. }
  53. }
  54. //==============================================================================
  55. Result FileBasedDocument::loadFrom (const File& newFile, const bool showMessageOnFailure)
  56. {
  57. MouseCursor::showWaitCursor();
  58. const File oldFile (documentFile);
  59. documentFile = newFile;
  60. Result result (Result::fail (TRANS("The file doesn't exist")));
  61. if (newFile.existsAsFile())
  62. {
  63. result = loadDocument (newFile);
  64. if (result.wasOk())
  65. {
  66. setChangedFlag (false);
  67. MouseCursor::hideWaitCursor();
  68. setLastDocumentOpened (newFile);
  69. return result;
  70. }
  71. }
  72. documentFile = oldFile;
  73. MouseCursor::hideWaitCursor();
  74. if (showMessageOnFailure)
  75. AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
  76. TRANS("Failed to open file..."),
  77. TRANS("There was an error while trying to load the file: FLNM")
  78. .replace ("FLNM", "\n" + newFile.getFullPathName())
  79. + "\n\n"
  80. + result.getErrorMessage());
  81. return result;
  82. }
  83. #if JUCE_MODAL_LOOPS_PERMITTED
  84. Result FileBasedDocument::loadFromUserSpecifiedFile (const bool showMessageOnFailure)
  85. {
  86. FileChooser fc (openFileDialogTitle,
  87. getLastDocumentOpened(),
  88. fileWildcard);
  89. if (fc.browseForFileToOpen())
  90. return loadFrom (fc.getResult(), showMessageOnFailure);
  91. return Result::fail (TRANS("User cancelled"));
  92. }
  93. static bool askToOverwriteFile (const File& newFile)
  94. {
  95. return AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
  96. TRANS("File already exists"),
  97. TRANS("There's already a file called: FLNM")
  98. .replace ("FLNM", newFile.getFullPathName())
  99. + "\n\n"
  100. + TRANS("Are you sure you want to overwrite it?"),
  101. TRANS("Overwrite"),
  102. TRANS("Cancel"));
  103. }
  104. //==============================================================================
  105. FileBasedDocument::SaveResult FileBasedDocument::save (const bool askUserForFileIfNotSpecified,
  106. const bool showMessageOnFailure)
  107. {
  108. return saveAs (documentFile,
  109. false,
  110. askUserForFileIfNotSpecified,
  111. showMessageOnFailure);
  112. }
  113. FileBasedDocument::SaveResult FileBasedDocument::saveAs (const File& newFile,
  114. const bool warnAboutOverwritingExistingFiles,
  115. const bool askUserForFileIfNotSpecified,
  116. const bool showMessageOnFailure)
  117. {
  118. if (newFile == File::nonexistent)
  119. {
  120. if (askUserForFileIfNotSpecified)
  121. return saveAsInteractive (true);
  122. // can't save to an unspecified file
  123. jassertfalse;
  124. return failedToWriteToFile;
  125. }
  126. if (warnAboutOverwritingExistingFiles
  127. && newFile.exists()
  128. && ! askToOverwriteFile (newFile))
  129. return userCancelledSave;
  130. MouseCursor::showWaitCursor();
  131. const File oldFile (documentFile);
  132. documentFile = newFile;
  133. const Result result (saveDocument (newFile));
  134. if (result.wasOk())
  135. {
  136. setChangedFlag (false);
  137. MouseCursor::hideWaitCursor();
  138. sendChangeMessage(); // because the filename may have changed
  139. return savedOk;
  140. }
  141. documentFile = oldFile;
  142. MouseCursor::hideWaitCursor();
  143. if (showMessageOnFailure)
  144. AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
  145. TRANS("Error writing to file..."),
  146. TRANS("An error occurred while trying to save \"DCNM\" to the file: FLNM")
  147. .replace ("DCNM", getDocumentTitle())
  148. .replace ("FLNM", "\n" + newFile.getFullPathName())
  149. + "\n\n"
  150. + result.getErrorMessage());
  151. sendChangeMessage(); // because the filename may have changed
  152. return failedToWriteToFile;
  153. }
  154. FileBasedDocument::SaveResult FileBasedDocument::saveIfNeededAndUserAgrees()
  155. {
  156. if (! hasChangedSinceSaved())
  157. return savedOk;
  158. const int r = AlertWindow::showYesNoCancelBox (AlertWindow::QuestionIcon,
  159. TRANS("Closing document..."),
  160. TRANS("Do you want to save the changes to \"DCNM\"?")
  161. .replace ("DCNM", getDocumentTitle()),
  162. TRANS("Save"),
  163. TRANS("Discard changes"),
  164. TRANS("Cancel"));
  165. if (r == 1) // save changes
  166. return save (true, true);
  167. if (r == 2) // discard changes
  168. return savedOk;
  169. return userCancelledSave;
  170. }
  171. File FileBasedDocument::getSuggestedSaveAsFile (const File& defaultFile)
  172. {
  173. return defaultFile.withFileExtension (fileExtension).getNonexistentSibling (true);
  174. }
  175. FileBasedDocument::SaveResult FileBasedDocument::saveAsInteractive (const bool warnAboutOverwritingExistingFiles)
  176. {
  177. File f;
  178. if (documentFile.existsAsFile())
  179. f = documentFile;
  180. else
  181. f = getLastDocumentOpened();
  182. String legalFilename (File::createLegalFileName (getDocumentTitle()));
  183. if (legalFilename.isEmpty())
  184. legalFilename = "unnamed";
  185. if (f.existsAsFile() || f.getParentDirectory().isDirectory())
  186. f = f.getSiblingFile (legalFilename);
  187. else
  188. f = File::getSpecialLocation (File::userDocumentsDirectory).getChildFile (legalFilename);
  189. f = getSuggestedSaveAsFile (f);
  190. FileChooser fc (saveFileDialogTitle, f, fileWildcard);
  191. if (fc.browseForFileToSave (warnAboutOverwritingExistingFiles))
  192. {
  193. File chosen (fc.getResult());
  194. if (chosen.getFileExtension().isEmpty())
  195. {
  196. chosen = chosen.withFileExtension (fileExtension);
  197. if (chosen.exists() && ! askToOverwriteFile (chosen))
  198. return userCancelledSave;
  199. }
  200. setLastDocumentOpened (chosen);
  201. return saveAs (chosen, false, false, true);
  202. }
  203. return userCancelledSave;
  204. }
  205. #endif