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 "main_window.hpp"
24 #include "settings/manager.hpp"
25 #include "../../common/SC_TextUtils.hpp"
27 #include <QPlainTextDocumentLayout>
31 #include <QMessageBox>
33 #include <QApplication>
35 using namespace ScIDE
;
38 mId( QUuid::createUuid().toString().toAscii() ),
39 mDoc( new QTextDocument(this) ),
43 mDoc
->setDocumentLayout( new QPlainTextDocumentLayout(mDoc
) );
45 new SyntaxHighlighter(mDoc
);
47 connect( Main::instance(), SIGNAL(applySettingsRequest(Settings::Manager
*)),
48 this, SLOT(applySettings(Settings::Manager
*)) );
50 applySettings( Main::settings() );
53 void Document::applySettings( Settings::Manager
*settings
)
55 QFont font
= settings
->codeFont();
56 int indentWidth
= settings
->value("IDE/editor/indentWidth").toInt();
59 setIndentWidth(indentWidth
);
62 void Document::deleteTrailingSpaces()
64 QTextCursor
cursor (textDocument());
65 cursor
.beginEditBlock();
66 cursor
.movePosition(QTextCursor::EndOfBlock
);
67 QTextDocument
* doc
= textDocument();
69 while( !cursor
.atEnd() ) {
70 while( (cursor
.block().length() > 1) && doc
->characterAt(cursor
.position() - 1).isSpace())
71 cursor
.deletePreviousChar();
73 cursor
.movePosition(QTextCursor::NextBlock
);
74 cursor
.movePosition(QTextCursor::EndOfBlock
);
76 cursor
.endEditBlock();
79 void Document::setDefaultFont( const QFont
& font
)
81 mDoc
->setDefaultFont( font
);
82 // update tab stop, since it depends on font:
83 setIndentWidth( mIndentWidth
);
84 emit
defaultFontChanged();
87 void Document::resetDefaultFont()
89 Settings::Manager
*settings
= Main::settings();
90 setDefaultFont( settings
->codeFont() );
93 void Document::setIndentWidth( int numSpaces
)
95 mIndentWidth
= numSpaces
;
97 QFontMetricsF
fontMetrics( mDoc
->defaultFont() );
98 qreal tabStop
= fontMetrics
.width(' ') * numSpaces
;
100 QTextOption options
= mDoc
->defaultTextOption();
101 options
.setTabStop(tabStop
);
102 mDoc
->setDefaultTextOption(options
);
106 DocumentManager::DocumentManager( Main
*main
, Settings::Manager
* settings
):
109 connect(&mFsWatcher
, SIGNAL(fileChanged(QString
)), this, SLOT(onFileChanged(QString
)));
111 connect(main
, SIGNAL(storeSettingsRequest(Settings::Manager
*)),
112 this, SLOT(storeSettings(Settings::Manager
*)));
114 loadRecentDocuments( settings
);
117 Document
* DocumentManager::createDocument()
119 Document
*doc
= new Document();
120 mDocHash
.insert( doc
->id(), doc
);
124 void DocumentManager::create()
126 Document
*doc
= createDocument();
128 Q_EMIT( opened(doc
, 0, 0) );
131 Document
*DocumentManager::open( const QString
& path
, int initialCursorPosition
, int selectionLength
, bool toRecent
)
133 QFileInfo
info(path
);
134 QString cpath
= info
.canonicalFilePath();
137 if (cpath
.isEmpty()) {
138 MainWindow::instance()->showStatusMessage(QString("Cannot open file: %1 (file does not exist)").arg(path
));
142 // Check if file already opened
143 for( DocIterator it
= mDocHash
.begin(); it
!= mDocHash
.end(); ++it
) {
144 Document
*doc
= it
.value();
145 if(doc
->mFilePath
== cpath
) {
146 Q_EMIT( showRequest(doc
, initialCursorPosition
) );
147 if (toRecent
) addToRecent(doc
);
154 if(!file
.open(QIODevice::ReadOnly
)) {
155 MainWindow::instance()->showStatusMessage(QString("Cannot open file for reading: %1").arg(cpath
));
158 QByteArray
bytes( file
.readAll() );
163 QString filePath
= cpath
;
164 if (info
.suffix() == QString("rtf")) {
167 filePath
+= QString(".scd");
168 int result
= rtf2txt(bytes
.data());
169 bytes
= bytes
.left(result
);
170 QMessageBox::warning(NULL
, QString(tr("Opening RTF File")),
171 QString(tr("Warning: RTF file will be converted to plain-text scd file.")));
174 Document
*doc
= createDocument();
175 doc
->mDoc
->setPlainText( QString::fromUtf8( bytes
.data(), bytes
.size() ) );
176 doc
->mDoc
->setModified(false);
177 doc
->mFilePath
= filePath
;
178 doc
->mTitle
= info
.fileName();
180 mDocHash
.insert( doc
->id(), doc
);
183 mFsWatcher
.addPath(cpath
);
185 Q_EMIT( opened(doc
, initialCursorPosition
, selectionLength
) );
187 if (toRecent
) this->addToRecent(doc
);
192 bool DocumentManager::reload( Document
*doc
)
196 if (doc
->mFilePath
.isEmpty())
199 QFile
file(doc
->mFilePath
);
200 if(!file
.open(QIODevice::ReadOnly
)) {
201 MainWindow::instance()->showStatusMessage(QString("Cannot open file for reading: %1").arg(doc
->mFilePath
));
205 QByteArray
bytes( file
.readAll() );
208 doc
->mDoc
->setPlainText( QString::fromUtf8( bytes
.data(), bytes
.size() ) );
209 doc
->mDoc
->setModified(false);
211 if (!mFsWatcher
.files().contains(doc
->mFilePath
))
212 mFsWatcher
.addPath(doc
->mFilePath
);
217 void DocumentManager::close( Document
*doc
)
221 if( mDocHash
.remove(doc
->id()) == 0 ) {
222 qWarning("DocumentManager: trying to close an unmanaged document.");
226 if (!doc
->mFilePath
.isEmpty())
227 mFsWatcher
.removePath(doc
->mFilePath
);
229 Q_EMIT( closed(doc
) );
233 bool DocumentManager::save( Document
*doc
)
237 return doSaveAs( doc
, doc
->mFilePath
);
240 bool DocumentManager::saveAs( Document
*doc
, const QString
& path
)
244 if (path
.isEmpty()) {
245 qWarning() << "DocumentManager: the saving path is empty.";
249 bool ok
= doSaveAs( doc
, path
);
255 bool DocumentManager::doSaveAs( Document
*doc
, const QString
& path
)
259 doc
->deleteTrailingSpaces();
262 if(!file
.open(QIODevice::WriteOnly
)) {
263 qWarning() << "DocumentManager: the file" << path
<< "could not be opened for writing.";
267 QString str
= doc
->textDocument()->toPlainText();
268 file
.write(str
.toUtf8());
271 QFileInfo
info(path
);
272 QString cpath
= info
.canonicalFilePath();
274 doc
->mFilePath
= cpath
;
275 doc
->mTitle
= info
.fileName();
276 doc
->mDoc
->setModified(false);
277 doc
->mSaveTime
= info
.lastModified();
279 // Always try to start watching, because the file could have been removed:
280 if (!mFsWatcher
.files().contains(cpath
))
281 mFsWatcher
.addPath(cpath
);
288 void DocumentManager::onFileChanged( const QString
& path
)
291 for( it
= mDocHash
.begin(); it
!= mDocHash
.end(); ++it
)
293 Document
*doc
= it
.value();
294 if (doc
->mFilePath
== path
) {
295 QFileInfo
info(doc
->mFilePath
);
296 if (doc
->mSaveTime
< info
.lastModified()) {
297 doc
->mDoc
->setModified(true);
298 emit
changedExternally(doc
);
304 void DocumentManager::addToRecent( Document
*doc
)
306 const QString
&path
= doc
->mFilePath
;
307 int i
= mRecent
.indexOf(path
);
309 mRecent
.move( i
, 0 );
311 mRecent
.prepend(path
);
312 if (mRecent
.count() > mMaxRecent
)
313 mRecent
.removeLast();
316 emit
recentsChanged();
319 void DocumentManager::clearRecents()
322 emit
recentsChanged();
325 void DocumentManager::loadRecentDocuments( Settings::Manager
*settings
)
327 QVariantList list
= settings
->value("IDE/recentDocuments").value
<QVariantList
>();
329 foreach (const QVariant
& var
, list
)
330 mRecent
<< var
.toString();
333 void DocumentManager::storeSettings( Settings::Manager
*settings
)
336 foreach (const QString
& path
, mRecent
)
337 list
<< QVariant(path
);
339 settings
->setValue("IDE/recentDocuments", QVariant::fromValue
<QVariantList
>(list
));