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.

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