on xenial help sign in
Cleanups, added test for ratings filter bindings.
31a0acePawel Stolowski
plugins/Unity/combinedfilteroptions.cpp+8−28
@@ -18,29 +18,14 @@
18 */
18 */
19
19
20#include "combinedfilteroptions.h"
20#include "combinedfilteroptions.h"
21+#include "combinedfilteroption.h"
21
22
22CombinedFilterOptions::CombinedFilterOptions(const std::vector<unity::dash::FilterOption::Ptr>& list, QObject *parent)
23CombinedFilterOptions::CombinedFilterOptions(const std::vector<unity::dash::FilterOption::Ptr>& list, QObject *parent)
23− : QAbstractListModel(parent)
24+ : GenericListModel(parent)
24{
25{
25 initList(list);
26 initList(list);
26}
27}
27
28
28−
29−QVariant CombinedFilterOptions::data(const QModelIndex& index, int /* role */) const
30−{
31− if (!index.isValid()) {
32− return QVariant();
33− }
34−
35− CombinedFilterOption* item = m_list.at(index.row());
36− return QVariant::fromValue(item);
37−}
38−
39−int CombinedFilterOptions::rowCount(const QModelIndex& /* parent */) const
40−{
41− return m_list.count();
42−}
43−
44void CombinedFilterOptions::initList(const std::vector<unity::dash::FilterOption::Ptr>& list)
29void CombinedFilterOptions::initList(const std::vector<unity::dash::FilterOption::Ptr>& list)
45{
30{
46 // combine options, e.g. A, B, C becomes A-B, B-C, C
31 // combine options, e.g. A, B, C becomes A-B, B-C, C
@@ -59,14 +44,6 @@ void CombinedFilterOptions::initList(const std::vector<unity::dash::FilterOption
59 }
44 }
60}
45}
61
46
62−void CombinedFilterOptions::addOption(CombinedFilterOption *option)
63−{
64− int index = m_list.count();
65− beginInsertRows(QModelIndex(), index, index);
66− m_list.insert(index, option);
67− endInsertRows();
68−}
69−
70void CombinedFilterOptions::onActiveChanged(bool state)
47void CombinedFilterOptions::onActiveChanged(bool state)
71{
48{
72 // if option became active, need to disable all other options
49 // if option became active, need to disable all other options
@@ -75,9 +52,12 @@ void CombinedFilterOptions::onActiveChanged(bool state)
75 if (option) {
52 if (option) {
76 Q_FOREACH (auto fo, m_list) {
53 Q_FOREACH (auto fo, m_list) {
77 if (option != fo) {
54 if (option != fo) {
55+ CombinedFilterOption *other = dynamic_cast<CombinedFilterOption*>(fo);
56+ if (fo) {
78− // note that changing state will result in onActiveChanged signal for that option, but
57+ // note that changing state will result in onActiveChanged signal for that option, but
79− // since it will be 'false', we won't end up in an infinite loop
58+ // since it will be 'false', we won't end up in an infinite loop
80− fo->setInactive(*option);
59+ other->setInactive(*option);
60+ }
81 }
61 }
82 }
62 }
83 }
63 }
plugins/Unity/combinedfilteroptions.h+2−9
@@ -22,32 +22,25 @@
22
22
23// Qt
23// Qt
24#include <QObject>
24#include <QObject>
25−#include <QAbstractListModel>
26
25
27// libunity-core
26// libunity-core
28#include <UnityCore/Filter.h>
27#include <UnityCore/Filter.h>
29
28
30// local
29// local
31−#include "combinedfilteroption.h"
30+#include "genericlistmodel.h"
32
31
33−class CombinedFilterOptions : public QAbstractListModel
32+class CombinedFilterOptions : public GenericListModel
34{
33{
35 Q_OBJECT
34 Q_OBJECT
36
35
37public:
36public:
38 CombinedFilterOptions(const std::vector<unity::dash::FilterOption::Ptr>& list, QObject *parent = 0);
37 CombinedFilterOptions(const std::vector<unity::dash::FilterOption::Ptr>& list, QObject *parent = 0);
39
38
40− QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
41− int rowCount(const QModelIndex& parent = QModelIndex()) const override;
42−
43private Q_SLOTS:
39private Q_SLOTS:
44 void onActiveChanged(bool state);
40 void onActiveChanged(bool state);
45
41
46private:
42private:
47 void initList(const std::vector<unity::dash::FilterOption::Ptr>& list);
43 void initList(const std::vector<unity::dash::FilterOption::Ptr>& list);
48− void addOption(CombinedFilterOption *option);
49−
50− QList<CombinedFilterOption*> m_list;
51};
44};
52
45
53Q_DECLARE_METATYPE(CombinedFilterOptions*)
46Q_DECLARE_METATYPE(CombinedFilterOptions*)
plugins/Unity/genericlistmodel.cpp+10
@@ -46,3 +46,13 @@ void GenericListModel::addOption(QObject *option)
46 m_list.insert(index, option);
46 m_list.insert(index, option);
47 endInsertRows();
47 endInsertRows();
48}
48}
49+
50+QList<QObject *>::Iterator GenericListModel::optionsBegin()
51+{
52+ return m_list.begin();
53+}
54+
55+QList<QObject *>::Iterator GenericListModel::optionsEnd()
56+{
57+ return m_list.end();
58+}
plugins/Unity/genericlistmodel.h+5−8
@@ -24,13 +24,7 @@
24#include <QObject>
24#include <QObject>
25#include <QAbstractListModel>
25#include <QAbstractListModel>
26
26
27−// libunity-core
28−#include <UnityCore/Filter.h>
29−
30−// local
31−#include "combinedfilteroption.h"
32−
33−class GenericListModel : public QAbstractListModel
27+class Q_DECL_EXPORT GenericListModel : public QAbstractListModel
34{
28{
35 Q_OBJECT
29 Q_OBJECT
36
30
@@ -39,9 +33,12 @@ public:
39
33
40 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
34 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
41 int rowCount(const QModelIndex& parent = QModelIndex()) const override;
35 int rowCount(const QModelIndex& parent = QModelIndex()) const override;
42−
43 void addOption(QObject* option);
36 void addOption(QObject* option);
44
37
38+ QList<QObject *>::Iterator optionsBegin();
39+ QList<QObject *>::Iterator optionsEnd();
40+
41+protected:
45 QList<QObject *> m_list;
42 QList<QObject *> m_list;
46};
43};
47
44
plugins/Unity/ratingsfilter.cpp+19−13
@@ -22,27 +22,21 @@
22
22
23// local
23// local
24#include "genericlistmodel.h"
24#include "genericlistmodel.h"
25+#include "ratingfilteroption.h"
26+
27+// Qt
28+#include <QDebug>
25
29
26RatingsFilter::RatingsFilter(QObject *parent) :
30RatingsFilter::RatingsFilter(QObject *parent) :
27 Filter(parent), m_unityRatingsFilter(NULL), m_options(nullptr)
31 Filter(parent), m_unityRatingsFilter(NULL), m_options(nullptr)
28{
32{
29}
33}
30
34
31−float RatingsFilter::rating() const
32−{
33− return m_unityRatingsFilter->rating();
34−}
35−
36GenericListModel* RatingsFilter::options() const
35GenericListModel* RatingsFilter::options() const
37{
36{
38 return m_options;
37 return m_options;
39}
38}
40
39
41−void RatingsFilter::setRating(float rating)
42−{
43− m_unityRatingsFilter->rating = rating;
44−}
45−
46void RatingsFilter::setUnityFilter(unity::dash::Filter::Ptr filter)
40void RatingsFilter::setUnityFilter(unity::dash::Filter::Ptr filter)
47{
41{
48 if (m_unityFilter != NULL) {
42 if (m_unityFilter != NULL) {
@@ -63,15 +57,27 @@ void RatingsFilter::setUnityFilter(unity::dash::Filter::Ptr filter)
63 m_options->addOption(opt);
57 m_options->addOption(opt);
64 }
58 }
65
59
66− /* Property change signals */
60+ Q_EMIT ratingsChanged();
67− m_signals << m_unityRatingsFilter->rating.changed.connect(sigc::mem_fun(this, &RatingsFilter::ratingChanged));
68}
61}
69
62
70void RatingsFilter::onActiveChanged()
63void RatingsFilter::onActiveChanged()
71{
64{
72 RatingFilterOption *option = dynamic_cast<RatingFilterOption*>(QObject::sender());
65 RatingFilterOption *option = dynamic_cast<RatingFilterOption*>(QObject::sender());
73 if (option != nullptr) {
66 if (option != nullptr) {
74− setRating(option->value());
67+ if (option->active()) {
68+ // disable all other options
69+ for (auto it = m_options->optionsBegin(); it != m_options->optionsEnd(); it++) {
70+ RatingFilterOption *opt = dynamic_cast<RatingFilterOption *>(*it);
71+ if (opt && opt != option && opt->active()) {
72+ opt->setActive(false);
73+ }
74+ }
75+ m_unityRatingsFilter->rating = option->value();
76+ }
77+
78+ Q_EMIT ratingsChanged();
79+ } else {
80+ qWarning() << "Invalid option";
75 }
81 }
76}
82}
77
83
plugins/Unity/ratingsfilter.h+2−10
@@ -30,8 +30,6 @@
30// Local
30// Local
31#include "filter.h"
31#include "filter.h"
32#include "signalslist.h"
32#include "signalslist.h"
33−#include "ratingfilteroption.h"
34−#include "ratingfilteroption.h"
35
33
36class GenericListModel;
34class GenericListModel;
37
35
@@ -39,22 +37,16 @@ class Q_DECL_EXPORT RatingsFilter : public Filter
39{
37{
40 Q_OBJECT
38 Q_OBJECT
41
39
42− Q_PROPERTY(float rating READ rating WRITE setRating NOTIFY ratingChanged)
40+ Q_PROPERTY(GenericListModel* options READ options NOTIFY ratingsChanged)
43
41
44public:
42public:
45 explicit RatingsFilter(QObject *parent = 0);
43 explicit RatingsFilter(QObject *parent = 0);
46
44
47− /* getters */
48− float rating() const;
49−
50 /* getters */
45 /* getters */
51 GenericListModel* options() const;
46 GenericListModel* options() const;
52
47
53− /* setters */
54− void setRating(float rating);
55−
56Q_SIGNALS:
48Q_SIGNALS:
57− void ratingChanged(float);
49+ void ratingsChanged();
58
50
59protected:
51protected:
60 virtual void setUnityFilter(unity::dash::Filter::Ptr filter);
52 virtual void setUnityFilter(unity::dash::Filter::Ptr filter);
tests/plugins/Unity/filtersbindingstest.cpp+83
@@ -33,6 +33,8 @@
33#include "combinedfilteroption.h"
33#include "combinedfilteroption.h"
34#include "checkoptionfilter.h"
34#include "checkoptionfilter.h"
35#include "radiooptionfilter.h"
35#include "radiooptionfilter.h"
36+#include "ratingsfilter.h"
37+#include "ratingfilteroption.h"
36
38
37void FiltersBindingsTest::initTestCase()
39void FiltersBindingsTest::initTestCase()
38{
40{
@@ -73,6 +75,30 @@ void FiltersBindingsTest::createCheckOptionFilter(DeeModel *model, const std::st
73 createFilter(model, "filter-checkoption", id, name, optionCount);
75 createFilter(model, "filter-checkoption", id, name, optionCount);
74}
76}
75
77
78+void FiltersBindingsTest::createRatingsFilter(DeeModel *model, const std::string &id, const std::string &name)
79+{
80+ GVariant* row[8];
81+
82+ row[0] = g_variant_new_string(id.c_str());
83+ row[1] = g_variant_new_string(name.c_str());
84+ row[2] = g_variant_new_string(""); // icon hint
85+ row[3] = g_variant_new_string("filter-ratings");
86+
87+ GVariant *children[2];
88+ GVariant *key1 = g_variant_new_string("show-all-button");
89+ GVariant *key2 = g_variant_new_string("rating");
90+ children[0] = g_variant_new_dict_entry(key1, g_variant_new_variant(g_variant_new_boolean(false)));
91+ children[1] = g_variant_new_dict_entry(key2, g_variant_new_variant(g_variant_new_double(0.0f)));
92+ auto fhints = g_variant_new_array(G_VARIANT_TYPE("{sv}"), children, 2);
93+
94+ row[4] = fhints;
95+ row[5] = g_variant_new_boolean(true); // visible
96+ row[6] = g_variant_new_boolean(false); // collapsed
97+ row[7] = g_variant_new_boolean(false); // filtering
98+
99+ dee_model_append_row(model, row);
100+}
101+
76void FiltersBindingsTest::createFilter(DeeModel *model, const std::string &renderer, const std::string &id, const std::string &name, int optionCount)
102void FiltersBindingsTest::createFilter(DeeModel *model, const std::string &renderer, const std::string &id, const std::string &name, int optionCount)
77{
103{
78 GVariant* row[8];
104 GVariant* row[8];
@@ -350,4 +376,61 @@ void FiltersBindingsTest::testRadioOptionFilter()
350 }
376 }
351}
377}
352
378
379+void FiltersBindingsTest::testRatingsFilter()
380+{
381+ auto model = createFilterModel();
382+
383+ createRatingsFilter(model, "f1", "Filter1");
384+
385+ // create filter out of 1st row
386+ auto iter = dee_model_get_first_iter(DEE_MODEL(model));
387+ {
388+ auto core_filter = unity::dash::Filter::FilterFromIter(model, iter);
389+ QVERIFY(core_filter != nullptr);
390+ auto bind_filter = Filter::newFromUnityFilter(core_filter);
391+ auto rating_filter = dynamic_cast<RatingsFilter*>(bind_filter);
392+ QVERIFY(rating_filter != nullptr);
393+ auto options = rating_filter->options();
394+ QCOMPARE(options->rowCount(), 5);
395+
396+ RatingFilterOption* opt[5];
397+ for (int i = 0; i<5; i++) {
398+ opt[i] = options->data(options->index(i)).value<RatingFilterOption*>();
399+ }
400+
401+ QSignalSpy opt0spy(opt[0], SIGNAL(activeChanged(bool)));
402+ QSignalSpy opt4spy(opt[4], SIGNAL(activeChanged(bool)));
403+
404+ QVERIFY(qAbs(opt[0]->value() - 0.2f) <= 0.0001f);
405+ QVERIFY(qAbs(opt[1]->value() - 0.4f) <= 0.0001f);
406+ QVERIFY(qAbs(opt[2]->value() - 0.6f) <= 0.0001f);
407+ QVERIFY(qAbs(opt[3]->value() - 0.8f) <= 0.0001f);
408+ QVERIFY(qAbs(opt[4]->value() - 1.0f) <= 0.0001f);
409+
410+ // all options initially inactive
411+ for (int i=0; i<5; i++) {
412+ QCOMPARE(opt[i]->active(), false);
413+ }
414+
415+ // verify activation for all options
416+ for (int i=0; i<5; i++) {
417+ opt[i]->setActive(true);
418+ QCOMPARE(opt[i]->active(), true);
419+
420+ // verify that all other options are inactive
421+ for (int j=0; j<5; j++) {
422+ if (i != j) {
423+ QCOMPARE(opt[j]->active(), false);
424+ }
425+ }
426+ }
427+
428+ QCOMPARE(opt0spy.count(), 2);
429+ QCOMPARE(opt4spy.count(), 1);
430+
431+ opt[4]->setActive(false);
432+ QCOMPARE(opt4spy.count(), 2);
433+ }
434+}
435+
353QTEST_MAIN(FiltersBindingsTest)
436QTEST_MAIN(FiltersBindingsTest)
tests/plugins/Unity/filtersbindingstest.h+2
@@ -29,6 +29,7 @@ class FiltersBindingsTest : public QObject
29 void testMultiRangeFilter();
29 void testMultiRangeFilter();
30 void testCheckOptionFilter();
30 void testCheckOptionFilter();
31 void testRadioOptionFilter();
31 void testRadioOptionFilter();
32+ void testRatingsFilter();
32
33
33 private:
34 private:
34 DeeModel* createFilterModel();
35 DeeModel* createFilterModel();
@@ -36,6 +37,7 @@ class FiltersBindingsTest : public QObject
36 void createMultiRangeFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount);
37 void createMultiRangeFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount);
37 void createCheckOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount);
38 void createCheckOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount);
38 void createRadioOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount);
39 void createRadioOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount);
40+ void createRatingsFilter(DeeModel *model, const std::string &id, const std::string &name);
39 void createFilter(DeeModel *model, const std::string &renderer, const std::string &id, const std::string &name, int optionCount);
41 void createFilter(DeeModel *model, const std::string &renderer, const std::string &id, const std::string &name, int optionCount);
40};
42};
41
43