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.

262 lines
8.9KB

  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. FileBasedDocument::FileBasedDocument (const String& fileExtension_,
  20. const String& fileWildcard_,
  21. const String& openFileDialogTitle_,
  22. const String& saveFileDialogTitle_)
  23. : changedSinceSave (false),
  24. fileExtension (fileExtension_),
  25. fileWildcard (fileWildcard_),
  26. openFileDialogTitle (openFileDialogTitle_),
  27. saveFileDialogTitle (saveFileDialogTitle_)
  28. {
  29. }
  30. FileBasedDocument::~FileBasedDocument()
  31. {
  32. }
  33. //==============================================================================
  34. void FileBasedDocument::setChangedFlag (const bool hasChanged)
  35. {
  36. if (changedSinceSave != hasChanged)
  37. {
  38. changedSinceSave = hasChanged;
  39. sendChangeMessage();
  40. }
  41. }
  42. void FileBasedDocument::changed()
  43. {
  44. changedSinceSave = true;
  45. sendChangeMessage();
  46. }
  47. //==============================================================================
  48. void FileBasedDocument::setFile (const File& newFile)
  49. {
  50. if (documentFile != newFile)
  51. {
  52. documentFile = newFile;
  53. changed();
  54. }
  55. }
  56. //==============================================================================
  57. Result FileBasedDocument::loadFrom (const File& newFile, const bool showMessageOnFailure)
  58. {
  59. MouseCursor::showWaitCursor();
  60. const File oldFile (documentFile);
  61. documentFile = newFile;
  62. Result result (Result::fail (TRANS("The file doesn't exist")));
  63. if (newFile.existsAsFile())
  64. {
  65. result = loadDocument (newFile);
  66. if (result.wasOk())
  67. {
  68. setChangedFlag (false);
  69. MouseCursor::hideWaitCursor();
  70. setLastDocumentOpened (newFile);
  71. return result;
  72. }
  73. }
  74. documentFile = oldFile;
  75. MouseCursor::hideWaitCursor();
  76. if (showMessageOnFailure)
  77. AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
  78. TRANS("Failed to open file..."),
  79. TRANS("There was an error while trying to load the file: FLNM")
  80. .replace ("FLNM", "\n" + newFile.getFullPathName())
  81. + "\n\n"
  82. + result.getErrorMessage());
  83. return result;
  84. }
  85. #if JUCE_MODAL_LOOPS_PERMITTED
  86. Result FileBasedDocument::loadFromUserSpecifiedFile (const bool showMessageOnFailure)
  87. {
  88. FileChooser fc (openFileDialogTitle,
  89. getLastDocumentOpened(),
  90. fileWildcard);
  91. if (fc.browseForFileToOpen())
  92. return loadFrom (fc.getResult(), showMessageOnFailure);
  93. return Result::fail (TRANS("User cancelled"));
  94. }
  95. static bool askToOverwriteFile (const File& newFile)
  96. {
  97. return AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
  98. TRANS("File already exists"),
  99. TRANS("There's already a file called: FLNM")
  100. .replace ("FLNM", newFile.getFullPathName())
  101. + "\n\n"
  102. + TRANS("Are you sure you want to overwrite it?"),
  103. TRANS("Overwrite"),
  104. TRANS("Cancel"));
  105. }
  106. //==============================================================================
  107. FileBasedDocument::SaveResult FileBasedDocument::save (const bool askUserForFileIfNotSpecified,
  108. const bool showMessageOnFailure)
  109. {
  110. return saveAs (documentFile,
  111. false,
  112. askUserForFileIfNotSpecified,
  113. showMessageOnFailure);
  114. }
  115. FileBasedDocument::SaveResult FileBasedDocument::saveAs (const File& newFile,
  116. const bool warnAboutOverwritingExistingFiles,
  117. const bool askUserForFileIfNotSpecified,
  118. const bool showMessageOnFailure)
  119. {
  120. if (newFile == File())
  121. {
  122. if (askUserForFileIfNotSpecified)
  123. return saveAsInteractive (true);
  124. // can't save to an unspecified file
  125. jassertfalse;
  126. return failedToWriteToFile;
  127. }
  128. if (warnAboutOverwritingExistingFiles
  129. && newFile.exists()
  130. && ! askToOverwriteFile (newFile))
  131. return userCancelledSave;
  132. MouseCursor::showWaitCursor();
  133. const File oldFile (documentFile);
  134. documentFile = newFile;
  135. const Result result (saveDocument (newFile));
  136. if (result.wasOk())
  137. {
  138. setChangedFlag (false);
  139. MouseCursor::hideWaitCursor();
  140. sendChangeMessage(); // because the filename may have changed
  141. return savedOk;
  142. }
  143. documentFile = oldFile;
  144. MouseCursor::hideWaitCursor();
  145. if (showMessageOnFailure)
  146. AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
  147. TRANS("Error writing to file..."),
  148. TRANS("An error occurred while trying to save \"DCNM\" to the file: FLNM")
  149. .replace ("DCNM", getDocumentTitle())
  150. .replace ("FLNM", "\n" + newFile.getFullPathName())
  151. + "\n\n"
  152. + result.getErrorMessage());
  153. sendChangeMessage(); // because the filename may have changed
  154. return failedToWriteToFile;
  155. }
  156. FileBasedDocument::SaveResult FileBasedDocument::saveIfNeededAndUserAgrees()
  157. {
  158. if (! hasChangedSinceSaved())
  159. return savedOk;
  160. const int r = AlertWindow::showYesNoCancelBox (AlertWindow::QuestionIcon,
  161. TRANS("Closing document..."),
  162. TRANS("Do you want to save the changes to \"DCNM\"?")
  163. .replace ("DCNM", getDocumentTitle()),
  164. TRANS("Save"),
  165. TRANS("Discard changes"),
  166. TRANS("Cancel"));
  167. if (r == 1) // save changes
  168. return save (true, true);
  169. if (r == 2) // discard changes
  170. return savedOk;
  171. return userCancelledSave;
  172. }
  173. File FileBasedDocument::getSuggestedSaveAsFile (const File& defaultFile)
  174. {
  175. return defaultFile.withFileExtension (fileExtension).getNonexistentSibling (true);
  176. }
  177. FileBasedDocument::SaveResult FileBasedDocument::saveAsInteractive (const bool warnAboutOverwritingExistingFiles)
  178. {
  179. File f;
  180. if (documentFile.existsAsFile())
  181. f = documentFile;
  182. else
  183. f = getLastDocumentOpened();
  184. String legalFilename (File::createLegalFileName (getDocumentTitle()));
  185. if (legalFilename.isEmpty())
  186. legalFilename = "unnamed";
  187. if (f.existsAsFile() || f.getParentDirectory().isDirectory())
  188. f = f.getSiblingFile (legalFilename);
  189. else
  190. f = File::getSpecialLocation (File::userDocumentsDirectory).getChildFile (legalFilename);
  191. f = getSuggestedSaveAsFile (f);
  192. FileChooser fc (saveFileDialogTitle, f, fileWildcard);
  193. if (fc.browseForFileToSave (warnAboutOverwritingExistingFiles))
  194. {
  195. File chosen (fc.getResult());
  196. if (chosen.getFileExtension().isEmpty())
  197. {
  198. chosen = chosen.withFileExtension (fileExtension);
  199. if (chosen.exists() && ! askToOverwriteFile (chosen))
  200. return userCancelledSave;
  201. }
  202. setLastDocumentOpened (chosen);
  203. return saveAs (chosen, false, false, true);
  204. }
  205. return userCancelledSave;
  206. }
  207. #endif