A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 957 lines 30 kB view raw
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}