1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00
JUCE/extras/Introjucer/Source/Application/jucer_OpenDocumentManager.cpp

430 lines
13 KiB
C++

/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/
#include "jucer_OpenDocumentManager.h"
#include "jucer_FilePreviewComponent.h"
#include "../Code Editor/jucer_SourceCodeEditor.h"
#include "jucer_Application.h"
//==============================================================================
class UnknownDocument : public OpenDocumentManager::Document
{
public:
UnknownDocument (Project* p, const File& f)
: project (p), file (f)
{
reloadFromFile();
}
//==============================================================================
struct Type : public OpenDocumentManager::DocumentType
{
bool canOpenFile (const File&) { return true; }
Document* openFile (Project* p, const File& f) { return new UnknownDocument (p, f); }
};
//==============================================================================
bool loadedOk() const { return true; }
bool isForFile (const File& f) const { return file == f; }
bool isForNode (const ValueTree&) const { return false; }
bool refersToProject (Project& p) const { return project == &p; }
Project* getProject() const { return project; }
bool needsSaving() const { return false; }
bool save() { return true; }
bool hasFileBeenModifiedExternally() { return fileModificationTime != file.getLastModificationTime(); }
void reloadFromFile() { fileModificationTime = file.getLastModificationTime(); }
String getName() const { return file.getFileName(); }
File getFile() const { return file; }
Component* createEditor() { return new ItemPreviewComponent (file); }
Component* createViewer() { return createEditor(); }
void fileHasBeenRenamed (const File& newFile) { file = newFile; }
String getState() const { return String::empty; }
void restoreState (const String&) {}
String getType() const
{
if (file.getFileExtension().isNotEmpty())
return file.getFileExtension() + " file";
jassertfalse
return "Unknown";
}
private:
Project* const project;
File file;
Time fileModificationTime;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UnknownDocument)
};
//==============================================================================
OpenDocumentManager::OpenDocumentManager()
{
registerType (new UnknownDocument::Type());
registerType (new SourceCodeDocument::Type());
}
OpenDocumentManager::~OpenDocumentManager()
{
}
void OpenDocumentManager::clear()
{
documents.clear();
types.clear();
}
//==============================================================================
void OpenDocumentManager::registerType (DocumentType* type)
{
types.add (type);
}
//==============================================================================
void OpenDocumentManager::addListener (DocumentCloseListener* listener)
{
listeners.addIfNotAlreadyThere (listener);
}
void OpenDocumentManager::removeListener (DocumentCloseListener* listener)
{
listeners.removeFirstMatchingValue (listener);
}
//==============================================================================
bool OpenDocumentManager::canOpenFile (const File& file)
{
for (int i = types.size(); --i >= 0;)
if (types.getUnchecked(i)->canOpenFile (file))
return true;
return false;
}
OpenDocumentManager::Document* OpenDocumentManager::openFile (Project* project, const File& file)
{
for (int i = documents.size(); --i >= 0;)
if (documents.getUnchecked(i)->isForFile (file))
return documents.getUnchecked(i);
Document* d = nullptr;
for (int i = types.size(); --i >= 0 && d == nullptr;)
{
if (types.getUnchecked(i)->canOpenFile (file))
{
d = types.getUnchecked(i)->openFile (project, file);
jassert (d != nullptr);
}
}
jassert (d != nullptr); // should always at least have been picked up by UnknownDocument
documents.add (d);
commandManager->commandStatusChanged();
return d;
}
int OpenDocumentManager::getNumOpenDocuments() const
{
return documents.size();
}
OpenDocumentManager::Document* OpenDocumentManager::getOpenDocument (int index) const
{
return documents.getUnchecked (index);
}
FileBasedDocument::SaveResult OpenDocumentManager::saveIfNeededAndUserAgrees (OpenDocumentManager::Document* doc)
{
if (! doc->needsSaving())
return FileBasedDocument::savedOk;
const int r = AlertWindow::showYesNoCancelBox (AlertWindow::QuestionIcon,
TRANS("Closing document..."),
TRANS("Do you want to save the changes to \"")
+ doc->getName() + "\"?",
TRANS("save"),
TRANS("discard changes"),
TRANS("cancel"));
if (r == 1)
{
// save changes
return doc->save() ? FileBasedDocument::savedOk
: FileBasedDocument::failedToWriteToFile;
}
else if (r == 2)
{
// discard changes
return FileBasedDocument::savedOk;
}
return FileBasedDocument::userCancelledSave;
}
bool OpenDocumentManager::closeDocument (int index, bool saveIfNeeded)
{
if (Document* doc = documents [index])
{
if (saveIfNeeded)
{
if (saveIfNeededAndUserAgrees (doc) != FileBasedDocument::savedOk)
return false;
}
for (int i = listeners.size(); --i >= 0;)
listeners.getUnchecked(i)->documentAboutToClose (doc);
documents.remove (index);
commandManager->commandStatusChanged();
}
return true;
}
bool OpenDocumentManager::closeDocument (Document* document, bool saveIfNeeded)
{
return closeDocument (documents.indexOf (document), saveIfNeeded);
}
void OpenDocumentManager::closeFile (const File& f, bool saveIfNeeded)
{
for (int i = documents.size(); --i >= 0;)
{
Document* d = documents.getUnchecked (i);
if (d->isForFile (f))
closeDocument (i, saveIfNeeded);
}
}
bool OpenDocumentManager::closeAll (bool askUserToSave)
{
for (int i = getNumOpenDocuments(); --i >= 0;)
if (! closeDocument (i, askUserToSave))
return false;
return true;
}
bool OpenDocumentManager::closeAllDocumentsUsingProject (Project& project, bool saveIfNeeded)
{
for (int i = documents.size(); --i >= 0;)
{
Document* d = documents.getUnchecked (i);
if (d->refersToProject (project))
{
if (! closeDocument (i, saveIfNeeded))
return false;
}
}
return true;
}
bool OpenDocumentManager::anyFilesNeedSaving() const
{
for (int i = documents.size(); --i >= 0;)
{
Document* d = documents.getUnchecked (i);
if (d->needsSaving())
return true;
}
return false;
}
bool OpenDocumentManager::saveAll()
{
for (int i = documents.size(); --i >= 0;)
{
Document* d = documents.getUnchecked (i);
if (! d->save())
return false;
}
return true;
}
void OpenDocumentManager::reloadModifiedFiles()
{
for (int i = documents.size(); --i >= 0;)
{
Document* d = documents.getUnchecked (i);
if (d->hasFileBeenModifiedExternally())
d->reloadFromFile();
}
}
void OpenDocumentManager::fileHasBeenRenamed (const File& oldFile, const File& newFile)
{
for (int i = documents.size(); --i >= 0;)
{
Document* d = documents.getUnchecked (i);
if (d->isForFile (oldFile))
d->fileHasBeenRenamed (newFile);
}
}
//==============================================================================
RecentDocumentList::RecentDocumentList()
{
IntrojucerApp::getApp().openDocumentManager.addListener (this);
}
RecentDocumentList::~RecentDocumentList()
{
IntrojucerApp::getApp().openDocumentManager.removeListener (this);
}
void RecentDocumentList::clear()
{
previousDocs.clear();
nextDocs.clear();
}
void RecentDocumentList::newDocumentOpened (OpenDocumentManager::Document* document)
{
if (document != nullptr && document != getCurrentDocument())
{
nextDocs.clear();
previousDocs.add (document);
}
}
bool RecentDocumentList::canGoToPrevious() const
{
return previousDocs.size() > 1;
}
bool RecentDocumentList::canGoToNext() const
{
return nextDocs.size() > 0;
}
OpenDocumentManager::Document* RecentDocumentList::getPrevious()
{
if (! canGoToPrevious())
return nullptr;
nextDocs.insert (0, previousDocs.remove (previousDocs.size() - 1));
return previousDocs.getLast();
}
OpenDocumentManager::Document* RecentDocumentList::getNext()
{
if (! canGoToNext())
return nullptr;
OpenDocumentManager::Document* d = nextDocs.remove (0);
previousDocs.add (d);
return d;
}
OpenDocumentManager::Document* RecentDocumentList::getClosestPreviousDocOtherThan (OpenDocumentManager::Document* oneToAvoid) const
{
for (int i = previousDocs.size(); --i >= 0;)
if (previousDocs.getUnchecked(i) != oneToAvoid)
return previousDocs.getUnchecked(i);
return nullptr;
}
void RecentDocumentList::documentAboutToClose (OpenDocumentManager::Document* document)
{
previousDocs.removeAllInstancesOf (document);
nextDocs.removeAllInstancesOf (document);
jassert (! previousDocs.contains (document));
jassert (! nextDocs.contains (document));
}
static void restoreDocList (Project& project, Array <OpenDocumentManager::Document*>& list, const XmlElement* xml)
{
if (xml != nullptr)
{
OpenDocumentManager& odm = IntrojucerApp::getApp().openDocumentManager;
forEachXmlChildElementWithTagName (*xml, e, "DOC")
{
const File file (e->getStringAttribute ("file"));
if (file.exists())
{
if (OpenDocumentManager::Document* doc = odm.openFile (&project, file))
{
doc->restoreState (e->getStringAttribute ("state"));
list.add (doc);
}
}
}
}
}
void RecentDocumentList::restoreFromXML (Project& project, const XmlElement& xml)
{
clear();
if (xml.hasTagName ("RECENT_DOCUMENTS"))
{
restoreDocList (project, previousDocs, xml.getChildByName ("PREVIOUS"));
restoreDocList (project, nextDocs, xml.getChildByName ("NEXT"));
}
}
static void saveDocList (const Array <OpenDocumentManager::Document*>& list, XmlElement& xml)
{
for (int i = 0; i < list.size(); ++i)
{
const OpenDocumentManager::Document& doc = *list.getUnchecked(i);
XmlElement* e = xml.createNewChildElement ("DOC");
e->setAttribute ("file", doc.getFile().getFullPathName());
e->setAttribute ("state", doc.getState());
}
}
XmlElement* RecentDocumentList::createXML() const
{
XmlElement* xml = new XmlElement ("RECENT_DOCUMENTS");
saveDocList (previousDocs, *xml->createNewChildElement ("PREVIOUS"));
saveDocList (nextDocs, *xml->createNewChildElement ("NEXT"));
return xml;
}