Theme Editor: Added an edit menu with a find/replace function (copied from an LGPL...
[kugel-rb.git] / utils / themeeditor / gui / editorwindow.cpp
blobea6c91f0746cc49fe7cb242fa16fc5cc723c2698
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"
26 #include <QDesktopWidget>
27 #include <QFileSystemModel>
28 #include <QSettings>
29 #include <QFileDialog>
30 #include <QGraphicsScene>
32 EditorWindow::EditorWindow(QWidget *parent) :
33 QMainWindow(parent), ui(new Ui::EditorWindow), parseTreeSelection(0)
35 ui->setupUi(this);
36 prefs = new PreferencesDialog(this);
37 project = 0;
38 setupUI();
39 loadSettings();
40 setupMenus();
44 EditorWindow::~EditorWindow()
46 delete ui;
47 delete prefs;
48 if(project)
49 delete project;
50 delete deviceConfig;
51 delete deviceDock;
54 void EditorWindow::loadTabFromSkinFile(QString fileName)
56 /* Checking to see if the file is already open */
57 for(int i = 0; i < ui->editorTabs->count(); i++)
59 TabContent* current = dynamic_cast<TabContent*>
60 (ui->editorTabs->widget(i));
61 if(current->file() == fileName)
63 ui->editorTabs->setCurrentIndex(i);
64 return;
68 /* Adding a new document*/
69 SkinDocument* doc = new SkinDocument(parseStatus, fileName, project,
70 deviceConfig);
71 addTab(doc);
72 ui->editorTabs->setCurrentWidget(doc);
76 void EditorWindow::loadConfigTab(ConfigDocument* doc)
78 for(int i = 0; i < ui->editorTabs->count(); i++)
80 TabContent* current = dynamic_cast<TabContent*>
81 (ui->editorTabs->widget(i));
82 if(current->file() == doc->file())
84 ui->editorTabs->setCurrentIndex(i);
85 doc->deleteLater();
86 return;
90 addTab(doc);
91 ui->editorTabs->setCurrentWidget(doc);
93 QObject::connect(doc, SIGNAL(titleChanged(QString)),
94 this, SLOT(tabTitleChanged(QString)));
97 void EditorWindow::loadSettings()
100 QSettings settings;
102 /* Main Window location */
103 settings.beginGroup("EditorWindow");
104 QSize size = settings.value("size").toSize();
105 QPoint pos = settings.value("position").toPoint();
106 QByteArray state = settings.value("state").toByteArray();
107 settings.endGroup();
109 if(!(size.isNull() || pos.isNull() || state.isNull()))
111 resize(size);
112 move(pos);
113 restoreState(state);
118 void EditorWindow::saveSettings()
121 QSettings settings;
123 /* Saving window and panel positions */
124 settings.beginGroup("EditorWindow");
125 settings.setValue("position", pos());
126 settings.setValue("size", size());
127 settings.setValue("state", saveState());
128 settings.endGroup();
131 void EditorWindow::setupUI()
133 /* Connecting the tab bar signals */
134 QObject::connect(ui->editorTabs, SIGNAL(currentChanged(int)),
135 this, SLOT(shiftTab(int)));
136 QObject::connect(ui->editorTabs, SIGNAL(tabCloseRequested(int)),
137 this, SLOT(closeTab(int)));
139 /* Connecting the code gen button */
140 QObject::connect(ui->fromTree, SIGNAL(pressed()),
141 this, SLOT(updateCurrent()));
143 /* Connecting the preferences dialog */
144 QObject::connect(ui->actionPreferences, SIGNAL(triggered()),
145 prefs, SLOT(exec()));
147 /* Setting up the parse status label */
148 parseStatus = new QLabel(this);
149 ui->statusbar->addPermanentWidget(parseStatus);
151 /* Setting the selection for parse tree highlighting initially NULL */
152 parseTreeSelection = 0;
154 /* Adding the skin viewer */
155 viewer = new SkinViewer(this);
156 ui->skinPreviewLayout->addWidget(viewer);
158 /* Positioning the device settings dialog */
159 deviceDock = new QDockWidget(tr("Device Configuration"), this);
160 deviceConfig = new DeviceState(deviceDock);
162 deviceDock->setObjectName("deviceDock");
163 deviceDock->setWidget(deviceConfig);
164 deviceDock->setFloating(true);
165 deviceDock->hide();
168 void EditorWindow::setupMenus()
170 /* Connecting panel show actions */
171 QObject::connect(ui->actionFile_Panel, SIGNAL(triggered()),
172 this, SLOT(showPanel()));
173 QObject::connect(ui->actionDisplay_Panel, SIGNAL(triggered()),
174 this, SLOT(showPanel()));
175 QObject::connect(ui->actionPreview_Panel, SIGNAL(triggered()),
176 this, SLOT(showPanel()));
177 QObject::connect(ui->actionDevice_Configuration, SIGNAL(triggered()),
178 deviceDock, SLOT(show()));
180 /* Connecting the document management actions */
181 QObject::connect(ui->actionNew_Document, SIGNAL(triggered()),
182 this, SLOT(newTab()));
183 QObject::connect(ui->actionToolbarNew, SIGNAL(triggered()),
184 this, SLOT(newTab()));
186 QObject::connect(ui->actionClose_Document, SIGNAL(triggered()),
187 this, SLOT(closeCurrent()));
189 QObject::connect(ui->actionSave_Document, SIGNAL(triggered()),
190 this, SLOT(saveCurrent()));
191 QObject::connect(ui->actionSave_Document_As, SIGNAL(triggered()),
192 this, SLOT(saveCurrentAs()));
193 QObject::connect(ui->actionToolbarSave, SIGNAL(triggered()),
194 this, SLOT(saveCurrent()));
196 QObject::connect(ui->actionOpen_Document, SIGNAL(triggered()),
197 this, SLOT(openFile()));
198 QObject::connect(ui->actionToolbarOpen, SIGNAL(triggered()),
199 this, SLOT(openFile()));
201 QObject::connect(ui->actionOpen_Project, SIGNAL(triggered()),
202 this, SLOT(openProject()));
204 /* Connecting the edit menu */
205 QObject::connect(ui->actionUndo, SIGNAL(triggered()),
206 this, SLOT(undo()));
207 QObject::connect(ui->actionRedo, SIGNAL(triggered()),
208 this, SLOT(redo()));
209 QObject::connect(ui->actionCut, SIGNAL(triggered()),
210 this, SLOT(cut()));
211 QObject::connect(ui->actionCopy, SIGNAL(triggered()),
212 this, SLOT(copy()));
213 QObject::connect(ui->actionPaste, SIGNAL(triggered()),
214 this, SLOT(paste()));
215 QObject::connect(ui->actionFind_Replace, SIGNAL(triggered()),
216 this, SLOT(findReplace()));
219 void EditorWindow::addTab(TabContent *doc)
221 ui->editorTabs->addTab(doc, doc->title());
223 /* Connecting to title change events */
224 QObject::connect(doc, SIGNAL(titleChanged(QString)),
225 this, SLOT(tabTitleChanged(QString)));
226 QObject::connect(doc, SIGNAL(lineChanged(int)),
227 this, SLOT(lineChanged(int)));
229 /* Connecting to settings change events */
230 if(doc->type() == TabContent::Skin)
231 dynamic_cast<SkinDocument*>(doc)->connectPrefs(prefs);
235 void EditorWindow::newTab()
237 SkinDocument* doc = new SkinDocument(parseStatus, project, deviceConfig);
238 addTab(doc);
239 ui->editorTabs->setCurrentWidget(doc);
242 void EditorWindow::shiftTab(int index)
244 TabContent* widget = dynamic_cast<TabContent*>
245 (ui->editorTabs->currentWidget());
246 if(index < 0)
248 ui->parseTree->setModel(0);
249 ui->actionSave_Document->setEnabled(false);
250 ui->actionSave_Document_As->setEnabled(false);
251 ui->actionClose_Document->setEnabled(false);
252 ui->actionToolbarSave->setEnabled(false);
253 ui->fromTree->setEnabled(false);
254 ui->actionUndo->setEnabled(false);
255 ui->actionRedo->setEnabled(false);
256 ui->actionCut->setEnabled(false);
257 ui->actionCopy->setEnabled(false);
258 ui->actionPaste->setEnabled(false);
259 ui->actionFind_Replace->setEnabled(false);
260 viewer->setScene(0);
262 else if(widget->type() == TabContent::Config)
264 ui->actionSave_Document->setEnabled(true);
265 ui->actionSave_Document_As->setEnabled(true);
266 ui->actionClose_Document->setEnabled(true);
267 ui->actionToolbarSave->setEnabled(true);
268 ui->actionUndo->setEnabled(false);
269 ui->actionRedo->setEnabled(false);
270 ui->actionCut->setEnabled(false);
271 ui->actionCopy->setEnabled(false);
272 ui->actionPaste->setEnabled(false);
273 ui->actionFind_Replace->setEnabled(false);
274 viewer->setScene(0);
276 else if(widget->type() == TabContent::Skin)
278 /* Syncing the tree view and the status bar */
279 SkinDocument* doc = dynamic_cast<SkinDocument*>(widget);
280 ui->parseTree->setModel(doc->getModel());
281 parseStatus->setText(doc->getStatus());
283 ui->actionSave_Document->setEnabled(true);
284 ui->actionSave_Document_As->setEnabled(true);
285 ui->actionClose_Document->setEnabled(true);
286 ui->actionToolbarSave->setEnabled(true);
287 ui->fromTree->setEnabled(true);
289 ui->actionUndo->setEnabled(true);
290 ui->actionRedo->setEnabled(true);
291 ui->actionCut->setEnabled(true);
292 ui->actionCopy->setEnabled(true);
293 ui->actionPaste->setEnabled(true);
294 ui->actionFind_Replace->setEnabled(true);
296 sizeColumns();
298 /* Syncing the preview */
299 viewer->setScene(doc->scene());
303 /* Hiding all the find/replace dialogs */
304 for(int i = 0; i < ui->editorTabs->count(); i++)
305 if(dynamic_cast<TabContent*>(ui->editorTabs->widget(i))->type() ==
306 TabContent::Skin)
307 dynamic_cast<SkinDocument*>(ui->editorTabs->widget(i))->hideFind();
311 bool EditorWindow::closeTab(int index)
313 TabContent* widget = dynamic_cast<TabContent*>
314 (ui->editorTabs->widget(index));
315 if(widget->requestClose())
317 ui->editorTabs->removeTab(index);
318 widget->deleteLater();
319 return true;
322 return false;
325 void EditorWindow::closeCurrent()
327 closeTab(ui->editorTabs->currentIndex());
330 void EditorWindow::saveCurrent()
332 if(ui->editorTabs->currentIndex() >= 0)
333 dynamic_cast<TabContent*>(ui->editorTabs->currentWidget())->save();
336 void EditorWindow::saveCurrentAs()
338 if(ui->editorTabs->currentIndex() >= 0)
339 dynamic_cast<TabContent*>(ui->editorTabs->currentWidget())->saveAs();
342 void EditorWindow::openFile()
344 QStringList fileNames;
345 QSettings settings;
347 settings.beginGroup("SkinDocument");
348 QString directory = settings.value("defaultDirectory", "").toString();
349 fileNames = QFileDialog::getOpenFileNames(this, tr("Open Files"), directory,
350 SkinDocument::fileFilter());
352 for(int i = 0; i < fileNames.count(); i++)
354 if(!QFile::exists(fileNames[i]))
355 continue;
357 QString current = fileNames[i];
359 loadTabFromSkinFile(current);
361 /* And setting the new default directory */
362 current.chop(current.length() - current.lastIndexOf('/') - 1);
363 settings.setValue("defaultDirectory", current);
367 settings.endGroup();
370 void EditorWindow::openProject()
372 QString fileName;
373 QSettings settings;
375 settings.beginGroup("ProjectModel");
376 QString directory = settings.value("defaultDirectory", "").toString();
377 fileName = QFileDialog::getOpenFileName(this, tr("Open Project"), directory,
378 ProjectModel::fileFilter());
380 if(QFile::exists(fileName))
383 if(project)
384 delete project;
386 project = new ProjectModel(fileName, this);
387 ui->projectTree->setModel(project);
389 if(project->getSetting("#screenwidth") != "")
390 deviceConfig->setData("screenwidth",
391 project->getSetting("#screenwidth"));
392 if(project->getSetting("#screenheight") != "")
393 deviceConfig->setData("screenheight",
394 project->getSetting("#screenheight"));
396 QObject::connect(ui->projectTree, SIGNAL(activated(QModelIndex)),
397 project, SLOT(activated(QModelIndex)));
399 fileName.chop(fileName.length() - fileName.lastIndexOf('/') - 1);
400 settings.setValue("defaultDirectory", fileName);
402 for(int i = 0; i < ui->editorTabs->count(); i++)
404 TabContent* doc = dynamic_cast<TabContent*>
405 (ui->editorTabs->widget(i));
406 if(doc->type() == TabContent::Skin)
408 dynamic_cast<SkinDocument*>(doc)->setProject(project);
409 if(i == ui->editorTabs->currentIndex())
411 viewer->setScene(dynamic_cast<SkinDocument*>(doc)->scene());
418 settings.endGroup();
422 void EditorWindow::configFileChanged(QString configFile)
425 if(QFile::exists(configFile))
428 if(project)
429 delete project;
431 project = new ProjectModel(configFile, this);
432 ui->projectTree->setModel(project);
434 QObject::connect(ui->projectTree, SIGNAL(activated(QModelIndex)),
435 project, SLOT(activated(QModelIndex)));
437 for(int i = 0; i < ui->editorTabs->count(); i++)
439 TabContent* doc = dynamic_cast<TabContent*>
440 (ui->editorTabs->widget(i));
441 if(doc->type() == TabContent::Skin)
443 dynamic_cast<SkinDocument*>(doc)->setProject(project);
444 if(i == ui->editorTabs->currentIndex())
446 viewer->setScene(dynamic_cast<SkinDocument*>(doc)->scene());
456 void EditorWindow::tabTitleChanged(QString title)
458 TabContent* sender = dynamic_cast<TabContent*>(QObject::sender());
459 ui->editorTabs->setTabText(ui->editorTabs->indexOf(sender), title);
462 void EditorWindow::showPanel()
464 if(sender() == ui->actionFile_Panel)
465 ui->projectDock->setVisible(true);
466 if(sender() == ui->actionPreview_Panel)
467 ui->skinPreviewDock->setVisible(true);
468 if(sender() == ui->actionDisplay_Panel)
469 ui->parseTreeDock->setVisible(true);
472 void EditorWindow::closeEvent(QCloseEvent* event)
475 saveSettings();
477 /* Closing all the tabs */
478 for(int i = 0; i < ui->editorTabs->count(); i++)
480 if(!dynamic_cast<TabContent*>
481 (ui->editorTabs->widget(i))->requestClose())
483 event->ignore();
484 return;
488 event->accept();
491 void EditorWindow::updateCurrent()
493 if(ui->editorTabs->currentIndex() < 0)
494 return;
496 dynamic_cast<SkinDocument*>
497 (ui->editorTabs->currentWidget())->genCode();
500 void EditorWindow::lineChanged(int line)
502 ui->parseTree->collapseAll();
503 ParseTreeModel* model = dynamic_cast<ParseTreeModel*>
504 (ui->parseTree->model());
505 parseTreeSelection = new QItemSelectionModel(model);
506 expandLine(model, QModelIndex(), line);
507 sizeColumns();
508 ui->parseTree->setSelectionModel(parseTreeSelection);
512 void EditorWindow::undo()
514 TabContent* doc = dynamic_cast<TabContent*>
515 (ui->editorTabs->currentWidget());
516 if(doc->type() == TabContent::Skin)
517 dynamic_cast<SkinDocument*>(doc)->getEditor()->undo();
520 void EditorWindow::redo()
522 TabContent* doc = dynamic_cast<TabContent*>
523 (ui->editorTabs->currentWidget());
524 if(doc->type() == TabContent::Skin)
525 dynamic_cast<SkinDocument*>(doc)->getEditor()->redo();
529 void EditorWindow::cut()
531 TabContent* doc = dynamic_cast<TabContent*>
532 (ui->editorTabs->currentWidget());
533 if(doc->type() == TabContent::Skin)
534 dynamic_cast<SkinDocument*>(doc)->getEditor()->cut();
537 void EditorWindow::copy()
539 TabContent* doc = dynamic_cast<TabContent*>
540 (ui->editorTabs->currentWidget());
541 if(doc->type() == TabContent::Skin)
542 dynamic_cast<SkinDocument*>(doc)->getEditor()->copy();
545 void EditorWindow::paste()
547 TabContent* doc = dynamic_cast<TabContent*>
548 (ui->editorTabs->currentWidget());
549 if(doc->type() == TabContent::Skin)
550 dynamic_cast<SkinDocument*>(doc)->getEditor()->paste();
553 void EditorWindow::findReplace()
555 TabContent* doc = dynamic_cast<TabContent*>
556 (ui->editorTabs->currentWidget());
557 if(doc->type() == TabContent::Skin)
558 dynamic_cast<SkinDocument*>(doc)->showFind();
562 void EditorWindow::expandLine(ParseTreeModel* model, QModelIndex parent,
563 int line)
565 for(int i = 0; i < model->rowCount(parent); i++)
567 QModelIndex dataType = model->index(i, ParseTreeModel::typeColumn,
568 parent);
569 QModelIndex dataVal = model->index(i, ParseTreeModel::valueColumn,
570 parent);
571 QModelIndex data = model->index(i, ParseTreeModel::lineColumn, parent);
572 QModelIndex recurse = model->index(i, 0, parent);
574 expandLine(model, recurse, line);
576 if(model->data(data, Qt::DisplayRole) == line)
578 ui->parseTree->expand(parent);
579 ui->parseTree->expand(data);
580 ui->parseTree->scrollTo(parent, QAbstractItemView::PositionAtTop);
582 parseTreeSelection->select(data, QItemSelectionModel::Select);
583 parseTreeSelection->select(dataType, QItemSelectionModel::Select);
584 parseTreeSelection->select(dataVal, QItemSelectionModel::Select);
590 void EditorWindow::sizeColumns()
592 /* Setting the column widths */
593 ui->parseTree->resizeColumnToContents(ParseTreeModel::lineColumn);
594 ui->parseTree->resizeColumnToContents(ParseTreeModel::typeColumn);
595 ui->parseTree->resizeColumnToContents(ParseTreeModel::valueColumn);