File indexing completed on 2024-12-15 03:45:04

0001 /*
0002     SPDX-FileCopyrightText: 2017 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: MIT
0005 */
0006 
0007 #include "selectionratiosource.h"
0008 #include "abstractdatasource_p.h"
0009 #include "logging_p.h"
0010 
0011 #include <QDebug>
0012 #include <QHash>
0013 #include <QItemSelectionModel>
0014 #include <QSettings>
0015 #include <QStringList>
0016 #include <QTime>
0017 #include <QElapsedTimer>
0018 
0019 #include <memory>
0020 
0021 using namespace KUserFeedback;
0022 
0023 namespace KUserFeedback {
0024 class SelectionRatioSourcePrivate : public AbstractDataSourcePrivate
0025 {
0026 public:
0027     SelectionRatioSourcePrivate();
0028     ~SelectionRatioSourcePrivate() override;
0029 
0030     void selectionChanged();
0031     QString selectedValue() const;
0032 
0033     QItemSelectionModel *model;
0034     QMetaObject::Connection monitorConnection;
0035     QString description;
0036     QString previousValue;
0037     QElapsedTimer lastChangeTime;
0038     QHash<QString, int> ratioSet; // data we are currently tracking
0039     QHash<QString, int> baseRatioSet; // data loaded from storage
0040     int role;
0041 };
0042 
0043 }
0044 
0045 SelectionRatioSourcePrivate::SelectionRatioSourcePrivate()
0046     : model(nullptr)
0047     , role(Qt::DisplayRole)
0048 {
0049 }
0050 
0051 SelectionRatioSourcePrivate::~SelectionRatioSourcePrivate()
0052 {
0053     QObject::disconnect(monitorConnection);
0054 }
0055 
0056 void SelectionRatioSourcePrivate::selectionChanged()
0057 {
0058     if (!previousValue.isEmpty() && lastChangeTime.elapsed() > 1000) {
0059         ratioSet[previousValue] += lastChangeTime.elapsed() / 1000;
0060     }
0061 
0062     lastChangeTime.start();
0063     previousValue = selectedValue();
0064 }
0065 
0066 QString SelectionRatioSourcePrivate::selectedValue() const
0067 {
0068     const auto idxs = model->selectedIndexes();
0069     if (!model->hasSelection() || idxs.isEmpty())
0070         return QString();
0071     Q_ASSERT(!idxs.isEmpty());
0072     const auto idx = idxs.at(0);
0073     return idx.data(role).toString();
0074 }
0075 
0076 SelectionRatioSource::SelectionRatioSource(QItemSelectionModel* selectionModel, const QString& sampleName)
0077     : AbstractDataSource(sampleName, Provider::DetailedUsageStatistics, new SelectionRatioSourcePrivate)
0078 {
0079     Q_D(SelectionRatioSource);
0080 
0081     d->model = selectionModel;
0082     Q_ASSERT(selectionModel);
0083 
0084     d->monitorConnection = QObject::connect(selectionModel, &QItemSelectionModel::selectionChanged, [this]() {
0085         Q_D(SelectionRatioSource);
0086         d->selectionChanged();
0087     });
0088     d->lastChangeTime.start();
0089     d->selectionChanged();
0090 }
0091 
0092 void SelectionRatioSource::setRole(int role)
0093 {
0094     Q_D(SelectionRatioSource);
0095     d->role = role;
0096 }
0097 
0098 QString SelectionRatioSource::description() const
0099 {
0100     Q_D(const SelectionRatioSource);
0101     return d->description;
0102 }
0103 
0104 void SelectionRatioSource::setDescription(const QString& desc)
0105 {
0106     Q_D(SelectionRatioSource);
0107     d->description = desc;
0108 }
0109 
0110 QVariant SelectionRatioSource::data()
0111 {
0112     Q_D(SelectionRatioSource);
0113     d->selectionChanged();
0114 
0115     QVariantMap m;
0116     int total = 0;
0117     for (auto it = d->ratioSet.constBegin(); it != d->ratioSet.constEnd(); ++it)
0118         total += it.value() + d->baseRatioSet.value(it.key());
0119     if (total <= 0)
0120         return m;
0121 
0122     for (auto it = d->ratioSet.constBegin(); it != d->ratioSet.constEnd(); ++it) {
0123         double currentValue = it.value() + d->baseRatioSet.value(it.key());
0124         QVariantMap v;
0125         v.insert(QStringLiteral("property"), currentValue / (double)(total));
0126         m.insert(it.key(), v);
0127     }
0128     return m;
0129 }
0130 
0131 void SelectionRatioSource::loadImpl(QSettings *settings)
0132 {
0133     Q_D(SelectionRatioSource);
0134     foreach (const auto &value, settings->childKeys()) {
0135         const auto amount = std::max(settings->value(value, 0).toInt(), 0);
0136         d->baseRatioSet.insert(value, amount);
0137         if (!d->ratioSet.contains(value))
0138             d->ratioSet.insert(value, 0);
0139     }
0140 }
0141 
0142 void SelectionRatioSource::storeImpl(QSettings *settings)
0143 {
0144     Q_D(SelectionRatioSource);
0145     d->selectionChanged();
0146 
0147     // note that a second process can have updated the data meanwhile!
0148     for (auto it = d->ratioSet.begin(); it != d->ratioSet.end(); ++it) {
0149         if (it.value() == 0)
0150             continue;
0151         const auto oldValue = std::max(settings->value(it.key(), 0).toInt(), 0);
0152         const auto newValue = oldValue + it.value();
0153         settings->setValue(it.key(), newValue);
0154         *it = 0;
0155         d->baseRatioSet.insert(it.key(), newValue);
0156     }
0157 }
0158 
0159 void SelectionRatioSource::resetImpl(QSettings* settings)
0160 {
0161     Q_D(SelectionRatioSource);
0162     d->baseRatioSet.clear();
0163     d->ratioSet.clear();
0164     settings->remove(QString());
0165 }