A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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; 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.
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 "editorwindow.h"
23#include "projectmodel.h"
24#include "ui_editorwindow.h"
25#include "rbfontcache.h"
26#include "rbtextcache.h"
27#include "newprojectdialog.h"
28#include "projectexporter.h"
29
30#include <QFileSystemModel>
31#include <QSettings>
32#include <QFileDialog>
33#include <QMessageBox>
34#include <QGraphicsScene>
35#include <QDir>
36#include <QFile>
37
38const int EditorWindow::numRecent = 5;
39
40EditorWindow::EditorWindow(QWidget *parent) :
41 QMainWindow(parent), ui(new Ui::EditorWindow), parseTreeSelection(0)
42{
43 ui->setupUi(this);
44 prefs = new PreferencesDialog(this);
45 project = 0;
46 setupUI();
47 loadSettings();
48 setupMenus();
49}
50
51
52EditorWindow::~EditorWindow()
53{
54 delete ui;
55 delete prefs;
56 if(project)
57 delete project;
58 delete deviceConfig;
59 delete deviceDock;
60 delete timer;
61 delete timerDock;
62
63 RBFontCache::clearCache();
64 RBTextCache::clearCache();
65}
66
67void EditorWindow::loadTabFromSkinFile(QString fileName)
68{
69 docToTop(fileName);
70
71 /* Checking to see if the file is already open */
72 for(int i = 0; i < ui->editorTabs->count(); i++)
73 {
74 TabContent* current = dynamic_cast<TabContent*>
75 (ui->editorTabs->widget(i));
76 if(current->file() == fileName)
77 {
78 ui->editorTabs->setCurrentIndex(i);
79 return;
80 }
81 }
82
83 /* Adding a new document*/
84 SkinDocument* doc = new SkinDocument(parseStatus, fileName, project,
85 deviceConfig);
86 addTab(doc);
87 ui->editorTabs->setCurrentWidget(doc);
88
89}
90
91void EditorWindow::loadConfigTab(ConfigDocument* doc)
92{
93 for(int i = 0; i < ui->editorTabs->count(); i++)
94 {
95 TabContent* current = dynamic_cast<TabContent*>
96 (ui->editorTabs->widget(i));
97 if(current->file() == doc->file())
98 {
99 ui->editorTabs->setCurrentIndex(i);
100 doc->deleteLater();
101 return;
102 }
103 }
104
105 addTab(doc);
106 ui->editorTabs->setCurrentWidget(doc);
107
108 QObject::connect(doc, SIGNAL(titleChanged(QString)),
109 this, SLOT(tabTitleChanged(QString)));
110}
111
112void EditorWindow::loadSettings()
113{
114
115 QSettings settings;
116
117 /* Main Window location */
118 settings.beginGroup("EditorWindow");
119 QSize size = settings.value("size").toSize();
120 QPoint pos = settings.value("position").toPoint();
121 QByteArray state = settings.value("state").toByteArray();
122
123 /* Recent docs/projects */
124 recentDocs = settings.value("recentDocs", QStringList()).toStringList();
125 recentProjects = settings.value("recentProjects",
126 QStringList()).toStringList();
127
128 settings.endGroup();
129
130 if(!(size.isNull() || pos.isNull() || state.isNull()))
131 {
132 resize(size);
133 move(pos);
134 restoreState(state);
135 }
136
137}
138
139void EditorWindow::saveSettings()
140{
141
142 QSettings settings;
143
144 /* Saving window and panel positions */
145 settings.beginGroup("EditorWindow");
146 settings.setValue("position", pos());
147 settings.setValue("size", size());
148 settings.setValue("state", saveState());
149
150 /* Saving recent docs/projects */
151 settings.setValue("recentDocs", recentDocs);
152 settings.setValue("recentProjects", recentProjects);
153
154 settings.endGroup();
155}
156
157void EditorWindow::setupUI()
158{
159 /* Connecting the tab bar signals */
160 QObject::connect(ui->editorTabs, SIGNAL(currentChanged(int)),
161 this, SLOT(shiftTab(int)));
162 QObject::connect(ui->editorTabs, SIGNAL(tabCloseRequested(int)),
163 this, SLOT(closeTab(int)));
164
165 /* Connecting the code gen button */
166 QObject::connect(ui->fromTree, SIGNAL(pressed()),
167 this, SLOT(updateCurrent()));
168
169 /* Connecting the preferences dialog */
170 QObject::connect(ui->actionPreferences, SIGNAL(triggered()),
171 prefs, SLOT(exec()));
172
173 /* Setting up the parse status label */
174 parseStatus = new QLabel(this);
175 ui->statusbar->addPermanentWidget(parseStatus);
176
177 /* Setting the selection for parse tree highlighting initially NULL */
178 parseTreeSelection = 0;
179
180 /* Adding the skin viewer */
181 viewer = new SkinViewer(this);
182 ui->skinPreviewLayout->addWidget(viewer);
183
184 /* Positioning the device settings dialog */
185 deviceDock = new QDockWidget(tr("Device Configuration"), this);
186 deviceConfig = new DeviceState(deviceDock);
187
188 deviceDock->setObjectName("deviceDock");
189 deviceDock->setWidget(deviceConfig);
190 deviceDock->setFloating(true);
191 deviceDock->move(QPoint(x() + width() / 2, y() + height() / 2));
192 deviceDock->hide();
193
194 /* Positioning the timer panel */
195 timerDock = new QDockWidget(tr("Timer"), this);
196 timer = new SkinTimer(deviceConfig, timerDock);
197
198 timerDock->setObjectName("timerDock");
199 timerDock->setWidget(timer);
200 timerDock->setFloating(true);
201 timerDock->move(QPoint(x() + width() / 2, y() + height() / 2));
202 timerDock->hide();
203
204 shiftTab(-1);
205}
206
207void EditorWindow::setupMenus()
208{
209 /* Adding actions to the toolbar */
210 ui->toolBar->addAction(ui->actionNew_Document);
211 ui->toolBar->addAction(ui->actionOpen_Document);
212 ui->toolBar->addAction(ui->actionSave_Document);
213 ui->toolBar->addAction(ui->actionSave_Document_As);
214
215 ui->toolBar->addSeparator();
216 ui->toolBar->addAction(ui->actionUndo);
217 ui->toolBar->addAction(ui->actionRedo);
218
219 ui->toolBar->addSeparator();
220 ui->toolBar->addAction(ui->actionCut);
221 ui->toolBar->addAction(ui->actionCopy);
222 ui->toolBar->addAction(ui->actionPaste);
223
224 ui->toolBar->addSeparator();
225 ui->toolBar->addAction(ui->actionFind_Replace);
226
227 /* Connecting panel show actions */
228 QObject::connect(ui->actionFile_Panel, SIGNAL(triggered()),
229 this, SLOT(showPanel()));
230 QObject::connect(ui->actionDisplay_Panel, SIGNAL(triggered()),
231 this, SLOT(showPanel()));
232 QObject::connect(ui->actionPreview_Panel, SIGNAL(triggered()),
233 this, SLOT(showPanel()));
234 QObject::connect(ui->actionDevice_Configuration, SIGNAL(triggered()),
235 deviceDock, SLOT(show()));
236 QObject::connect(ui->actionTimer, SIGNAL(triggered()),
237 timerDock, SLOT(show()));
238
239 /* Connecting the document management actions */
240 QObject::connect(ui->actionNew_Document, SIGNAL(triggered()),
241 this, SLOT(newTab()));
242 QObject::connect(ui->actionNew_Project, SIGNAL(triggered()),
243 this, SLOT(newProject()));
244
245 QObject::connect(ui->actionClose_Document, SIGNAL(triggered()),
246 this, SLOT(closeCurrent()));
247 QObject::connect(ui->actionClose_Project, SIGNAL(triggered()),
248 this, SLOT(closeProject()));
249
250 QObject::connect(ui->actionSave_Document, SIGNAL(triggered()),
251 this, SLOT(saveCurrent()));
252 QObject::connect(ui->actionSave_Document_As, SIGNAL(triggered()),
253 this, SLOT(saveCurrentAs()));
254 QObject::connect(ui->actionExport_Project, SIGNAL(triggered()),
255 this, SLOT(exportProject()));
256
257 QObject::connect(ui->actionOpen_Document, SIGNAL(triggered()),
258 this, SLOT(openFile()));
259
260 QObject::connect(ui->actionOpen_Project, SIGNAL(triggered()),
261 this, SLOT(openProject()));
262
263 /* Connecting the edit menu */
264 QObject::connect(ui->actionUndo, SIGNAL(triggered()),
265 this, SLOT(undo()));
266 QObject::connect(ui->actionRedo, SIGNAL(triggered()),
267 this, SLOT(redo()));
268 QObject::connect(ui->actionCut, SIGNAL(triggered()),
269 this, SLOT(cut()));
270 QObject::connect(ui->actionCopy, SIGNAL(triggered()),
271 this, SLOT(copy()));
272 QObject::connect(ui->actionPaste, SIGNAL(triggered()),
273 this, SLOT(paste()));
274 QObject::connect(ui->actionFind_Replace, SIGNAL(triggered()),
275 this, SLOT(findReplace()));
276
277 /* Adding the recent docs/projects menus */
278 for(int i = 0; i < numRecent; i++)
279 {
280 recentDocsMenu.append(new QAction(tr("Recent Doc"),
281 ui->menuRecent_Files));
282 recentDocsMenu.last()
283 ->setShortcut(QKeySequence(tr("CTRL+")
284 + QString::number(i + 1)));
285 QObject::connect(recentDocsMenu.last(), SIGNAL(triggered()),
286 this, SLOT(openRecentFile()));
287 ui->menuRecent_Files->addAction(recentDocsMenu.last());
288
289
290 recentProjectsMenu.append(new QAction(tr("Recent Project"),
291 ui->menuRecent_Projects));
292 recentProjectsMenu.last()
293 ->setShortcut(QKeySequence(tr("CTRL+SHIFT+") +
294 QString::number(i + 1)));
295 QObject::connect(recentProjectsMenu.last(), SIGNAL(triggered()),
296 this, SLOT(openRecentProject()));
297 ui->menuRecent_Projects->addAction(recentProjectsMenu.last());
298 }
299 refreshRecentMenus();
300}
301
302void EditorWindow::addTab(TabContent *doc)
303{
304 ui->editorTabs->addTab(doc, doc->title());
305
306 /* Connecting to title change events */
307 QObject::connect(doc, SIGNAL(titleChanged(QString)),
308 this, SLOT(tabTitleChanged(QString)));
309 QObject::connect(doc, SIGNAL(lineChanged(int)),
310 this, SLOT(lineChanged(int)));
311
312 /* Connecting to settings change events */
313 doc->connectPrefs(prefs);
314}
315
316
317void EditorWindow::newTab()
318{
319 SkinDocument* doc = new SkinDocument(parseStatus, project, deviceConfig);
320 addTab(doc);
321 ui->editorTabs->setCurrentWidget(doc);
322}
323
324void EditorWindow::newProject()
325{
326 NewProjectDialog dialog(this);
327 if(dialog.exec() == QDialog::Rejected)
328 return;
329
330 /* Assembling the new project if the dialog was accepted */
331 NewProjectDialog::NewProjectInfo info = dialog.results();
332
333 QDir path(info.path);
334 if(!path.exists())
335 {
336 QMessageBox::warning(this, tr("Error Creating Project"), tr("Error:"
337 " Project directory does not exist"));
338 return;
339 }
340
341 if(path.exists(info.name))
342 {
343 QMessageBox::warning(this, tr("Error Creating Project"), tr("Error:"
344 " Project directory already exists"));
345 return;
346 }
347
348 if(!path.mkdir(info.name))
349 {
350 QMessageBox::warning(this, tr("Error Creating Project"), tr("Error:"
351 " Project directory not writeable"));
352 return;
353 }
354
355 path.cd(info.name);
356
357 /* Making standard directories */
358 path.mkdir("fonts");
359 path.mkdir("icons");
360 path.mkdir("backdrops");
361
362 /* Adding the desired wps documents */
363 path.mkdir("wps");
364 path.cd("wps");
365
366 if(info.sbs)
367 createFile(path.filePath(info.name + ".sbs"), tr("# SBS Document\n"));
368 if(info.wps)
369 createFile(path.filePath(info.name + ".wps"), tr("# WPS Document\n"));
370 if(info.fms)
371 createFile(path.filePath(info.name + ".fms"), tr("# FMS Document\n"));
372 if(info.rsbs)
373 createFile(path.filePath(info.name + ".rsbs"), tr("# RSBS Document\n"));
374 if(info.rwps)
375 createFile(path.filePath(info.name + ".rwps"), tr("# RWPS Document\n"));
376 if(info.rfms)
377 createFile(path.filePath(info.name + ".rfms"), tr("# RFMS Document\n"));
378
379 path.mkdir(info.name);
380
381 path.cdUp();
382
383 /* Adding the config file */
384 path.mkdir("themes");
385 path.cd("themes");
386
387 /* Generating the config file */
388 QString config = tr("# Config file for ") + info.name + "\n";
389 config.append("#target: " + info.target + "\n\n");
390 QString wpsBase = "/.rockbox/wps/";
391 if(info.sbs)
392 config.append("sbs: " + wpsBase + info.name + ".sbs\n");
393 if(info.wps)
394 config.append("wps: " + wpsBase + info.name + ".wps\n");
395 if(info.fms)
396 config.append("fms: " + wpsBase + info.name + ".fms\n");
397 if(info.rsbs)
398 config.append("rsbs: " + wpsBase + info.name + ".rsbs\n");
399 if(info.rwps)
400 config.append("rwps: " + wpsBase + info.name + ".rwps\n");
401 if(info.rfms)
402 config.append("rfms: " + wpsBase + info.name + ".rfms\n");
403
404
405 createFile(path.filePath(info.name + ".cfg"),
406 config);
407
408 /* Opening the new project */
409 loadProjectFile(path.filePath(info.name + ".cfg"));
410}
411
412void EditorWindow::shiftTab(int index)
413{
414 TabContent* widget = dynamic_cast<TabContent*>
415 (ui->editorTabs->currentWidget());
416 if(index < 0)
417 {
418 ui->parseTree->setModel(0);
419 ui->actionSave_Document->setEnabled(false);
420 ui->actionSave_Document_As->setEnabled(false);
421 ui->actionClose_Document->setEnabled(false);
422 ui->fromTree->setEnabled(false);
423 ui->actionUndo->setEnabled(false);
424 ui->actionRedo->setEnabled(false);
425 ui->actionCut->setEnabled(false);
426 ui->actionCopy->setEnabled(false);
427 ui->actionPaste->setEnabled(false);
428 ui->actionFind_Replace->setEnabled(false);
429 viewer->connectSkin(0);
430 }
431 else if(widget->type() == TabContent::Config)
432 {
433 ui->actionSave_Document->setEnabled(true);
434 ui->actionSave_Document_As->setEnabled(true);
435 ui->actionClose_Document->setEnabled(true);
436 ui->actionUndo->setEnabled(false);
437 ui->actionRedo->setEnabled(false);
438 ui->actionCut->setEnabled(false);
439 ui->actionCopy->setEnabled(false);
440 ui->actionPaste->setEnabled(false);
441 ui->actionFind_Replace->setEnabled(false);
442 viewer->connectSkin(0);
443 }
444 else if(widget->type() == TabContent::Skin)
445 {
446 /* Syncing the tree view and the status bar */
447 SkinDocument* doc = dynamic_cast<SkinDocument*>(widget);
448 ui->parseTree->setModel(doc->getModel());
449 parseStatus->setText(doc->getStatus());
450
451 ui->actionSave_Document->setEnabled(true);
452 ui->actionSave_Document_As->setEnabled(true);
453 ui->actionClose_Document->setEnabled(true);
454 ui->fromTree->setEnabled(true);
455
456 ui->actionUndo->setEnabled(true);
457 ui->actionRedo->setEnabled(true);
458 ui->actionCut->setEnabled(true);
459 ui->actionCopy->setEnabled(true);
460 ui->actionPaste->setEnabled(true);
461 ui->actionFind_Replace->setEnabled(true);
462
463 sizeColumns();
464
465 /* Syncing the preview */
466 viewer->connectSkin(doc);
467
468
469 }
470
471 /* Hiding all the find/replace dialogs */
472 for(int i = 0; i < ui->editorTabs->count(); i++)
473 if(dynamic_cast<TabContent*>(ui->editorTabs->widget(i))->type() ==
474 TabContent::Skin)
475 dynamic_cast<SkinDocument*>(ui->editorTabs->widget(i))->hideFind();
476
477}
478
479bool EditorWindow::closeTab(int index)
480{
481 TabContent* widget = dynamic_cast<TabContent*>
482 (ui->editorTabs->widget(index));
483 if(widget->requestClose())
484 {
485 ui->editorTabs->removeTab(index);
486 widget->deleteLater();
487 return true;
488 }
489
490 return false;
491}
492
493void EditorWindow::closeCurrent()
494{
495 closeTab(ui->editorTabs->currentIndex());
496}
497
498void EditorWindow::closeProject()
499{
500 if(project)
501 {
502 project->deleteLater();
503 project = 0;
504 }
505
506 for(int i = 0; i < ui->editorTabs->count(); i++)
507 {
508 TabContent* doc = dynamic_cast<TabContent*>
509 (ui->editorTabs->widget(i));
510 if(doc->type() == TabContent::Skin)
511 {
512 dynamic_cast<SkinDocument*>(doc)->setProject(project);
513 if(i == ui->editorTabs->currentIndex())
514 {
515 viewer->connectSkin(dynamic_cast<SkinDocument*>(doc));
516 }
517 }
518 }
519
520 ui->actionClose_Project->setEnabled(false);
521 ui->actionExport_Project->setEnabled(false);
522}
523
524void EditorWindow::saveCurrent()
525{
526 if(ui->editorTabs->currentIndex() >= 0)
527 dynamic_cast<TabContent*>(ui->editorTabs->currentWidget())->save();
528}
529
530void EditorWindow::saveCurrentAs()
531{
532 if(ui->editorTabs->currentIndex() >= 0)
533 dynamic_cast<TabContent*>(ui->editorTabs->currentWidget())->saveAs();
534}
535
536void EditorWindow::exportProject()
537{
538 QDir dir = project->getSetting("themebase", "");
539 dir.cdUp();
540 QString file = project->getSetting("configfile", "").split("/").
541 last().split(".").first() + ".zip";
542 file = dir.filePath(file);
543
544 file = QFileDialog::getSaveFileName(this, tr("Export Project"),
545 file, "Zip Files (*.zip *.ZIP);;"
546 "All Files (*)");
547
548 if(file != "")
549 {
550 ProjectExporter* exporter = new ProjectExporter(file, project, this);
551 exporter->show();
552 }
553}
554
555void EditorWindow::openFile()
556{
557 QStringList fileNames;
558 QSettings settings;
559
560 settings.beginGroup("SkinDocument");
561 QString directory = settings.value("defaultDirectory", "").toString();
562 fileNames = QFileDialog::getOpenFileNames(this, tr("Open Files"), directory,
563 SkinDocument::fileFilter());
564
565 for(int i = 0; i < fileNames.count(); i++)
566 {
567 if(!QFile::exists(fileNames[i]))
568 continue;
569
570 QString current = fileNames[i];
571
572 loadTabFromSkinFile(current);
573
574 /* And setting the new default directory */
575 current.chop(current.length() - current.lastIndexOf('/') - 1);
576 settings.setValue("defaultDirectory", current);
577
578 }
579
580 settings.endGroup();
581}
582
583void EditorWindow::openProject()
584{
585 QString fileName;
586 QSettings settings;
587
588 settings.beginGroup("ProjectModel");
589 QString directory = settings.value("defaultDirectory", "").toString();
590 fileName = QFileDialog::getOpenFileName(this, tr("Open Project"), directory,
591 ProjectModel::fileFilter());
592
593 settings.endGroup();
594 loadProjectFile(fileName);
595
596}
597
598void EditorWindow::openRecentFile()
599{
600 loadTabFromSkinFile(dynamic_cast<QAction*>(QObject::sender())->text());
601}
602
603void EditorWindow::openRecentProject()
604{
605 loadProjectFile(dynamic_cast<QAction*>(QObject::sender())->text());
606}
607
608void EditorWindow::configFileChanged(QString configFile)
609{
610
611 if(QFile::exists(configFile))
612 {
613
614 if(project)
615 delete project;
616
617 project = new ProjectModel(configFile, this);
618 ui->projectTree->setModel(project);
619
620 QObject::connect(ui->projectTree, SIGNAL(activated(QModelIndex)),
621 project, SLOT(activated(QModelIndex)));
622
623 for(int i = 0; i < ui->editorTabs->count(); i++)
624 {
625 TabContent* doc = dynamic_cast<TabContent*>
626 (ui->editorTabs->widget(i));
627 if(doc->type() == TabContent::Skin)
628 {
629 dynamic_cast<SkinDocument*>(doc)->setProject(project);
630 if(i == ui->editorTabs->currentIndex())
631 {
632 viewer->connectSkin(dynamic_cast<SkinDocument*>(doc));
633 }
634 }
635 }
636
637 }
638
639
640}
641
642void EditorWindow::tabTitleChanged(QString title)
643{
644 TabContent* sender = dynamic_cast<TabContent*>(QObject::sender());
645 ui->editorTabs->setTabText(ui->editorTabs->indexOf(sender), title);
646}
647
648void EditorWindow::showPanel()
649{
650 if(sender() == ui->actionFile_Panel)
651 ui->projectDock->setVisible(true);
652 if(sender() == ui->actionPreview_Panel)
653 ui->skinPreviewDock->setVisible(true);
654 if(sender() == ui->actionDisplay_Panel)
655 ui->parseTreeDock->setVisible(true);
656}
657
658void EditorWindow::closeEvent(QCloseEvent* event)
659{
660
661 saveSettings();
662
663 /* Closing all the tabs */
664 for(int i = 0; i < ui->editorTabs->count(); i++)
665 {
666 if(!dynamic_cast<TabContent*>
667 (ui->editorTabs->widget(i))->requestClose())
668 {
669 event->ignore();
670 return;
671 }
672 }
673
674 event->accept();
675}
676
677void EditorWindow::updateCurrent()
678{
679 if(ui->editorTabs->currentIndex() < 0)
680 return;
681
682 dynamic_cast<SkinDocument*>
683 (ui->editorTabs->currentWidget())->genCode();
684}
685
686void EditorWindow::lineChanged(int line)
687{
688 QSettings settings;
689 settings.beginGroup("EditorWindow");
690
691 if(settings.value("autoExpandTree", false).toBool())
692 {
693 ui->parseTree->collapseAll();
694 ParseTreeModel* model = dynamic_cast<ParseTreeModel*>
695 (ui->parseTree->model());
696 parseTreeSelection = new QItemSelectionModel(model);
697 expandLine(model, QModelIndex(), line,
698 settings.value("autoHighlightTree", false).toBool());
699 sizeColumns();
700 ui->parseTree->setSelectionModel(parseTreeSelection);
701 }
702
703 settings.endGroup();
704}
705
706void EditorWindow::undo()
707{
708 TabContent* doc = dynamic_cast<TabContent*>
709 (ui->editorTabs->currentWidget());
710 if(doc->type() == TabContent::Skin)
711 dynamic_cast<SkinDocument*>(doc)->getEditor()->undo();
712}
713
714void EditorWindow::redo()
715{
716 TabContent* doc = dynamic_cast<TabContent*>
717 (ui->editorTabs->currentWidget());
718 if(doc->type() == TabContent::Skin)
719 dynamic_cast<SkinDocument*>(doc)->getEditor()->redo();
720
721}
722
723void EditorWindow::cut()
724{
725 TabContent* doc = dynamic_cast<TabContent*>
726 (ui->editorTabs->currentWidget());
727 if(doc->type() == TabContent::Skin)
728 dynamic_cast<SkinDocument*>(doc)->getEditor()->cut();
729}
730
731void EditorWindow::copy()
732{
733 TabContent* doc = dynamic_cast<TabContent*>
734 (ui->editorTabs->currentWidget());
735 if(doc->type() == TabContent::Skin)
736 dynamic_cast<SkinDocument*>(doc)->getEditor()->copy();
737}
738
739void EditorWindow::paste()
740{
741 TabContent* doc = dynamic_cast<TabContent*>
742 (ui->editorTabs->currentWidget());
743 if(doc->type() == TabContent::Skin)
744 dynamic_cast<SkinDocument*>(doc)->getEditor()->paste();
745}
746
747void EditorWindow::findReplace()
748{
749 TabContent* doc = dynamic_cast<TabContent*>
750 (ui->editorTabs->currentWidget());
751 if(doc->type() == TabContent::Skin)
752 dynamic_cast<SkinDocument*>(doc)->showFind();
753}
754
755
756void EditorWindow::expandLine(ParseTreeModel* model, QModelIndex parent,
757 int line, bool highlight)
758{
759 for(int i = 0; i < model->rowCount(parent); i++)
760 {
761 QModelIndex dataType = model->index(i, ParseTreeModel::typeColumn,
762 parent);
763 QModelIndex dataVal = model->index(i, ParseTreeModel::valueColumn,
764 parent);
765 QModelIndex data = model->index(i, ParseTreeModel::lineColumn, parent);
766 QModelIndex recurse = model->index(i, 0, parent);
767
768 expandLine(model, recurse, line, highlight);
769
770 if(model->data(data, Qt::DisplayRole) == line)
771 {
772 ui->parseTree->expand(parent);
773 ui->parseTree->expand(data);
774 ui->parseTree->scrollTo(parent, QAbstractItemView::PositionAtTop);
775
776 if(highlight)
777 {
778 parseTreeSelection->select(data,
779 QItemSelectionModel::Select);
780 parseTreeSelection->select(dataType,
781 QItemSelectionModel::Select);
782 parseTreeSelection->select(dataVal,
783 QItemSelectionModel::Select);
784 }
785 }
786 }
787
788}
789
790void EditorWindow::sizeColumns()
791{
792 /* Setting the column widths */
793 ui->parseTree->resizeColumnToContents(ParseTreeModel::lineColumn);
794 ui->parseTree->resizeColumnToContents(ParseTreeModel::typeColumn);
795 ui->parseTree->resizeColumnToContents(ParseTreeModel::valueColumn);
796}
797
798void EditorWindow::loadProjectFile(QString fileName)
799{
800 QSettings settings;
801 settings.beginGroup("ProjectModel");
802
803 if(QFile::exists(fileName))
804 {
805 projectToTop(fileName);
806
807 if(project)
808 project->deleteLater();
809
810 ui->actionClose_Project->setEnabled(true);
811 ui->actionExport_Project->setEnabled(true);
812
813 project = new ProjectModel(fileName, this);
814 ui->projectTree->setModel(project);
815
816 /* Setting target info if necessary */
817 TargetData targets;
818 QString target = project->getSetting("#target", "");
819 if(target != "" && targets.index(target) >= 0)
820 {
821 int index = targets.index(target);
822
823 QRect screen = targets.screenSize(index);
824 deviceConfig->setData("screenwidth", screen.width());
825 deviceConfig->setData("screenheight", screen.height());
826
827 if(targets.remoteDepth(index) != TargetData::None)
828 {
829 QRect remote = targets.remoteSize(index);
830 deviceConfig->setData("remotewidth", remote.width());
831 deviceConfig->setData("remoteheight", remote.height());
832 }
833
834 deviceConfig->setData("tp", targets.fm(index));
835 deviceConfig->setData("Rp", targets.canRecord(index));
836 }
837
838 if(project->getSetting("#screenwidth") != "")
839 deviceConfig->setData("screenwidth",
840 project->getSetting("#screenwidth"));
841 if(project->getSetting("#screenheight") != "")
842 deviceConfig->setData("screenheight",
843 project->getSetting("#screenheight"));
844
845 QObject::connect(ui->projectTree, SIGNAL(activated(QModelIndex)),
846 project, SLOT(activated(QModelIndex)));
847
848 fileName.chop(fileName.length() - fileName.lastIndexOf('/') - 1);
849 settings.setValue("defaultDirectory", fileName);
850
851 for(int i = 0; i < ui->editorTabs->count(); i++)
852 {
853 TabContent* doc = dynamic_cast<TabContent*>
854 (ui->editorTabs->widget(i));
855 if(doc->type() == TabContent::Skin)
856 {
857 dynamic_cast<SkinDocument*>(doc)->setProject(project);
858 if(i == ui->editorTabs->currentIndex())
859 {
860 viewer->connectSkin(dynamic_cast<SkinDocument*>(doc));
861 }
862 }
863 }
864
865 }
866
867 settings.endGroup();
868
869}
870
871void EditorWindow::createFile(QString filename, QString contents)
872{
873 QFile fout(filename);
874 fout.open(QFile::WriteOnly);
875
876 fout.write(contents.toLatin1());
877
878 fout.close();
879}
880
881void EditorWindow::docToTop(QString file)
882{
883 if(!QFile::exists(file))
884 return;
885
886 int index = recentDocs.indexOf(file);
887 if(index == -1)
888 {
889 /* Bumping off the last file */
890 if(recentDocs.count() >= numRecent)
891 recentDocs.removeLast();
892 recentDocs.prepend(file);
893 }
894 else
895 {
896 /* Shuffling file to the top of the list */
897 recentDocs.removeAt(index);
898 recentDocs.prepend(file);
899 }
900
901 refreshRecentMenus();
902}
903
904void EditorWindow::projectToTop(QString file)
905{
906 if(!QFile::exists(file))
907 return;
908
909 int index = recentProjects.indexOf(file);
910 if(index == -1)
911 {
912 /* Bumping off the last project */
913 if(recentProjects.count() >= numRecent)
914 recentProjects.removeLast();
915 recentProjects.prepend(file);
916 }
917 else
918 {
919 /* Shuffling file to the top of the list */
920 recentProjects.removeAt(index);
921 recentProjects.prepend(file);
922 }
923
924 refreshRecentMenus();
925}
926
927void EditorWindow::refreshRecentMenus()
928{
929 /* Clearing any deleted documents */
930 for(int i = 0; i < recentDocs.count(); i++)
931 if(!QFile::exists(recentDocs[i]))
932 recentDocs.removeAt(i--);
933
934 /* Clearing any deleted projects */
935 for(int i = 0; i < recentProjects.count(); i++)
936 if(!QFile::exists(recentProjects[i]))
937 recentProjects.removeAt(i--);
938
939 /* First hiding all the menu items */
940 for(int i = 0; i < recentDocsMenu.count(); i++)
941 recentDocsMenu[i]->setVisible(false);
942 for(int i = 0; i < recentProjectsMenu.count(); i++)
943 recentProjectsMenu[i]->setVisible(false);
944
945 /* Then setting the text of and showing any available */
946 for(int i = 0; i < recentDocs.count(); i++)
947 {
948 recentDocsMenu[i]->setText(recentDocs[i]);
949 recentDocsMenu[i]->setVisible(true);
950 }
951
952 for(int i = 0; i < recentProjects.count(); i++)
953 {
954 recentProjectsMenu[i]->setText(recentProjects[i]);
955 recentProjectsMenu[i]->setVisible(true);
956 }
957}