diff --git a/CMakeLists.txt b/CMakeLists.txt index c28e6433..7be4c4c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,101 +1,99 @@ ## # This file is part of Rocs. # Copyright 2008-2011 Tomaz Canabrava # Copyright 2010 Wagner Reck # Copyright 2011-2014 Andreas Cord-Landwehr # # 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 2 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 . ## project(rocs) cmake_minimum_required(VERSION 3.3) # KDE Application Version, managed by release script set(KDE_APPLICATIONS_VERSION_MAJOR "20") set(KDE_APPLICATIONS_VERSION_MINOR "03") set(KDE_APPLICATIONS_VERSION_MICRO "70") set(KDE_APPLICATIONS_VERSION "${KDE_APPLICATIONS_VERSION_MAJOR}.${KDE_APPLICATIONS_VERSION_MINOR}.${KDE_APPLICATIONS_VERSION_MICRO}") find_package(ECM 5.15.0 REQUIRED NO_MODULE) find_package(KF5DocTools) find_package(Boost "1.49" REQUIRED) find_package(Grantlee5 "5.0.0" REQUIRED) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) include(ECMAddAppIcon) include(ECMAddTests) include(ECMInstallIcons) include(ECMOptionalAddSubdirectory) include(ECMSetupVersion) include(KDEInstallDirs) include(KDECompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) include(FeatureSummary) include(GenerateExportHeader) find_package(Qt5 5.4 REQUIRED NO_MODULE COMPONENTS Core Gui QuickWidgets Script - WebKit - WebKitWidgets Widgets ScriptTools Svg Test XmlPatterns ) find_package(KF5 5.15 REQUIRED COMPONENTS Archive Config CoreAddons Crash Declarative I18n ItemViews TextEditor XmlGui ) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${Boost_INCLUDE_DIRS} ) add_definitions(-DQT_NO_CAST_TO_ASCII) add_definitions(-DQT_NO_URL_CAST_FROM_STRING) remove_definitions(-DQT_NO_CAST_FROM_ASCII) remove_definitions(-DQT_NO_CAST_FROM_BYTEARRAY) remove_definitions(-DQT_NO_KEYWORDS) if(NOT KF5Declarative_VERSION VERSION_LESS "5.45") add_definitions(-DKDECLARATIVE_HAVE_SETCONTEXT=1) else() add_definitions(-DKDECLARATIVE_HAVE_SETCONTEXT=0) endif() ecm_optional_add_subdirectory(libgraphtheory) ecm_optional_add_subdirectory(src) ecm_optional_add_subdirectory(icons) if(KF5DocTools_FOUND) ecm_optional_add_subdirectory(doc) endif() set_package_properties(Boost PROPERTIES DESCRIPTION "Boost C++ Libraries" URL "https://www.boost.org") feature_summary(WHAT ALL) install(FILES org.kde.rocs.appdata.xml DESTINATION ${CMAKE_INSTALL_METAINFODIR}) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 08a9890e..1a8fd1a7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,118 +1,116 @@ ## # This file is part of Rocs. # Copyright 2008-2011 Tomaz Canabrava # Copyright 2010-2012 Wagner Reck # Copyright 2011-2014 Andreas Cord-Landwehr # # 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 2 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 . ## project(rocs) add_definitions(-DTRANSLATION_DOMAIN=\"rocs\") ecm_setup_version(KDE_APPLICATIONS_VERSION VARIABLE_PREFIX ROCS VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/rocsversion.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/RocsConfigVersion.cmake" ) ecm_optional_add_subdirectory(plugins) include_directories( ./ ) set( rocs_interface_SRCS ui/journalwidget.cpp ui/sidedockwidget.cpp ui/fileformatdialog.cpp ui/mainwindow.cpp ui/codeeditorwidget.cpp ui/documenttypeswidget.cpp ui/grapheditorwidget.cpp ui/nodetypesdelegate.cpp ui/edgetypesdelegate.cpp ui/scriptoutputwidget.cpp project/project.cpp plugins/scriptapi/scriptapiwidget.cpp plugins/scriptapi/object.cpp plugins/scriptapi/property.cpp plugins/scriptapi/method.cpp plugins/scriptapi/parameter.cpp plugins/scriptapi/scriptapimanager.cpp plugins/scriptapi/scriptapimodel.cpp ) set( rocs_SRCS main.cpp ${rocs_interface_SRCS} ${rocs_script_SRC} ) ki18n_wrap_ui( rocs_SRCS ui/journalwidget.ui ui/scriptoutputwidget.ui plugins/scriptapi/scriptapiwidget.ui ) kconfig_add_kcfg_files(rocs_Settings_SRCS settings.kcfgc) # add icon to executable on windows and mac ecm_add_app_icon(rocs_SRCS ICONS ${CMAKE_CURRENT_SOURCE_DIR}/../icons/16-apps-rocs.png ${CMAKE_CURRENT_SOURCE_DIR}/../icons/22-apps-rocs.png ${CMAKE_CURRENT_SOURCE_DIR}/../icons/32-apps-rocs.png ${CMAKE_CURRENT_SOURCE_DIR}/../icons/48-apps-rocs.png ${CMAKE_CURRENT_SOURCE_DIR}/../icons/64-apps-rocs.png ${CMAKE_CURRENT_SOURCE_DIR}/../icons/128-apps-rocs.png ) add_executable( rocs ${rocs_SRCS} ${rocs_Settings_SRCS} ) target_link_libraries(rocs PUBLIC rocsgraphtheory Grantlee5::Templates KF5::Archive KF5::CoreAddons KF5::Crash KF5::Declarative KF5::I18n KF5::ItemViews KF5::Parts KF5::Service KF5::TextEditor Qt5::Core Qt5::Quick Qt5::QuickWidgets - Qt5::WebKit - Qt5::WebKitWidgets Qt5::XmlPatterns ) ################## INSTALLS ########################## install(TARGETS rocs ${INSTALL_TARGETS_DEFAULT_ARGS}) install(PROGRAMS org.kde.rocs.desktop DESTINATION ${XDG_APPS_INSTALL_DIR}) install(FILES rocsui.rc DESTINATION ${KXMLGUI_INSTALL_DIR}/rocs) install(FILES rocs.kcfg DESTINATION ${KCFG_INSTALL_DIR}) ecm_optional_add_subdirectory(plugins/scriptapi) ecm_optional_add_subdirectory(autotests) diff --git a/src/plugins/scriptapi/html/objectApi.html b/src/plugins/scriptapi/html/objectApi.html index 1552c0f6..7e1bb41c 100644 --- a/src/plugins/scriptapi/html/objectApi.html +++ b/src/plugins/scriptapi/html/objectApi.html @@ -1,94 +1,94 @@ Script API Documentation Plugin: Object

{{ object.title }}

{% for para in object.description %}

{{ para }}

{% endfor %} {% if object.syntaxExample %}

{{ i18nSyntax }}

{{ object.syntaxExample }}
{% endif %} {% if properties %}

{{ i18nProperties }}

    {% for property in properties %}
  • {{ property.name }} : {% if property.typeLink %} - {{ property.type }} + {{ property.type }} {% else %} {{ property.type }} {% endif %} {% for paragraph in property.description %}

    {{ paragraph }}

    {% endfor %}
  • {% endfor %}
{% endif %} {% if methods %}

{{ i18nMethods }}

{{ i18nDetailedDescription }}

{% for method in methods %}

{{ method.name }}

{% for paragraph in method.description %}

{{ paragraph }}

{% endfor %} {% if method.parameters.count %} {% for parameter in method.parameters %} {% endfor %}
{{ i18nParameter }}{{ i18nDescription }}
{{ parameter.name }} : {% if parameter.typeLink %} - {{ parameter.type }} + {{ parameter.type }} {% else %} {{ parameter.type }} {% endif %} {{ parameter.info }}
{% endif %}

{{ i18nReturnType }} : {% if method.returnTypeLink %} - {{ method.returnType }} + {{ method.returnType }} {% else %} {{ method.returnType }} {% endif %}

{% endfor %} {% endif %}
diff --git a/src/plugins/scriptapi/html/overview.html b/src/plugins/scriptapi/html/overview.html index 2b1a56e3..87f7ac7c 100644 --- a/src/plugins/scriptapi/html/overview.html +++ b/src/plugins/scriptapi/html/overview.html @@ -1,39 +1,39 @@ Script API Documentation Plugin: Overview

{{ i18nScriptEngineApi }}

{{ i18nDocument }}

{{ i18nEngineComponents }}

diff --git a/src/plugins/scriptapi/scriptapimanager.cpp b/src/plugins/scriptapi/scriptapimanager.cpp index 4d068060..2aa0202d 100644 --- a/src/plugins/scriptapi/scriptapimanager.cpp +++ b/src/plugins/scriptapi/scriptapimanager.cpp @@ -1,328 +1,328 @@ /* * Copyright 2013-2014 Andreas Cord-Landwehr * * 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 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * 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 . */ #include "scriptapimanager.h" #include "object.h" #include "property.h" #include "method.h" #include "parameter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include ScriptApiManager::ScriptApiManager(QObject *parent) : QObject(parent) { } void ScriptApiManager::loadLocalData() { // locate directory const QString dir = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("rocs/kernelapi"), QStandardPaths::LocateDirectory); if (dir.isEmpty()) { qCritical() << "Could not locate \"rocs/kernelapi\" directory, abort loading script API documentation."; return; } const QStringList files = QDir(dir).entryList(QStringList() << QStringLiteral("*.xml")); Q_FOREACH (const QString &file, files) { loadObjectApi(QUrl::fromLocalFile(dir + '/' + file)); } } QList ScriptApiManager::objectApiList() const { return m_objectApiList; } Object * ScriptApiManager::objectApi(int index) const { Q_ASSERT (index >= 0 && index < m_objectApiList.count()); return m_objectApiList.at(index); } QString ScriptApiManager::objectApiDocument(const QString &identifier) { if (m_objectApiDocuments.contains(identifier)) { return m_objectApiDocuments.value(identifier); } // get object API object - Object *objectApi = 0; - foreach (Object *obj, m_objectApiList) { + Object *objectApi {nullptr}; + for (Object *obj : m_objectApiList) { if (obj->id() == identifier) { objectApi = obj; break; } } if (!objectApi) { qCritical() << "Could not find Object API with ID " << identifier; return QString(); } // initialize Grantlee engine Grantlee::Engine *engine = new Grantlee::Engine(this); QSharedPointer loader = QSharedPointer(new Grantlee::FileSystemTemplateLoader); loader->setTemplateDirs(QStandardPaths::standardLocations(QStandardPaths::DataLocation)); engine->addTemplateLoader(loader); Grantlee::Template t = engine->loadByName("plugin/apidoc/objectApi.html"); // create mapping QVariantHash mapping; // object QVariant objectVar = QVariant::fromValue(objectApi); mapping.insert("object", objectVar); // properties // we use QHash to override parent properties QHash propertyList; foreach (Property *property, objectApi->properties()) { propertyList.insert(property->name(), QVariant::fromValue(property)); } mapping.insert("properties", propertyList.values()); // properties QVariantList methodList; foreach (Method *method, objectApi->methods()) { methodList.append(QVariant::fromValue(method)); } mapping.insert("methods", methodList); mapping.insert("i18nSyntax", i18nc("@title", "Syntax")); mapping.insert("i18nProperties", i18nc("@title", "Properties")); mapping.insert("i18nParameters", i18nc("@title", "Parameters")); mapping.insert("i18nParameter", i18nc("@title", "Parameter")); mapping.insert("i18nMethods", i18nc("@title", "Methods")); mapping.insert("i18nType", i18nc("@title", "Type")); mapping.insert("i18nReturnType", i18nc("@title", "Return Type")); mapping.insert("i18nDetailedDescription", i18nc("@title", "Detailed Description")); mapping.insert("i18nDescription", i18nc("@title", "Description")); Grantlee::Context c(mapping); // create and cache HTML file m_objectApiDocuments.insert(objectApi->id(), t->render(&c)); return m_objectApiDocuments.value(identifier); } bool ScriptApiManager::loadObjectApi(const QUrl &path) { if (!path.isLocalFile()) { qWarning() << "Cannot open API file at " << path.toLocalFile() << ", aborting."; return false; } QXmlSchema schema = loadXmlSchema("kernelapi"); if (!schema.isValid()) { return false; } QDomDocument document = loadDomDocument(path, schema); if (document.isNull()) { qWarning() << "Could not parse document " << path.toLocalFile() << ", aborting."; return false; } QDomElement root(document.documentElement()); // this addition must be performed for every object before any HTML documentation page // is created m_objectApiCache.append(root.firstChildElement("id").text()); // create object documentation Object *objectApi = new Object(this); m_objectApiList.append(objectApi); emit objectApiAboutToBeAdded(objectApi, m_objectApiList.count() - 1); objectApi->setTitle(root.firstChildElement("name").text()); objectApi->setId(root.firstChildElement("id").text()); objectApi->setComponentType(root.firstChildElement("componentType").text()); objectApi->setSyntaxExample(root.firstChildElement("syntax").text()); QStringList paragraphs; for (QDomElement descriptionNode = root.firstChildElement("description").firstChildElement("para"); !descriptionNode.isNull(); descriptionNode = descriptionNode.nextSiblingElement()) { paragraphs.append(i18nc("Scripting API Description", descriptionNode.text().toUtf8())); } objectApi->setDescription(paragraphs); // set property documentation for (QDomElement propertyNode = root.firstChildElement("properties").firstChildElement(); !propertyNode.isNull(); propertyNode = propertyNode.nextSiblingElement()) { Property *property = new Property(objectApi); property->setName(propertyNode.firstChildElement("name").text()); property->setType(propertyNode.firstChildElement("type").text()); QStringList paragraphs; for (QDomElement descriptionNode = propertyNode.firstChildElement("description").firstChildElement("para"); !descriptionNode.isNull(); descriptionNode = descriptionNode.nextSiblingElement()) { paragraphs.append(i18nc("Scripting API Description", descriptionNode.text().toUtf8())); } property->setDescription(paragraphs); if (m_objectApiCache.contains(property->type())) { property->setTypeLink(property->type()); } objectApi->addProperty(property); } // set method documentation for (QDomElement methodNode = root.firstChildElement("methods").firstChildElement(); !methodNode.isNull(); methodNode = methodNode.nextSiblingElement()) { Method *method = new Method(objectApi); method->setName(methodNode.firstChildElement("name").text()); method->setReturnType(methodNode.firstChildElement("returnType").text()); if (m_objectApiCache.contains(method->returnType())) { method->setReturnTypeLink(method->returnType()); } QStringList paragraphs; for (QDomElement descriptionNode = methodNode.firstChildElement("description").firstChildElement("para"); !descriptionNode.isNull(); descriptionNode = descriptionNode.nextSiblingElement()) { paragraphs.append(i18nc("Scripting API Description", descriptionNode.text().toUtf8())); } method->setDescription(paragraphs); for (QDomElement parameterNode = methodNode.firstChildElement("parameters").firstChildElement(); !parameterNode.isNull(); parameterNode = parameterNode.nextSiblingElement()) { QString typeLink; if (m_objectApiCache.contains(parameterNode.firstChildElement("type").text())) { typeLink = parameterNode.firstChildElement("type").text(); } method->addParameter( parameterNode.firstChildElement("name").text(), parameterNode.firstChildElement("type").text(), parameterNode.firstChildElement("info").text(), typeLink); } objectApi->addMethod(method); } emit objectApiAdded(); return true; } QString ScriptApiManager::apiOverviewDocument() const { // initialize Grantlee engine Grantlee::Engine engine; QSharedPointer loader = QSharedPointer(new Grantlee::FileSystemTemplateLoader); loader->setTemplateDirs(QStandardPaths::standardLocations(QStandardPaths::DataLocation)); engine.addTemplateLoader(loader); Grantlee::Template t = engine.loadByName("plugin/apidoc/overview.html"); // create mapping QVariantHash mapping; // objects QVariantList kernelModuleList; QVariantList elementList; foreach (Object *object, m_objectApiList) { switch (object->componentType()) { case Object::KernelModule: kernelModuleList.append(QVariant::fromValue(object)); break; case Object::Document: elementList.append(QVariant::fromValue(object)); break; case Object::Edge: elementList.append(QVariant::fromValue(object)); break; case Object::Node: elementList.append(QVariant::fromValue(object)); break; } } mapping.insert("kernelModules", kernelModuleList); mapping.insert("kernelElements", elementList); // localized strings mapping.insert("i18nScriptEngineApi", i18nc("@title", "Script Engine API")); mapping.insert("i18nDocument", i18nc("@title", "The Graph Document")); mapping.insert("i18nObjects", i18nc("@title", "Objects")); mapping.insert("i18nEngineComponents", i18nc("@title", "Script Engine Modules")); Grantlee::Context c(mapping); // create HTML file return t->render(&c); } QXmlSchema ScriptApiManager::loadXmlSchema(const QString &schemeName) const { QString relPath = QString("rocs/schemes/%1.xsd").arg(schemeName); QUrl file = QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, relPath)); QXmlSchema schema; if (file.isEmpty() || schema.load(file) == false) { qWarning() << "Schema at file " << file.toLocalFile() << " is invalid."; } return schema; } QDomDocument ScriptApiManager::loadDomDocument(const QUrl &path, const QXmlSchema &schema) const { QDomDocument document; QXmlSchemaValidator validator(schema); if (!validator.validate(path)) { qWarning() << "Schema is not valid, aborting loading of XML document:" << path.toLocalFile(); return document; } QString errorMsg; QFile file(path.toLocalFile()); if (file.open(QIODevice::ReadOnly)) { if (!document.setContent(&file, &errorMsg)) { qWarning() << errorMsg; } } else { qWarning() << "Could not open XML document " << path.toLocalFile() << " for reading, aborting."; } return document; } diff --git a/src/plugins/scriptapi/scriptapiwidget.cpp b/src/plugins/scriptapi/scriptapiwidget.cpp index 3f83f550..ea9a7801 100644 --- a/src/plugins/scriptapi/scriptapiwidget.cpp +++ b/src/plugins/scriptapi/scriptapiwidget.cpp @@ -1,192 +1,188 @@ /* * Copyright 2013-2014 Andreas Cord-Landwehr * * 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 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * 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 . */ #include "scriptapiwidget.h" #include "scriptapimanager.h" #include "scriptapimodel.h" -#include #include +#include #include #include ScriptApiWidget::ScriptApiWidget(QWidget* parent) : QWidget(parent) , m_manager(new ScriptApiManager(this)) , m_historyPointer(-1) { m_baseUrl = QUrl::fromLocalFile( QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("rocs/plugin/apidoc/"), QStandardPaths::LocateDirectory)); ui = new Ui::ScriptApiWidget; ui->setupUi(this); ui->buttonTree->setIcon(QIcon::fromTheme("view-sidetree")); ui->buttonHome->setIcon(QIcon::fromTheme("go-home")); ui->buttonPrev->setIcon(QIcon::fromTheme("go-previous-view")); ui->buttonNext->setIcon(QIcon::fromTheme("go-next-view")); ui->buttonPrev->setEnabled(false); ui->buttonNext->setEnabled(false); m_manager->loadLocalData(); m_model = new ScriptApiModel(m_manager->objectApiList(), this); connect(ui->buttonTree, &QPushButton::clicked, this, &ScriptApiWidget::showTreeOutline); connect(ui->buttonHome, &QPushButton::clicked, this, static_cast(&ScriptApiWidget::showHtmlOutline)); connect(ui->docTree, &QTreeView::clicked, this, &ScriptApiWidget::showDetails); connect(ui->buttonNext, &QPushButton::clicked, this, &ScriptApiWidget::historyGoForward); connect(ui->buttonPrev, &QPushButton::clicked, this, &ScriptApiWidget::historyGoBack); // listen to all links for ids - connect(ui->docDetails, &QWebView::linkClicked, this, static_cast(&ScriptApiWidget::showObjectApi)); + connect(ui->docDetails, &QTextBrowser::anchorClicked, this, static_cast(&ScriptApiWidget::showObjectApi)); // this option has the following idea: // * handle relative anchor calls directly in the web engine // * use for switching between object pages the path "http://virtual/" // such that that path is handles as external and progapages to this widget // drawback: history only works for object pages, not for anchors - ui->docDetails->page()->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks); + ui->docDetails->setOpenExternalLinks(false); ui->docTree->setModel(m_model); + showHtmlOutline(); } void ScriptApiWidget::showTreeOutline() { ui->pageStack->setCurrentIndex(0); } void ScriptApiWidget::showHtmlOutline() { showHtmlOutline(true); } void ScriptApiWidget::showHtmlOutline(bool logHistory) { - ui->docDetails->setHtml(m_manager->apiOverviewDocument(), m_baseUrl); + ui->docDetails->setHtml(m_manager->apiOverviewDocument()); ui->pageStack->setCurrentIndex(1); if (!logHistory) { return; } // clear forward history if (m_historyPointer < m_history.count() - 1) { while (m_historyPointer < m_history.count() - 1) { m_history.removeAt(m_history.count() - 1); } ui->buttonNext->setEnabled(false); } ++m_historyPointer; m_history.append("m_outline"); // use this identifier for the script api html outline if (m_historyPointer > 0) { ui->buttonPrev->setEnabled(true); } } void ScriptApiWidget::showDetails(const QModelIndex &index) { showObjectApi(m_model->data(index, ScriptApiModel::DocumentRole).toString(), true); ui->pageStack->setCurrentIndex(1); // TODO jump to anchor // m_model->data(index, ApiDocModel::AnchorRole).toString(); } void ScriptApiWidget::showObjectApi(const QString &id, bool logHistory=true) { QString htmlDocument = m_manager->objectApiDocument(id); - ui->docDetails->setHtml(htmlDocument, m_baseUrl); + ui->docDetails->setHtml(htmlDocument); ui->pageStack->setCurrentIndex(1); if (logHistory) { // update history if (m_historyPointer < m_history.count() - 1) { while (m_historyPointer < m_history.count() -1) { m_history.removeAt(m_history.count() - 1); } ui->buttonNext->setEnabled(false); } m_history.append(id); ++m_historyPointer; if (m_historyPointer > 0) { ui->buttonPrev->setEnabled(true); } } } void ScriptApiWidget::showObjectApi(const QUrl &aliasPage) { if (aliasPage.toString().isEmpty()) { qCritical() << "No path given, aborting."; return; } - QString path = aliasPage.toString(); - int len = path.length() - 1; - while (path.at(len) != '/' && len >= 0) { - --len; - } - - if (len <= 0) { - showObjectApi(path); + // distinguish anchors and pages + const QString path = aliasPage.toString(); + if (path.startsWith('#')) { + ui->docDetails->scrollToAnchor(path); } else { - QString id = path.mid(len + 1); - showObjectApi(id); + showObjectApi(path); } } void ScriptApiWidget::historyGoBack() { if (m_historyPointer <= 0) { qCritical() << "Cannot go back in history, none exist"; return; } --m_historyPointer; if (m_history.at(m_historyPointer) == "m_outline") { showHtmlOutline(false); } else { showObjectApi(m_history.at(m_historyPointer), false); } // set buttons ui->buttonNext->setEnabled(true); if (m_historyPointer <= 0) { ui->buttonPrev->setEnabled(false); } } void ScriptApiWidget::historyGoForward() { if (m_historyPointer >= m_history.length() - 1) { qCritical() << "Cannot go forward in history, none exist"; return; } ++m_historyPointer; if (m_history.at(m_historyPointer) == "m_outline") { showHtmlOutline(false); } else { showObjectApi(m_history.at(m_historyPointer), false); } // set buttons ui->buttonPrev->setEnabled(true); if (m_historyPointer >= m_history.count() - 1) { ui->buttonNext->setEnabled(false); } } diff --git a/src/plugins/scriptapi/scriptapiwidget.ui b/src/plugins/scriptapi/scriptapiwidget.ui index f6e36d28..c200a0f5 100644 --- a/src/plugins/scriptapi/scriptapiwidget.ui +++ b/src/plugins/scriptapi/scriptapiwidget.ui @@ -1,131 +1,118 @@ ScriptApiWidget 0 0 400 333 Rocs Scripting API - 0 + 1 - - - - about:blank - - - + 24 16777215 0 0 24 16777215 Qt::Horizontal 40 20 24 16777215 Qt::Vertical 24 16777215 - - - QWebView - QWidget -
QtWebKit/QWebView
-
-
diff --git a/src/ui/documenttypeswidget.cpp b/src/ui/documenttypeswidget.cpp index 846c2008..04105405 100644 --- a/src/ui/documenttypeswidget.cpp +++ b/src/ui/documenttypeswidget.cpp @@ -1,139 +1,134 @@ /* * Copyright 2014 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "documenttypeswidget.h" #include "nodetypesdelegate.h" #include "edgetypesdelegate.h" #include "libgraphtheory/models/nodetypemodel.h" #include "libgraphtheory/models/edgetypemodel.h" #include "libgraphtheory/nodetype.h" #include "libgraphtheory/edgetype.h" #include #include #include #include #include #include #include using namespace GraphTheory; DocumentTypesWidget::DocumentTypesWidget(QWidget *parent) : QWidget(parent) , m_createNodeTypeButton(new QPushButton(this)) , m_createEdgeTypeButton(new QPushButton(this)) { QGridLayout *layout = new QGridLayout(this); // node types layout->addWidget(new QLabel(i18nc("@title", "Node Types"))); m_createNodeTypeButton->setText(i18n("Create Type")); layout->addWidget(m_createNodeTypeButton); QListView *nodeTypeView = new QListView(this); NodeTypesDelegate *nodeDelegate = new NodeTypesDelegate(nodeTypeView); nodeTypeView->setItemDelegate(nodeDelegate); nodeTypeView->setModel(&m_nodeTypeModel); layout->addWidget(nodeTypeView); connect(nodeDelegate, &NodeTypesDelegate::colorChanged, this, &DocumentTypesWidget::onNodeTypeColorChanged); connect(nodeDelegate, &NodeTypesDelegate::nameChanged, this, &DocumentTypesWidget::onNodeTypeNameChanged); connect(m_createNodeTypeButton, &QPushButton::clicked, this, &DocumentTypesWidget::onCreateNodeType); // edge types layout->addWidget(new QLabel(i18nc("@title", "Edge Types"))); m_createEdgeTypeButton->setText(i18n("Create Type")); layout->addWidget(m_createEdgeTypeButton); QListView *edgeTypeView = new QListView(this); EdgeTypesDelegate *edgeDelegate = new EdgeTypesDelegate(edgeTypeView); edgeTypeView->setItemDelegate(edgeDelegate); edgeTypeView->setModel(&m_edgeTypeModel); layout->addWidget(edgeTypeView); connect(edgeDelegate, &EdgeTypesDelegate::colorChanged, this, &DocumentTypesWidget::onEdgeTypeColorChanged); connect(edgeDelegate, &EdgeTypesDelegate::nameChanged, this, &DocumentTypesWidget::onEdgeTypeNameChanged); connect(edgeDelegate, &EdgeTypesDelegate::directionChanged, this, &DocumentTypesWidget::onEdgeTypeDirectionChanged); connect(m_createEdgeTypeButton, &QPushButton::clicked, this, &DocumentTypesWidget::onCreateEdgeType); setLayout(layout); show(); } -DocumentTypesWidget::~DocumentTypesWidget() -{ - -} - void DocumentTypesWidget::setDocument(GraphDocumentPtr document) { m_createNodeTypeButton->setEnabled(document ? true : false); m_createEdgeTypeButton->setEnabled(document ? true : false); m_document = document; m_nodeTypeModel.setDocument(document); m_edgeTypeModel.setDocument(document); } void DocumentTypesWidget::onNodeTypeColorChanged(const QModelIndex &index, const QColor &color) { m_nodeTypeModel.setData(index, QVariant::fromValue(color), NodeTypeModel::ColorRole); } void DocumentTypesWidget::onNodeTypeNameChanged(const QModelIndex& index, const QString& name) { m_nodeTypeModel.setData(index, QVariant(name), NodeTypeModel::TitleRole); } void DocumentTypesWidget::onCreateNodeType() { NodeTypePtr type = NodeType::create(m_document); type->setName(i18n("unnamed")); } void DocumentTypesWidget::onEdgeTypeColorChanged(const QModelIndex &index, const QColor &color) { m_edgeTypeModel.setData(index, QVariant::fromValue(color), EdgeTypeModel::ColorRole); } void DocumentTypesWidget::onEdgeTypeNameChanged(const QModelIndex& index, const QString& name) { m_edgeTypeModel.setData(index, QVariant(name), EdgeTypeModel::TitleRole); } void DocumentTypesWidget::onEdgeTypeDirectionChanged(const QModelIndex& index, const EdgeType::Direction& direction) { m_edgeTypeModel.setData(index, direction, EdgeTypeModel::DirectionRole); } void DocumentTypesWidget::onCreateEdgeType() { EdgeTypePtr type = EdgeType::create(m_document); type->setName(i18n("unnamed")); } diff --git a/src/ui/documenttypeswidget.h b/src/ui/documenttypeswidget.h index 0d1c705a..a7046273 100644 --- a/src/ui/documenttypeswidget.h +++ b/src/ui/documenttypeswidget.h @@ -1,58 +1,58 @@ /* * Copyright 2014 Andreas Cord-Landwehr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef DOCUMENTTYPESWIDGET_H #define DOCUMENTTYPESWIDGET_H #include "libgraphtheory/edgetype.h" #include "libgraphtheory/models/nodetypemodel.h" #include "libgraphtheory/models/edgetypemodel.h" #include class QPushButton; class DocumentTypesWidget : public QWidget { Q_OBJECT public: explicit DocumentTypesWidget(QWidget *parent); - ~DocumentTypesWidget(); + ~DocumentTypesWidget() = default; public Q_SLOTS: void setDocument(GraphTheory::GraphDocumentPtr document); private Q_SLOTS: void onNodeTypeColorChanged(const QModelIndex &index, const QColor &color); void onNodeTypeNameChanged(const QModelIndex &index, const QString &name); void onCreateNodeType(); void onEdgeTypeColorChanged(const QModelIndex &index, const QColor &color); void onEdgeTypeNameChanged(const QModelIndex &index, const QString &name); void onEdgeTypeDirectionChanged(const QModelIndex &index, const GraphTheory::EdgeType::Direction &direction); void onCreateEdgeType(); private: GraphTheory::GraphDocumentPtr m_document; GraphTheory::NodeTypeModel m_nodeTypeModel; GraphTheory::EdgeTypeModel m_edgeTypeModel; QPushButton *m_createNodeTypeButton; QPushButton *m_createEdgeTypeButton; }; #endif diff --git a/src/ui/journalwidget.cpp b/src/ui/journalwidget.cpp index af54c135..d6b78ae2 100644 --- a/src/ui/journalwidget.cpp +++ b/src/ui/journalwidget.cpp @@ -1,69 +1,69 @@ /* * Copyright 2012-2014 Andreas Cord-Landwehr * * 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 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * 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 . */ #include "journalwidget.h" #include "project/project.h" #include "ui_journalwidget.h" #include #include #include #include #include #include JournalEditorWidget::JournalEditorWidget(QWidget* parent) : QWidget(parent) - , m_currentProject(0) + , m_currentProject(nullptr) , m_modified(false) { ui = new Ui::JournalEditorWidget; ui->setupUi(this); connect(ui->editor, &KRichTextWidget::textChanged, this, &JournalEditorWidget::setModified); } void JournalEditorWidget::openJournal(Project *project) { m_currentProject = project; if (!project) { qCritical() << "No project specified! Cannot set journal widget."; return; } if (!project->journalDocument()) { qDebug() << "Skipping loading of journal file, project does not contain any, yet."; ui->editor->setHtml(QString()); } else { ui->editor->setHtml(project->journalDocument()->text()); } // explicitly set journal to be unmodified, since setting of text to editor caused modifed // value to be true m_modified = false; } void JournalEditorWidget::setModified() { m_modified = true; } bool JournalEditorWidget::isModified() const { return m_modified; } diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index fc607445..bd0359dc 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -1,617 +1,617 @@ /* This file is part of Rocs. Copyright 2008-2011 Tomaz Canabrava Copyright 2008 Ugo Sangiori Copyright 2010-2011 Wagner Reck Copyright 2011-2014 Andreas Cord-Landwehr 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 2 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 . */ #include "mainwindow.h" #include "rocsversion.h" #include "settings.h" #include "libgraphtheory/editor.h" #include "libgraphtheory/editorplugins/editorpluginmanager.h" #include "libgraphtheory/kernel/kernel.h" #include "libgraphtheory/view.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ui/documenttypeswidget.h" #include "ui/codeeditorwidget.h" #include "ui/scriptoutputwidget.h" #include "ui/sidedockwidget.h" #include "ui/fileformatdialog.h" #include "ui/journalwidget.h" #include "grapheditorwidget.h" #include "plugins/scriptapi/scriptapiwidget.h" #include "project/project.h" using namespace GraphTheory; MainWindow::MainWindow() : KXmlGuiWindow() - , m_currentProject(0) + , m_currentProject(nullptr) , m_kernel(new Kernel) , m_codeEditorWidget(new CodeEditorWidget(this)) , m_graphEditorWidget(new GraphEditorWidget(this)) , m_outputWidget(new ScriptOutputWidget(this)) { setObjectName("RocsMainWindow"); m_graphEditor = new GraphTheory::Editor(); setupWidgets(); setupActions(); setupGUI(Keys | Save | Create); setupToolsPluginsAction(); // setup kernel connect(m_kernel, &Kernel::message, m_outputWidget, &ScriptOutputWidget::processMessage); // TODO: use welcome widget instead of creating default empty project createProject(); updateCaption(); // update rocs config version Settings::setVersion(ROCS_VERSION_STRING); // disable save action from kpart, since we take care for the editor by global save action // here "file_save" is the action identifier from katepartui.rc // note that we may not use that name for our own actions foreach(KActionCollection *ac, KActionCollection::allCollections()) { if (ac->action("file_save")) { ac->action("file_save")->setDisabled(true); } } } MainWindow::~MainWindow() { Settings::setVSplitterSizeTop(m_vSplitter->sizes() [0]); Settings::setVSplitterSizeBottom(m_vSplitter->sizes() [1]); Settings::setHSplitterSizeLeft(m_hSplitter->sizes() [0]); Settings::setHSplitterSizeRight(m_hSplitter->sizes() [1]); Settings::setHScriptSplitterSizeLeft(m_hScriptSplitter->sizes() [0]); Settings::setHScriptSplitterSizeRight(m_hScriptSplitter->sizes() [1]); m_recentProjects->saveEntries(Settings::self()->config()->group("RecentFiles")); Settings::self()->save(); m_graphEditor->deleteLater(); m_kernel->deleteLater(); } void MainWindow::closeEvent(QCloseEvent *event) { if (queryClose() == true) { event->accept(); } else { event->ignore(); } return; } void MainWindow::setupWidgets() { // setup main widgets QWidget *sidePanel = setupSidePanel(); QWidget *scriptPanel = setupScriptPanel(); // splits the main window horizontal m_vSplitter = new QSplitter(this); m_vSplitter->setOrientation(Qt::Vertical); m_vSplitter->addWidget(m_graphEditorWidget); m_vSplitter->addWidget(scriptPanel); // horizontal arrangement m_hSplitter = new QSplitter(this); m_hSplitter->setOrientation(Qt::Horizontal); m_hSplitter->addWidget(m_vSplitter); m_hSplitter->addWidget(sidePanel); // set sizes for script panel m_hScriptSplitter->setSizes({ Settings::hScriptSplitterSizeLeft(), Settings::hScriptSplitterSizeRight(), 80 }); // set sizes for vertical splitter m_vSplitter->setSizes({ Settings::vSplitterSizeTop(), Settings::vSplitterSizeBottom() }); // set sizes for side panel // the following solves the setting of the panel width if it was closed at previous session int panelWidth = Settings::hSplitterSizeRight(); if (panelWidth == 0) { //FIXME this is only a workaround // that fixes the wrong saving of hSplitterSizeRight panelWidth = 400; } m_hSplitter->setSizes({ Settings::hSplitterSizeLeft(), panelWidth }); setCentralWidget(m_hSplitter); } QWidget* MainWindow::setupScriptPanel() { m_hScriptSplitter = new QSplitter(this); m_hScriptSplitter->setOrientation(Qt::Horizontal); KToolBar *executeCommands = new KToolBar(this); executeCommands->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); executeCommands->setOrientation(Qt::Vertical); m_runScript = new QAction(QIcon::fromTheme("media-playback-start"), i18nc("@action:intoolbar Script Execution", "Run"), this); m_runScript->setToolTip(i18nc("@info:tooltip", "Execute currently active script on active graph document.")); m_stopScript = new QAction(QIcon::fromTheme("process-stop"), i18nc("@action:intoolbar Script Execution", "Stop"), this); m_stopScript->setToolTip(i18nc("@info:tooltip", "Stop script execution.")); m_stopScript->setEnabled(false); m_openDebugger = new QAction(QIcon::fromTheme("system-run"), i18nc("@action:intoolbar Open Debugger", "Debugger"), this); m_openDebugger->setToolTip(i18nc("@info:tooltip", "Open the Javascript code debugger.")); m_openDebugger->setCheckable(true); executeCommands->addAction(m_runScript); executeCommands->addAction(m_stopScript); executeCommands->addAction(m_openDebugger); // add actions to action collection to be able to set shortcuts on them in the ui actionCollection()->addAction("_runScript", m_runScript); actionCollection()->addAction("_stopScript", m_stopScript); actionCollection()->addAction("_openDebugger", m_openDebugger); connect(m_runScript, &QAction::triggered, this, &MainWindow::executeScript); connect(m_stopScript, &QAction::triggered, this, &MainWindow::stopScript); connect(m_openDebugger, &QAction::triggered, this, &MainWindow::checkDebugger); m_hScriptSplitter->addWidget(m_codeEditorWidget); m_hScriptSplitter->addWidget(m_outputWidget); QWidget *scriptInterface = new QWidget(this); scriptInterface->setLayout(new QHBoxLayout); scriptInterface->layout()->addWidget(m_hScriptSplitter); scriptInterface->layout()->addWidget(executeCommands); return scriptInterface; } QWidget* MainWindow::setupSidePanel() { // add sidebar SidedockWidget* sideDock = new SidedockWidget(this); addToolBar(Qt::RightToolBarArea, sideDock->toolbar()); // add widgets to dock // document property widgets DocumentTypesWidget *documentTypesWidget = new DocumentTypesWidget(this); connect(this, &MainWindow::graphDocumentChanged, documentTypesWidget, &DocumentTypesWidget::setDocument); sideDock->addDock(documentTypesWidget, i18n("Element Types"), QIcon::fromTheme("document-properties")); if (m_currentProject && m_currentProject->activeGraphDocument()) { documentTypesWidget->setDocument(m_currentProject->activeGraphDocument()); } // Project Journal m_journalWidget = new JournalEditorWidget(this); sideDock->addDock(m_journalWidget, i18nc("@title", "Journal"), QIcon::fromTheme("story-editor")); // Rocs scripting API documentation ScriptApiWidget* apiDoc = new ScriptApiWidget(this); sideDock->addDock(apiDoc, i18nc("@title", "Scripting API"), QIcon::fromTheme("documentation")); return sideDock; } void MainWindow::setProject(Project *project) { m_codeEditorWidget->setProject(project); m_graphEditorWidget->setProject(project); m_journalWidget->openJournal(project); updateCaption(); if (m_currentProject) { m_currentProject->disconnect(this); m_currentProject->deleteLater(); } connect(project, static_cast(&Project::activeGraphDocumentChanged), this, &MainWindow::graphDocumentChanged); connect(project, &Project::modifiedChanged, this, &MainWindow::updateCaption); m_currentProject = project; emit graphDocumentChanged(m_currentProject->activeGraphDocument()); } void MainWindow::setupActions() { KStandardAction::quit(this, SLOT(quit()), actionCollection()); KStandardAction::preferences(this, SLOT(showConfigurationDialog()), actionCollection()); // setup graph visual editor actions and add them to mainwindow action collection // m_graphEditor->setupActions(actionCollection()); //FIXME add editor actions to main action collection // Menu actions QAction *newProjectAction = new QAction(QIcon::fromTheme("document-new"), i18nc("@action:inmenu", "New Project"), this); newProjectAction->setShortcutContext(Qt::ApplicationShortcut); actionCollection()->addAction("new-project", newProjectAction); actionCollection()->setDefaultShortcut(newProjectAction, QKeySequence::New); connect(newProjectAction, &QAction::triggered, this, &MainWindow::createProject); QAction *projectSaveAction = new QAction(QIcon::fromTheme("document-save"), i18nc("@action:inmenu", "Save Project"), this); projectSaveAction->setShortcutContext(Qt::ApplicationShortcut); actionCollection()->addAction("save-project", projectSaveAction); actionCollection()->setDefaultShortcut(projectSaveAction, QKeySequence::Save); connect(projectSaveAction, &QAction::triggered, this, &MainWindow::saveProject); QAction *projectOpenAction = new QAction(QIcon::fromTheme("document-open"), i18nc("@action:inmenu", "Open Project"), this); projectOpenAction->setShortcutContext(Qt::ApplicationShortcut); actionCollection()->addAction("open-project", projectOpenAction); actionCollection()->setDefaultShortcut(projectOpenAction, QKeySequence::Open); connect(projectOpenAction, &QAction::triggered, this, [=] () { openProject(); }); m_recentProjects = new KRecentFilesAction(QIcon ("document-open"), i18nc("@action:inmenu","Recent Projects"), this); connect(m_recentProjects, &KRecentFilesAction::urlSelected, this, &MainWindow::openProject); actionCollection()->addAction("recent-project", m_recentProjects); m_recentProjects->loadEntries(Settings::self()->config()->group("RecentFiles")); createAction("document-save-as", i18nc("@action:inmenu", "Save Project as"), "save-project-as", SLOT(saveProjectAs()), this); createAction("document-new", i18nc("@action:inmenu", "New Graph Document"), "new-graph", SLOT(createGraphDocument()), this); createAction("document-new", i18nc("@action:inmenu", "New Script File"), "new-script", SLOT(tryToCreateCodeDocument()), this); createAction("document-import", i18nc("@action:inmenu", "Import Graph"), "import-graph", SLOT(importGraphDocument()), this); createAction("document-export", i18nc("@action:inmenu", "Export Graph as"), "export-graph-as", SLOT(exportGraphDocument()), this); createAction("document-import", i18nc("@action:inmenu", "Import Script"), "add-script", SLOT(importCodeDocument()), this); createAction("document-export", i18nc("@action:inmenu", "Export Script"), "export-script", SLOT(exportCodeDocument()), this); } void MainWindow::createAction(const QByteArray& iconName, const QString& actionTitle, const QString& actionName, const char* slot, QObject *parent) { QAction* action = new QAction(QIcon::fromTheme(iconName), actionTitle, parent); actionCollection()->addAction(actionName, action); connect(action, SIGNAL(triggered(bool)), parent, slot); } void MainWindow::showConfigurationDialog() { QPointer dialog = new KConfigDialog(this, "settings", Settings::self()); KTextEditor::Editor *editor = KTextEditor::Editor::instance(); for (int index = 0; index < editor->configPages(); ++index) { KTextEditor::ConfigPage *page = editor->configPage(index, dialog); dialog->addPage(page, page->name(), page->icon().name(), page->fullName()); } dialog->exec(); } void MainWindow::setupToolsPluginsAction() { QList availablePlugins = m_graphEditorPluginManager.plugins(); QList actions; int count = 0; for (auto plugin : availablePlugins) { auto *action = new QAction(plugin->displayName(), this); action->setData(count++); connect(action, &QAction::triggered, this, &MainWindow::showEditorPluginDialog); actions << action; } unplugActionList("tools_plugins"); plugActionList("tools_plugins", actions); } void MainWindow::importCodeDocument() { QString startDirectory = Settings::lastOpenedDirectory(); QUrl fileUrl = QUrl::fromLocalFile(QFileDialog::getOpenFileName(this, i18nc("@title:window", "Import Script into Project"), startDirectory)); if (fileUrl.isEmpty()) { return; } m_currentProject->importCodeDocument(fileUrl); Settings::setLastOpenedDirectory(startDirectory); } void MainWindow::exportCodeDocument() { QString startDirectory = Settings::lastOpenedDirectory(); QUrl fileUrl = QUrl::fromLocalFile(QFileDialog::getSaveFileName(this, i18nc("@title:window", "Export Script"), startDirectory, i18n("JavaScript (*.js)"))); m_codeEditorWidget->activeDocument()->saveAs(fileUrl); } void MainWindow::createProject() { if (!queryClose()) { return; } Project *project = new Project(m_graphEditor); project->createCodeDocument(i18n("untitled")); project->addGraphDocument(m_graphEditor->createDocument()); project->setModified(false); setProject(project); } void MainWindow::saveProject() { if (m_currentProject->projectUrl().isEmpty()) { saveProjectAs(); return; } m_currentProject->projectSave(); m_recentProjects->addUrl(m_currentProject->projectUrl()); updateCaption(); } void MainWindow::saveProjectAs() { QString startDirectory = Settings::lastOpenedDirectory(); QString file = QFileDialog::getSaveFileName(this, i18nc("@title:window", "Save Project As"), startDirectory, i18n("Rocs Projects (*.rocs)")); if (file.isEmpty()) { qCritical() << "Filename is empty and no script file was created."; return; } QFileInfo fi(file); if (fi.exists()) { const int btnCode = KMessageBox::warningContinueCancel( this, i18nc("@info", "A file named \"%1\" already exists. Are you sure you want to overwrite it?", fi.fileName()), i18nc("@title:window", "Overwrite File?"), KStandardGuiItem::overwrite()); if (btnCode == KMessageBox::Cancel) { return; // cancel saving } } Settings::setLastOpenedDirectory(m_currentProject->projectUrl().path()); m_currentProject->projectSaveAs(QUrl::fromLocalFile(file)); m_recentProjects->addUrl(QUrl::fromLocalFile(file)); updateCaption(); } void MainWindow::openProject(const QUrl &fileName) { if (!queryClose()) { return; } QString startDirectory = Settings::lastOpenedDirectory(); QUrl file = fileName; if (file.isEmpty()) { // show open dialog file = QUrl::fromLocalFile(QFileDialog::getOpenFileName(this, i18nc("@title:window", "Open Project Files"), startDirectory, i18n("Rocs projects (*.rocs)"))); } if (file.isEmpty()) { return; } Project *project = new Project(file, m_graphEditor); setProject(project); m_recentProjects->addUrl(file); updateCaption(); Settings::setLastOpenedDirectory(file.path()); } void MainWindow::updateCaption() { if (!m_currentProject) { return; } QString modified; if (m_currentProject->isModified()) { modified = '*'; } if (m_currentProject->projectUrl().isEmpty()) { setCaption(i18nc("caption text for temporary project", "[ untitled ]%1", modified)); } else { setCaption(QString("[ %1 ]%2").arg(m_currentProject->projectUrl().toLocalFile()).arg(modified)); } } QString MainWindow::uniqueFilename(const QString &basePrefix, const QString &suffix) { QFile targetFile; QString basePath = m_currentProject->projectUrl().path(); QString fullSuffix = '.' + suffix; QString fullPrefix = basePrefix; if (fullPrefix.isNull()) { fullPrefix = m_currentProject->projectUrl().fileName().remove(QRegExp(".rocs*$")); } else if (fullPrefix.endsWith(fullSuffix)) { fullPrefix.remove(QRegExp(fullSuffix + '$')); } targetFile.setFileName(basePath + fullPrefix + fullSuffix); for(int i = 1; targetFile.exists(); i++) { targetFile.setFileName(basePath + fullPrefix + QString::number(i) + fullSuffix); } return targetFile.fileName(); } void MainWindow::tryToCreateCodeDocument() { QString basePrefix = QInputDialog::getText(this, i18n("ScriptName"), i18n("Enter the name of your new script")); if (basePrefix.isNull()) { qDebug() << "Filename is empty and no script file was created."; return; } QString fullPath = m_currentProject->workingDir() + QLatin1Char('/') + basePrefix + QStringLiteral(".js"); QFileInfo file(fullPath); if (file.exists()) { KMessageBox::error(this, i18n("File already exists.")); return; } m_currentProject->createCodeDocument(basePrefix); } void MainWindow::createGraphDocument() { GraphDocumentPtr document = m_graphEditor->createDocument(); m_currentProject->addGraphDocument(document); } bool MainWindow::queryClose() { if (!m_currentProject) { return true; } if (!m_currentProject->isModified()) { return true; } const int btnCode = KMessageBox::warningYesNoCancel(this, i18nc( "@info", "Changes on your project are unsaved. Do you want to save your changes?")); if (btnCode == KMessageBox::Cancel) { return false; } if (btnCode == KMessageBox::Yes) { saveProject(); } return true; } void MainWindow::quit() { if (queryClose()) { QApplication::quit(); } } void MainWindow::importGraphDocument() { FileFormatDialog importer(this); GraphDocumentPtr document = importer.importFile(); if (!document) { qWarning() << "No graph document was imported."; return; } m_currentProject->addGraphDocument(document); } void MainWindow::exportGraphDocument() { FileFormatDialog exporter(this); exporter.exportFile(m_currentProject->activeGraphDocument()); } void MainWindow::showEditorPluginDialog() { QAction *action = qobject_cast (sender()); if (!action) { return; } if (EditorPluginInterface *plugin = m_graphEditorPluginManager.plugins().value(action->data().toInt())) { plugin->showDialog(m_currentProject->activeGraphDocument()); } } void MainWindow::executeScript() { if (m_outputWidget->isOutputClearEnabled()) { m_outputWidget->clear(); } QString script = m_codeEditorWidget->activeDocument()->text(); enableStopAction(); if (m_openDebugger->isChecked()) { m_kernel->triggerInterruptAction(); } m_kernel->execute(m_currentProject->activeGraphDocument(), script); } void MainWindow::stopScript() { m_kernel->stop(); disableStopAction(); } void MainWindow::checkDebugger() { if (m_openDebugger->isChecked()) { m_kernel->attachDebugger(); } else { m_kernel->detachDebugger(); } } void MainWindow::enableStopAction() { m_stopScript->setEnabled(true); } void MainWindow::disableStopAction() { m_stopScript->setEnabled(false); }