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"