/* * Copyright 2008 Ben Boeckel * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ // Header include #include "PokeModrUI.h" // PokeModr includes #include "ObjectUI.h" #include "PokemodTreeModel.h" // Pokemod includes #include "../pokemod/Pokemod.h" // Qt includes #include #include // KDE includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include PokeModrUI::PokeModrUI(KConfigGroup config, KConfigGroup history, QWidget* parent) : KMainWindow(parent), m_config(config), m_recent(new KRecentFilesAction("&Recent Files...", this)) { setupUi(this); m_recent->loadEntries(history); // FIXME: Somehow get KAction/KMenus into the ui files KMenuBar* menubar = new KMenuBar(this); KMenu* menuFile = new KMenu("&File", menubar); menuFile->addAction(KStandardAction::openNew(this, SLOT(newPokemod()), menuFile)); menuFile->addAction(KStandardAction::open(this, SLOT(openPokemod()), menuFile)); menuFile->addAction(KStandardAction::openRecent(this, SLOT(openPokemod(const KUrl&)), menuFile)); menuFile->addAction(KStandardAction::close(this, SLOT(closePokemod()), menuFile)); menuFile->addSeparator(); menuFile->addAction(KStandardAction::save(this, SLOT(savePokemod()), menuFile)); menuFile->addAction(KStandardAction::saveAs(this, SLOT(saveAsPokemod()), menuFile)); menuFile->addSeparator(); menuFile->addAction(KStandardAction::quit(this, SLOT(quit()), menuFile)); menubar->addMenu(menuFile); KMenu* menuEdit = new KMenu("&Edit", menubar); menuEdit->addAction(KStandardAction::cut(menuEdit)); menuEdit->addAction(KStandardAction::copy(menuEdit)); menuEdit->addAction(KStandardAction::paste(menuEdit)); menuEdit->addSeparator(); KAction* menuCut = new KAction(KIcon("edit-cut"), "Cu&t Object", menuEdit); menuCut->setShortcut(KShortcut("Alt+X")); menuEdit->addAction(menuCut); connect(menuCut, SIGNAL(triggered()), this, SLOT(cutObject())); KAction* menuCopy = new KAction(KIcon("edit-copy"), "Cop&y Object", menuEdit); menuCopy->setShortcut(KShortcut("Alt+C")); menuEdit->addAction(menuCopy); connect(menuCopy, SIGNAL(triggered()), this, SLOT(copyObject())); KAction* menuPaste = new KAction(KIcon("edit-paste"), "Past&e Object", menuEdit); menuPaste->setShortcut(KShortcut("Alt+V")); menuEdit->addAction(menuPaste); connect(menuPaste, SIGNAL(triggered()), this, SLOT(pasteObject())); menuEdit->addSeparator(); menuEdit->addAction(KStandardAction::preferences(this, SLOT(preferences()), menuEdit)); menubar->addMenu(menuEdit); menubar->addMenu(customHelpMenu(false)); setMenuBar(menubar); KToolBar* toolbar = new KToolBar("toolbar", this, Qt::TopToolBarArea, false, true, true); toolbar->addAction(KStandardAction::openNew(this, SLOT(newPokemod()), toolbar)); toolbar->addAction(KStandardAction::open(this, SLOT(openPokemod()), toolbar)); toolbar->addAction(KStandardAction::openRecent(this, SLOT(openPokemod(const KUrl&)), toolbar)); toolbar->addAction(KStandardAction::close(this, SLOT(closePokemod()), toolbar)); toolbar->addSeparator(); toolbar->addAction(KStandardAction::save(this, SLOT(savePokemod()), toolbar)); toolbar->addAction(KStandardAction::saveAs(this, SLOT(saveAsPokemod()), toolbar)); toolbar->addSeparator(); toolbar->addAction(KStandardAction::cut(toolbar)); toolbar->addAction(KStandardAction::copy(toolbar)); toolbar->addAction(KStandardAction::paste(toolbar)); toolbar->addSeparator(); KAction* toolbarCut = new KAction(KIcon("edit-cut"), "Cu&t Object", toolbar); toolbar->addAction(toolbarCut); connect(toolbarCut, SIGNAL(triggered()), this, SLOT(cutObject())); KAction* toolbarCopy = new KAction(KIcon("edit-copy"), "Cop&y Object", toolbar); toolbar->addAction(toolbarCopy); connect(toolbarCopy, SIGNAL(triggered()), this, SLOT(copyObject())); KAction* toolbarPaste = new KAction(KIcon("edit-paste"), "Past&e Object", toolbar); toolbar->addAction(toolbarPaste); connect(toolbarPaste, SIGNAL(triggered()), this, SLOT(pasteObject())); toolbar->addSeparator(); toolbar->addAction(KStandardAction::preferences(this, SLOT(preferences()), toolbar)); toolbar->addSeparator(); toolbar->addAction(KStandardAction::quit(this, SLOT(quit()), toolbar)); addToolBar(toolbar); splitter->setSizes(QList() << config.readEntry("treeWidth", 100) << config.readEntry("panelWidth", 100)); connect(buttonApply, SIGNAL(clicked()), this, SLOT(update())); KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); if (args) { for(int i = 0; i < args->count(); ++i) openPokemod(args->url(i)); args->clear(); } if (config.readEntry("reloadOnStart", false)) { for (int i = 0; i < config.readEntry("openedFiles", 0); ++i) openPokemod(m_recent->urls().at(i)); } setAutoSaveSettings("MainWindow", true); } PokeModrUI::~PokeModrUI() { // delete m_recent; // on_actionQuit_triggered(); } void PokeModrUI::update() { treePokemod->update(treePokemod->currentIndex()); } void PokeModrUI::closeEvent(QCloseEvent* event) { quit(); event->accept(); } void PokeModrUI::setChangedTitle(const bool changed) { setWindowTitle(QString::fromUtf8("%1%2 - PokéModr").arg(treePokemod->description(treePokemod->currentIndex()), changed ? "*" : "")); } void PokeModrUI::setDirty(const bool dirty) { const Pokemod* pokemod = static_cast(static_cast(treePokemod->currentIndex().internalPointer())->pokemod()); treePokemod->setDirty(pokemod, dirty); } void PokeModrUI::newPokemod() { treePokemod->addPokemod(new Pokemod()); } void PokeModrUI::openPokemod() { KUrl::List urls(KFileDialog::getOpenUrls(KUrl("kfiledialog:///pokemod"), QString::fromUtf8("*.pmod|PokéMod files"), this)); foreach (KUrl url, urls) { if (!url.isEmpty()) { if (openPokemod(url)) { m_recent->addUrl(url); m_recent->saveEntries(m_config); } } } } bool PokeModrUI::openPokemod(const KUrl& url) { if (url.isLocalFile()) return openPokemod(url.path()); else { QString temp; if (KIO::NetAccess::download(url, temp, this)) { if (openPokemod(temp)) return true; KIO::NetAccess::removeTempFile(temp); } else KMessageBox::error(this, KIO::NetAccess::lastErrorString(), "KIO Error"); } return false; } bool PokeModrUI::openPokemod(const QString& path) { QFile file(path); if (file.open(QIODevice::ReadOnly)) { QDomDocument xml; if (xml.setContent(&file)) { if (xml.doctype().name() == "Pokemod") { treePokemod->addPokemod(new Pokemod(xml.documentElement())); return true; } else KMessageBox::error(this, QString::fromUtf8("The file is not a PokéMod."), QString::fromUtf8("Invalid PokéMod")); } else KMessageBox::error(this, "The file is not a valid XML file.", QString::fromUtf8("Invalid PokéMod")); file.close(); } return false; } void PokeModrUI::savePokemod() { const Pokemod* pokemod = currentPokemod(); if (pokemod) { KUrl url = treePokemod->url(pokemod); if (url.isEmpty()) saveAsPokemod(); else savePokemod(url); } } void PokeModrUI::saveAsPokemod() { const Pokemod* pokemod = currentPokemod(); if (pokemod) { KUrl url = KFileDialog::getSaveUrl(KUrl("kfiledialog:///pokemod"), QString::fromUtf8("*.pmod|PokéMod files"), this, QString::fromUtf8("Open PokéMod")); if (!url.isEmpty()) { if (savePokemod(url)) treePokemod->setUrl(pokemod, url); } } } bool PokeModrUI::savePokemod(const KUrl& url) { const Pokemod* pokemod = currentPokemod(); if (pokemod) { if (url.isLocalFile()) { QFile file(url.path()); if (file.open(QIODevice::ReadWrite)) { file.write(Object::xml(pokemod).toByteArray()); file.close(); return true; } else KMessageBox::error(this, QString::fromUtf8("Error saving the PokéMod!"), "Save error"); } else { KTemporaryFile temp; if (temp.open()) { temp.write(Object::xml(pokemod).toByteArray()); if (KIO::NetAccess::upload(temp.fileName(), url, this)) return true; else KMessageBox::error(this, KIO::NetAccess::lastErrorString(), "KIO Error"); } else KMessageBox::error(this, QString::fromUtf8("Error saving the PokéMod!"), "Save error"); } } return false; } void PokeModrUI::closePokemod() { closePokemod(currentPokemod()); } void PokeModrUI::closePokemod(const Pokemod* pokemod) { if (pokemod) { if (treePokemod->dirty(pokemod)) { switch (KMessageBox::questionYesNoCancel(this, "You have unsaved changes, would you like to save them?", QString::fromUtf8("Unsaved PokéMod"))) { case KMessageBox::Yes: savePokemod(); case KMessageBox::No: break; case KMessageBox::Cancel: return; } } treePokemod->deletePokemod(currentPokemod()); } } void PokeModrUI::quit() { // TODO: close all pokemods and cancel if any are left open close(); } void PokeModrUI::cutObject() { m_clipboard = treePokemod->cut(treePokemod->currentIndex()); } void PokeModrUI::copyObject() { m_clipboard = treePokemod->copy(treePokemod->currentIndex()); } void PokeModrUI::pasteObject() { treePokemod->paste(treePokemod->currentIndex(), m_clipboard); } void PokeModrUI::preferences() { // TODO: preferences } void PokeModrUI::on_splitter_splitterMoved() { m_config.writeEntry("treeWidth", splitter->sizes()[0]); m_config.writeEntry("panelWidth", splitter->sizes()[1]); } void PokeModrUI::on_treePokemod_clicked(const QModelIndex& index) { ObjectUI* widget = treePokemod->editorWidget(index); if (widget) { if (formPanel->widget() && boxButtons->isEnabled()) { switch (KMessageBox::questionYesNoCancel(this, "You have unsaved changes, would you like to save them?", QString("Unsaved %1").arg(static_cast(formPanel->widget())->original()->className()))) { case KMessageBox::Yes: static_cast(formPanel->widget())->apply(); break; case KMessageBox::No: static_cast(formPanel->widget())->discard(); break; case KMessageBox::Cancel: return; } } boxButtons->setEnabled(false); connect(widget, SIGNAL(changed(bool)), this, SLOT(setChangedTitle(bool))); connect(widget, SIGNAL(changed(bool)), boxButtons, SLOT(setEnabled(bool))); connect(buttonApply, SIGNAL(clicked()), widget, SLOT(apply())); // TODO: set as dirty // connect(buttonApply, SIGNAL(clicked(bool)), this, SLOT(setDirty())); connect(buttonDiscard, SIGNAL(clicked()), widget, SLOT(discard())); setChangedTitle(false); formPanel->setWidget(widget); formPanel->show(); } } void PokeModrUI::on_treePokemod_customContextMenuRequested(const QPoint& position) { KMenu* menu = treePokemod->contextMenu(treePokemod->indexAt(position)); if (menu) menu->popup(mapToGlobal(position)); } const Pokemod* PokeModrUI::currentPokemod() const { QModelIndex index = treePokemod->currentIndex(); if (index.isValid()) { const Object* object = static_cast(index.internalPointer())->object(); if (object) return static_cast(object->pokemod()); } return NULL; }