1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2010 Robert Bieber
12 * This program is free software; can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your optiyouon) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "skindocument.h"
27 #include <QMessageBox>
28 #include <QFileDialog>
34 const int SkinDocument::updateInterval
= 500;
36 SkinDocument::SkinDocument(QLabel
* statusLabel
, ProjectModel
* project
,
37 DeviceState
* device
, QWidget
*parent
)
38 :TabContent(parent
), statusLabel(statusLabel
),
39 project(project
), device(device
)
43 titleText
= "Untitled";
46 parseStatus
= tr("Empty document");
51 SkinDocument::SkinDocument(QLabel
* statusLabel
, QString file
,
52 ProjectModel
* project
, DeviceState
* device
,
54 :TabContent(parent
), fileName(file
),
55 statusLabel(statusLabel
), project(project
),
61 /* Loading the file */
62 if(QFile::exists(fileName
))
65 fin
.open(QFile::ReadOnly
);
66 editor
->document()->setPlainText(QString(fin
.readAll()));
67 saved
= editor
->document()->toPlainText();
68 editor
->setTextCursor(QTextCursor(editor
->document()->begin()));
72 /* Setting the title */
73 QStringList decomposed
= fileName
.split('/');
74 titleText
= decomposed
.last();
76 lastUpdate
= QTime::currentTime();
79 SkinDocument::~SkinDocument()
81 highlighter
->deleteLater();
85 void SkinDocument::connectPrefs(PreferencesDialog
* prefs
)
87 QObject::connect(prefs
, SIGNAL(accepted()),
88 this, SLOT(settingsChanged()));
89 QObject::connect(prefs
, SIGNAL(accepted()),
90 highlighter
, SLOT(loadSettings()));
93 bool SkinDocument::requestClose()
95 /* Storing the response in blockUpdate will also block updates to the
96 status bar if the tab is being closed */
97 if(editor
->document()->toPlainText() != saved
)
99 /* Spawning the "Are you sure?" dialog */
100 QMessageBox
confirm(this);
101 confirm
.setWindowTitle(tr("Confirm Close"));
102 confirm
.setText(titleText
+ tr(" has been modified."));
103 confirm
.setInformativeText(tr("Do you want to save your changes?"));
104 confirm
.setStandardButtons(QMessageBox::Save
| QMessageBox::Discard
105 | QMessageBox::Cancel
);
106 confirm
.setDefaultButton(QMessageBox::Save
);
107 int confirmation
= confirm
.exec();
111 case QMessageBox::Save
:
113 /* After calling save, make sure the user actually went through */
114 if(editor
->document()->toPlainText() != saved
)
120 case QMessageBox::Discard
:
124 case QMessageBox::Cancel
:
135 void SkinDocument::setupUI()
137 /* Setting up the text edit */
138 layout
= new QHBoxLayout
;
139 editor
= new CodeEditor(this);
140 editor
->setLineWrapMode(QPlainTextEdit::NoWrap
);
141 layout
->addWidget(editor
);
145 /* Attaching the syntax highlighter */
146 highlighter
= new SkinHighlighter(editor
->document());
148 /* Setting up the model */
149 model
= new ParseTreeModel("");
151 /* Connecting the editor's signal */
152 QObject::connect(editor
, SIGNAL(textChanged()),
153 this, SLOT(codeChanged()));
154 QObject::connect(editor
, SIGNAL(cursorPositionChanged()),
155 this, SLOT(cursorChanged()));
157 /* Connecting to device setting changes */
158 QObject::connect(device
, SIGNAL(settingsChanged()),
159 this, SLOT(deviceChanged()));
161 /* Attaching the find/replace dialog */
162 findReplace
= new FindReplaceDialog(this);
163 findReplace
->setModal(false);
164 findReplace
->setTextEdit(editor
);
169 /* Setting up a timer to check for updates */
170 checkUpdate
.setInterval(500);
171 QObject::connect(&checkUpdate
, SIGNAL(timeout()),
172 this, SLOT(codeChanged()));
175 void SkinDocument::settingsChanged()
177 /* Setting the editor colors */
179 settings
.beginGroup("SkinDocument");
181 QColor fg
= settings
.value("fgColor", Qt::black
).value
<QColor
>();
182 QColor bg
= settings
.value("bgColor", Qt::white
).value
<QColor
>();
184 palette
.setColor(QPalette::All
, QPalette::Base
, bg
);
185 palette
.setColor(QPalette::All
, QPalette::Text
, fg
);
186 editor
->setPalette(palette
);
188 QColor highlight
= settings
.value("errorColor", Qt::red
).value
<QColor
>();
189 editor
->setErrorColor(highlight
);
191 /* Setting the font */
192 QFont
def("Monospace");
193 def
.setStyleHint(QFont::TypeWriter
);
194 QFont family
= settings
.value("fontFamily", def
).value
<QFont
>();
195 family
.setPointSize(settings
.value("fontSize", 12).toInt());
196 editor
->setFont(family
);
204 void SkinDocument::cursorChanged()
206 if(editor
->isError(editor
->textCursor().blockNumber() + 1))
208 QTextCursor line
= editor
->textCursor();
209 line
.movePosition(QTextCursor::StartOfLine
);
210 line
.movePosition(QTextCursor::EndOfLine
, QTextCursor::KeepAnchor
);
211 skin_parse(line
.selectedText().toAscii());
212 if(skin_error_line() > 0)
213 parseStatus
= tr("Error on line ") +
214 QString::number(line
.blockNumber() + 1)
215 + tr(", column ") + QString::number(skin_error_col())
217 skin_error_message();
218 statusLabel
->setText(parseStatus
);
220 else if(editor
->hasErrors())
222 parseStatus
= tr("Errors in document");
223 statusLabel
->setText(parseStatus
);
225 else if(editor
->textCursor().blockNumber() != currentLine
)
227 currentLine
= editor
->textCursor().blockNumber();
228 emit
lineChanged(editor
->textCursor().blockNumber() + 1);
233 void SkinDocument::codeChanged()
238 if(editor
->document()->isEmpty())
240 parseStatus
= tr("Empty document");
241 statusLabel
->setText(parseStatus
);
245 editor
->clearErrors();
246 parseStatus
= model
->changeTree(editor
->document()->
247 toPlainText().toAscii());
248 if(skin_error_line() > 0)
249 parseStatus
= tr("Errors in document");
250 statusLabel
->setText(parseStatus
);
252 /* Highlighting if an error was found */
253 if(skin_error_line() > 0)
255 editor
->addError(skin_error_line());
257 /* Now we're going to attempt parsing again at each line, until we find
258 one that won't error out*/
259 QTextDocument
doc(editor
->document()->toPlainText());
261 while(skin_error_line() > 0 && !doc
.isEmpty())
263 QTextCursor
rest(&doc
);
265 for(int i
= 0; i
< skin_error_line(); i
++)
266 rest
.movePosition(QTextCursor::NextBlock
,
267 QTextCursor::KeepAnchor
);
268 if(skin_error_line() == doc
.blockCount())
269 rest
.movePosition(QTextCursor::End
, QTextCursor::KeepAnchor
);
271 rest
.removeSelectedText();
272 base
+= skin_error_line();
274 skin_parse(doc
.toPlainText().toAscii());
276 if(skin_error_line() > 0)
277 editor
->addError(base
+ skin_error_line());
282 if(editor
->document()->toPlainText() != saved
)
283 emit
titleChanged(titleText
+ QChar('*'));
285 emit
titleChanged(titleText
);
287 if(lastUpdate
.msecsTo(QTime::currentTime()) >= updateInterval
)
289 model
->render(project
, device
, &fileName
);
291 lastUpdate
= QTime::currentTime();
301 void SkinDocument::save()
303 QFile
fout(fileName
);
311 fout
.open(QFile::WriteOnly
);
312 fout
.write(editor
->document()->toPlainText().toAscii());
315 saved
= editor
->document()->toPlainText();
316 QStringList decompose
= fileName
.split('/');
317 titleText
= decompose
.last();
318 emit
titleChanged(titleText
);
324 void SkinDocument::saveAs()
326 /* Determining the directory to open */
327 QString directory
= fileName
;
330 settings
.beginGroup("SkinDocument");
332 directory
= settings
.value("defaultDirectory", "").toString();
334 fileName
= QFileDialog::getSaveFileName(this, tr("Save Document"),
335 directory
, fileFilter());
336 directory
= fileName
;
340 directory
.chop(fileName
.length() - fileName
.lastIndexOf('/') - 1);
341 settings
.setValue("defaultDirectory", directory
);
344 QFile
fout(fileName
);
345 fout
.open(QFile::WriteOnly
);
346 fout
.write(editor
->document()->toPlainText().toAscii());
349 saved
= editor
->document()->toPlainText();
350 QStringList decompose
= fileName
.split('/');
351 titleText
= decompose
[decompose
.count() - 1];
352 emit
titleChanged(titleText
);
358 QString
SkinDocument::findSetting(QString key
, QString fallback
)
363 return project
->getSetting(key
, fallback
);