File indexing completed on 2024-05-12 08:39:47
0001 /* 0002 SPDX-FileCopyrightText: 2017 Anton Anikin <anton.anikin@htower.ru> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "plugin.h" 0008 0009 #include "config/globalconfigpage.h" 0010 #include "debug.h" 0011 #include "job.h" 0012 #include "utils.h" 0013 #include "visualizer.h" 0014 0015 #include <config-kdevelop.h> 0016 #if HAVE_KSYSGUARD 0017 #include "dialogs/processselection.h" 0018 #include <QPointer> 0019 #endif 0020 0021 #include <execute/iexecuteplugin.h> 0022 #include <interfaces/iplugincontroller.h> 0023 #include <interfaces/iuicontroller.h> 0024 #include <interfaces/launchconfigurationtype.h> 0025 #include <shell/core.h> 0026 #include <shell/launchconfiguration.h> 0027 #include <shell/runcontroller.h> 0028 #include <sublime/message.h> 0029 #include <util/executecompositejob.h> 0030 // KF 0031 #include <KActionCollection> 0032 #include <KPluginFactory> 0033 // Qt 0034 #include <QAction> 0035 #include <QApplication> 0036 #include <QFile> 0037 0038 K_PLUGIN_FACTORY_WITH_JSON(HeaptrackFactory, "kdevheaptrack.json", registerPlugin<Heaptrack::Plugin>();) 0039 0040 namespace { 0041 void postErrorMessage(const QString& messageText) 0042 { 0043 auto* const message = new Sublime::Message(messageText, Sublime::Message::Error); 0044 KDevelop::ICore::self()->uiController()->postMessage(message); 0045 } 0046 } 0047 0048 namespace Heaptrack 0049 { 0050 0051 Plugin::Plugin(QObject* parent, const QVariantList&) 0052 : IPlugin(QStringLiteral("kdevheaptrack"), parent) 0053 { 0054 setXMLFile(QStringLiteral("kdevheaptrack.rc")); 0055 0056 m_launchAction = new QAction( 0057 QIcon::fromTheme(QStringLiteral("office-chart-area")), 0058 i18nc("@action", "Run Heaptrack Analysis"), 0059 this); 0060 0061 connect(m_launchAction, &QAction::triggered, this, &Plugin::launchHeaptrack); 0062 actionCollection()->addAction(QStringLiteral("heaptrack_launch"), m_launchAction); 0063 0064 #if HAVE_KSYSGUARD 0065 m_attachAction = new QAction( 0066 QIcon::fromTheme(QStringLiteral("office-chart-area")), 0067 i18nc("@action", "Attach to Process with Heaptrack"), 0068 this); 0069 0070 connect(m_attachAction, &QAction::triggered, this, &Plugin::attachHeaptrack); 0071 actionCollection()->addAction(QStringLiteral("heaptrack_attach"), m_attachAction); 0072 #endif 0073 } 0074 0075 Plugin::~Plugin() 0076 { 0077 } 0078 0079 void Plugin::launchHeaptrack() 0080 { 0081 IExecutePlugin* executePlugin = nullptr; 0082 0083 // First we should check that our "kdevexecute" plugin is loaded. This is needed since 0084 // current plugin controller logic allows us to unload this plugin with keeping dependent 0085 // plugins like Heaptrack in "loaded" state. This seems to be wrong behaviour but now we have 0086 // to do additional checks. 0087 // TODO fix plugin controller to avoid such inconsistent states. 0088 auto pluginController = core()->pluginController(); 0089 if (auto plugin = pluginController->pluginForExtension( 0090 QStringLiteral("org.kdevelop.IExecutePlugin"), QStringLiteral("kdevexecute"))) { 0091 executePlugin = plugin->extension<IExecutePlugin>(); 0092 } else { 0093 auto pluginInfo = pluginController->infoForPluginId(QStringLiteral("kdevexecute")); 0094 postErrorMessage(i18n("Unable to start Heaptrack analysis - \"%1\" plugin is not loaded.", pluginInfo.name())); 0095 return; 0096 } 0097 0098 auto runController = KDevelop::Core::self()->runControllerInternal(); 0099 auto defaultLaunch = runController->defaultLaunch(); 0100 if (!defaultLaunch) { 0101 runController->showConfigurationDialog(); 0102 defaultLaunch = runController->defaultLaunch(); 0103 if (!defaultLaunch) { 0104 postErrorMessage(i18n("Configure a native application launch to perform Heaptrack analysis on.")); 0105 return; 0106 } 0107 } 0108 0109 if (!defaultLaunch->type()->launcherForId(QStringLiteral("nativeAppLauncher"))) { 0110 postErrorMessage(i18n("Heaptrack analysis can be started only for native applications.")); 0111 return; 0112 } 0113 0114 auto heaptrackJob = new Job(defaultLaunch, executePlugin); 0115 connect(heaptrackJob, &Job::finished, this, &Plugin::jobFinished); 0116 0117 QList<KJob*> jobList; 0118 if (KJob* depJob = executePlugin->dependencyJob(defaultLaunch)) { 0119 jobList += depJob; 0120 } 0121 jobList += heaptrackJob; 0122 0123 auto ecJob = new KDevelop::ExecuteCompositeJob(runController, jobList); 0124 ecJob->setObjectName(heaptrackJob->statusName()); 0125 runController->registerJob(ecJob); 0126 0127 m_launchAction->setEnabled(false); 0128 } 0129 0130 void Plugin::attachHeaptrack() 0131 { 0132 #if HAVE_KSYSGUARD 0133 QPointer<KDevMI::ProcessSelectionDialog> dlg = new KDevMI::ProcessSelectionDialog(activeMainWindow()); 0134 if (!dlg->exec() || !dlg->pidSelected()) { 0135 delete dlg; 0136 return; 0137 } 0138 0139 auto heaptrackJob = new Job(dlg->pidSelected()); 0140 delete dlg; 0141 connect(heaptrackJob, &Job::finished, this, &Plugin::jobFinished); 0142 0143 heaptrackJob->setObjectName(heaptrackJob->statusName()); 0144 core()->runController()->registerJob(heaptrackJob); 0145 0146 m_launchAction->setEnabled(false); 0147 #endif 0148 } 0149 0150 void Plugin::jobFinished(KJob* kjob) 0151 { 0152 auto job = static_cast<Job*>(kjob); 0153 Q_ASSERT(job); 0154 0155 if (job->status() == KDevelop::OutputExecuteJob::JobStatus::JobSucceeded) { 0156 auto visualizer = new Visualizer(job->resultsFile(), this); 0157 visualizer->start(); 0158 } else { 0159 QFile::remove(job->resultsFile()); 0160 } 0161 0162 m_launchAction->setEnabled(true); 0163 } 0164 0165 int Plugin::configPages() const 0166 { 0167 return 1; 0168 } 0169 0170 KDevelop::ConfigPage* Plugin::configPage(int number, QWidget* parent) 0171 { 0172 if (number) { 0173 return nullptr; 0174 } 0175 0176 return new GlobalConfigPage(this, parent); 0177 } 0178 0179 } 0180 0181 #include "plugin.moc" 0182 #include "moc_plugin.cpp"