File indexing completed on 2024-05-19 05:38:05
0001 /* 0002 SPDX-FileCopyrightText: 2019 David Edmundson <davidedmundson@kde.org> 0003 SPDX-FileCopyrightText: 2019 Aleix Pol Gonzalez <aleixpol@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "feedback.h" 0009 #include "kcm_feedback_debug.h" 0010 0011 #include <KConfigGroup> 0012 #include <KLocalizedString> 0013 #include <KPluginFactory> 0014 0015 #include <QFileInfo> 0016 #include <QList> 0017 #include <QProcess> 0018 0019 #include <KUserFeedback/FeedbackConfigUiController> 0020 #include <KUserFeedback/Provider> 0021 0022 #include "feedbackdata.h" 0023 #include "feedbacksettings.h" 0024 0025 K_PLUGIN_FACTORY_WITH_JSON(FeedbackFactory, "kcm_feedback.json", registerPlugin<Feedback>(); registerPlugin<FeedbackData>();) 0026 0027 struct Information { 0028 QString icon; 0029 QString kuserfeedbackComponent; 0030 }; 0031 static QHash<QString, Information> s_programs = { 0032 {"plasmashell", {"plasmashell", "plasmashell"}}, 0033 {"plasma-discover", {"plasmadiscover", "discover"}}, 0034 }; 0035 0036 inline void swap(QJsonValueRef v1, QJsonValueRef v2) 0037 { 0038 QJsonValue temp(v1); 0039 v1 = QJsonValue(v2); 0040 v2 = temp; 0041 } 0042 0043 Feedback::Feedback(QObject *parent, const KPluginMetaData &data) 0044 : KQuickManagedConfigModule(parent, data) 0045 // UserFeedback.conf is used by KUserFeedback which uses QSettings and won't go through globals 0046 , m_data(new FeedbackData(this)) 0047 { 0048 qmlRegisterAnonymousType<FeedbackSettings>("org.kde.userfeedback.kcm", 1); 0049 0050 for (const auto &[program, _] : s_programs.asKeyValueRange()) { 0051 auto p = new QProcess(this); 0052 p->setProgram(program); 0053 p->setArguments({QStringLiteral("--feedback")}); 0054 p->start(); 0055 connect(p, &QProcess::finished, this, &Feedback::programFinished); 0056 // deleted by finished slot 0057 } 0058 } 0059 0060 void Feedback::programFinished(int exitCode) 0061 { 0062 const auto modeEnum = QMetaEnum::fromType<KUserFeedback::Provider::TelemetryMode>(); 0063 Q_ASSERT(modeEnum.isValid()); 0064 0065 auto p = qobject_cast<QProcess *>(sender()); 0066 const QString program = p->program(); 0067 0068 if (exitCode) { 0069 qCWarning(KCM_FEEDBACK_DEBUG) << "Could not check" << program; 0070 return; 0071 } 0072 0073 QTextStream stream(p); 0074 for (QString line; stream.readLineInto(&line);) { 0075 auto sepIdx = line.indexOf(QLatin1String(": ")); 0076 if (sepIdx < 0) { 0077 break; 0078 } 0079 0080 const QString mode = line.left(sepIdx); 0081 bool ok = false; 0082 const int modeValue = modeEnum.keyToValue(qPrintable(mode), &ok); 0083 if (!ok) { 0084 qCWarning(KCM_FEEDBACK_DEBUG) << "error:" << mode << "is not a valid mode"; 0085 continue; 0086 } 0087 0088 const QString description = line.mid(sepIdx + 1); 0089 m_uses[modeValue][description] << s_programs[program].icon; 0090 } 0091 p->deleteLater(); 0092 m_feedbackSources = {}; 0093 for (const auto &[mode, modeUses] : m_uses.asKeyValueRange()) { 0094 for (const auto &[description, icon] : modeUses.asKeyValueRange()) { 0095 m_feedbackSources << QJsonObject({{"mode", mode}, {"icons", icon}, {"description", description}}); 0096 } 0097 } 0098 std::sort(m_feedbackSources.begin(), m_feedbackSources.end(), [](const QJsonValue &valueL, const QJsonValue &valueR) { 0099 const QJsonObject objL(valueL.toObject()); 0100 const QJsonObject objR(valueR.toObject()); 0101 const auto modeL = objL["mode"].toInt(); 0102 const auto modeR = objR["mode"].toInt(); 0103 return modeL < modeR || (modeL == modeR && objL["description"].toString() < objR["description"].toString()); 0104 }); 0105 Q_EMIT feedbackSourcesChanged(); 0106 } 0107 0108 bool Feedback::feedbackEnabled() const 0109 { 0110 KUserFeedback::Provider p; 0111 return p.isEnabled(); 0112 } 0113 0114 FeedbackSettings *Feedback::feedbackSettings() const 0115 { 0116 return m_data->settings(); 0117 } 0118 0119 QJsonArray Feedback::audits() const 0120 { 0121 QJsonArray ret; 0122 for (const auto &[program, info] : s_programs.asKeyValueRange()) { 0123 QString feedbackLocation = 0124 QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + '/' + info.kuserfeedbackComponent + QStringLiteral("/kuserfeedback/audit"); 0125 0126 if (QFileInfo::exists(feedbackLocation)) { 0127 ret += QJsonObject{ 0128 {"program", program}, 0129 {"audits", feedbackLocation}, 0130 }; 0131 } 0132 } 0133 return ret; 0134 } 0135 0136 #include "feedback.moc" 0137 #include "moc_feedback.cpp"