diff --git a/interfaces/configpage.h b/interfaces/configpage.h index 2a3aaa015a..90a06f8abe 100644 --- a/interfaces/configpage.h +++ b/interfaces/configpage.h @@ -1,112 +1,113 @@ /* * This file is part of KDevelop * Copyright 2014 Alex Richardson * * 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 KDEVELOP_CONFIGPAGE_H #define KDEVELOP_CONFIGPAGE_H #include #include #include "interfacesexport.h" class KCoreConfigSkeleton; namespace KDevelop { class IPlugin; struct ConfigPagePrivate; class KDEVPLATFORMINTERFACES_EXPORT ConfigPage : public KTextEditor::ConfigPage { Q_OBJECT public: /** * Create a new config page * @param plugin the plugin that created this config page * @param config the config skeleton that is used to store the preferences. If you don't use * a K(Core)ConfigSkeleton to save the settings you can also pass null here. * However this means that you will have to manually implement the apply(), defaults() and reset() slots */ explicit ConfigPage(IPlugin* plugin, KCoreConfigSkeleton* config = nullptr, QWidget* parent = nullptr); ~ConfigPage() override; /** * Get the number of subpages of this page * @return The number of child pages or an integer < 1 if there are none. * The default implementation returns zero. */ virtual int childPages() const; /** * @return the child config page for index @p number or @c nullptr if there is none. * The default implementation returns @c nullptr. */ virtual ConfigPage* childPage(int number); enum ConfigPageType { DefaultConfigPage, LanguageConfigPage, ///< A config page that contains language specific settings. This page is appended as a child page to the "Language support" config page. AnalyzerConfigPage, ///< A config page that contains settings for some analyzer. This page is appended as a child page to the "Analyzers" config page. - DocumentationConfigPage ///< A config page that contains settings for some documentation plugin. This page is appended as a child page to the "Documentation" config page. + DocumentationConfigPage, ///< A config page that contains settings for some documentation plugin. This page is appended as a child page to the "Documentation" config page. + RuntimeConfigPage ///< A config page that contains settings for some runtime plugin. This page is appended as a child page to the "Runtimes" config page. }; /** * @return The type of this config page. Default implementaion returns DefaultConfigPageType */ virtual ConfigPageType configPageType() const; /** * @return the plugin that this config page was created by or nullptr if it was not created by a plugin. */ IPlugin* plugin() const; /** * Initializes the KConfigDialogManager. * Must be called explicitly since not all child widgets are available at the end of the constructor. * This is handled automatically by KDevelop::ConfigDialog, subclasses don't need to call this. */ void initConfigManager(); /** * @return the KCoreConfigSkeleton used to store the settings for this page or @c nullptr * if settings are managed differently */ KCoreConfigSkeleton* configSkeleton() const; /** * Sets the config skeleton to @p skel and will create a KConfigDialogManager if needed. * This can be used if the KCoreConfigSkeleton* doesn't exist yet when calling the base class constructor. */ void setConfigSkeleton(KCoreConfigSkeleton* skel); public Q_SLOTS: void apply() override; void defaults() override; void reset() override; private: QScopedPointer d; }; } #endif // KDEVELOP_CONFIGPAGE_H diff --git a/plugins/docker/dockerpreferences.cpp b/plugins/docker/dockerpreferences.cpp index e372c3cb67..271e6097c9 100644 --- a/plugins/docker/dockerpreferences.cpp +++ b/plugins/docker/dockerpreferences.cpp @@ -1,34 +1,39 @@ /* Copyright 2017 Aleix Pol Gonzalez This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "dockerpreferences.h" #include "ui_dockerpreferences.h" DockerPreferences::DockerPreferences(KDevelop::IPlugin* plugin, KCoreConfigSkeleton* config, QWidget* parent) : KDevelop::ConfigPage(plugin, config, parent) { auto m_prefsUi = new Ui::DockerPreferences; m_prefsUi->setupUi(this); } DockerPreferences::~DockerPreferences() = default; +KDevelop::ConfigPage::ConfigPageType DockerPreferences::configPageType() const +{ + return KDevelop::ConfigPage::RuntimeConfigPage; +} + QString DockerPreferences::name() const { return QStringLiteral("Docker"); } diff --git a/plugins/docker/dockerpreferences.h b/plugins/docker/dockerpreferences.h index c7f3fca8df..3da80bd416 100644 --- a/plugins/docker/dockerpreferences.h +++ b/plugins/docker/dockerpreferences.h @@ -1,39 +1,40 @@ /* Copyright 2017 Aleix Pol Gonzalez This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef DOCKERPREFERENCES_H #define DOCKERPREFERENCES_H #include #include namespace Ui { class DockerPreferences; } class DockerPreferences : public KDevelop::ConfigPage { Q_OBJECT public: explicit DockerPreferences(KDevelop::IPlugin* plugin, KCoreConfigSkeleton* config, QWidget* parent = nullptr); ~DockerPreferences() override; + KDevelop::ConfigPage::ConfigPageType configPageType() const override; QString name() const override; private: QScopedPointer m_prefsUi; }; #endif diff --git a/plugins/docker/kdevdocker.json b/plugins/docker/kdevdocker.json index 863e0fcf57..7db38268b4 100644 --- a/plugins/docker/kdevdocker.json +++ b/plugins/docker/kdevdocker.json @@ -1,38 +1,38 @@ { "KPlugin": { "Authors": [ { "Email": "aleixpol@kde.org", "Name": "Aleix Pol", "Name[x-test]": "xxAleix Polxx" } ], - "Category": "Global", + "Category": "Runtimes", "Description": "Exposes Docker runtimes", "Description[ca@valencia]": "Exposa el temps d'execució del Docker", "Description[ca]": "Exposa el temps d'execució del Docker", "Description[nl]": "Toont Docker runtimes", "Description[pt]": "Expõe as bibliotecas do Docker", "Description[sv]": "Exponerar Docker-körtidsprogram", "Description[uk]": "Надає доступ до середовищ виконання Docker", "Description[x-test]": "xxExposes Docker runtimesxx", "Icon": "docker", "Id": "kdevdocker", "License": "GPL", "Name": "Docker Support", "Name[ca@valencia]": "Implementació del Docker", "Name[ca]": "Implementació del Docker", "Name[it]": "Supporto per Docker", "Name[nl]": "Ondersteuning van Docker", "Name[pt]": "Suporte para o Docker", "Name[sv]": "Docker-stöd", "Name[uk]": "Підтримка Docker", "Name[x-test]": "xxDocker Supportxx", "ServiceTypes": [ "KDevelop/Plugin" ], "Version": "0.1" }, "X-KDevelop-Category": "Global", "X-KDevelop-Mode": "NoGUI" } diff --git a/plugins/flatpak/kdevflatpak.json b/plugins/flatpak/kdevflatpak.json index 6524ffc893..b9c55bc31b 100644 --- a/plugins/flatpak/kdevflatpak.json +++ b/plugins/flatpak/kdevflatpak.json @@ -1,38 +1,38 @@ { "KPlugin": { "Authors": [ { "Email": "aleixpol@kde.org", "Name": "Aleix Pol", "Name[x-test]": "xxAleix Polxx" } ], - "Category": "Global", + "Category": "Runtimes", "Description": "Exposes Flatpak runtimes", "Description[ca@valencia]": "Exposa el temps d'execució del Flatpak", "Description[ca]": "Exposa el temps d'execució del Flatpak", "Description[nl]": "Toont Flatpak runtimes", "Description[pt]": "Expõe as bibliotecas do Flatpak", "Description[sv]": "Exponerar Flatpak-körtidsprogram", "Description[uk]": "Надає доступ до середовищ виконання Flatpak", "Description[x-test]": "xxExposes Flatpak runtimesxx", "Icon": "flatpak", "Id": "kdevflatpak", "License": "GPL", "Name": "Flatpak Support", "Name[ca@valencia]": "Implementació del Flatpak", "Name[ca]": "Implementació del Flatpak", "Name[it]": "Supporto per Flatpak", "Name[nl]": "Ondersteuning van Flatpak", "Name[pt]": "Suporte para o Flatpak", "Name[sv]": "Flatpak-stöd", "Name[uk]": "Підтримка Flatpak", "Name[x-test]": "xxFlatpak Supportxx", "ServiceTypes": [ "KDevelop/Plugin" ], "Version": "0.1" }, "X-KDevelop-Category": "Global", "X-KDevelop-Mode": "GUI" } diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt index 6a3a1dc00c..b64217af98 100644 --- a/shell/CMakeLists.txt +++ b/shell/CMakeLists.txt @@ -1,189 +1,190 @@ add_definitions(-DTRANSLATION_DOMAIN=\"kdevplatform\") add_subdirectory(tests) set(KDevPlatformShell_LIB_SRCS workingsetcontroller.cpp workingsets/workingset.cpp workingsets/workingsetfilelabel.cpp workingsets/workingsettoolbutton.cpp workingsets/workingsettooltipwidget.cpp workingsets/workingsetwidget.cpp workingsets/closedworkingsetswidget.cpp workingsets/workingsethelpers.cpp mainwindow.cpp mainwindow_p.cpp plugincontroller.cpp ktexteditorpluginintegration.cpp shellextension.cpp core.cpp uicontroller.cpp colorschemechooser.cpp projectcontroller.cpp project.cpp partcontroller.cpp #document.cpp partdocument.cpp textdocument.cpp documentcontroller.cpp languagecontroller.cpp statusbar.cpp runcontroller.cpp unitylauncher.cpp sessioncontroller.cpp session.cpp sessionlock.cpp sessionchooserdialog.cpp savedialog.cpp sourceformattercontroller.cpp completionsettings.cpp openprojectpage.cpp openprojectdialog.cpp projectinfopage.cpp selectioncontroller.cpp documentationcontroller.cpp debugcontroller.cpp launchconfiguration.cpp launchconfigurationdialog.cpp loadedpluginsdialog.cpp testcontroller.cpp projectsourcepage.cpp configdialog.cpp editorconfigpage.cpp environmentconfigurebutton.cpp runtimecontroller.cpp checkerstatus.cpp problem.cpp problemmodelset.cpp problemmodel.cpp problemstore.cpp watcheddocumentset.cpp filteredproblemstore.cpp progresswidget/progressmanager.cpp progresswidget/statusbarprogresswidget.cpp progresswidget/overlaywidget.cpp progresswidget/progressdialog.cpp areadisplay.cpp settings/uipreferences.cpp settings/pluginpreferences.cpp settings/sourceformattersettings.cpp settings/editstyledialog.cpp settings/projectpreferences.cpp settings/environmentwidget.cpp settings/environmentprofilemodel.cpp settings/environmentprofilelistmodel.cpp settings/environmentpreferences.cpp settings/languagepreferences.cpp settings/bgpreferences.cpp settings/templateconfig.cpp settings/templatepage.cpp settings/analyzerspreferences.cpp + settings/runtimespreferences.cpp settings/documentationpreferences.cpp ) if(APPLE) set(KDevPlatformShell_LIB_SRCS ${KDevPlatformShell_LIB_SRCS} macdockprogressview.mm ) endif() ecm_qt_declare_logging_category(KDevPlatformShell_LIB_SRCS HEADER debug.h IDENTIFIER SHELL CATEGORY_NAME "kdevplatform.shell" ) kconfig_add_kcfg_files(KDevPlatformShell_LIB_SRCS settings/uiconfig.kcfgc settings/projectconfig.kcfgc settings/languageconfig.kcfgc settings/bgconfig.kcfgc ) ki18n_wrap_ui(KDevPlatformShell_LIB_SRCS projectinfopage.ui launchconfigurationdialog.ui projectsourcepage.ui settings/uiconfig.ui settings/editstyledialog.ui settings/sourceformattersettings.ui settings/projectpreferences.ui settings/environmentwidget.ui settings/languagepreferences.ui settings/bgpreferences.ui settings/templateconfig.ui settings/templatepage.ui ) qt5_add_resources(KDevPlatformShell_LIB_SRCS kdevplatformshell.qrc) kdevplatform_add_library(KDevPlatformShell SOURCES ${KDevPlatformShell_LIB_SRCS}) target_link_libraries(KDevPlatformShell LINK_PUBLIC KF5::XmlGui KDev::Sublime KDev::OutputView KDev::Interfaces LINK_PRIVATE KF5::GuiAddons KF5::ConfigWidgets KF5::IconThemes KF5::KIOFileWidgets KF5::KIOWidgets KF5::Parts KF5::Notifications KF5::NotifyConfig KF5::TextEditor KF5::ThreadWeaver KF5::JobWidgets KF5::ItemViews KF5::WindowSystem KF5::KCMUtils #for KPluginSelector, not sure why it is in kcmutils KF5::NewStuff # template config page KF5::Archive # template config page KDev::Debugger KDev::Project KDev::Vcs KDev::Language KDev::Util KDev::Documentation ) if(APPLE) target_link_libraries(KDevPlatformShell PRIVATE "-framework AppKit") endif() install(FILES mainwindow.h plugincontroller.h shellextension.h core.h uicontroller.h colorschemechooser.h projectcontroller.h project.h partcontroller.h partdocument.h textdocument.h documentcontroller.h languagecontroller.h session.h sessioncontroller.h sessionlock.h sourceformattercontroller.h selectioncontroller.h runcontroller.h launchconfiguration.h environmentconfigurebutton.h checkerstatus.h problem.h problemmodel.h problemmodelset.h problemconstants.h filteredproblemstore.h DESTINATION ${KDE_INSTALL_INCLUDEDIR}/kdevplatform/shell COMPONENT Devel ) diff --git a/shell/settings/pluginpreferences.cpp b/shell/settings/pluginpreferences.cpp index 71dc088ad4..671777b4c7 100644 --- a/shell/settings/pluginpreferences.cpp +++ b/shell/settings/pluginpreferences.cpp @@ -1,107 +1,108 @@ /* KDevelop Project Settings * * Copyright 2008 Andreas Pakulat * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "pluginpreferences.h" #include #include #include #include #include "../core.h" #include "../plugincontroller.h" #include "debug.h" namespace KDevelop { PluginPreferences::PluginPreferences(QWidget* parent) : ConfigPage(nullptr, nullptr, parent) { QVBoxLayout* lay = new QVBoxLayout(this ); lay->setMargin(0); selector = new KPluginSelector( this ); lay->addWidget( selector ); QMap> plugins; const QMap categories = { { "Core", i18nc("@title:group", "Core") }, { "Project Management", i18nc("@title:group", "Project Management") }, { "Version Control", i18nc("@title:group", "Version Control") }, { "Utilities", i18nc("@title:group", "Utilities") }, { "Documentation", i18nc("@title:group", "Documentation") }, { "Language Support", i18nc("@title:group", "Language Support") }, { "Debugging", i18nc("@title:group", "Debugging") }, { "Testing", i18nc("@title:group", "Testing") }, { "Analyzers", i18nc("@title:group", "Analyzers") }, + { "Runtimes", i18nc("@title:group", "Runtimes") }, { "Other", i18nc("@title:group", "Other") } }; foreach (const KPluginMetaData& info, Core::self()->pluginControllerInternal()->allPluginInfos()) { const QString loadMode = info.value(QStringLiteral("X-KDevelop-LoadMode")); if( loadMode.isEmpty() || loadMode == QLatin1String("UserSelectable") ) { QString category = info.category(); if (!categories.contains(category)) { if (!category.isEmpty()) { qCWarning(SHELL) << "unknown category for plugin" << info.name() << ":" << info.category(); } category = QStringLiteral("Other"); } KPluginInfo kpi(info); kpi.setPluginEnabled(Core::self()->pluginControllerInternal()->isEnabled(info)); plugins[category] << kpi; } else qCDebug(SHELL) << "skipping..." << info.pluginId() << info.value(QStringLiteral("X-KDevelop-Category")) << loadMode; } for (auto it = plugins.constBegin(), end = plugins.constEnd(); it != end; ++it) { selector->addPlugins(it.value(), KPluginSelector::ReadConfigFile, categories.value(it.key()), it.key(), Core::self()->activeSession()->config() ); } connect(selector, &KPluginSelector::changed, this, &PluginPreferences::changed); selector->load(); } void PluginPreferences::defaults() { Core::self()->pluginControllerInternal()->resetToDefaults(); selector->load(); } void PluginPreferences::apply() { selector->save(); qCDebug(SHELL) << "Plugins before apply: " << Core::self()->pluginControllerInternal()->allPluginNames(); Core::self()->pluginControllerInternal()->updateLoadedPlugins(); qCDebug(SHELL) << "Plugins after apply: " << Core::self()->pluginControllerInternal()->allPluginNames(); selector->load(); // Some plugins may have failed to load, they must be unchecked. } void PluginPreferences::reset() { selector->load(); } } diff --git a/shell/settings/runtimespreferences.cpp b/shell/settings/runtimespreferences.cpp new file mode 100644 index 0000000000..be44308454 --- /dev/null +++ b/shell/settings/runtimespreferences.cpp @@ -0,0 +1,62 @@ +/* This file is part of KDevelop + * + * Copyright 2017 Friedrich W. H. Kossebau + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "runtimespreferences.h" + +#include + +namespace KDevelop +{ + +RuntimesPreferences::RuntimesPreferences(QWidget* parent) + : ConfigPage(nullptr, nullptr, parent) +{ +} + +RuntimesPreferences::~RuntimesPreferences() = default; + +QString RuntimesPreferences::name() const +{ + return i18n("Runtimes"); +} + +QIcon RuntimesPreferences::icon() const +{ + return QIcon::fromTheme(QStringLiteral("file-library-symbolic")); +} + +QString RuntimesPreferences::fullName() const +{ + return i18n("Configure Runtimes"); +} + +void RuntimesPreferences::apply() +{ +} + +void RuntimesPreferences::defaults() +{ +} + +void RuntimesPreferences::reset() +{ +} + +} diff --git a/shell/settings/runtimespreferences.h b/shell/settings/runtimespreferences.h new file mode 100644 index 0000000000..33a1707b7c --- /dev/null +++ b/shell/settings/runtimespreferences.h @@ -0,0 +1,48 @@ +/* This file is part of KDevelop + * + * Copyright 2017 Friedrich W. H. Kossebau + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef KDEVPLATFORM_RUNTIMES_PREFERENCES_H +#define KDEVPLATFORM_RUNTIMES_PREFERENCES_H + +#include + +namespace KDevelop +{ + +class RuntimesPreferences : public ConfigPage +{ + Q_OBJECT +public: + explicit RuntimesPreferences(QWidget* parent); + ~RuntimesPreferences() override; + + QString name() const override; + QIcon icon() const override; + QString fullName() const override; + +public Q_SLOTS: + void apply() override; + void defaults() override; + void reset() override; +}; + +} + +#endif diff --git a/shell/uicontroller.cpp b/shell/uicontroller.cpp index adfcef9e14..34d38b7388 100644 --- a/shell/uicontroller.cpp +++ b/shell/uicontroller.cpp @@ -1,754 +1,759 @@ /*************************************************************************** * Copyright 2007 Alexander Dymo * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library 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 Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "uicontroller.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "core.h" #include "configpage.h" #include "configdialog.h" #include "debug.h" #include "editorconfigpage.h" #include "shellextension.h" #include "plugincontroller.h" #include "mainwindow.h" #include "workingsetcontroller.h" #include "workingsets/workingset.h" #include "settings/bgpreferences.h" #include "settings/languagepreferences.h" #include "settings/environmentpreferences.h" #include "settings/pluginpreferences.h" #include "settings/projectpreferences.h" #include "settings/sourceformattersettings.h" #include "settings/uipreferences.h" #include "settings/templateconfig.h" #include "settings/analyzerspreferences.h" #include "settings/documentationpreferences.h" +#include "settings/runtimespreferences.h" namespace KDevelop { class UiControllerPrivate { public: explicit UiControllerPrivate(UiController *controller) : areasRestored(false), m_controller(controller) { if (Core::self()->workingSetControllerInternal()) Core::self()->workingSetControllerInternal()->initializeController(m_controller); m_controller->connect(m_controller, &Sublime::Controller::mainWindowAdded, m_controller, &UiController::mainWindowAdded); QMap desired; desired[QStringLiteral("org.kdevelop.ClassBrowserView")] = Sublime::Left; desired[QStringLiteral("org.kdevelop.DocumentsView")] = Sublime::Left; desired[QStringLiteral("org.kdevelop.ProjectsView")] = Sublime::Left; desired[QStringLiteral("org.kdevelop.FileManagerView")] = Sublime::Left; desired[QStringLiteral("org.kdevelop.ProblemReporterView")] = Sublime::Bottom; desired[QStringLiteral("org.kdevelop.OutputView")] = Sublime::Bottom; desired[QStringLiteral("org.kdevelop.ContextBrowser")] = Sublime::Bottom; desired[QStringLiteral("org.kdevelop.KonsoleView")] = Sublime::Bottom; desired[QStringLiteral("org.kdevelop.SnippetView")] = Sublime::Right; desired[QStringLiteral("org.kdevelop.ExternalScriptView")] = Sublime::Right; Sublime::Area* a = new Sublime::Area(m_controller, QStringLiteral("code"), i18n("Code")); a->setDesiredToolViews(desired); a->setIconName(QStringLiteral("document-edit")); m_controller->addDefaultArea(a); desired.clear(); desired[QStringLiteral("org.kdevelop.debugger.VariablesView")] = Sublime::Left; desired[QStringLiteral("org.kdevelop.debugger.BreakpointsView")] = Sublime::Bottom; desired[QStringLiteral("org.kdevelop.debugger.StackView")] = Sublime::Bottom; desired[QStringLiteral("org.kdevelop.debugger.ConsoleView")] = Sublime::Bottom; desired[QStringLiteral("org.kdevelop.KonsoleView")] = Sublime::Bottom; a = new Sublime::Area(m_controller, QStringLiteral("debug"), i18n("Debug")); a->setDesiredToolViews(desired); a->setIconName(QStringLiteral("debug-run")); m_controller->addDefaultArea(a); desired.clear(); desired[QStringLiteral("org.kdevelop.ProjectsView")] = Sublime::Left; desired[QStringLiteral("org.kdevelop.PatchReview")] = Sublime::Bottom; a = new Sublime::Area(m_controller, QStringLiteral("review"), i18n("Review")); a->setDesiredToolViews(desired); a->setIconName(QStringLiteral("applications-engineering")); m_controller->addDefaultArea(a); if(!(Core::self()->setupFlags() & Core::NoUi)) { defaultMainWindow = new MainWindow(m_controller); m_controller->addMainWindow(defaultMainWindow); activeSublimeWindow = defaultMainWindow; } else { activeSublimeWindow = defaultMainWindow = nullptr; } m_assistantTimer.setSingleShot(true); m_assistantTimer.setInterval(100); } void widgetChanged(QWidget*, QWidget* now) { if (now) { Sublime::MainWindow* win = qobject_cast(now->window()); if( win ) { activeSublimeWindow = win; } } } Core *core; QPointer defaultMainWindow; QHash factoryDocuments; QPointer activeSublimeWindow; bool areasRestored; /// QWidget implementing IToolViewActionListener interface, or null QPointer activeActionListener; QTimer m_assistantTimer; private: UiController *m_controller; }; class UiToolViewFactory: public Sublime::ToolFactory { public: explicit UiToolViewFactory(IToolViewFactory *factory): m_factory(factory) {} ~UiToolViewFactory() override { delete m_factory; } QWidget* create(Sublime::ToolDocument *doc, QWidget *parent = nullptr) override { Q_UNUSED( doc ); return m_factory->create(parent); } QList< QAction* > contextMenuActions(QWidget* viewWidget) const override { return m_factory->contextMenuActions( viewWidget ); } QList toolBarActions( QWidget* viewWidget ) const override { return m_factory->toolBarActions( viewWidget ); } QString id() const override { return m_factory->id(); } private: IToolViewFactory *m_factory; }; class ViewSelectorItem: public QListWidgetItem { public: explicit ViewSelectorItem(const QString &text, QListWidget *parent = nullptr, int type = Type) :QListWidgetItem(text, parent, type) {} IToolViewFactory *factory; }; class NewToolViewListWidget: public QListWidget { Q_OBJECT public: explicit NewToolViewListWidget(MainWindow *mw, QWidget* parent = nullptr) :QListWidget(parent), m_mw(mw) { connect(this, &NewToolViewListWidget::doubleClicked, this, &NewToolViewListWidget::addNewToolViewByDoubleClick); } Q_SIGNALS: void addNewToolView(MainWindow *mw, QListWidgetItem *item); private Q_SLOTS: void addNewToolViewByDoubleClick(const QModelIndex& index) { QListWidgetItem *item = itemFromIndex(index); // Disable item so that the toolview can not be added again. item->setFlags(item->flags() & ~Qt::ItemIsEnabled); emit addNewToolView(m_mw, item); } private: MainWindow *m_mw; }; UiController::UiController(Core *core) :Sublime::Controller(nullptr), IUiController(), d(new UiControllerPrivate(this)) { setObjectName(QStringLiteral("UiController")); d->core = core; if (!defaultMainWindow() || (Core::self()->setupFlags() & Core::NoUi)) return; connect(qApp, &QApplication::focusChanged, this, [&] (QWidget* old, QWidget* now) { d->widgetChanged(old, now); } ); setupActions(); } UiController::~UiController() { delete d; } void UiController::setupActions() { } void UiController::mainWindowAdded(Sublime::MainWindow* mainWindow) { connect(mainWindow, &MainWindow::activeToolViewChanged, this, &UiController::slotActiveToolViewChanged); connect(mainWindow, &MainWindow::areaChanged, this, &UiController::slotAreaChanged); // also check after area reconstruction } // FIXME: currently, this always create new window. Probably, // should just rename it. void UiController::switchToArea(const QString &areaName, SwitchMode switchMode) { if (switchMode == ThisWindow) { showArea(areaName, activeSublimeWindow()); return; } MainWindow *main = new MainWindow(this); addMainWindow(main); showArea(areaName, main); main->initialize(); // WTF? First, enabling this code causes crashes since we // try to disconnect some already-deleted action, or something. // Second, this code will disconnection the clients from guiFactory // of the previous main window. Ick! #if 0 //we need to add all existing guiclients to the new mainwindow //@todo adymo: add only ones that belong to the area (when the area code is there) foreach (KXMLGUIClient *client, oldMain->guiFactory()->clients()) main->guiFactory()->addClient(client); #endif main->show(); } QWidget* UiController::findToolView(const QString& name, IToolViewFactory *factory, FindFlags flags) { if(!d->areasRestored || !activeArea()) return nullptr; QList< Sublime::View* > views = activeArea()->toolViews(); foreach(Sublime::View* view, views) { Sublime::ToolDocument *doc = dynamic_cast(view->document()); if(doc && doc->title() == name && view->widget()) { if(flags & Raise) view->requestRaise(); return view->widget(); } } QWidget* ret = nullptr; if(flags & Create) { Sublime::ToolDocument* doc = d->factoryDocuments.value(factory); if(!doc) { doc = new Sublime::ToolDocument(name, this, new UiToolViewFactory(factory)); d->factoryDocuments.insert(factory, doc); } Sublime::View* view = addToolViewToArea(factory, doc, activeArea()); if(view) ret = view->widget(); if(flags & Raise) findToolView(name, factory, Raise); } return ret; } void UiController::raiseToolView(QWidget* toolViewWidget) { if(!d->areasRestored) return; QList< Sublime::View* > views = activeArea()->toolViews(); foreach(Sublime::View* view, views) { if(view->widget() == toolViewWidget) { view->requestRaise(); return; } } } void UiController::addToolView(const QString & name, IToolViewFactory *factory, FindFlags state) { if (!factory) return; qCDebug(SHELL) ; Sublime::ToolDocument *doc = new Sublime::ToolDocument(name, this, new UiToolViewFactory(factory)); d->factoryDocuments[factory] = doc; /* Until areas are restored, we don't know which views should be really added, and which not, so we just record view availability. */ if (d->areasRestored && state != None) { foreach (Sublime::Area* area, allAreas()) { addToolViewToArea(factory, doc, area); } } } void KDevelop::UiController::raiseToolView(Sublime::View * view) { foreach( Sublime::Area* area, allAreas() ) { if( area->toolViews().contains( view ) ) area->raiseToolView( view ); } slotActiveToolViewChanged(view); } void UiController::slotAreaChanged(Sublime::Area*) { // this slot gets call if an area in *any* MainWindow changed // so let's first get the "active area" const auto area = activeSublimeWindow()->area(); if (area) { // walk through shown tool views and maku sure the const auto shownIds = area->shownToolViews(Sublime::AllPositions); foreach (Sublime::View* toolView, area->toolViews()) { if (shownIds.contains(toolView->document()->documentSpecifier())) { slotActiveToolViewChanged(toolView); } } } } void UiController::slotActiveToolViewChanged(Sublime::View* view) { if (!view) { return; } // record the last active tool view action listener if (qobject_cast(view->widget())) { d->activeActionListener = view->widget(); } } void KDevelop::UiController::removeToolView(IToolViewFactory *factory) { if (!factory) return; qCDebug(SHELL) ; //delete the tooldocument Sublime::ToolDocument *doc = d->factoryDocuments.value(factory); ///@todo adymo: on document deletion all its views shall be also deleted foreach (Sublime::View *view, doc->views()) { foreach (Sublime::Area *area, allAreas()) if (area->removeToolView(view)) view->deleteLater(); } d->factoryDocuments.remove(factory); delete doc; } Sublime::Area *UiController::activeArea() { Sublime::MainWindow *m = activeSublimeWindow(); if (m) return activeSublimeWindow()->area(); return nullptr; } Sublime::MainWindow *UiController::activeSublimeWindow() { return d->activeSublimeWindow; } MainWindow *UiController::defaultMainWindow() { return d->defaultMainWindow; } void UiController::initialize() { defaultMainWindow()->initialize(); } void UiController::cleanup() { foreach (Sublime::MainWindow* w, mainWindows()) w->saveSettings(); saveAllAreas(KSharedConfig::openConfig()); } void UiController::selectNewToolViewToAdd(MainWindow *mw) { if (!mw || !mw->area()) return; QDialog *dia = new QDialog(mw); dia->setWindowTitle(i18n("Select Tool View to Add")); auto mainLayout = new QVBoxLayout(dia); NewToolViewListWidget *list = new NewToolViewListWidget(mw, dia); list->setSelectionMode(QAbstractItemView::ExtendedSelection); list->setSortingEnabled(true); for (QHash::const_iterator it = d->factoryDocuments.constBegin(); it != d->factoryDocuments.constEnd(); ++it) { ViewSelectorItem *item = new ViewSelectorItem(it.value()->title(), list); item->factory = it.key(); if (!item->factory->allowMultiple() && toolViewPresent(it.value(), mw->area())) { // Disable item if the toolview is already present. item->setFlags(item->flags() & ~Qt::ItemIsEnabled); } list->addItem(item); } list->setFocus(); connect(list, &NewToolViewListWidget::addNewToolView, this, &UiController::addNewToolView); mainLayout->addWidget(list); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); auto okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); dia->connect(buttonBox, &QDialogButtonBox::accepted, dia, &QDialog::accept); dia->connect(buttonBox, &QDialogButtonBox::rejected, dia, &QDialog::reject); mainLayout->addWidget(buttonBox); if (dia->exec() == QDialog::Accepted) { foreach (QListWidgetItem* item, list->selectedItems()) { addNewToolView(mw, item); } } delete dia; } void UiController::addNewToolView(MainWindow *mw, QListWidgetItem* item) { ViewSelectorItem *current = static_cast(item); Sublime::ToolDocument *doc = d->factoryDocuments[current->factory]; Sublime::View *view = doc->createView(); mw->area()->addToolView(view, Sublime::dockAreaToPosition(current->factory->defaultPosition())); current->factory->viewCreated(view); } void UiController::showSettingsDialog() { ConfigDialog cfgDlg(activeMainWindow()); auto editorConfigPage = new EditorConfigPage(&cfgDlg); auto languageConfigPage = new LanguagePreferences(&cfgDlg); auto analyzersPreferences = new AnalyzersPreferences(&cfgDlg); auto documentationPreferences = new DocumentationPreferences(&cfgDlg); + auto runtimesPreferences = new RuntimesPreferences(&cfgDlg); const auto configPages = QVector { new UiPreferences(&cfgDlg), new PluginPreferences(&cfgDlg), new SourceFormatterSettings(&cfgDlg), new ProjectPreferences(&cfgDlg), new EnvironmentPreferences(QString(), &cfgDlg), new TemplateConfig(&cfgDlg), editorConfigPage }; for (auto page : configPages) { cfgDlg.addConfigPage(page); } auto addPluginPages = [&](IPlugin* plugin) { for (int i = 0, numPages = plugin->configPages(); i < numPages; ++i) { auto page = plugin->configPage(i, &cfgDlg); if (!page) continue; if (page->configPageType() == ConfigPage::LanguageConfigPage) { cfgDlg.addSubConfigPage(languageConfigPage, page); } else if (page->configPageType() == ConfigPage::AnalyzerConfigPage) { cfgDlg.addSubConfigPage(analyzersPreferences, page); + } else if (page->configPageType() == ConfigPage::RuntimeConfigPage) { + cfgDlg.addSubConfigPage(runtimesPreferences, page); } else if (page->configPageType() == ConfigPage::DocumentationConfigPage) { cfgDlg.addSubConfigPage(documentationPreferences, page); } else { // insert them before the editor config page cfgDlg.addConfigPage(page, editorConfigPage); } } }; cfgDlg.addConfigPage(documentationPreferences, configPages[5]); cfgDlg.addConfigPage(analyzersPreferences, documentationPreferences); + cfgDlg.addConfigPage(runtimesPreferences, analyzersPreferences); - cfgDlg.addConfigPage(languageConfigPage, analyzersPreferences); + cfgDlg.addConfigPage(languageConfigPage, runtimesPreferences); cfgDlg.addSubConfigPage(languageConfigPage, new BGPreferences(&cfgDlg)); foreach (IPlugin* plugin, ICore::self()->pluginController()->loadedPlugins()) { addPluginPages(plugin); } // TODO: only load settings if a UI related page was changed? connect(&cfgDlg, &ConfigDialog::configSaved, activeSublimeWindow(), &Sublime::MainWindow::loadSettings); // make sure that pages get added whenever a new plugin is loaded (probably from the plugin selection dialog) // removal on plugin unload is already handled in ConfigDialog connect(ICore::self()->pluginController(), &IPluginController::pluginLoaded, &cfgDlg, addPluginPages); cfgDlg.exec(); } Sublime::Controller* UiController::controller() { return this; } KParts::MainWindow *UiController::activeMainWindow() { return activeSublimeWindow(); } void UiController::saveArea(Sublime::Area * area, KConfigGroup & group) { area->save(group); if (!area->workingSet().isEmpty()) { WorkingSet* set = Core::self()->workingSetControllerInternal()->getWorkingSet(area->workingSet()); set->saveFromArea(area, area->rootIndex()); } } void UiController::loadArea(Sublime::Area * area, const KConfigGroup & group) { area->load(group); if (!area->workingSet().isEmpty()) { WorkingSet* set = Core::self()->workingSetControllerInternal()->getWorkingSet(area->workingSet()); Q_ASSERT(set->isConnected(area)); Q_UNUSED(set); } } void UiController::saveAllAreas(KSharedConfigPtr config) { KConfigGroup uiConfig(config, "User Interface"); int wc = mainWindows().size(); uiConfig.writeEntry("Main Windows Count", wc); for (int w = 0; w < wc; ++w) { KConfigGroup mainWindowConfig(&uiConfig, QStringLiteral("Main Window %1").arg(w)); foreach (Sublime::Area* defaultArea, defaultAreas()) { // FIXME: using object name seems ugly. QString type = defaultArea->objectName(); Sublime::Area* area = this->area(w, type); KConfigGroup areaConfig(&mainWindowConfig, "Area " + type); areaConfig.deleteGroup(); areaConfig.writeEntry("id", type); saveArea(area, areaConfig); areaConfig.sync(); } } uiConfig.sync(); } void UiController::loadAllAreas(KSharedConfigPtr config) { KConfigGroup uiConfig(config, "User Interface"); int wc = uiConfig.readEntry("Main Windows Count", 1); /* It is expected the main windows are restored before restoring areas. */ if (wc > mainWindows().size()) wc = mainWindows().size(); QList changedAreas; /* Offer all toolviews to the default areas. */ foreach (Sublime::Area *area, defaultAreas()) { QHash::const_iterator i, e; for (i = d->factoryDocuments.constBegin(), e = d->factoryDocuments.constEnd(); i != e; ++i) { addToolViewIfWanted(i.key(), i.value(), area); } } /* Restore per-windows areas. */ for (int w = 0; w < wc; ++w) { KConfigGroup mainWindowConfig(&uiConfig, QStringLiteral("Main Window %1").arg(w)); Sublime::MainWindow *mw = mainWindows()[w]; /* We loop over default areas. This means that if the config file has an area of some type that is not in default set, we'd just ignore it. I think it's fine -- the model were a given mainwindow can has it's own area types not represented in the default set is way too complex. */ foreach (Sublime::Area* defaultArea, defaultAreas()) { QString type = defaultArea->objectName(); Sublime::Area* area = this->area(w, type); KConfigGroup areaConfig(&mainWindowConfig, "Area " + type); qCDebug(SHELL) << "Trying to restore area " << type; /* This is just an easy check that a group exists, to avoid "restoring" area from empty config group, wiping away programmatically installed defaults. */ if (areaConfig.readEntry("id", "") == type) { qCDebug(SHELL) << "Restoring area " << type; loadArea(area, areaConfig); } // At this point we know which toolviews the area wants. // Tender all tool views we have. QHash::const_iterator i, e; for (i = d->factoryDocuments.constBegin(), e = d->factoryDocuments.constEnd(); i != e; ++i) { addToolViewIfWanted(i.key(), i.value(), area); } } // Force reload of the changes. showAreaInternal(mw->area(), mw); mw->enableAreaSettingsSave(); } d->areasRestored = true; } void UiController::addToolViewToDockArea(IToolViewFactory* factory, Qt::DockWidgetArea area) { addToolViewToArea(factory, d->factoryDocuments.value(factory), activeArea(), Sublime::dockAreaToPosition(area)); } bool UiController::toolViewPresent(Sublime::ToolDocument* doc, Sublime::Area* area) { for (Sublime::View *view : doc->views()) { if( area->toolViews().contains( view ) ) return true; } return false; } void UiController::addToolViewIfWanted(IToolViewFactory* factory, Sublime::ToolDocument* doc, Sublime::Area* area) { if (area->wantToolView(factory->id())) { addToolViewToArea(factory, doc, area); } } Sublime::View* UiController::addToolViewToArea(IToolViewFactory* factory, Sublime::ToolDocument* doc, Sublime::Area* area, Sublime::Position p) { Sublime::View* view = doc->createView(); area->addToolView( view, p == Sublime::AllPositions ? Sublime::dockAreaToPosition(factory->defaultPosition()) : p); connect(view, &Sublime::View::raise, this, static_cast(&UiController::raiseToolView)); factory->viewCreated(view); return view; } void UiController::registerStatus(QObject* status) { Sublime::MainWindow* w = activeSublimeWindow(); if (!w) return; MainWindow* mw = qobject_cast(w); if (!mw) return; mw->registerStatus(status); } void UiController::showErrorMessage(const QString& message, int timeout) { Sublime::MainWindow* w = activeSublimeWindow(); if (!w) return; MainWindow* mw = qobject_cast(w); if (!mw) return; QMetaObject::invokeMethod(mw, "showErrorMessage", Q_ARG(QString, message), Q_ARG(int, timeout)); } const QHash< IToolViewFactory*, Sublime::ToolDocument* >& UiController::factoryDocuments() const { return d->factoryDocuments; } QWidget* UiController::activeToolViewActionListener() const { return d->activeActionListener; } QList UiController::allAreas() const { return Sublime::Controller::allAreas(); } } #include "uicontroller.moc" #include "moc_uicontroller.cpp"