1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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>
31 #include <QFileDialog>
32 #include <QGraphicsScene>
34 EditorWindow::EditorWindow(QWidget
*parent
) :
35 QMainWindow(parent
), ui(new Ui::EditorWindow
), parseTreeSelection(0)
38 prefs
= new PreferencesDialog(this);
46 EditorWindow::~EditorWindow()
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
);
73 /* Adding a new document*/
74 SkinDocument
* doc
= new SkinDocument(parseStatus
, fileName
, project
,
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
);
96 ui
->editorTabs
->setCurrentWidget(doc
);
98 QObject::connect(doc
, SIGNAL(titleChanged(QString
)),
99 this, SLOT(tabTitleChanged(QString
)));
102 void EditorWindow::loadSettings()
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();
114 if(!(size
.isNull() || pos
.isNull() || state
.isNull()))
123 void EditorWindow::saveSettings()
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());
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));
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));
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()),
227 QObject::connect(ui
->actionRedo
, SIGNAL(triggered()),
229 QObject::connect(ui
->actionCut
, SIGNAL(triggered()),
231 QObject::connect(ui
->actionCopy
, SIGNAL(triggered()),
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
);
259 ui
->editorTabs
->setCurrentWidget(doc
);
262 void EditorWindow::shiftTab(int index
)
264 TabContent
* widget
= dynamic_cast<TabContent
*>
265 (ui
->editorTabs
->currentWidget());
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);
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);
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);
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() ==
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();
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
;
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
]))
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
);
390 void EditorWindow::openProject()
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
))
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());
442 void EditorWindow::configFileChanged(QString configFile
)
445 if(QFile::exists(configFile
))
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
)
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())
511 void EditorWindow::updateCurrent()
513 if(ui
->editorTabs
->currentIndex() < 0)
516 dynamic_cast<SkinDocument
*>
517 (ui
->editorTabs
->currentWidget())->genCode();
520 void EditorWindow::lineChanged(int line
)
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());
534 ui
->parseTree
->setSelectionModel(parseTreeSelection
);
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
,
597 QModelIndex dataVal
= model
->index(i
, ParseTreeModel::valueColumn
,
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
);
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
);