Commit 11ced149 authored by Volker Krause's avatar Volker Krause
Browse files

Add selection ratio source

Same concept and data format as the property ratio source, just monitoring
a QItemSelectionModel instead.
parent 0c05f7bd
......@@ -21,6 +21,7 @@ endfunction()
uf_add_test(datasourcetest UserFeedbackCore Qt5::Gui) # needs Gui for ScreenInfoSource to work
uf_add_test(providertest UserFeedbackCore Qt5::Gui)
uf_add_test(selectionratiosourcetest.cpp UserFeedbackCore Qt5::Gui)
uf_add_test(feedbackconfigtest UserFeedbackWidgets)
......
/*
Copyright (C) 2017 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <provider/core/selectionratiosource.h>
#include <QDebug>
#include <QItemSelectionModel>
#include <QtTest/qtest.h>
#include <QObject>
#include <QSettings>
#include <QStandardItemModel>
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
#include <QStandardPaths>
#endif
using namespace UserFeedback;
class SelectionRatioSourceTest : public QObject
{
Q_OBJECT
private slots:
void initTestCase()
{
QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org"));
QCoreApplication::setOrganizationName(QStringLiteral("KDE"));
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
QStandardPaths::setTestModeEnabled(true);
#endif
}
void testPropertyRatioSource()
{
QStandardItemModel model;
model.appendRow(new QStandardItem(QStringLiteral("row1")));
model.appendRow(new QStandardItem(QStringLiteral("row2")));
model.appendRow(new QStandardItem(QStringLiteral("row3")));
QItemSelectionModel sel(&model);
sel.select(model.index(1, 0), QItemSelectionModel::ClearAndSelect);
SelectionRatioSource src(&sel, QStringLiteral("selection"));
QTest::qWait(1);
auto v = src.data();
QVERIFY(v.canConvert<QVariantMap>());
auto o = v.toMap();
QCOMPARE(o.size(), 0); // nothing recorded
QTest::qWait(1200);
v = src.data();
o = v.toMap();
QCOMPARE(o.size(), 1);
QVERIFY(o.contains(QLatin1String("row2")));
v = o.value(QLatin1String("row2")).toMap().value(QLatin1String("property"));
QCOMPARE(v.type(), QVariant::Double);
sel.select(model.index(2, 0), QItemSelectionModel::ClearAndSelect);
QTest::qWait(1200);
v = src.data();
o = v.toMap();
QCOMPARE(o.size(), 2);
QVERIFY(o.contains(QLatin1String("row2")));
v = o.value(QLatin1String("row2")).toMap().value(QLatin1String("property"));
QCOMPARE(v.type(), QVariant::Double);
}
};
QTEST_MAIN(SelectionRatioSourceTest)
#include "selectionratiosourcetest.moc"
......@@ -10,6 +10,7 @@ set(userfeedback_core_srcs
provider.cpp
qtversionsource.cpp
screeninfosource.cpp
selectionratiosource.cpp
startcountsource.cpp
surveyinfo.cpp
usagetimesource.cpp
......
/*
Copyright (C) 2017 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "selectionratiosource.h"
#include "abstractdatasource_p.h"
#include "logging_p.h"
#include <QDebug>
#include <QHash>
#include <QItemSelectionModel>
#include <QSettings>
#include <QStringList>
#include <QTime>
#include <memory>
using namespace UserFeedback;
namespace UserFeedback {
class SelectionRatioSourcePrivate : public AbstractDataSourcePrivate
{
public:
SelectionRatioSourcePrivate();
void selectionChanged();
QString selectedValue() const;
QItemSelectionModel *model;
std::unique_ptr<QObject> monitor;
QString description;
QString previousValue;
QTime lastChangeTime;
QHash<QString, int> ratioSet; // data we are currently tracking
QHash<QString, int> baseRatioSet; // data loaded from storage
int role;
};
class SelectionMonitor : public QObject
{
Q_OBJECT
public:
explicit SelectionMonitor(SelectionRatioSourcePrivate *d) : m_receiver(d) {}
public Q_SLOTS:
void selectionChanged()
{
m_receiver->selectionChanged();
}
private:
SelectionRatioSourcePrivate *m_receiver;
};
}
SelectionRatioSourcePrivate::SelectionRatioSourcePrivate()
: model(nullptr)
, role(Qt::DisplayRole)
{
}
void SelectionRatioSourcePrivate::selectionChanged()
{
if (!previousValue.isEmpty() && lastChangeTime.elapsed() > 1000) {
ratioSet[previousValue] += lastChangeTime.elapsed() / 1000;
}
lastChangeTime.start();
previousValue = selectedValue();
}
QString SelectionRatioSourcePrivate::selectedValue() const
{
if (!model->hasSelection())
return QString();
const auto idxs = model->selectedIndexes();
Q_ASSERT(!idxs.isEmpty());
const auto idx = idxs.at(0);
return idx.data(role).toString();
}
SelectionRatioSource::SelectionRatioSource(QItemSelectionModel* selectionModel, const QString& sampleName)
: AbstractDataSource(sampleName, new SelectionRatioSourcePrivate)
{
Q_D(SelectionRatioSource);
d->model = selectionModel;
Q_ASSERT(selectionModel);
d->monitor.reset(new SelectionMonitor(d));
QObject::connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), d->monitor.get(), SLOT(selectionChanged()));
d->lastChangeTime.start();
d->selectionChanged();
}
void SelectionRatioSource::setRole(int role)
{
Q_D(SelectionRatioSource);
d->role = role;
}
QString SelectionRatioSource::description() const
{
Q_D(const SelectionRatioSource);
return d->description;
}
void SelectionRatioSource::setDescription(const QString& desc)
{
Q_D(SelectionRatioSource);
d->description = desc;
}
QVariant SelectionRatioSource::data()
{
Q_D(SelectionRatioSource);
d->selectionChanged();
QVariantMap m;
int total = 0;
for (auto it = d->ratioSet.constBegin(); it != d->ratioSet.constEnd(); ++it)
total += it.value() + d->baseRatioSet.value(it.key());
for (auto it = d->ratioSet.constBegin(); it != d->ratioSet.constEnd(); ++it) {
double currentValue = it.value() + d->baseRatioSet.value(it.key());
QVariantMap v;
v.insert(QStringLiteral("property"), currentValue / (double)(total));
m.insert(it.key(), v);
}
return m;
}
void SelectionRatioSource::load(QSettings *settings)
{
Q_D(SelectionRatioSource);
foreach (const auto &value, settings->childKeys()) {
const auto amount = std::max(settings->value(value, 0).toInt(), 0);
d->baseRatioSet.insert(value, amount);
if (!d->ratioSet.contains(value))
d->ratioSet.insert(value, 0);
}
}
void SelectionRatioSource::store(QSettings *settings)
{
Q_D(SelectionRatioSource);
d->selectionChanged();
// note that a second process can have updated the data meanwhile!
for (auto it = d->ratioSet.begin(); it != d->ratioSet.end(); ++it) {
if (it.value() == 0)
continue;
const auto oldValue = std::max(settings->value(it.key(), 0).toInt(), 0);
const auto newValue = oldValue + it.value();
settings->setValue(it.key(), newValue);
*it = 0;
d->baseRatioSet.insert(it.key(), newValue);
}
}
void SelectionRatioSource::reset(QSettings* settings)
{
Q_D(SelectionRatioSource);
d->baseRatioSet.clear();
d->ratioSet.clear();
settings->remove(QString());
}
#include "selectionratiosource.moc"
/*
Copyright (C) 2017 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef USERFEEDBACK_SELECTIONRATIOSOURCE_H
#define USERFEEDBACK_SELECTIONRATIOSOURCE_H
#include "userfeedbackcore_export.h"
#include "abstractdatasource.h"
QT_BEGIN_NAMESPACE
class QItemSelectionModel;
QT_END_NAMESPACE
namespace UserFeedback {
class SelectionRatioSourcePrivate;
/*! Records the time ratio a given entry is selected via a QItemSelectionModel.
*
* An example use-case would be the usage ratio of a applications
* views/modes selected using a model-based view sidebar (such as
* used in e.g. Kontact).
*/
class USERFEEDBACKCORE_EXPORT SelectionRatioSource : public AbstractDataSource
{
public:
/*! Create a new selection ratio data source.
* @param selectionModel The selection to monitor.
* @param sampleName This is the name of the database field this data source is
* associated with.
*/
explicit SelectionRatioSource(QItemSelectionModel *selectionModel, const QString &sampleName);
/*! Determine which role to consider for the reported value.
* By default this is Qt::DisplayRole.
*/
void setRole(int role);
QString description() const override;
/*! Set human-readable and translated description of the data provided by this source.
* @note This must be set before adding this source, sources without description are
* discarded.
* @param desc The description.
*/
void setDescription(const QString &desc);
QVariant data() override;
void load(QSettings *settings) override;
void store(QSettings *settings) override;
void reset(QSettings *settings) override;
private:
Q_DECLARE_PRIVATE(SelectionRatioSource)
};
}
#endif // USERFEEDBACK_SELECTIONRATIOSOURCE_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment