Skip to content

Commit

Permalink
sc ide: enhance document management
Browse files Browse the repository at this point in the history
* Notify the user of unsaved documents when quitting.

* Notify the user on external modifications of documents.

* Implement document reloading from disk.
  • Loading branch information
jleben committed May 18, 2012
1 parent 173c4a2 commit cc14c61
Show file tree
Hide file tree
Showing 8 changed files with 611 additions and 93 deletions.
2 changes: 2 additions & 0 deletions editors/sc-ide/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ set ( ide_moc_hdr
widgets/multi_editor.hpp
widgets/doc_list.hpp
widgets/cmd_line.hpp
widgets/documents_dialog.hpp
widgets/code_editor/editor.hpp
widgets/code_editor/highlighter.hpp
widgets/code_editor/overlay.hpp
Expand All @@ -39,6 +40,7 @@ set ( ide_src
widgets/post_window.cpp
widgets/doc_list.cpp
widgets/cmd_line.cpp
widgets/documents_dialog.cpp
widgets/code_editor/editor.cpp
widgets/code_editor/highlighter.cpp
widgets/code_editor/overlay.cpp
Expand Down
119 changes: 68 additions & 51 deletions editors/sc-ide/core/doc_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@

using namespace ScIDE;

DocumentManager::DocumentManager( QObject *parent ):
QObject(parent)
{
connect(&mFsWatcher, SIGNAL(fileChanged(QString)), this, SLOT(onFileChanged(QString)));
}

void DocumentManager::create()
{
Document *doc = new Document();
Expand Down Expand Up @@ -56,9 +62,7 @@ void DocumentManager::open( const QString & filename, int initialCursorPosition
qWarning() << "DocumentManager: the file" << filename << "could not be opened for reading.";
return;
}

QByteArray bytes( file.readAll() );

file.close();

Document *doc = new Document();
Expand All @@ -69,95 +73,108 @@ void DocumentManager::open( const QString & filename, int initialCursorPosition

mDocHash.insert( doc->id(), doc );

mFsWatcher.addPath(filename);

Q_EMIT( opened(doc, initialCursorPosition) );
}

void DocumentManager::close( Document *doc, bool * p_ok )
bool DocumentManager::reload( Document *doc )
{
Q_ASSERT(doc);

bool ok = true;

if(doc->textDocument()->isModified()) {
QMessageBox::StandardButton ret;
ret = QMessageBox::warning(
NULL,
tr("SuperCollider IDE"),
tr("There are unsaved changes to document '%1'.\n"
"Do you want to save the document?").arg(doc->title()),
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel
);
if( ret == QMessageBox::Save ) {
save(doc, &ok);
}
else if( ret == QMessageBox::Cancel )
ok = false;
}
if (doc->mFileName.isEmpty())
return false;

if( ok && mDocHash.remove(doc->id()) == 0 ) {
qWarning("DocumentManager: trying to close an unmanaged document.");
ok = false;
QFile file(doc->mFileName);
if(!file.open(QIODevice::ReadOnly)) {
qWarning() << "DocumentManager: the file" << doc->mFileName << "could not be opened for reading.";
return false;
}
QByteArray bytes( file.readAll() );
file.close();

if(ok) {
Q_EMIT( closed(doc) );
delete doc;
}
doc->mDoc->setPlainText( QString::fromUtf8( bytes.data(), bytes.size() ) );
doc->mDoc->setModified(false);

if(p_ok) *p_ok = ok;
if (!mFsWatcher.files().contains(doc->mFileName))
mFsWatcher.addPath(doc->mFileName);

return true;
}

void DocumentManager::closeAll( bool * p_ok )
void DocumentManager::close( Document *doc )
{
bool ok = true;
QHash<QByteArray, Document*>::iterator it;
while((it = mDocHash.begin()) != mDocHash.end())
{
Document *doc = it.value();
close(doc, &ok);
if(!ok) break;
Q_ASSERT(doc);

if( mDocHash.remove(doc->id()) == 0 ) {
qWarning("DocumentManager: trying to close an unmanaged document.");
return;
}
if(p_ok) *p_ok = ok;

if (!doc->mFileName.isEmpty())
mFsWatcher.removePath(doc->mFileName);

Q_EMIT( closed(doc) );
delete doc;
}

void DocumentManager::save( Document *doc, bool * p_ok )
bool DocumentManager::save( Document *doc )
{
Q_ASSERT(doc);

bool ok = false;

if (!doc->mFileName.isEmpty())
ok = doSaveAs( doc, doc->mFileName );
if (doc->mFileName.isEmpty())
return false;

if(p_ok) *p_ok = ok;
return doSaveAs( doc, doc->mFileName );
}

void DocumentManager::saveAs( Document *doc, const QString & filename, bool * p_ok )
bool DocumentManager::saveAs( Document *doc, const QString & filename )
{
Q_ASSERT(doc);
bool ok = doSaveAs( doc, filename );
if(p_ok) *p_ok = ok;
return doSaveAs( doc, filename );
}

bool DocumentManager::doSaveAs( Document *doc, const QString & filename )
bool DocumentManager::doSaveAs( Document *doc, const QString & fileName )
{
Q_ASSERT(doc);

QFile file(filename);
QFile file(fileName);
if(!file.open(QIODevice::WriteOnly)) {
qWarning() << "DocumentManager: the file" << filename << "could not be opened for writing.";
qWarning() << "DocumentManager: the file" << fileName << "could not be opened for writing.";
return false;
}

QString str = doc->textDocument()->toPlainText();
file.write(str.toUtf8());
file.close();

doc->mFileName = filename;
doc->mTitle = QDir(filename).dirName();
doc->mFileName = fileName;
doc->mTitle = QDir(fileName).dirName();
doc->mDoc->setModified(false);
QFileInfo finfo(file);
doc->mSaveTime = finfo.lastModified();

// Always try to start watching, because the file could have been removed:
if (!mFsWatcher.files().contains(fileName))
mFsWatcher.addPath(fileName);

Q_EMIT(saved(doc));

return true;
}

void DocumentManager::onFileChanged( const QString & path )
{
DocIterator it;
for( it = mDocHash.begin(); it != mDocHash.end(); ++it )
{
Document *doc = it.value();
if (doc->mFileName == path) {
QFileInfo info(doc->mFileName);
if (doc->mSaveTime < info.lastModified()) {
doc->mDoc->setModified(true);
emit changedExternally(doc);
}
}
}
}
20 changes: 13 additions & 7 deletions editors/sc-ide/core/doc_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include <QTextDocument>
#include <QUuid>
#include <QHash>
#include <QFileSystemWatcher>
#include <QDateTime>

namespace ScIDE
{
Expand Down Expand Up @@ -54,6 +56,7 @@ class Document : public QObject
QTextDocument *mDoc;
QString mFileName;
QString mTitle;
QDateTime mSaveTime;
};

class DocumentManager : public QObject
Expand All @@ -62,34 +65,37 @@ class DocumentManager : public QObject

public:

DocumentManager( QObject *parent = 0 ) : QObject(parent) {}
DocumentManager( QObject *parent = 0 );
QList<Document*> documents() {
return mDocHash.values();
}

public Q_SLOTS:

void create();
// initialCursorPosition -1 means "don't change position if already open"
void open( const QString & filename, int initialCursorPosition = -1 );
void close( Document *, bool * ok = 0 );
void closeAll( bool * ok = 0 );
void save( Document *, bool * ok = 0 );
void saveAs( Document *, const QString & filename, bool * ok = 0 );
void close( Document * );
bool save( Document * );
bool saveAs( Document *, const QString & filename );
bool reload( Document * );

Q_SIGNALS:

void opened( Document *, int );
void closed( Document * );
void saved( Document * );
void showRequest( Document *, int pos = -1 );
void changedExternally( Document * );

private slots:
void onFileChanged( const QString & path );

private:
bool doSaveAs( Document *, const QString & filename );

typedef QHash<QByteArray, Document*>::iterator DocIterator;

QHash<QByteArray, Document*> mDocHash;
QFileSystemWatcher mFsWatcher;
};

} // namespace ScIDE
Expand Down
1 change: 1 addition & 0 deletions editors/sc-ide/core/settings/manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ void Manager::initDefaults()
setDefault("newDocument", tr("Ctrl+N", "New document"));
setDefault("openDocument", tr("Ctrl+O", "Open document"));
setDefault("saveDocument", tr("Ctrl+S", "Save document"));
setDefault("reloadDocument", tr("F5", "Reload document"));
setDefault("closeDocument", tr("Ctrl+W", "Close document"));
setDefault("undo", tr("Ctrl+Z", "Undo"));
setDefault("redo", tr("Ctrl+Shift+Z", "Redo"));
Expand Down
Loading

0 comments on commit cc14c61

Please sign in to comment.