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.

314 lines
9.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #include "jucer_OpenDocumentManager.h"
  19. #include "jucer_FilePreviewComponent.h"
  20. #include "../Code Editor/jucer_SourceCodeEditor.h"
  21. //==============================================================================
  22. Component* SourceCodeDocument::createEditor() { return SourceCodeEditor::createFor (this, *codeDoc); }
  23. //==============================================================================
  24. class UnknownDocument : public OpenDocumentManager::Document
  25. {
  26. public:
  27. UnknownDocument (Project* project_, const File& file_)
  28. : project (project_), file (file_)
  29. {
  30. reloadFromFile();
  31. }
  32. //==============================================================================
  33. struct Type : public OpenDocumentManager::DocumentType
  34. {
  35. bool canOpenFile (const File&) { return true; }
  36. Document* openFile (Project* project, const File& file) { return new UnknownDocument (project, file); }
  37. };
  38. //==============================================================================
  39. bool loadedOk() const { return true; }
  40. bool isForFile (const File& file_) const { return file == file_; }
  41. bool isForNode (const ValueTree& node_) const { return false; }
  42. bool refersToProject (Project& p) const { return project == &p; }
  43. Project* getProject() const { return project; }
  44. bool needsSaving() const { return false; }
  45. bool save() { return true; }
  46. bool canSaveAs() const { return false; }
  47. bool saveAs() { return false; }
  48. bool hasFileBeenModifiedExternally() { return fileModificationTime != file.getLastModificationTime(); }
  49. void reloadFromFile() { fileModificationTime = file.getLastModificationTime(); }
  50. String getName() const { return file.getFileName(); }
  51. File getFile() const { return file; }
  52. Component* createEditor() { return new ItemPreviewComponent (file); }
  53. Component* createViewer() { return createEditor(); }
  54. void fileHasBeenRenamed (const File& newFile) { file = newFile; }
  55. String getType() const
  56. {
  57. if (file.getFileExtension().isNotEmpty())
  58. return file.getFileExtension() + " file";
  59. jassertfalse
  60. return "Unknown";
  61. }
  62. private:
  63. Project* const project;
  64. File file;
  65. Time fileModificationTime;
  66. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UnknownDocument);
  67. };
  68. //==============================================================================
  69. OpenDocumentManager::OpenDocumentManager()
  70. {
  71. registerType (new UnknownDocument::Type());
  72. registerType (new SourceCodeDocument::Type());
  73. }
  74. OpenDocumentManager::~OpenDocumentManager()
  75. {
  76. clearSingletonInstance();
  77. }
  78. juce_ImplementSingleton_SingleThreaded (OpenDocumentManager);
  79. //==============================================================================
  80. void OpenDocumentManager::registerType (DocumentType* type)
  81. {
  82. types.add (type);
  83. }
  84. //==============================================================================
  85. void OpenDocumentManager::addListener (DocumentCloseListener* listener)
  86. {
  87. listeners.addIfNotAlreadyThere (listener);
  88. }
  89. void OpenDocumentManager::removeListener (DocumentCloseListener* listener)
  90. {
  91. listeners.removeValue (listener);
  92. }
  93. //==============================================================================
  94. bool OpenDocumentManager::canOpenFile (const File& file)
  95. {
  96. for (int i = types.size(); --i >= 0;)
  97. if (types.getUnchecked(i)->canOpenFile (file))
  98. return true;
  99. return false;
  100. }
  101. OpenDocumentManager::Document* OpenDocumentManager::openFile (Project* project, const File& file)
  102. {
  103. for (int i = documents.size(); --i >= 0;)
  104. if (documents.getUnchecked(i)->isForFile (file))
  105. return documents.getUnchecked(i);
  106. Document* d = nullptr;
  107. for (int i = types.size(); --i >= 0 && d == nullptr;)
  108. {
  109. if (types.getUnchecked(i)->canOpenFile (file))
  110. {
  111. d = types.getUnchecked(i)->openFile (project, file);
  112. jassert (d != nullptr);
  113. }
  114. }
  115. jassert (d != nullptr); // should always at least have been picked up by UnknownDocument
  116. documents.add (d);
  117. commandManager->commandStatusChanged();
  118. return d;
  119. }
  120. int OpenDocumentManager::getNumOpenDocuments() const
  121. {
  122. return documents.size();
  123. }
  124. OpenDocumentManager::Document* OpenDocumentManager::getOpenDocument (int index) const
  125. {
  126. return documents.getUnchecked (index);
  127. }
  128. void OpenDocumentManager::moveDocumentToTopOfStack (Document* doc)
  129. {
  130. for (int i = documents.size(); --i >= 0;)
  131. {
  132. if (doc == documents.getUnchecked(i))
  133. {
  134. documents.move (i, 0);
  135. commandManager->commandStatusChanged();
  136. break;
  137. }
  138. }
  139. }
  140. FileBasedDocument::SaveResult OpenDocumentManager::saveIfNeededAndUserAgrees (OpenDocumentManager::Document* doc)
  141. {
  142. if (! doc->needsSaving())
  143. return FileBasedDocument::savedOk;
  144. const int r = AlertWindow::showYesNoCancelBox (AlertWindow::QuestionIcon,
  145. TRANS("Closing document..."),
  146. TRANS("Do you want to save the changes to \"")
  147. + doc->getName() + "\"?",
  148. TRANS("save"),
  149. TRANS("discard changes"),
  150. TRANS("cancel"));
  151. if (r == 1)
  152. {
  153. // save changes
  154. return doc->save() ? FileBasedDocument::savedOk
  155. : FileBasedDocument::failedToWriteToFile;
  156. }
  157. else if (r == 2)
  158. {
  159. // discard changes
  160. return FileBasedDocument::savedOk;
  161. }
  162. return FileBasedDocument::userCancelledSave;
  163. }
  164. bool OpenDocumentManager::closeDocument (int index, bool saveIfNeeded)
  165. {
  166. Document* doc = documents [index];
  167. if (doc != nullptr)
  168. {
  169. if (saveIfNeeded)
  170. {
  171. if (saveIfNeededAndUserAgrees (doc) != FileBasedDocument::savedOk)
  172. return false;
  173. }
  174. for (int i = listeners.size(); --i >= 0;)
  175. listeners.getUnchecked(i)->documentAboutToClose (doc);
  176. documents.remove (index);
  177. commandManager->commandStatusChanged();
  178. }
  179. return true;
  180. }
  181. bool OpenDocumentManager::closeDocument (Document* document, bool saveIfNeeded)
  182. {
  183. return closeDocument (documents.indexOf (document), saveIfNeeded);
  184. }
  185. void OpenDocumentManager::closeFile (const File& f, bool saveIfNeeded)
  186. {
  187. for (int i = documents.size(); --i >= 0;)
  188. {
  189. Document* d = documents.getUnchecked (i);
  190. if (d->isForFile (f))
  191. closeDocument (i, saveIfNeeded);
  192. }
  193. }
  194. bool OpenDocumentManager::closeAll (bool askUserToSave)
  195. {
  196. for (int i = getNumOpenDocuments(); --i >= 0;)
  197. if (! closeDocument (i, askUserToSave))
  198. return false;
  199. return true;
  200. }
  201. bool OpenDocumentManager::closeAllDocumentsUsingProject (Project& project, bool saveIfNeeded)
  202. {
  203. for (int i = documents.size(); --i >= 0;)
  204. {
  205. Document* d = documents.getUnchecked (i);
  206. if (d->refersToProject (project))
  207. {
  208. if (! closeDocument (i, saveIfNeeded))
  209. return false;
  210. }
  211. }
  212. return true;
  213. }
  214. bool OpenDocumentManager::anyFilesNeedSaving() const
  215. {
  216. for (int i = documents.size(); --i >= 0;)
  217. {
  218. Document* d = documents.getUnchecked (i);
  219. if (d->needsSaving())
  220. return true;
  221. }
  222. return false;
  223. }
  224. bool OpenDocumentManager::saveAll()
  225. {
  226. for (int i = documents.size(); --i >= 0;)
  227. {
  228. Document* d = documents.getUnchecked (i);
  229. if (! d->save())
  230. return false;
  231. }
  232. return true;
  233. }
  234. void OpenDocumentManager::reloadModifiedFiles()
  235. {
  236. for (int i = documents.size(); --i >= 0;)
  237. {
  238. Document* d = documents.getUnchecked (i);
  239. if (d->hasFileBeenModifiedExternally())
  240. d->reloadFromFile();
  241. }
  242. }
  243. void OpenDocumentManager::fileHasBeenRenamed (const File& oldFile, const File& newFile)
  244. {
  245. for (int i = documents.size(); --i >= 0;)
  246. {
  247. Document* d = documents.getUnchecked (i);
  248. if (d->isForFile (oldFile))
  249. d->fileHasBeenRenamed (newFile);
  250. }
  251. }