3 Copyright (c) 2012 Jakob Leben & Tim Blechmann
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "doc_manager.hpp"
23 #include "settings/manager.hpp"
24 #include "../../common/SC_TextUtils.hpp"
26 #include <QPlainTextDocumentLayout>
30 #include <QMessageBox>
32 #include <QApplication>
34 using namespace ScIDE
;
37 mId( QUuid::createUuid().toString().toAscii() ),
38 mDoc( new QTextDocument(this) ),
42 mDoc
->setDocumentLayout( new QPlainTextDocumentLayout(mDoc
) );
44 new SyntaxHighlighter(mDoc
);
46 connect( Main::instance(), SIGNAL(applySettingsRequest(Settings::Manager
*)),
47 this, SLOT(applySettings(Settings::Manager
*)) );
49 applySettings( Main::settings() );
52 void Document::applySettings( Settings::Manager
*settings
)
54 QFont font
= settings
->codeFont();
55 int indentWidth
= settings
->value("IDE/editor/indentWidth").toInt();
58 setIndentWidth(indentWidth
);
61 void Document::deleteTrailingSpaces()
63 QTextCursor
cursor (textDocument());
64 cursor
.beginEditBlock();
65 cursor
.movePosition(QTextCursor::EndOfBlock
);
66 QTextDocument
* doc
= textDocument();
68 while( !cursor
.atEnd() ) {
69 while( (cursor
.block().length() > 1) && doc
->characterAt(cursor
.position() - 1).isSpace())
70 cursor
.deletePreviousChar();
72 cursor
.movePosition(QTextCursor::NextBlock
);
73 cursor
.movePosition(QTextCursor::EndOfBlock
);
75 cursor
.endEditBlock();
78 void Document::setDefaultFont( const QFont
& font
)
80 mDoc
->setDefaultFont( font
);
81 // update tab stop, since it depends on font:
82 setIndentWidth( mIndentWidth
);
83 emit
defaultFontChanged();
86 void Document::resetDefaultFont()
88 Settings::Manager
*settings
= Main::settings();
89 setDefaultFont( settings
->codeFont() );
92 void Document::setIndentWidth( int numSpaces
)
94 mIndentWidth
= numSpaces
;
96 QFontMetricsF
fontMetrics( mDoc
->defaultFont() );
97 qreal tabStop
= fontMetrics
.width(' ') * numSpaces
;
99 QTextOption options
= mDoc
->defaultTextOption();
100 options
.setTabStop(tabStop
);
101 mDoc
->setDefaultTextOption(options
);
105 DocumentManager::DocumentManager( Main
*main
, Settings::Manager
* settings
):
108 connect(&mFsWatcher
, SIGNAL(fileChanged(QString
)), this, SLOT(onFileChanged(QString
)));
110 connect(main
, SIGNAL(storeSettingsRequest(Settings::Manager
*)),
111 this, SLOT(storeSettings(Settings::Manager
*)));
113 loadRecentDocuments( settings
);
116 Document
* DocumentManager::createDocument()
118 Document
*doc
= new Document();
119 mDocHash
.insert( doc
->id(), doc
);
123 void DocumentManager::create()
125 Document
*doc
= createDocument();
127 Q_EMIT( opened(doc
, 0, 0) );
130 Document
*DocumentManager::open( const QString
& path
, int initialCursorPosition
, int selectionLength
, bool toRecent
)
132 QFileInfo
info(path
);
133 QString cpath
= info
.canonicalFilePath();
136 if (cpath
.isEmpty()) {
137 qWarning() << "DocumentManager: Can not open file: canonical path is empty.";
141 // Check if file already opened
142 for( DocIterator it
= mDocHash
.begin(); it
!= mDocHash
.end(); ++it
) {
143 Document
*doc
= it
.value();
144 if(doc
->mFilePath
== cpath
) {
145 Q_EMIT( showRequest(doc
, initialCursorPosition
) );
146 if (toRecent
) addToRecent(doc
);
153 if(!file
.open(QIODevice::ReadOnly
)) {
154 qWarning() << "DocumentManager: the file" << cpath
<< "could not be opened for reading.";
157 QByteArray
bytes( file
.readAll() );
162 QString filePath
= cpath
;
163 if (info
.suffix() == QString("rtf")) {
166 filePath
+= QString(".scd");
167 int result
= rtf2txt(bytes
.data());
168 bytes
= bytes
.left(result
);
169 QMessageBox::warning(NULL
, QString(tr("Opening RTF File")),
170 QString(tr("Warning: RTF file will be converted to plain-text scd file.")));
173 Document
*doc
= createDocument();
174 doc
->mDoc
->setPlainText( QString::fromUtf8( bytes
.data(), bytes
.size() ) );
175 doc
->mDoc
->setModified(false);
176 doc
->mFilePath
= filePath
;
177 doc
->mTitle
= info
.fileName();
179 mDocHash
.insert( doc
->id(), doc
);
182 mFsWatcher
.addPath(cpath
);
184 Q_EMIT( opened(doc
, initialCursorPosition
, selectionLength
) );
186 if (toRecent
) this->addToRecent(doc
);
191 bool DocumentManager::reload( Document
*doc
)
195 if (doc
->mFilePath
.isEmpty())
198 QFile
file(doc
->mFilePath
);
199 if(!file
.open(QIODevice::ReadOnly
)) {
200 qWarning() << "DocumentManager: the file" << doc
->mFilePath
<< "could not be opened for reading.";
203 QByteArray
bytes( file
.readAll() );
206 doc
->mDoc
->setPlainText( QString::fromUtf8( bytes
.data(), bytes
.size() ) );
207 doc
->mDoc
->setModified(false);
209 if (!mFsWatcher
.files().contains(doc
->mFilePath
))
210 mFsWatcher
.addPath(doc
->mFilePath
);
215 void DocumentManager::close( Document
*doc
)
219 if( mDocHash
.remove(doc
->id()) == 0 ) {
220 qWarning("DocumentManager: trying to close an unmanaged document.");
224 if (!doc
->mFilePath
.isEmpty())
225 mFsWatcher
.removePath(doc
->mFilePath
);
227 Q_EMIT( closed(doc
) );
231 bool DocumentManager::save( Document
*doc
)
235 return doSaveAs( doc
, doc
->mFilePath
);
238 bool DocumentManager::saveAs( Document
*doc
, const QString
& path
)
242 if (path
.isEmpty()) {
243 qWarning() << "DocumentManager: the saving path is empty.";
247 bool ok
= doSaveAs( doc
, path
);
253 bool DocumentManager::doSaveAs( Document
*doc
, const QString
& path
)
257 doc
->deleteTrailingSpaces();
260 if(!file
.open(QIODevice::WriteOnly
)) {
261 qWarning() << "DocumentManager: the file" << path
<< "could not be opened for writing.";
265 QString str
= doc
->textDocument()->toPlainText();
266 file
.write(str
.toUtf8());
269 QFileInfo
info(path
);
270 QString cpath
= info
.canonicalFilePath();
272 doc
->mFilePath
= cpath
;
273 doc
->mTitle
= info
.fileName();
274 doc
->mDoc
->setModified(false);
275 doc
->mSaveTime
= info
.lastModified();
277 // Always try to start watching, because the file could have been removed:
278 if (!mFsWatcher
.files().contains(cpath
))
279 mFsWatcher
.addPath(cpath
);
286 void DocumentManager::onFileChanged( const QString
& path
)
289 for( it
= mDocHash
.begin(); it
!= mDocHash
.end(); ++it
)
291 Document
*doc
= it
.value();
292 if (doc
->mFilePath
== path
) {
293 QFileInfo
info(doc
->mFilePath
);
294 if (doc
->mSaveTime
< info
.lastModified()) {
295 doc
->mDoc
->setModified(true);
296 emit
changedExternally(doc
);
302 void DocumentManager::addToRecent( Document
*doc
)
304 const QString
&path
= doc
->mFilePath
;
305 int i
= mRecent
.indexOf(path
);
307 mRecent
.move( i
, 0 );
309 mRecent
.prepend(path
);
310 if (mRecent
.count() > mMaxRecent
)
311 mRecent
.removeLast();
314 emit
recentsChanged();
317 void DocumentManager::clearRecents()
320 emit
recentsChanged();
323 void DocumentManager::loadRecentDocuments( Settings::Manager
*settings
)
325 QVariantList list
= settings
->value("IDE/recentDocuments").value
<QVariantList
>();
327 foreach (const QVariant
& var
, list
)
328 mRecent
<< var
.toString();
331 void DocumentManager::storeSettings( Settings::Manager
*settings
)
334 foreach (const QString
& path
, mRecent
)
335 list
<< QVariant(path
);
337 settings
->setValue("IDE/recentDocuments", QVariant::fromValue
<QVariantList
>(list
));