File indexing completed on 2024-04-21 04:36:01

0001 /* This file is part of KDevelop
0002    Copyright 2002 Harald Fernengel <harry@kdevelop.org>
0003    Copyright 2007 Hamish Rodda <rodda@kde.org>
0004    Copyright 2016-2017 Anton Anikin <anton@anikin.xyz>
0005 
0006    This program is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU General Public
0008    License as published by the Free Software Foundation; either
0009    version 2 of the License, or (at your option) any later version.
0010 
0011    This program is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014    General Public License for more details.
0015 
0016    You should have received a copy of the GNU General Public License
0017    along with this program; see the file COPYING.  If not, write to
0018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019    Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #include "plugin.h"
0023 
0024 #include "globalconfigpage.h"
0025 
0026 #include "debug.h"
0027 #include "job.h"
0028 #include "launchmode.h"
0029 #include "problemmodel.h"
0030 #include "toolviewfactory.h"
0031 
0032 #include "tools/cachegrind/cachegrind_tool.h"
0033 #include "tools/callgrind/callgrind_tool.h"
0034 #include "tools/drd/drd_tool.h"
0035 #include "tools/helgrind/helgrind_tool.h"
0036 #include "tools/massif/massif_tool.h"
0037 #include "tools/memcheck/memcheck_tool.h"
0038 
0039 #include <execute/iexecuteplugin.h>
0040 #include <interfaces/ilauncher.h>
0041 #include <interfaces/iplugincontroller.h>
0042 #include <interfaces/launchconfigurationtype.h>
0043 #include <qtcompat_p.h>
0044 #include <shell/core.h>
0045 #include <shell/launchconfiguration.h>
0046 #include <shell/runcontroller.h>
0047 
0048 #include <KActionCollection>
0049 #include <KPluginFactory>
0050 
0051 K_PLUGIN_FACTORY_WITH_JSON(ValgrindFactory, "kdevvalgrind.json",  registerPlugin<Valgrind::Plugin>();)
0052 
0053 namespace Valgrind
0054 {
0055 
0056 Plugin* Plugin::m_self = nullptr;
0057 
0058 Plugin::Plugin(QObject* parent, const QVariantList&)
0059     : IPlugin("kdevvalgrind", parent)
0060     , m_toolViewFactory(new ToolViewFactory)
0061     , m_launchMode(new LaunchMode)
0062     , m_problemModel(new ProblemModel)
0063     , m_isRunning(false)
0064 {
0065     m_self = this;
0066     setXMLFile("kdevvalgrind.rc");
0067 
0068     core()->uiController()->addToolView(i18n("Valgrind"), m_toolViewFactory);
0069     core()->runController()->addLaunchMode(m_launchMode.data());
0070 
0071     m_tools += MemcheckTool::self();
0072     m_tools += CachegrindTool::self();
0073     m_tools += CallgrindTool::self();
0074     m_tools += HelgrindTool::self();
0075     m_tools += DrdTool::self();
0076     m_tools += MassifTool::self();
0077 
0078     for (auto tool : qAsConst(m_tools)) {
0079         auto action = new QAction(i18n("Run %1", tool->fullName()), this);
0080         connect(action, &QAction::triggered, this, [this, tool]() {
0081                 executeDefaultLaunch(tool->id());
0082         });
0083         actionCollection()->addAction(tool->menuActionName(), action);
0084     }
0085 
0086     auto pluginController = core()->pluginController();
0087     const auto plugins = pluginController->allPluginsForExtension(QStringLiteral("org.kdevelop.IExecutePlugin"));
0088     for (auto plugin : plugins) {
0089         setupExecutePlugin(plugin, true);
0090     }
0091 
0092     connect(pluginController, &KDevelop::IPluginController::pluginLoaded,
0093             this, [this](KDevelop::IPlugin* plugin) {
0094                 setupExecutePlugin(plugin, true);
0095             });
0096 
0097     connect(pluginController, &KDevelop::IPluginController::unloadingPlugin,
0098             this, [this](KDevelop::IPlugin* plugin) {
0099                 setupExecutePlugin(plugin, false);
0100             });
0101 }
0102 
0103 Plugin::~Plugin()
0104 {
0105     m_self = nullptr;
0106 }
0107 
0108 Plugin* Plugin::self()
0109 {
0110     return m_self;
0111 }
0112 
0113 void Plugin::unload()
0114 {
0115     core()->uiController()->removeToolView(m_toolViewFactory);
0116     m_problemModel.reset(nullptr);
0117 
0118     const auto plugins = core()->pluginController()->allPluginsForExtension(QStringLiteral("org.kdevelop.IExecutePlugin"));
0119     for (auto plugin : plugins) {
0120         setupExecutePlugin(plugin, false);
0121     }
0122     Q_ASSERT(m_launchers.isEmpty());
0123 
0124     core()->runController()->removeLaunchMode(m_launchMode.data());
0125     m_launchMode.reset(nullptr);
0126 
0127     qDeleteAll(m_tools);
0128 }
0129 
0130 void Plugin::setupExecutePlugin(KDevelop::IPlugin* plugin, bool load)
0131 {
0132     if (plugin == this) {
0133         return;
0134     }
0135 
0136     auto iface = plugin->extension<IExecutePlugin>();
0137     if (!iface) {
0138         return;
0139     }
0140 
0141     auto type = core()->runController()->launchConfigurationTypeForId(iface->nativeAppConfigTypeId());
0142     Q_ASSERT(type);
0143 
0144     if (load) {
0145         for (auto tool : qAsConst(m_tools)) {
0146             auto launcher = tool->createLauncher();
0147             m_launchers.insert(plugin, launcher);
0148             type->addLauncher(launcher);
0149         }
0150     }
0151 
0152     else {
0153         auto pluginLaunchers = m_launchers.values(plugin);
0154         for (auto launcher : pluginLaunchers) {
0155             Q_ASSERT(launcher);
0156 
0157             m_launchers.remove(plugin, launcher);
0158             type->removeLauncher(launcher);
0159             delete launcher;
0160         }
0161     }
0162 }
0163 
0164 int Plugin::configPages() const
0165 {
0166     return 1;
0167 }
0168 
0169 KDevelop::ConfigPage* Plugin::configPage(int number, QWidget* parent)
0170 {
0171     if (number) {
0172         return nullptr;
0173     }
0174 
0175     return new GlobalConfigPage(this, parent);
0176 }
0177 
0178 Valgrind::LaunchMode* Plugin::launchMode() const
0179 {
0180     return m_launchMode.data();
0181 }
0182 
0183 ProblemModel* Plugin::problemModel() const
0184 {
0185     return m_problemModel.data();
0186 }
0187 
0188 void Plugin::jobReadyToStart(Job* job)
0189 {
0190     m_isRunning = true;
0191 
0192     const auto actions = actionCollection()->actions();
0193     for (auto action : actions) {
0194         action->setEnabled(false);
0195     }
0196 
0197     Q_ASSERT(job);
0198     if (!job->tool()->hasView()) {
0199         m_problemModel->reset(job->tool());
0200     }
0201 }
0202 
0203 void Plugin::jobReadyToFinish(Job* job, bool ok)
0204 {
0205     if (!ok) {
0206         return;
0207     }
0208 
0209     Q_ASSERT(job);
0210     if (job->tool()->hasView()) {
0211         emit addView(job->createView(), job->statusName());
0212 
0213         core()->uiController()->findToolView(i18n("Valgrind"), m_toolViewFactory);
0214     } else {
0215         m_problemModel->show();
0216     }
0217 }
0218 
0219 void Plugin::jobFinished(KJob* job)
0220 {
0221     Q_UNUSED(job);
0222 
0223     const auto actions = actionCollection()->actions();
0224     for (auto action : actions) {
0225         action->setEnabled(true);
0226     }
0227     m_isRunning = false;
0228 }
0229 
0230 bool Plugin::isRunning()
0231 {
0232     return m_isRunning;
0233 }
0234 
0235 void Plugin::executeDefaultLaunch(const QString& launcherId)
0236 {
0237     auto runController = KDevelop::Core::self()->runControllerInternal();
0238     Q_ASSERT(runController);
0239 
0240     if (runController->launchConfigurations().isEmpty()) {
0241         runController->showConfigurationDialog();
0242     }
0243 
0244     auto defaultLaunch = runController->defaultLaunch();
0245     if (defaultLaunch) {
0246         defaultLaunch->setLauncherForMode(m_launchMode->id(), launcherId);
0247         runController->executeDefaultLaunch(m_launchMode->id());
0248     }
0249 }
0250 
0251 }
0252 
0253 #include "plugin.moc"