diff options
Diffstat (limited to 'utils/themeeditor/gui/skindocument.cpp')
-rw-r--r-- | utils/themeeditor/gui/skindocument.cpp | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/utils/themeeditor/gui/skindocument.cpp b/utils/themeeditor/gui/skindocument.cpp new file mode 100644 index 0000000000..82c7106051 --- /dev/null +++ b/utils/themeeditor/gui/skindocument.cpp | |||
@@ -0,0 +1,311 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 Robert Bieber | ||
11 | * | ||
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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "skindocument.h" | ||
23 | |||
24 | #include <QFile> | ||
25 | #include <QSettings> | ||
26 | #include <QColor> | ||
27 | #include <QMessageBox> | ||
28 | #include <QFileDialog> | ||
29 | |||
30 | #include <iostream> | ||
31 | |||
32 | SkinDocument::SkinDocument(QLabel* statusLabel, QWidget *parent) : | ||
33 | TabContent(parent), statusLabel(statusLabel) | ||
34 | { | ||
35 | setupUI(); | ||
36 | |||
37 | titleText = "Untitled"; | ||
38 | fileName = ""; | ||
39 | saved = ""; | ||
40 | parseStatus = tr("Empty document"); | ||
41 | blockUpdate = false; | ||
42 | } | ||
43 | |||
44 | SkinDocument::SkinDocument(QLabel* statusLabel, QString file, QWidget *parent): | ||
45 | TabContent(parent), fileName(file), statusLabel(statusLabel) | ||
46 | { | ||
47 | setupUI(); | ||
48 | blockUpdate = false; | ||
49 | |||
50 | /* Loading the file */ | ||
51 | if(QFile::exists(fileName)) | ||
52 | { | ||
53 | QFile fin(fileName); | ||
54 | fin.open(QFile::ReadOnly); | ||
55 | editor->document()->setPlainText(QString(fin.readAll())); | ||
56 | saved = editor->document()->toPlainText(); | ||
57 | editor->setTextCursor(QTextCursor(editor->document()->begin())); | ||
58 | fin.close(); | ||
59 | } | ||
60 | |||
61 | /* Setting the title */ | ||
62 | QStringList decomposed = fileName.split('/'); | ||
63 | titleText = decomposed.last(); | ||
64 | } | ||
65 | |||
66 | SkinDocument::~SkinDocument() | ||
67 | { | ||
68 | delete highlighter; | ||
69 | delete model; | ||
70 | } | ||
71 | |||
72 | void SkinDocument::connectPrefs(PreferencesDialog* prefs) | ||
73 | { | ||
74 | QObject::connect(prefs, SIGNAL(accepted()), | ||
75 | this, SLOT(settingsChanged())); | ||
76 | QObject::connect(prefs, SIGNAL(accepted()), | ||
77 | highlighter, SLOT(loadSettings())); | ||
78 | } | ||
79 | |||
80 | bool SkinDocument::requestClose() | ||
81 | { | ||
82 | /* Storing the response in blockUpdate will also block updates to the | ||
83 | status bar if the tab is being closed */ | ||
84 | if(editor->document()->toPlainText() != saved) | ||
85 | { | ||
86 | /* Spawning the "Are you sure?" dialog */ | ||
87 | QMessageBox confirm(this); | ||
88 | confirm.setWindowTitle(tr("Confirm Close")); | ||
89 | confirm.setText(titleText + tr(" has been modified.")); | ||
90 | confirm.setInformativeText(tr("Do you want to save your changes?")); | ||
91 | confirm.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | ||
92 | | QMessageBox::Cancel); | ||
93 | confirm.setDefaultButton(QMessageBox::Save); | ||
94 | int confirmation = confirm.exec(); | ||
95 | |||
96 | switch(confirmation) | ||
97 | { | ||
98 | case QMessageBox::Save: | ||
99 | save(); | ||
100 | /* After calling save, make sure the user actually went through */ | ||
101 | if(editor->document()->toPlainText() != saved) | ||
102 | blockUpdate = false; | ||
103 | else | ||
104 | blockUpdate = true; | ||
105 | break; | ||
106 | |||
107 | case QMessageBox::Discard: | ||
108 | blockUpdate = true; | ||
109 | break; | ||
110 | |||
111 | case QMessageBox::Cancel: | ||
112 | blockUpdate = false; | ||
113 | break; | ||
114 | } | ||
115 | } | ||
116 | else | ||
117 | blockUpdate = true; | ||
118 | |||
119 | return blockUpdate; | ||
120 | } | ||
121 | |||
122 | void SkinDocument::setupUI() | ||
123 | { | ||
124 | /* Setting up the text edit */ | ||
125 | layout = new QHBoxLayout; | ||
126 | editor = new CodeEditor(this); | ||
127 | editor->setLineWrapMode(QPlainTextEdit::NoWrap); | ||
128 | layout->addWidget(editor); | ||
129 | |||
130 | setLayout(layout); | ||
131 | |||
132 | /* Attaching the syntax highlighter */ | ||
133 | highlighter = new SkinHighlighter(editor->document()); | ||
134 | |||
135 | /* Setting up the model */ | ||
136 | model = new ParseTreeModel(""); | ||
137 | |||
138 | /* Connecting the editor's signal */ | ||
139 | QObject::connect(editor, SIGNAL(textChanged()), | ||
140 | this, SLOT(codeChanged())); | ||
141 | QObject::connect(editor, SIGNAL(cursorPositionChanged()), | ||
142 | this, SLOT(cursorChanged())); | ||
143 | |||
144 | settingsChanged(); | ||
145 | } | ||
146 | |||
147 | void SkinDocument::settingsChanged() | ||
148 | { | ||
149 | /* Setting the editor colors */ | ||
150 | QSettings settings; | ||
151 | settings.beginGroup("SkinDocument"); | ||
152 | |||
153 | QColor fg = settings.value("fgColor", Qt::black).value<QColor>(); | ||
154 | QColor bg = settings.value("bgColor", Qt::white).value<QColor>(); | ||
155 | QPalette palette; | ||
156 | palette.setColor(QPalette::All, QPalette::Base, bg); | ||
157 | palette.setColor(QPalette::All, QPalette::Text, fg); | ||
158 | editor->setPalette(palette); | ||
159 | |||
160 | QColor highlight = settings.value("errorColor", Qt::red).value<QColor>(); | ||
161 | editor->setErrorColor(highlight); | ||
162 | |||
163 | /* Setting the font */ | ||
164 | QFont def("Monospace"); | ||
165 | def.setStyleHint(QFont::TypeWriter); | ||
166 | QFont family = settings.value("fontFamily", def).value<QFont>(); | ||
167 | family.setPointSize(settings.value("fontSize", 12).toInt()); | ||
168 | editor->setFont(family); | ||
169 | |||
170 | editor->repaint(); | ||
171 | |||
172 | settings.endGroup(); | ||
173 | |||
174 | } | ||
175 | |||
176 | void SkinDocument::cursorChanged() | ||
177 | { | ||
178 | if(editor->isError(editor->textCursor().blockNumber() + 1)) | ||
179 | { | ||
180 | QTextCursor line = editor->textCursor(); | ||
181 | line.movePosition(QTextCursor::StartOfLine); | ||
182 | line.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor); | ||
183 | skin_parse(line.selectedText().toAscii()); | ||
184 | if(skin_error_line() > 0) | ||
185 | parseStatus = tr("Error on line ") + | ||
186 | QString::number(line.blockNumber() + 1) + tr(": ") + | ||
187 | skin_error_message(); | ||
188 | statusLabel->setText(parseStatus); | ||
189 | } | ||
190 | else if(editor->hasErrors()) | ||
191 | { | ||
192 | parseStatus = tr("Errors in document"); | ||
193 | statusLabel->setText(parseStatus); | ||
194 | } | ||
195 | else | ||
196 | { | ||
197 | emit lineChanged(editor->textCursor().blockNumber() + 1); | ||
198 | } | ||
199 | |||
200 | } | ||
201 | |||
202 | void SkinDocument::codeChanged() | ||
203 | { | ||
204 | if(blockUpdate) | ||
205 | return; | ||
206 | |||
207 | if(editor->document()->isEmpty()) | ||
208 | { | ||
209 | parseStatus = tr("Empty document"); | ||
210 | statusLabel->setText(parseStatus); | ||
211 | return; | ||
212 | } | ||
213 | |||
214 | editor->clearErrors(); | ||
215 | parseStatus = model->changeTree(editor->document()-> | ||
216 | toPlainText().toAscii()); | ||
217 | if(skin_error_line() > 0) | ||
218 | parseStatus = tr("Errors in document"); | ||
219 | statusLabel->setText(parseStatus); | ||
220 | |||
221 | /* Highlighting if an error was found */ | ||
222 | if(skin_error_line() > 0) | ||
223 | { | ||
224 | editor->addError(skin_error_line()); | ||
225 | |||
226 | /* Now we're going to attempt parsing again at each line, until we find | ||
227 | one that won't error out*/ | ||
228 | QTextDocument doc(editor->document()->toPlainText()); | ||
229 | int base = 0; | ||
230 | while(skin_error_line() > 0 && !doc.isEmpty()) | ||
231 | { | ||
232 | QTextCursor rest(&doc); | ||
233 | |||
234 | for(int i = 0; i < skin_error_line(); i++) | ||
235 | rest.movePosition(QTextCursor::NextBlock, | ||
236 | QTextCursor::KeepAnchor); | ||
237 | if(skin_error_line() == doc.blockCount()) | ||
238 | rest.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); | ||
239 | |||
240 | rest.removeSelectedText(); | ||
241 | base += skin_error_line(); | ||
242 | |||
243 | skin_parse(doc.toPlainText().toAscii()); | ||
244 | |||
245 | if(skin_error_line() > 0) | ||
246 | editor->addError(base + skin_error_line()); | ||
247 | |||
248 | } | ||
249 | } | ||
250 | |||
251 | if(editor->document()->toPlainText() != saved) | ||
252 | emit titleChanged(titleText + QChar('*')); | ||
253 | else | ||
254 | emit titleChanged(titleText); | ||
255 | |||
256 | cursorChanged(); | ||
257 | |||
258 | } | ||
259 | |||
260 | void SkinDocument::save() | ||
261 | { | ||
262 | QFile fout(fileName); | ||
263 | |||
264 | if(!fout.exists()) | ||
265 | { | ||
266 | saveAs(); | ||
267 | return; | ||
268 | } | ||
269 | |||
270 | fout.open(QFile::WriteOnly); | ||
271 | fout.write(editor->document()->toPlainText().toAscii()); | ||
272 | fout.close(); | ||
273 | |||
274 | saved = editor->document()->toPlainText(); | ||
275 | QStringList decompose = fileName.split('/'); | ||
276 | titleText = decompose.last(); | ||
277 | emit titleChanged(titleText); | ||
278 | |||
279 | } | ||
280 | |||
281 | void SkinDocument::saveAs() | ||
282 | { | ||
283 | /* Determining the directory to open */ | ||
284 | QString directory = fileName; | ||
285 | |||
286 | QSettings settings; | ||
287 | settings.beginGroup("SkinDocument"); | ||
288 | if(directory == "") | ||
289 | directory = settings.value("defaultDirectory", "").toString(); | ||
290 | |||
291 | fileName = QFileDialog::getSaveFileName(this, tr("Save Document"), | ||
292 | directory, fileFilter()); | ||
293 | directory = fileName; | ||
294 | if(fileName == "") | ||
295 | return; | ||
296 | |||
297 | directory.chop(fileName.length() - fileName.lastIndexOf('/') - 1); | ||
298 | settings.setValue("defaultDirectory", directory); | ||
299 | settings.endGroup(); | ||
300 | |||
301 | QFile fout(fileName); | ||
302 | fout.open(QFile::WriteOnly); | ||
303 | fout.write(editor->document()->toPlainText().toAscii()); | ||
304 | fout.close(); | ||
305 | |||
306 | saved = editor->document()->toPlainText(); | ||
307 | QStringList decompose = fileName.split('/'); | ||
308 | titleText = decompose[decompose.count() - 1]; | ||
309 | emit titleChanged(titleText); | ||
310 | |||
311 | } | ||