/* * 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 "SigmodrUI.h" // Configuration includes #include "SigmodrPreferences.h" // Sigmodr includes #include "ObjectUI.h" #include "SigmodrPreferencesWidget.h" #include "SigmodTreeModel.h" // Sigmod includes #include "../sigmod/Rules.h" #include "../sigmod/Sigmod.h" // KDE includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Qt includes #include #include #include #include #include Sigmodr::SigmodrUI::SigmodrUI(QWidget* parent) : KXmlGuiWindow(parent) { setupUi(this); setupActions(); setAcceptDrops(true); buttonApply->setIcon(KIcon("dialog-ok-apply")); buttonReset->setIcon(KIcon("edit-undo")); splitter->setSizes(QList() << SigmodrPreferences::treeWidth() << SigmodrPreferences::panelWidth()); connect(buttonApply, SIGNAL(clicked()), this, SLOT(update())); KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); if (args && args->count()) { for(int i = 0; i < args->count(); ++i) openSigmod(args->url(i)); args->clear(); } else if (SigmodrPreferences::reloadOnStart()) { QStringList urls = SigmodrPreferences::openFiles(); foreach (const QString& url, urls) openSigmod(KUrl(url)); } setAutoSaveSettings("MainWindow", true); } Sigmodr::SigmodrUI::~SigmodrUI() { closeAllSigmods(true); SigmodrPreferences::self()->writeConfig(); KGlobal::config()->sync(); } void Sigmodr::SigmodrUI::dragEnterEvent(QDragEnterEvent* event) { const QMimeData* data = event->mimeData(); if (data->hasFormat("application/x-sigmod+xml") || data->hasFormat("text/uri-list")) event->acceptProposedAction(); } void Sigmodr::SigmodrUI::dropEvent(QDropEvent* event) { const QMimeData* data = event->mimeData(); bool loaded = false; event->setDropAction(Qt::CopyAction); if (data->hasFormat("application/x-sigmod+xml")) { QDomDocument xml; QString error; int line; int column; if (xml.setContent(data->data("application/x-sigmod+xml"), &error, &line, &column)) { if (xml.doctype().name() == "Sigmod") { treeSigmod->addSigmod(new Sigmod::Sigmod(xml.documentElement())); loaded = true; } else KMessageBox::error(this, "The file is not a Sigmod.", "Invalid Sigmod"); } else KMessageBox::error(this, QString("%1 at line %2, column %3").arg(error).arg(line).arg(column), "XML Error"); } else if (data->hasFormat("text/uri-list")) { QList urls = data->urls(); foreach (const QUrl& url, urls) loaded = openSigmod(url); } if (loaded) event->acceptProposedAction(); } void Sigmodr::SigmodrUI::update() { treeSigmod->update(treeSigmod->currentIndex()); } void Sigmodr::SigmodrUI::closeEvent(QCloseEvent* event) { KRecentFilesAction *recent = qobject_cast(actionCollection()->action(KStandardAction::name(KStandardAction::OpenRecent))); recent->saveEntries(KGlobal::config()->group("Recent Files")); if (closeAllSigmods()) event->accept(); else event->ignore(); } void Sigmodr::SigmodrUI::resizeEvent(QResizeEvent* event) { event->accept(); on_splitter_splitterMoved(); } void Sigmodr::SigmodrUI::setChangedTitle(const bool changed) { setCaption(treeSigmod->description(treeSigmod->currentIndex()), changed); } void Sigmodr::SigmodrUI::setDirty(const bool dirty) { const Sigmod::Sigmod* sigmod = static_cast(treeSigmod->currentIndex().internalPointer())->sigmod(); treeSigmod->setDirty(sigmod, dirty); setChangedTitle(dirty); actionCollection()->action("file_save")->setEnabled(dirty); } void Sigmodr::SigmodrUI::newSigmod() { treeSigmod->addSigmod(new Sigmod::Sigmod); } void Sigmodr::SigmodrUI::openSigmod() { KUrl::List urls = KFileDialog::getOpenUrls(KUrl("kfiledialog:///sigmod"), "*.smod|Sigmod files", this); foreach (const KUrl& url, urls) { if (!url.isEmpty()) openSigmod(url); } } bool Sigmodr::SigmodrUI::openSigmod(const KUrl& url) { bool opened = false; if (treeSigmod->isOpen(url)) { KMessageBox::error(this, "File is already opened", "Sigmod error"); return false; } if (url.isValid()) { if (url.isLocalFile()) opened = openSigmod(url.path()); else { QString temp; if (KIO::NetAccess::download(url, temp, this)) { opened = openSigmod(temp, true); KIO::NetAccess::removeTempFile(temp); } else KMessageBox::error(this, KIO::NetAccess::lastErrorString(), "KIO Error"); } } else KMessageBox::error(this, "The URL is not valid", "Malformed URL"); if (opened) qobject_cast(actionCollection()->action(KStandardAction::name(KStandardAction::OpenRecent)))->addUrl(url); return opened; } bool Sigmodr::SigmodrUI::openSigmod(const QString& path, const bool isRemote) { QFile file(path); if (file.open(QIODevice::ReadOnly)) { QDomDocument xml; QString error; int line; int column; if (xml.setContent(&file, &error, &line, &column)) { if (xml.doctype().name() == "Sigmod") { treeSigmod->addSigmod(new Sigmod::Sigmod(xml.documentElement()), isRemote ? KUrl() : KUrl(path)); return true; } else KMessageBox::error(this, "The file is not a Sigmod.", "Invalid Sigmod"); } else KMessageBox::error(this, QString("%1 at line %2, column %3").arg(error).arg(line).arg(column), "XML Error"); file.close(); } else KMessageBox::error(this, file.errorString(), "File Error"); return false; } void Sigmodr::SigmodrUI::saveSigmod() { saveSigmod(treeSigmod->currentSigmod()); } void Sigmodr::SigmodrUI::saveSigmod(const Sigmod::Sigmod* sigmod) { const KUrl url = treeSigmod->url(sigmod); if (url.isEmpty()) saveAsSigmod(sigmod); else saveSigmod(sigmod, url); } bool Sigmodr::SigmodrUI::saveSigmod(const Sigmod::Sigmod* sigmod, const KUrl& url) { if (sigmod) { if (url.isLocalFile()) { QFile file(url.path()); if (file.open(QIODevice::WriteOnly)) { file.write(Sigmod::Object::xml(sigmod).toByteArray()); treeSigmod->setDirty(sigmod, false); file.close(); return true; } else KMessageBox::error(this, "Error saving the Sigmod!", "Save error"); } else { KTemporaryFile temp; if (temp.open()) { temp.write(Sigmod::Object::xml(sigmod).toByteArray()); if (KIO::NetAccess::upload(temp.fileName(), url, this)) { treeSigmod->setDirty(sigmod, false); return true; } else KMessageBox::error(this, KIO::NetAccess::lastErrorString(), "KIO Error"); } else KMessageBox::error(this, "Error saving the Sigmod!", "Save error"); temp.close(); } } return false; } void Sigmodr::SigmodrUI::saveAsSigmod() { saveAsSigmod(treeSigmod->currentSigmod()); } void Sigmodr::SigmodrUI::saveAsSigmod(const Sigmod::Sigmod* sigmod) { if (sigmod) { KUrl url = KFileDialog::getSaveUrl(KUrl("kfiledialog:///sigmod"), "*.smod|Sigmod files", this, "Open Sigmod"); if (!url.isEmpty()) { if (saveSigmod(sigmod, url)) treeSigmod->setUrl(sigmod, url); } } } void Sigmodr::SigmodrUI::downloadSigmod() { KNS::Engine engine(this); if (engine.init("sigmod.knsrc")) engine.downloadDialogModal(); } void Sigmodr::SigmodrUI::uploadSigmod() { uploadSigmod(treeSigmod->currentSigmod()); } void Sigmodr::SigmodrUI::uploadSigmod(const Sigmod::Sigmod* sigmod) { KUrl url = treeSigmod->url(sigmod); if (url == KUrl()) { KMessageBox::error(this, "The Sigmod has not been saved!", "Upload error"); return; } if (!url.isLocalFile()) { KMessageBox::error(this, "The Sigmod is not local!", "Upload error"); return; } KNS::Engine engine(this); if (engine.init("sigmod.knsrc")) { if (!engine.uploadDialogModal(url.path())) KMessageBox::error(this, "An error occurred attempting to upload!", "Upload error"); } } void Sigmodr::SigmodrUI::closeSigmod() { closeSigmod(treeSigmod->currentSigmod()); setChangedTitle(treeSigmod->dirty()); } bool Sigmodr::SigmodrUI::closeSigmod(const Sigmod::Sigmod* sigmod, const bool force) { if (sigmod) { if (treeSigmod->dirty(sigmod)) { int result; if (force) result = KMessageBox::questionYesNo(this, "You have unsaved changes, would you like to save them?", "Unsaved Sigmod"); else result = KMessageBox::questionYesNoCancel(this, "You have unsaved changes, would you like to save them?", "Unsaved Sigmod"); switch (result) { case KMessageBox::Yes: saveSigmod(sigmod); case KMessageBox::No: break; case KMessageBox::Cancel: return false; } } treeSigmod->deleteSigmod(sigmod); if (formPanel->widget()) delete formPanel->takeWidget(); } return true; } bool Sigmodr::SigmodrUI::closeAllSigmods(const bool force) { QList sigmods = treeSigmod->openedSigmods(); if (sigmods.size()) SigmodrPreferences::setOpenFiles(treeSigmod->urls()); for (int i = 0; i < sigmods.size(); ) { if (closeSigmod(sigmods[i], force)) sigmods.removeAt(i); else ++i; } if (!sigmods.size() || force) close(); return !sigmods.size(); } void Sigmodr::SigmodrUI::copyObject() { m_clipboard = treeSigmod->copy(treeSigmod->currentIndex()); } void Sigmodr::SigmodrUI::pasteObject() { treeSigmod->paste(treeSigmod->currentIndex(), m_clipboard); } void Sigmodr::SigmodrUI::preferences() { if (KConfigDialog::showDialog("sigmodr-prefs")) return; KConfigDialog* dialog = new KConfigDialog(this, "sigmodr-prefs", SigmodrPreferences::self()); SigmodrPreferencesWidget* widget = new SigmodrPreferencesWidget; dialog->addPage(widget, i18n("General"), "configure"); connect(dialog, SIGNAL(okClicked()), widget, SLOT(save())); dialog->exec(); } void Sigmodr::SigmodrUI::toggleMenubar() { if (menuBar()->isVisible()) menuBar()->hide(); else menuBar()->show(); } void Sigmodr::SigmodrUI::on_splitter_splitterMoved() { SigmodrPreferences::setTreeWidth(splitter->sizes()[0]); SigmodrPreferences::setPanelWidth(splitter->sizes()[1]); } void Sigmodr::SigmodrUI::on_treeSigmod_clicked(const QModelIndex& index) { if (!(treeSigmod->model()->flags(index) & Qt::ItemIsSelectable)) return; ObjectUI* widget = treeSigmod->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(qobject_cast(formPanel->widget())->original()->className()))) { case KMessageBox::Yes: qobject_cast(formPanel->widget())->apply(); break; case KMessageBox::No: qobject_cast(formPanel->widget())->discard(); break; case KMessageBox::Cancel: return; } } boxButtons->setEnabled(false); connect(widget, SIGNAL(changed(bool)), boxButtons, SLOT(setEnabled(bool))); connect(buttonApply, SIGNAL(clicked()), widget, SLOT(apply())); connect(buttonApply, SIGNAL(clicked()), this, SLOT(setDirty())); connect(buttonReset, SIGNAL(clicked()), widget, SLOT(discard())); setChangedTitle(treeSigmod->dirty(treeSigmod->currentSigmod())); formPanel->setWidget(widget); formPanel->show(); } } void Sigmodr::SigmodrUI::on_treeSigmod_customContextMenuRequested(const QPoint& position) { QModelIndex index = treeSigmod->indexAt(position); KMenu* menu = treeSigmod->contextMenu(index); if (menu) { QString type = treeSigmod->model()->data(index, BaseModel::TypeRole).toString(); QStringList types = treeSigmod->model()->data(index, BaseModel::DropAcceptRole).toString().split(';'); KAction* paste = new KAction("&Paste", this); connect(paste, SIGNAL(triggered()), this, SLOT(pasteObject())); paste->setEnabled(types.contains(m_clipboard.doctype().name())); menu->addSeparator(); if (!type.isEmpty()) menu->addAction("&Copy", this, SLOT(copyObject())); menu->addAction(paste); menu->popup(treeSigmod->mapToGlobal(position)); } } void Sigmodr::SigmodrUI::setupActions() { KStandardAction::openNew(this, SLOT(newSigmod()), actionCollection()); KStandardAction::open(this, SLOT(openSigmod()), actionCollection()); KRecentFilesAction* recent = KStandardAction::openRecent(this, SLOT(openSigmod(const KUrl&)), actionCollection()); recent->loadEntries(KGlobal::config()->group("Recent Files")); KStandardAction::save(this, SLOT(saveSigmod()), actionCollection()); KStandardAction::saveAs(this, SLOT(saveAsSigmod()), actionCollection()); KStandardAction::close(this, SLOT(closeSigmod()), actionCollection()); KStandardAction::quit(this, SLOT(closeAllSigmods()), actionCollection()); KStandardAction::cut(actionCollection()); KStandardAction::copy(actionCollection()); KStandardAction::paste(actionCollection()); KAction* download = actionCollection()->addAction("download_sigmod"); download->setText(i18n("Download")); download->setIcon(KIcon("arrow-down-double")); download->setShortcut(Qt::CTRL + Qt::Key_D); connect(download, SIGNAL(triggered()), this, SLOT(downloadSigmod())); KAction* upload = actionCollection()->addAction("upload_sigmod"); upload->setText(i18n("Upload")); upload->setIcon(KIcon("arrow-up-double")); upload->setShortcut(Qt::CTRL + Qt::Key_U); upload->setEnabled(false); connect(upload, SIGNAL(triggered()), this, SLOT(uploadSigmod())); KStandardAction::showMenubar(this, SLOT(toggleMenubar()), actionCollection()); KStandardAction::configureToolbars(this, SLOT(configureToolbars()), actionCollection()); createStandardStatusBarAction(); setStandardToolBarMenuEnabled(true); KStandardAction::keyBindings(guiFactory(), SLOT(configureShortcuts()), actionCollection()); KStandardAction::preferences(this, SLOT(preferences()), actionCollection()); setHelpMenuEnabled(true); createGUI(); }