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.

312 lines
9.7KB

  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 hasFileBeenModifiedExternally() { return fileModificationTime != file.getLastModificationTime(); }
  47. void reloadFromFile() { fileModificationTime = file.getLastModificationTime(); }
  48. String getName() const { return file.getFileName(); }
  49. File getFile() const { return file; }
  50. Component* createEditor() { return new ItemPreviewComponent (file); }
  51. Component* createViewer() { return createEditor(); }
  52. void fileHasBeenRenamed (const File& newFile) { file = newFile; }
  53. String getType() const
  54. {
  55. if (file.getFileExtension().isNotEmpty())
  56. return file.getFileExtension() + " file";
  57. jassertfalse
  58. return "Unknown";
  59. }
  60. private:
  61. Project* const project;
  62. File file;
  63. Time fileModificationTime;
  64. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UnknownDocument);
  65. };
  66. //==============================================================================
  67. OpenDocumentManager::OpenDocumentManager()
  68. {
  69. registerType (new UnknownDocument::Type());
  70. registerType (new SourceCodeDocument::Type());
  71. }
  72. OpenDocumentManager::~OpenDocumentManager()
  73. {
  74. clearSingletonInstance();
  75. }
  76. juce_ImplementSingleton_SingleThreaded (OpenDocumentManager);
  77. //==============================================================================
  78. void OpenDocumentManager::registerType (DocumentType* type)
  79. {
  80. types.add (type);
  81. }
  82. //==============================================================================
  83. void OpenDocumentManager::addListener (DocumentCloseListener* listener)
  84. {
  85. listeners.addIfNotAlreadyThere (listener);
  86. }
  87. void OpenDocumentManager::removeListener (DocumentCloseListener* listener)
  88. {
  89. listeners.removeValue (listener);
  90. }
  91. //==============================================================================
  92. bool OpenDocumentManager::canOpenFile (const File& file)
  93. {
  94. for (int i = types.size(); --i >= 0;)
  95. if (types.getUnchecked(i)->canOpenFile (file))
  96. return true;
  97. return false;
  98. }
  99. OpenDocumentManager::Document* OpenDocumentManager::openFile (Project* project, const File& file)
  100. {
  101. for (int i = documents.size(); --i >= 0;)
  102. if (documents.getUnchecked(i)->isForFile (file))
  103. return documents.getUnchecked(i);
  104. Document* d = nullptr;
  105. for (int i = types.size(); --i >= 0 && d == nullptr;)
  106. {
  107. if (types.getUnchecked(i)->canOpenFile (file))
  108. {
  109. d = types.getUnchecked(i)->openFile (project, file);
  110. jassert (d != nullptr);
  111. }
  112. }
  113. jassert (d != nullptr); // should always at least have been picked up by UnknownDocument
  114. documents.add (d);
  115. commandManager->commandStatusChanged();
  116. return d;
  117. }
  118. int OpenDocumentManager::getNumOpenDocuments() const
  119. {
  120. return documents.size();
  121. }
  122. OpenDocumentManager::Document* OpenDocumentManager::getOpenDocument (int index) const
  123. {
  124. return documents.getUnchecked (index);
  125. }
  126. void OpenDocumentManager::moveDocumentToTopOfStack (Document* doc)
  127. {
  128. for (int i = documents.size(); --i >= 0;)
  129. {
  130. if (doc == documents.getUnchecked(i))
  131. {
  132. documents.move (i, 0);
  133. commandManager->commandStatusChanged();
  134. break;
  135. }
  136. }
  137. }
  138. FileBasedDocument::SaveResult OpenDocumentManager::saveIfNeededAndUserAgrees (OpenDocumentManager::Document* doc)
  139. {
  140. if (! doc->needsSaving())
  141. return FileBasedDocument::savedOk;
  142. const int r = AlertWindow::showYesNoCancelBox (AlertWindow::QuestionIcon,
  143. TRANS("Closing document..."),
  144. TRANS("Do you want to save the changes to \"")
  145. + doc->getName() + "\"?",
  146. TRANS("save"),
  147. TRANS("discard changes"),
  148. TRANS("cancel"));
  149. if (r == 1)
  150. {
  151. // save changes
  152. return doc->save() ? FileBasedDocument::savedOk
  153. : FileBasedDocument::failedToWriteToFile;
  154. }
  155. else if (r == 2)
  156. {
  157. // discard changes
  158. return FileBasedDocument::savedOk;
  159. }
  160. return FileBasedDocument::userCancelledSave;
  161. }
  162. bool OpenDocumentManager::closeDocument (int index, bool saveIfNeeded)
  163. {
  164. Document* doc = documents [index];
  165. if (doc != nullptr)
  166. {
  167. if (saveIfNeeded)
  168. {
  169. if (saveIfNeededAndUserAgrees (doc) != FileBasedDocument::savedOk)
  170. return false;
  171. }
  172. for (int i = listeners.size(); --i >= 0;)
  173. listeners.getUnchecked(i)->documentAboutToClose (doc);
  174. documents.remove (index);
  175. commandManager->commandStatusChanged();
  176. }
  177. return true;
  178. }
  179. bool OpenDocumentManager::closeDocument (Document* document, bool saveIfNeeded)
  180. {
  181. return closeDocument (documents.indexOf (document), saveIfNeeded);
  182. }
  183. void OpenDocumentManager::closeFile (const File& f, bool saveIfNeeded)
  184. {
  185. for (int i = documents.size(); --i >= 0;)
  186. {
  187. Document* d = documents.getUnchecked (i);
  188. if (d->isForFile (f))
  189. closeDocument (i, saveIfNeeded);
  190. }
  191. }
  192. bool OpenDocumentManager::closeAll (bool askUserToSave)
  193. {
  194. for (int i = getNumOpenDocuments(); --i >= 0;)
  195. if (! closeDocument (i, askUserToSave))
  196. return false;
  197. return true;
  198. }
  199. bool OpenDocumentManager::closeAllDocumentsUsingProject (Project& project, bool saveIfNeeded)
  200. {
  201. for (int i = documents.size(); --i >= 0;)
  202. {
  203. Document* d = documents.getUnchecked (i);
  204. if (d->refersToProject (project))
  205. {
  206. if (! closeDocument (i, saveIfNeeded))
  207. return false;
  208. }
  209. }
  210. return true;
  211. }
  212. bool OpenDocumentManager::anyFilesNeedSaving() const
  213. {
  214. for (int i = documents.size(); --i >= 0;)
  215. {
  216. Document* d = documents.getUnchecked (i);
  217. if (d->needsSaving())
  218. return true;
  219. }
  220. return false;
  221. }
  222. bool OpenDocumentManager::saveAll()
  223. {
  224. for (int i = documents.size(); --i >= 0;)
  225. {
  226. Document* d = documents.getUnchecked (i);
  227. if (! d->save())
  228. return false;
  229. }
  230. return true;
  231. }
  232. void OpenDocumentManager::reloadModifiedFiles()
  233. {
  234. for (int i = documents.size(); --i >= 0;)
  235. {
  236. Document* d = documents.getUnchecked (i);
  237. if (d->hasFileBeenModifiedExternally())
  238. d->reloadFromFile();
  239. }
  240. }
  241. void OpenDocumentManager::fileHasBeenRenamed (const File& oldFile, const File& newFile)
  242. {
  243. for (int i = documents.size(); --i >= 0;)
  244. {
  245. Document* d = documents.getUnchecked (i);
  246. if (d->isForFile (oldFile))
  247. d->fileHasBeenRenamed (newFile);
  248. }
  249. }