Make it work for files also
[kugel-rb.git] / utils / themeeditor / gui / editorwindow.cpp
blobb81e41a2f58b9bb063dace4f7ab8a3c4a71c0b3c
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; you 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 option) 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 "editorwindow.h"
23 #include "projectmodel.h"
24 #include "ui_editorwindow.h"
25 #include "rbfontcache.h"
26 #include "rbtextcache.h"
28 #include <QDesktopWidget>
29 #include <QFileSystemModel>
30 #include <QSettings>
31 #include <QFileDialog>
32 #include <QGraphicsScene>
34 EditorWindow::EditorWindow(QWidget *parent) :
35 QMainWindow(parent), ui(new Ui::EditorWindow), parseTreeSelection(0)
37 ui->setupUi(this);
38 prefs = new PreferencesDialog(this);
39 project = 0;
40 setupUI();
41 loadSettings();
42 setupMenus();
46 EditorWindow::~EditorWindow()
48 delete ui;
49 delete prefs;
50 if(project)
51 delete project;
52 delete deviceConfig;
53 delete deviceDock;
55 RBFontCache::clearCache();
56 RBTextCache::clearCache();
59 void EditorWindow::loadTabFromSkinFile(QString fileName)
61 /* Checking to see if the file is already open */
62 for(int i = 0; i < ui->editorTabs->count(); i++)
64 TabContent* current = dynamic_cast<TabContent*>
65 (ui->editorTabs->widget(i));
66 if(current->file() == fileName)
68 ui->editorTabs->setCurrentIndex(i);
69 return;
73 /* Adding a new document*/
74 SkinDocument* doc = new SkinDocument(parseStatus, fileName, project,
75 deviceConfig);
76 addTab(doc);
77 ui->editorTabs->setCurrentWidget(doc);
81 void EditorWindow::loadConfigTab(ConfigDocument* doc)
83 for(int i = 0; i < ui->editorTabs->count(); i++)
85 TabContent* current = dynamic_cast<TabContent*>
86 (ui->editorTabs->widget(i));
87 if(current->file() == doc->file())
89 ui->editorTabs->setCurrentIndex(i);
90 doc->deleteLater();
91 return;
95 addTab(doc);
96 ui->editorTabs->setCurrentWidget(doc);
98 QObject::connect(doc, SIGNAL(titleChanged(QString)),
99 this, SLOT(tabTitleChanged(QString)));
102 void EditorWindow::loadSettings()
105 QSettings settings;
107 /* Main Window location */
108 settings.beginGroup("EditorWindow");
109 QSize size = settings.value("size").toSize();
110 QPoint pos = settings.value("position").toPoint();
111 QByteArray state = settings.value("state").toByteArray();
112 settings.endGroup();
114 if(!(size.isNull() || pos.isNull() || state.isNull()))
116 resize(size);
117 move(pos);
118 restoreState(state);
123 void EditorWindow::saveSettings()
126 QSettings settings;
128 /* Saving window and panel positions */
129 settings.beginGroup("EditorWindow");
130 settings.setValue("position", pos());
131 settings.setValue("size", size());
132 settings.setValue("state", saveState());
133 settings.endGroup();
136 void EditorWindow::setupUI()
138 /* Connecting the tab bar signals */
139 QObject::connect(ui->editorTabs, SIGNAL(currentChanged(int)),
140 this, SLOT(shiftTab(int)));
141 QObject::connect(ui->editorTabs, SIGNAL(tabCloseRequested(int)),
142 this, SLOT(closeTab(int)));
144 /* Connecting the code gen button */
145 QObject::connect(ui->fromTree, SIGNAL(pressed()),
146 this, SLOT(updateCurrent()));
148 /* Connecting the preferences dialog */
149 QObject::connect(ui->actionPreferences, SIGNAL(triggered()),
150 prefs, SLOT(exec()));
152 /* Setting up the parse status label */
153 parseStatus = new QLabel(this);
154 ui->statusbar->addPermanentWidget(parseStatus);
156 /* Setting the selection for parse tree highlighting initially NULL */
157 parseTreeSelection = 0;
159 /* Adding the skin viewer */
160 viewer = new SkinViewer(this);
161 ui->skinPreviewLayout->addWidget(viewer);
163 /* Positioning the device settings dialog */
164 deviceDock = new QDockWidget(tr("Device Configuration"), this);
165 deviceConfig = new DeviceState(deviceDock);
167 deviceDock->setObjectName("deviceDock");
168 deviceDock->setWidget(deviceConfig);
169 deviceDock->setFloating(true);
170 deviceDock->move(QPoint(x() + width() / 2, y() + height() / 2));
171 deviceDock->hide();
173 /* Positioning the timer panel */
174 timerDock = new QDockWidget(tr("Timer"), this);
175 timer = new SkinTimer(deviceConfig, timerDock);
177 timerDock->setObjectName("timerDock");
178 timerDock->setWidget(timer);
179 timerDock->setFloating(true);
180 timerDock->move(QPoint(x() + width() / 2, y() + height() / 2));
181 timerDock->hide();
183 shiftTab(-1);
186 void EditorWindow::setupMenus()
188 /* Connecting panel show actions */
189 QObject::connect(ui->actionFile_Panel, SIGNAL(triggered()),
190 this, SLOT(showPanel()));
191 QObject::connect(ui->actionDisplay_Panel, SIGNAL(triggered()),
192 this, SLOT(showPanel()));
193 QObject::connect(ui->actionPreview_Panel, SIGNAL(triggered()),
194 this, SLOT(showPanel()));
195 QObject::connect(ui->actionDevice_Configuration, SIGNAL(triggered()),
196 deviceDock, SLOT(show()));
197 QObject::connect(ui->actionTimer, SIGNAL(triggered()),
198 timerDock, SLOT(show()));
200 /* Connecting the document management actions */
201 QObject::connect(ui->actionNew_Document, SIGNAL(triggered()),
202 this, SLOT(newTab()));
203 QObject::connect(ui->actionToolbarNew, SIGNAL(triggered()),
204 this, SLOT(newTab()));
206 QObject::connect(ui->actionClose_Document, SIGNAL(triggered()),
207 this, SLOT(closeCurrent()));
209 QObject::connect(ui->actionSave_Document, SIGNAL(triggered()),
210 this, SLOT(saveCurrent()));
211 QObject::connect(ui->actionSave_Document_As, SIGNAL(triggered()),
212 this, SLOT(saveCurrentAs()));
213 QObject::connect(ui->actionToolbarSave, SIGNAL(triggered()),
214 this, SLOT(saveCurrent()));
216 QObject::connect(ui->actionOpen_Document, SIGNAL(triggered()),
217 this, SLOT(openFile()));
218 QObject::connect(ui->actionToolbarOpen, SIGNAL(triggered()),
219 this, SLOT(openFile()));
221 QObject::connect(ui->actionOpen_Project, SIGNAL(triggered()),
222 this, SLOT(openProject()));
224 /* Connecting the edit menu */
225 QObject::connect(ui->actionUndo, SIGNAL(triggered()),
226 this, SLOT(undo()));
227 QObject::connect(ui->actionRedo, SIGNAL(triggered()),
228 this, SLOT(redo()));
229 QObject::connect(ui->actionCut, SIGNAL(triggered()),
230 this, SLOT(cut()));
231 QObject::connect(ui->actionCopy, SIGNAL(triggered()),
232 this, SLOT(copy()));
233 QObject::connect(ui->actionPaste, SIGNAL(triggered()),
234 this, SLOT(paste()));
235 QObject::connect(ui->actionFind_Replace, SIGNAL(triggered()),
236 this, SLOT(findReplace()));
239 void EditorWindow::addTab(TabContent *doc)
241 ui->editorTabs->addTab(doc, doc->title());
243 /* Connecting to title change events */
244 QObject::connect(doc, SIGNAL(titleChanged(QString)),
245 this, SLOT(tabTitleChanged(QString)));
246 QObject::connect(doc, SIGNAL(lineChanged(int)),
247 this, SLOT(lineChanged(int)));
249 /* Connecting to settings change events */
250 if(doc->type() == TabContent::Skin)
251 dynamic_cast<SkinDocument*>(doc)->connectPrefs(prefs);
255 void EditorWindow::newTab()
257 SkinDocument* doc = new SkinDocument(parseStatus, project, deviceConfig);
258 addTab(doc);
259 ui->editorTabs->setCurrentWidget(doc);
262 void EditorWindow::shiftTab(int index)
264 TabContent* widget = dynamic_cast<TabContent*>
265 (ui->editorTabs->currentWidget());
266 if(index < 0)
268 ui->parseTree->setModel(0);
269 ui->actionSave_Document->setEnabled(false);
270 ui->actionSave_Document_As->setEnabled(false);
271 ui->actionClose_Document->setEnabled(false);
272 ui->actionToolbarSave->setEnabled(false);
273 ui->fromTree->setEnabled(false);
274 ui->actionUndo->setEnabled(false);
275 ui->actionRedo->setEnabled(false);
276 ui->actionCut->setEnabled(false);
277 ui->actionCopy->setEnabled(false);
278 ui->actionPaste->setEnabled(false);
279 ui->actionFind_Replace->setEnabled(false);
280 viewer->setScene(0);
282 else if(widget->type() == TabContent::Config)
284 ui->actionSave_Document->setEnabled(true);
285 ui->actionSave_Document_As->setEnabled(true);
286 ui->actionClose_Document->setEnabled(true);
287 ui->actionToolbarSave->setEnabled(true);
288 ui->actionUndo->setEnabled(false);
289 ui->actionRedo->setEnabled(false);
290 ui->actionCut->setEnabled(false);
291 ui->actionCopy->setEnabled(false);
292 ui->actionPaste->setEnabled(false);
293 ui->actionFind_Replace->setEnabled(false);
294 viewer->setScene(0);
296 else if(widget->type() == TabContent::Skin)
298 /* Syncing the tree view and the status bar */
299 SkinDocument* doc = dynamic_cast<SkinDocument*>(widget);
300 ui->parseTree->setModel(doc->getModel());
301 parseStatus->setText(doc->getStatus());
303 ui->actionSave_Document->setEnabled(true);
304 ui->actionSave_Document_As->setEnabled(true);
305 ui->actionClose_Document->setEnabled(true);
306 ui->actionToolbarSave->setEnabled(true);
307 ui->fromTree->setEnabled(true);
309 ui->actionUndo->setEnabled(true);
310 ui->actionRedo->setEnabled(true);
311 ui->actionCut->setEnabled(true);
312 ui->actionCopy->setEnabled(true);
313 ui->actionPaste->setEnabled(true);
314 ui->actionFind_Replace->setEnabled(true);
316 sizeColumns();
318 /* Syncing the preview */
319 viewer->setScene(doc->scene());
323 /* Hiding all the find/replace dialogs */
324 for(int i = 0; i < ui->editorTabs->count(); i++)
325 if(dynamic_cast<TabContent*>(ui->editorTabs->widget(i))->type() ==
326 TabContent::Skin)
327 dynamic_cast<SkinDocument*>(ui->editorTabs->widget(i))->hideFind();
331 bool EditorWindow::closeTab(int index)
333 TabContent* widget = dynamic_cast<TabContent*>
334 (ui->editorTabs->widget(index));
335 if(widget->requestClose())
337 ui->editorTabs->removeTab(index);
338 widget->deleteLater();
339 return true;
342 return false;
345 void EditorWindow::closeCurrent()
347 closeTab(ui->editorTabs->currentIndex());
350 void EditorWindow::saveCurrent()
352 if(ui->editorTabs->currentIndex() >= 0)
353 dynamic_cast<TabContent*>(ui->editorTabs->currentWidget())->save();
356 void EditorWindow::saveCurrentAs()
358 if(ui->editorTabs->currentIndex() >= 0)
359 dynamic_cast<TabContent*>(ui->editorTabs->currentWidget())->saveAs();
362 void EditorWindow::openFile()
364 QStringList fileNames;
365 QSettings settings;
367 settings.beginGroup("SkinDocument");
368 QString directory = settings.value("defaultDirectory", "").toString();
369 fileNames = QFileDialog::getOpenFileNames(this, tr("Open Files"), directory,
370 SkinDocument::fileFilter());
372 for(int i = 0; i < fileNames.count(); i++)
374 if(!QFile::exists(fileNames[i]))
375 continue;
377 QString current = fileNames[i];
379 loadTabFromSkinFile(current);
381 /* And setting the new default directory */
382 current.chop(current.length() - current.lastIndexOf('/') - 1);
383 settings.setValue("defaultDirectory", current);
387 settings.endGroup();
390 void EditorWindow::openProject()
392 QString fileName;
393 QSettings settings;
395 settings.beginGroup("ProjectModel");
396 QString directory = settings.value("defaultDirectory", "").toString();
397 fileName = QFileDialog::getOpenFileName(this, tr("Open Project"), directory,
398 ProjectModel::fileFilter());
400 if(QFile::exists(fileName))
403 if(project)
404 delete project;
406 project = new ProjectModel(fileName, this);
407 ui->projectTree->setModel(project);
409 if(project->getSetting("#screenwidth") != "")
410 deviceConfig->setData("screenwidth",
411 project->getSetting("#screenwidth"));
412 if(project->getSetting("#screenheight") != "")
413 deviceConfig->setData("screenheight",
414 project->getSetting("#screenheight"));
416 QObject::connect(ui->projectTree, SIGNAL(activated(QModelIndex)),
417 project, SLOT(activated(QModelIndex)));
419 fileName.chop(fileName.length() - fileName.lastIndexOf('/') - 1);
420 settings.setValue("defaultDirectory", fileName);
422 for(int i = 0; i < ui->editorTabs->count(); i++)
424 TabContent* doc = dynamic_cast<TabContent*>
425 (ui->editorTabs->widget(i));
426 if(doc->type() == TabContent::Skin)
428 dynamic_cast<SkinDocument*>(doc)->setProject(project);
429 if(i == ui->editorTabs->currentIndex())
431 viewer->setScene(dynamic_cast<SkinDocument*>(doc)->scene());
438 settings.endGroup();
442 void EditorWindow::configFileChanged(QString configFile)
445 if(QFile::exists(configFile))
448 if(project)
449 delete project;
451 project = new ProjectModel(configFile, this);
452 ui->projectTree->setModel(project);
454 QObject::connect(ui->projectTree, SIGNAL(activated(QModelIndex)),
455 project, SLOT(activated(QModelIndex)));
457 for(int i = 0; i < ui->editorTabs->count(); i++)
459 TabContent* doc = dynamic_cast<TabContent*>
460 (ui->editorTabs->widget(i));
461 if(doc->type() == TabContent::Skin)
463 dynamic_cast<SkinDocument*>(doc)->setProject(project);
464 if(i == ui->editorTabs->currentIndex())
466 viewer->setScene(dynamic_cast<SkinDocument*>(doc)->scene());
476 void EditorWindow::tabTitleChanged(QString title)
478 TabContent* sender = dynamic_cast<TabContent*>(QObject::sender());
479 ui->editorTabs->setTabText(ui->editorTabs->indexOf(sender), title);
482 void EditorWindow::showPanel()
484 if(sender() == ui->actionFile_Panel)
485 ui->projectDock->setVisible(true);
486 if(sender() == ui->actionPreview_Panel)
487 ui->skinPreviewDock->setVisible(true);
488 if(sender() == ui->actionDisplay_Panel)
489 ui->parseTreeDock->setVisible(true);
492 void EditorWindow::closeEvent(QCloseEvent* event)
495 saveSettings();
497 /* Closing all the tabs */
498 for(int i = 0; i < ui->editorTabs->count(); i++)
500 if(!dynamic_cast<TabContent*>
501 (ui->editorTabs->widget(i))->requestClose())
503 event->ignore();
504 return;
508 event->accept();
511 void EditorWindow::updateCurrent()
513 if(ui->editorTabs->currentIndex() < 0)
514 return;
516 dynamic_cast<SkinDocument*>
517 (ui->editorTabs->currentWidget())->genCode();
520 void EditorWindow::lineChanged(int line)
522 QSettings settings;
523 settings.beginGroup("EditorWindow");
525 if(settings.value("autoExpandTree", false).toBool())
527 ui->parseTree->collapseAll();
528 ParseTreeModel* model = dynamic_cast<ParseTreeModel*>
529 (ui->parseTree->model());
530 parseTreeSelection = new QItemSelectionModel(model);
531 expandLine(model, QModelIndex(), line,
532 settings.value("autoHighlightTree", false).toBool());
533 sizeColumns();
534 ui->parseTree->setSelectionModel(parseTreeSelection);
537 settings.endGroup();
540 void EditorWindow::undo()
542 TabContent* doc = dynamic_cast<TabContent*>
543 (ui->editorTabs->currentWidget());
544 if(doc->type() == TabContent::Skin)
545 dynamic_cast<SkinDocument*>(doc)->getEditor()->undo();
548 void EditorWindow::redo()
550 TabContent* doc = dynamic_cast<TabContent*>
551 (ui->editorTabs->currentWidget());
552 if(doc->type() == TabContent::Skin)
553 dynamic_cast<SkinDocument*>(doc)->getEditor()->redo();
557 void EditorWindow::cut()
559 TabContent* doc = dynamic_cast<TabContent*>
560 (ui->editorTabs->currentWidget());
561 if(doc->type() == TabContent::Skin)
562 dynamic_cast<SkinDocument*>(doc)->getEditor()->cut();
565 void EditorWindow::copy()
567 TabContent* doc = dynamic_cast<TabContent*>
568 (ui->editorTabs->currentWidget());
569 if(doc->type() == TabContent::Skin)
570 dynamic_cast<SkinDocument*>(doc)->getEditor()->copy();
573 void EditorWindow::paste()
575 TabContent* doc = dynamic_cast<TabContent*>
576 (ui->editorTabs->currentWidget());
577 if(doc->type() == TabContent::Skin)
578 dynamic_cast<SkinDocument*>(doc)->getEditor()->paste();
581 void EditorWindow::findReplace()
583 TabContent* doc = dynamic_cast<TabContent*>
584 (ui->editorTabs->currentWidget());
585 if(doc->type() == TabContent::Skin)
586 dynamic_cast<SkinDocument*>(doc)->showFind();
590 void EditorWindow::expandLine(ParseTreeModel* model, QModelIndex parent,
591 int line, bool highlight)
593 for(int i = 0; i < model->rowCount(parent); i++)
595 QModelIndex dataType = model->index(i, ParseTreeModel::typeColumn,
596 parent);
597 QModelIndex dataVal = model->index(i, ParseTreeModel::valueColumn,
598 parent);
599 QModelIndex data = model->index(i, ParseTreeModel::lineColumn, parent);
600 QModelIndex recurse = model->index(i, 0, parent);
602 expandLine(model, recurse, line, highlight);
604 if(model->data(data, Qt::DisplayRole) == line)
606 ui->parseTree->expand(parent);
607 ui->parseTree->expand(data);
608 ui->parseTree->scrollTo(parent, QAbstractItemView::PositionAtTop);
610 if(highlight)
612 parseTreeSelection->select(data,
613 QItemSelectionModel::Select);
614 parseTreeSelection->select(dataType,
615 QItemSelectionModel::Select);
616 parseTreeSelection->select(dataVal,
617 QItemSelectionModel::Select);
624 void EditorWindow::sizeColumns()
626 /* Setting the column widths */
627 ui->parseTree->resizeColumnToContents(ParseTreeModel::lineColumn);
628 ui->parseTree->resizeColumnToContents(ParseTreeModel::typeColumn);
629 ui->parseTree->resizeColumnToContents(ParseTreeModel::valueColumn);