File indexing completed on 2024-04-28 04:37:24

0001 /*
0002     SPDX-FileCopyrightText: 2017 Aleix Pol Gonzalez <aleixpol@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-only
0005 */
0006 
0007 #include "runtimecontroller.h"
0008 #include <QProcess>
0009 #include <QComboBox>
0010 #include <KActionCollection>
0011 #include <KLocalizedString>
0012 #include <KProcess>
0013 #include <KShell>
0014 #include <util/path.h>
0015 #include "core.h"
0016 #include "uicontroller.h"
0017 #include "mainwindow.h"
0018 #include "debug.h"
0019 
0020 using namespace KDevelop;
0021 
0022 class IdentityRuntime : public IRuntime
0023 {
0024     Q_OBJECT
0025 public:
0026     QString name() const override { return i18n("Host System"); }
0027 
0028     void startProcess(KProcess *process) const override {
0029         catchErrors(*process);
0030         process->start();
0031     }
0032     void startProcess(QProcess *process) const override {
0033         catchErrors(*process);
0034         process->start();
0035     }
0036     KDevelop::Path pathInHost(const KDevelop::Path & runtimePath) const override { return runtimePath; }
0037     KDevelop::Path pathInRuntime(const KDevelop::Path & localPath) const override { return localPath; }
0038     QString findExecutable(const QString& executableName) const override
0039     {
0040         return QStandardPaths::findExecutable(executableName);
0041     }
0042     void setEnabled(bool /*enabled*/) override {}
0043     QByteArray getenv(const QByteArray & varname) const override { return qgetenv(varname.constData()); }
0044     KDevelop::Path buildPath() const override { return {}; }
0045 
0046 private:
0047     static void catchErrors(const QProcess& process)
0048     {
0049         connect(&process, &QProcess::errorOccurred, [&process](QProcess::ProcessError error) {
0050             qCWarning(SHELL).noquote().nospace()
0051                 << "process finished with error: " << error << " \"" << process.errorString()
0052                 << "\", the command line: \"" << KShell::quoteArg(process.program()) << ' '
0053                 << KShell::joinArgs(process.arguments()) << '"';
0054         });
0055     }
0056 };
0057 
0058 KDevelop::RuntimeController::RuntimeController(KDevelop::Core* core)
0059     : m_core(core)
0060 {
0061     const bool haveUI = (core->setupFlags() != Core::NoUi);
0062     if (haveUI) {
0063         m_runtimesMenu.reset(new QMenu());
0064     }
0065 
0066     addRuntimes(new IdentityRuntime);
0067     setCurrentRuntime(m_runtimes.first());
0068 
0069     if (haveUI) {
0070         setupActions();
0071     }
0072 }
0073 
0074 KDevelop::RuntimeController::~RuntimeController()
0075 {
0076     m_currentRuntime->setEnabled(false);
0077     m_currentRuntime = nullptr;
0078 }
0079 
0080 void RuntimeController::setupActions()
0081 {
0082     // TODO not multi-window friendly, FIXME
0083     KActionCollection* ac = m_core->uiControllerInternal()->defaultMainWindow()->actionCollection();
0084 
0085     auto action = new QAction(this);
0086     action->setToolTip(i18n("Allows to select a runtime"));
0087     action->setMenu(m_runtimesMenu.data());
0088     action->setIcon(QIcon::fromTheme(QStringLiteral("file-library-symbolic")));
0089     auto updateActionText = [action](IRuntime* currentRuntime){
0090         action->setText(i18n("Runtime: %1", currentRuntime->name()));
0091     };
0092     connect(this, &RuntimeController::currentRuntimeChanged, action, updateActionText);
0093     updateActionText(m_currentRuntime);
0094 
0095     ac->addAction(QStringLiteral("switch_runtimes"), action);
0096 }
0097 
0098 void KDevelop::RuntimeController::initialize()
0099 {
0100 }
0101 
0102 KDevelop::IRuntime * KDevelop::RuntimeController::currentRuntime() const
0103 {
0104     Q_ASSERT(m_currentRuntime);
0105     return m_currentRuntime;
0106 }
0107 
0108 QVector<KDevelop::IRuntime *> KDevelop::RuntimeController::availableRuntimes() const
0109 {
0110     return m_runtimes;
0111 }
0112 
0113 void KDevelop::RuntimeController::setCurrentRuntime(KDevelop::IRuntime* runtime)
0114 {
0115     if (m_currentRuntime == runtime)
0116         return;
0117 
0118     Q_ASSERT(m_runtimes.contains(runtime));
0119 
0120     if (m_currentRuntime) {
0121         m_currentRuntime->setEnabled(false);
0122     }
0123     qCDebug(SHELL) << "setting runtime..." << runtime->name() << "was" << m_currentRuntime;
0124     m_currentRuntime = runtime;
0125     m_currentRuntime->setEnabled(true);
0126     Q_EMIT currentRuntimeChanged(runtime);
0127 }
0128 
0129 void KDevelop::RuntimeController::addRuntimes(KDevelop::IRuntime * runtime)
0130 {
0131     if (!runtime->parent())
0132         runtime->setParent(this);
0133 
0134     if (m_core->setupFlags() != Core::NoUi) {
0135         auto* runtimeAction = new QAction(runtime->name(), m_runtimesMenu.data());
0136         runtimeAction->setCheckable(true);
0137         connect(runtimeAction, &QAction::triggered, runtime, [this, runtime]() {
0138             setCurrentRuntime(runtime);
0139         });
0140         connect(this, &RuntimeController::currentRuntimeChanged, runtimeAction, [runtimeAction, runtime](IRuntime* currentRuntime) {
0141             runtimeAction->setChecked(runtime == currentRuntime);
0142         });
0143 
0144         connect(runtime, &QObject::destroyed, this, [this, runtimeAction](QObject* obj) {
0145             Q_ASSERT(m_currentRuntime != obj);
0146             m_runtimes.removeAll(qobject_cast<KDevelop::IRuntime *>(obj));
0147             delete runtimeAction;
0148         });
0149         m_runtimesMenu->addAction(runtimeAction);
0150     } else {
0151         connect(runtime, &QObject::destroyed, this, [this](QObject* obj) {
0152             Q_ASSERT(m_currentRuntime != obj);
0153             m_runtimes.removeAll(qobject_cast<KDevelop::IRuntime *>(obj));
0154         });
0155     }
0156 
0157     m_runtimes << runtime;
0158 }
0159 
0160 #include "runtimecontroller.moc"
0161 #include "moc_runtimecontroller.cpp"