Warning, file /plasma/kinfocenter/src/CommandOutputContext.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0003 SPDX-FileCopyrightText: 2021-2022 Harald Sitter <sitter@kde.org> 0004 */ 0005 0006 #include "CommandOutputContext.h" 0007 0008 #include <utility> 0009 0010 #include <QDebug> 0011 #include <QProcess> 0012 #include <QStandardPaths> 0013 0014 #include <KLocalizedString> 0015 #include <KOSRelease> 0016 0017 CommandOutputContext::CommandOutputContext(const QStringList &findExecutables, const QString &executable, const QStringList &arguments, QObject *parent) 0018 : QObject(parent) 0019 , m_executableName(executable) 0020 , m_executablePath(QStandardPaths::findExecutable(m_executableName)) 0021 , m_arguments(arguments) 0022 , m_bugReportUrl(KOSRelease().bugReportUrl()) 0023 { 0024 // Various utilities are installed in sbin, but work without elevated privileges 0025 if (m_executablePath.isEmpty()) { 0026 m_executablePath = 0027 QStandardPaths::findExecutable(m_executableName, {QStringLiteral("/usr/local/sbin"), QStringLiteral("/usr/sbin"), QStringLiteral("/sbin")}); 0028 } 0029 0030 m_foundExecutablePaths[executable] = m_executablePath; 0031 for (const QString &findExecutable : findExecutables) { 0032 m_foundExecutablePaths[findExecutable] = QStandardPaths::findExecutable(findExecutable); 0033 } 0034 0035 metaObject()->invokeMethod(this, &CommandOutputContext::load); 0036 } 0037 0038 CommandOutputContext::CommandOutputContext(const QString &executable, const QStringList &arguments, QObject *parent) 0039 : CommandOutputContext({/* executable is by default always searched for */}, executable, arguments, parent) 0040 { 0041 } 0042 0043 QString CommandOutputContext::executableName() const 0044 { 0045 return m_executableName; 0046 } 0047 0048 QStringList CommandOutputContext::arguments() const 0049 { 0050 return m_arguments; 0051 } 0052 0053 QString CommandOutputContext::filter() const 0054 { 0055 return m_filter; 0056 } 0057 0058 void CommandOutputContext::setFilter(const QString &filter) 0059 { 0060 m_filter = filter; 0061 if (m_filter.isEmpty()) { 0062 m_text = m_originalLines.join('\n'); 0063 } else { 0064 m_text.clear(); 0065 for (const QString &line : std::as_const(m_originalLines)) { 0066 if (line.contains(filter, Qt::CaseInsensitive)) { 0067 m_text += line + '\n'; 0068 } 0069 } 0070 } 0071 Q_EMIT textChanged(); 0072 Q_EMIT filterChanged(); 0073 } 0074 0075 void CommandOutputContext::reset() 0076 { 0077 m_ready = false; 0078 m_error.clear(); 0079 m_explanation.clear(); 0080 m_text.clear(); 0081 m_filter.clear(); 0082 Q_EMIT readyChanged(); 0083 Q_EMIT errorChanged(); 0084 Q_EMIT explanationChanged(); 0085 Q_EMIT textChanged(); 0086 Q_EMIT filterChanged(); 0087 0088 // Not exposed as properties 0089 m_originalLines.clear(); 0090 } 0091 0092 void CommandOutputContext::load() 0093 { 0094 reset(); 0095 0096 for (auto it = m_foundExecutablePaths.cbegin(); it != m_foundExecutablePaths.cend(); ++it) { 0097 if (it.value().isEmpty()) { 0098 setError(xi18nc("@info", "The <command>%1</command> tool is required to display this page, but could not be found", it.key()), 0099 xi18nc("@info", 0100 "You can search for it and install it using your package manager.<nl/>" 0101 "Then please report this packaging issue to your distribution.")); 0102 return; 0103 } 0104 } 0105 0106 auto proc = new QProcess(this); 0107 proc->setProcessChannelMode(QProcess::MergedChannels); 0108 connect(proc, &QProcess::finished, this, [this, proc](int /* exitCode */, QProcess::ExitStatus exitStatus) { 0109 proc->deleteLater(); 0110 0111 switch (exitStatus) { 0112 case QProcess::CrashExit: 0113 return setError(xi18nc("@info", "The <command>%1</command> tool crashed while generating page content", m_executableName), 0114 xi18nc("@Info", "Try again later. If keeps happening, please report the crash to your distribution.")); 0115 case QProcess::NormalExit: 0116 break; 0117 } 0118 0119 m_text = QString::fromLocal8Bit(proc->readAllStandardOutput()); 0120 m_text = m_text.trimmed(); 0121 m_originalLines = m_text.split('\n'); 0122 if (!m_filter.isEmpty()) { 0123 // re-apply filter on new text 0124 setFilter(m_filter); 0125 } 0126 0127 Q_EMIT textChanged(); 0128 setReady(); 0129 }); 0130 proc->start(m_executablePath, m_arguments); 0131 } 0132 0133 void CommandOutputContext::setError(const QString &message, const QString &explanation = QString()) 0134 { 0135 m_error = message; 0136 0137 if (!explanation.isEmpty()) { 0138 m_explanation = explanation; 0139 } 0140 0141 Q_EMIT errorChanged(); 0142 Q_EMIT explanationChanged(); 0143 0144 setReady(); 0145 } 0146 0147 void CommandOutputContext::setReady() 0148 { 0149 m_ready = true; 0150 Q_EMIT readyChanged(); 0151 }