2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-10 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "jucer_OpenDocumentManager.h"
27 #include "jucer_FilePreviewComponent.h"
28 #include "../Code Editor/jucer_SourceCodeEditor.h"
31 //==============================================================================
32 class SourceCodeDocument
: public OpenDocumentManager::Document
35 //==============================================================================
36 SourceCodeDocument (const File
& file_
)
39 codeDoc
= new CodeDocument();
47 //==============================================================================
48 class Type
: public OpenDocumentManager::DocumentType
54 bool canOpenFile (const File
& file
) { return SourceCodeEditor::isTextFile (file
); }
55 Document
* openFile (Project
*, const File
& file
) { return new SourceCodeDocument (file
); }
58 //==============================================================================
59 bool loadedOk() const { return true; }
60 bool isForFile (const File
& file
) const { return modDetector
.getFile() == file
; }
61 bool isForNode (const ValueTree
& node
) const { return false; }
62 bool refersToProject (Project
& project
) const { return false; }
63 const String
getName() const { return modDetector
.getFile().getFileName(); }
64 const String
getType() const { return modDetector
.getFile().getFileExtension() + " file"; }
65 bool needsSaving() const { return codeDoc
!= nullptr && codeDoc
->hasChangedSinceSavePoint(); }
66 bool hasFileBeenModifiedExternally() { return modDetector
.hasBeenModified(); }
67 void fileHasBeenRenamed (const File
& newFile
) { modDetector
.fileHasBeenRenamed (newFile
); }
71 modDetector
.updateHash();
73 ScopedPointer
<InputStream
> in (modDetector
.getFile().createInputStream());
76 codeDoc
->loadFromStream (*in
);
81 TemporaryFile
temp (modDetector
.getFile());
82 ScopedPointer
<FileOutputStream
> out (temp
.getFile().createOutputStream());
84 if (out
== nullptr || ! codeDoc
->writeToStream (*out
))
88 if (! temp
.overwriteTargetFileWithTemporary())
91 modDetector
.updateHash();
95 Component
* createEditor()
97 CodeTokeniser
* tokeniser
= nullptr;
99 if (SourceCodeEditor::isCppFile (modDetector
.getFile()))
100 tokeniser
= &cppTokeniser
;
102 return new SourceCodeEditor (this, *codeDoc
, tokeniser
);
105 Component
* createViewer() { return createEditor(); }
108 FileModificationDetector modDetector
;
109 ScopedPointer
<CodeDocument
> codeDoc
;
110 CPlusPlusCodeTokeniser cppTokeniser
;
113 //==============================================================================
114 class UnknownDocument
: public OpenDocumentManager::Document
117 UnknownDocument (Project
* project_
, const File
& file_
)
118 : project (project_
), file (file_
)
123 ~UnknownDocument() {}
125 //==============================================================================
126 class Type
: public OpenDocumentManager::DocumentType
132 bool canOpenFile (const File
& file
) { return true; }
133 Document
* openFile (Project
* project
, const File
& file
) { return new UnknownDocument (project
, file
); }
136 //==============================================================================
137 bool loadedOk() const { return true; }
138 bool isForFile (const File
& file_
) const { return file
== file_
; }
139 bool isForNode (const ValueTree
& node_
) const { return false; }
140 bool refersToProject (Project
& p
) const { return project
== &p
; }
141 bool needsSaving() const { return false; }
142 bool save() { return true; }
143 bool hasFileBeenModifiedExternally() { return fileModificationTime
!= file
.getLastModificationTime(); }
144 void reloadFromFile() { fileModificationTime
= file
.getLastModificationTime(); }
145 const String
getName() const { return file
.getFileName(); }
146 Component
* createEditor() { return new ItemPreviewComponent (file
); }
147 Component
* createViewer() { return createEditor(); }
148 void fileHasBeenRenamed (const File
& newFile
) { file
= newFile
; }
150 const String
getType() const
152 if (file
.getFileExtension().isNotEmpty())
153 return file
.getFileExtension() + " file";
160 Project
* const project
;
162 Time fileModificationTime
;
164 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UnknownDocument
);
168 //==============================================================================
169 OpenDocumentManager::OpenDocumentManager()
171 registerType (new UnknownDocument::Type());
172 registerType (new SourceCodeDocument::Type());
175 OpenDocumentManager::~OpenDocumentManager()
177 clearSingletonInstance();
180 juce_ImplementSingleton_SingleThreaded (OpenDocumentManager
);
182 //==============================================================================
183 void OpenDocumentManager::registerType (DocumentType
* type
)
188 //==============================================================================
189 void OpenDocumentManager::addListener (DocumentCloseListener
* listener
)
191 listeners
.addIfNotAlreadyThere (listener
);
194 void OpenDocumentManager::removeListener (DocumentCloseListener
* listener
)
196 listeners
.removeValue (listener
);
199 //==============================================================================
200 bool OpenDocumentManager::canOpenFile (const File
& file
)
202 for (int i
= types
.size(); --i
>= 0;)
203 if (types
.getUnchecked(i
)->canOpenFile (file
))
209 OpenDocumentManager::Document
* OpenDocumentManager::getDocumentForFile (Project
* project
, const File
& file
)
211 for (int i
= documents
.size(); --i
>= 0;)
212 if (documents
.getUnchecked(i
)->isForFile (file
))
213 return documents
.getUnchecked(i
);
215 Document
* d
= nullptr;
217 for (int i
= types
.size(); --i
>= 0 && d
== nullptr;)
219 if (types
.getUnchecked(i
)->canOpenFile (file
))
221 d
= types
.getUnchecked(i
)->openFile (project
, file
);
222 jassert (d
!= nullptr);
226 jassert (d
!= nullptr);
231 commandManager
->commandStatusChanged();
235 int OpenDocumentManager::getNumOpenDocuments() const
237 return documents
.size();
240 OpenDocumentManager::Document
* OpenDocumentManager::getOpenDocument (int index
) const
242 return documents
.getUnchecked (index
);
245 void OpenDocumentManager::moveDocumentToTopOfStack (Document
* doc
)
247 for (int i
= documents
.size(); --i
>= 0;)
249 if (doc
== documents
.getUnchecked(i
))
251 documents
.move (i
, 0);
252 commandManager
->commandStatusChanged();
258 FileBasedDocument::SaveResult
OpenDocumentManager::saveIfNeededAndUserAgrees (OpenDocumentManager::Document
* doc
)
260 if (! doc
->needsSaving())
261 return FileBasedDocument::savedOk
;
263 const int r
= AlertWindow::showYesNoCancelBox (AlertWindow::QuestionIcon
,
264 TRANS("Closing document..."),
265 TRANS("Do you want to save the changes to \"")
266 + doc
->getName() + "\"?",
268 TRANS("discard changes"),
274 return doc
->save() ? FileBasedDocument::savedOk
275 : FileBasedDocument::failedToWriteToFile
;
280 return FileBasedDocument::savedOk
;
283 return FileBasedDocument::userCancelledSave
;
287 bool OpenDocumentManager::closeDocument (int index
, bool saveIfNeeded
)
289 Document
* doc
= documents
[index
];
295 if (saveIfNeededAndUserAgrees (doc
) != FileBasedDocument::savedOk
)
299 for (int i
= listeners
.size(); --i
>= 0;)
300 listeners
.getUnchecked(i
)->documentAboutToClose (doc
);
302 documents
.remove (index
);
303 commandManager
->commandStatusChanged();
309 bool OpenDocumentManager::closeDocument (Document
* document
, bool saveIfNeeded
)
311 return closeDocument (documents
.indexOf (document
), saveIfNeeded
);
314 void OpenDocumentManager::closeFile (const File
& f
, bool saveIfNeeded
)
316 for (int i
= documents
.size(); --i
>= 0;)
318 Document
* d
= documents
.getUnchecked (i
);
320 if (d
->isForFile (f
))
321 closeDocument (i
, saveIfNeeded
);
325 bool OpenDocumentManager::closeAllDocumentsUsingProject (Project
& project
, bool saveIfNeeded
)
327 for (int i
= documents
.size(); --i
>= 0;)
329 Document
* d
= documents
.getUnchecked (i
);
331 if (d
->refersToProject (project
))
333 if (! closeDocument (i
, saveIfNeeded
))
341 bool OpenDocumentManager::anyFilesNeedSaving() const
343 for (int i
= documents
.size(); --i
>= 0;)
345 Document
* d
= documents
.getUnchecked (i
);
347 if (d
->needsSaving())
354 bool OpenDocumentManager::saveAll()
356 for (int i
= documents
.size(); --i
>= 0;)
358 Document
* d
= documents
.getUnchecked (i
);
367 void OpenDocumentManager::reloadModifiedFiles()
369 for (int i
= documents
.size(); --i
>= 0;)
371 Document
* d
= documents
.getUnchecked (i
);
373 if (d
->hasFileBeenModifiedExternally())
378 void OpenDocumentManager::fileHasBeenRenamed (const File
& oldFile
, const File
& newFile
)
380 for (int i
= documents
.size(); --i
>= 0;)
382 Document
* d
= documents
.getUnchecked (i
);
384 if (d
->isForFile (oldFile
))
385 d
->fileHasBeenRenamed (newFile
);