Support new Fuzev2 revisions (fuzev2_variant == 1)
[kugel-rb.git] / utils / themeeditor / gui / skindocument.cpp
blob18877d14ee57ba914b5cc2a211d0c1cb976aa1d2
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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"
24 #include <QFile>
25 #include <QSettings>
26 #include <QColor>
27 #include <QMessageBox>
28 #include <QFileDialog>
30 #include <iostream>
32 #include <QDebug>
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)
41 setupUI();
43 titleText = "Untitled";
44 fileName = "";
45 saved = "";
46 parseStatus = tr("Empty document");
47 blockUpdate = false;
48 currentLine = -1;
51 SkinDocument::SkinDocument(QLabel* statusLabel, QString file,
52 ProjectModel* project, DeviceState* device,
53 QWidget *parent)
54 :TabContent(parent), fileName(file),
55 statusLabel(statusLabel), project(project),
56 device(device)
58 setupUI();
59 blockUpdate = false;
61 /* Loading the file */
62 if(QFile::exists(fileName))
64 QFile fin(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()));
69 fin.close();
72 /* Setting the title */
73 QStringList decomposed = fileName.split('/');
74 titleText = decomposed.last();
76 lastUpdate = QTime::currentTime();
79 SkinDocument::~SkinDocument()
81 highlighter->deleteLater();
82 model->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();
109 switch(confirmation)
111 case QMessageBox::Save:
112 save();
113 /* After calling save, make sure the user actually went through */
114 if(editor->document()->toPlainText() != saved)
115 blockUpdate = false;
116 else
117 blockUpdate = true;
118 break;
120 case QMessageBox::Discard:
121 blockUpdate = true;
122 break;
124 case QMessageBox::Cancel:
125 blockUpdate = false;
126 break;
129 else
130 blockUpdate = true;
132 return blockUpdate;
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);
143 setLayout(layout);
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);
165 findReplace->hide();
167 settingsChanged();
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 */
178 QSettings settings;
179 settings.beginGroup("SkinDocument");
181 QColor fg = settings.value("fgColor", Qt::black).value<QColor>();
182 QColor bg = settings.value("bgColor", Qt::white).value<QColor>();
183 QPalette palette;
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);
198 editor->repaint();
200 settings.endGroup();
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())
216 + tr(": ") +
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()
235 if(blockUpdate)
236 return;
238 if(editor->document()->isEmpty())
240 parseStatus = tr("Empty document");
241 statusLabel->setText(parseStatus);
242 return;
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());
260 int base = 0;
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('*'));
284 else
285 emit titleChanged(titleText);
287 if(lastUpdate.msecsTo(QTime::currentTime()) >= updateInterval)
289 model->render(project, device, &fileName);
290 checkUpdate.stop();
291 lastUpdate = QTime::currentTime();
293 else
295 checkUpdate.start();
297 cursorChanged();
301 void SkinDocument::save()
303 QFile fout(fileName);
305 if(!fout.exists())
307 saveAs();
308 return;
311 fout.open(QFile::WriteOnly);
312 fout.write(editor->document()->toPlainText().toAscii());
313 fout.close();
315 saved = editor->document()->toPlainText();
316 QStringList decompose = fileName.split('/');
317 titleText = decompose.last();
318 emit titleChanged(titleText);
320 scene();
324 void SkinDocument::saveAs()
326 /* Determining the directory to open */
327 QString directory = fileName;
329 QSettings settings;
330 settings.beginGroup("SkinDocument");
331 if(directory == "")
332 directory = settings.value("defaultDirectory", "").toString();
334 fileName = QFileDialog::getSaveFileName(this, tr("Save Document"),
335 directory, fileFilter());
336 directory = fileName;
337 if(fileName == "")
338 return;
340 directory.chop(fileName.length() - fileName.lastIndexOf('/') - 1);
341 settings.setValue("defaultDirectory", directory);
342 settings.endGroup();
344 QFile fout(fileName);
345 fout.open(QFile::WriteOnly);
346 fout.write(editor->document()->toPlainText().toAscii());
347 fout.close();
349 saved = editor->document()->toPlainText();
350 QStringList decompose = fileName.split('/');
351 titleText = decompose[decompose.count() - 1];
352 emit titleChanged(titleText);
354 scene();
358 QString SkinDocument::findSetting(QString key, QString fallback)
360 if(!project)
361 return fallback;
362 else
363 return project->getSetting(key, fallback);