on xenial help sign in
Use proper models for filter options: created GenericOptionsModel and UnityOptionsModel + RatingOptionsModel. Removed CombinedFilterOption. Lots of other refactorings.
commit066af94146eb860b5a9f63f340f0857e3bef81b8 authorPawel Stolowski <pawel.stolowski@canonical.com> dateMon 12 Aug 2013, 17:41 (13 years ago) parentdc77e47
29 files changed+590−752
plugins/Unity/CMakeLists.txt+4−4 plugins/Unity/abstractfilteroption.h+1−1 plugins/Unity/checkoptionfilter.cpp+14−28 plugins/Unity/checkoptionfilter.h+5−13 plugins/Unity/combinedfilteroption.cpp−139 plugins/Unity/combinedfilteroption.h−78 plugins/Unity/combinedfilteroptions.cpp−65 plugins/Unity/filter.cpp+1−1 plugins/Unity/filter.h+5 plugins/Unity/filteroption.h−4 plugins/Unity/filters.cpp+6−3 plugins/Unity/genericlistmodel.cpp−58 plugins/Unity/genericlistmodel.h−50 plugins/Unity/genericoptionsmodel.cpp+155 plugins/Unity/genericoptionsmodel.h+77 plugins/Unity/listmodelwrapper.h−146 plugins/Unity/multirangefilter.cpp+9−2 plugins/Unity/multirangefilter.h+5−9 plugins/Unity/radiooptionfilter.cpp+9−15 plugins/Unity/radiooptionfilter.h+4−10 plugins/Unity/ratingfilteroption.cpp+12−1 plugins/Unity/ratingfilteroption.h+8−9 plugins/Unity/ratingoptionsmodel.cpp+33 plugins/Unity/combinedfilteroptions.h → plugins/Unity/ratingoptionsmodel.h+6−21 plugins/Unity/ratingsfilter.cpp+24−36 plugins/Unity/ratingsfilter.h+10−9 plugins/Unity/unityoptionsmodel.cpp+67 plugins/Unity/unityoptionsmodel.h+49 tests/plugins/Unity/filtersbindingstest.cpp+86−50
plugins/Unity/CMakeLists.txt+4−4
@@ -18,8 +18,6 @@ include_directories(
1818
1919set(QMLPLUGIN_SRC
2020 abstractfilteroption.cpp
21− combinedfilteroption.cpp
22− combinedfilteroptions.cpp
2321 scope.cpp
2422 scopes.cpp
2523 categories.cpp
@@ -27,7 +25,9 @@ set(QMLPLUGIN_SRC
2725 filter.cpp
2826 filteroption.cpp
2927 filters.cpp
30− genericlistmodel.cpp
28+ genericoptionsmodel.cpp
29+ ratingoptionsmodel.cpp
30+ unityoptionsmodel.cpp
3131 categoryresults.cpp
3232 plugin.cpp
3333 multirangefilter.cpp
@@ -46,7 +46,7 @@ set(QMLPLUGIN_SRC
4646 socialpreview.cpp
4747 socialpreviewcomment.cpp
4848 variantutils.cpp
49− )
49+)
5050
5151add_library(Unity-qml MODULE
5252 ${QMLPLUGIN_SRC}
plugins/Unity/abstractfilteroption.h+1−1
@@ -24,7 +24,7 @@
2424#include <QObject>
2525#include <QMetaType>
2626
27−class AbstractFilterOption : public QObject
27+class Q_DECL_EXPORT AbstractFilterOption : public QObject
2828{
2929 Q_OBJECT
3030
plugins/Unity/checkoptionfilter.cpp+14−28
@@ -20,12 +20,17 @@
2020// Self
2121#include "checkoptionfilter.h"
2222
23+// local
24+#include "unityoptionsmodel.h"
25+
2326CheckOptionFilter::CheckOptionFilter(QObject *parent) :
24− Filter(parent), m_unityCheckOptionFilter(nullptr), m_options(nullptr)
27+ Filter(parent),
28+ m_unityCheckOptionFilter(nullptr),
29+ m_options(nullptr)
2530{
2631}
2732
28−FilterOptions* CheckOptionFilter::options() const
33+GenericOptionsModel* CheckOptionFilter::options() const
2934{
3035 return m_options;
3136}
@@ -34,44 +39,25 @@ void CheckOptionFilter::setUnityFilter(unity::dash::Filter::Ptr filter)
3439{
3540 Filter::setUnityFilter(filter);
3641 m_unityCheckOptionFilter = std::dynamic_pointer_cast<unity::dash::CheckOptionFilter>(m_unityFilter);
37−
3842 onOptionsChanged(m_unityCheckOptionFilter->options);
3943}
4044
41−void CheckOptionFilter::onOptionsChanged(unity::dash::CheckOptionFilter::CheckOptions /* options */)
45+void CheckOptionFilter::onOptionsChanged(unity::dash::CheckOptionFilter::CheckOptions options)
4246{
4347 if (m_options != nullptr) {
4448 m_signals.disconnectAll();
4549 delete m_options;
4650 m_options = nullptr;
4751 }
48− m_options = new FilterOptions(m_unityCheckOptionFilter->options,
49− m_unityCheckOptionFilter->option_added,
50− m_unityCheckOptionFilter->option_removed);
5152
52− Q_FOREACH(FilterOption* option, m_options->rawList()) {
53− connect(option, SIGNAL(activeChanged(bool)), this, SLOT(onActiveChanged(bool)));
54− }
53+ m_options = new UnityOptionsModel(this, options,
54+ m_unityCheckOptionFilter->option_added,
55+ m_unityCheckOptionFilter->option_removed);
56+
57+ connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), m_options, SLOT(ensureTheOnlyActive(AbstractFilterOption *)));
5558
5659 /* Property change signals */
57− m_signals.append(m_unityCheckOptionFilter->options.changed.connect(sigc::mem_fun(this, &CheckOptionFilter::onOptionsChanged)));
60+ m_signals << m_unityCheckOptionFilter->options.changed.connect(sigc::mem_fun(this, &CheckOptionFilter::onOptionsChanged));
5861
5962 Q_EMIT optionsChanged();
6063}
61−
62−void CheckOptionFilter::onActiveChanged(bool state)
63−{
64− if (state == false)
65− return;
66−
67− FilterOption *selected_option = dynamic_cast<FilterOption*>(QObject::sender());
68− if (selected_option) {
69− Q_FOREACH(FilterOption* option, m_options->rawList()) {
70− if (option != selected_option && option->active()) {
71− option->setActive(false);
72− // we know only one option can be selected, so break immediately
73− break;
74− }
75− }
76− }
77−}
plugins/Unity/checkoptionfilter.h+5−13
@@ -36,29 +36,21 @@ class Q_DECL_EXPORT CheckOptionFilter : public Filter
3636{
3737 Q_OBJECT
3838
39− Q_PROPERTY(FilterOptions* options READ options NOTIFY optionsChanged)
40−
4139public:
4240 explicit CheckOptionFilter(QObject *parent = nullptr);
4341
4442 /* getters */
45− FilterOptions* options() const;
46−
47−Q_SIGNALS:
48− void optionsChanged();
49−
50−private Q_SLOTS:
51− void onActiveChanged(bool state);
43+ GenericOptionsModel* options() const override;
5244
5345protected:
54− virtual void setUnityFilter(unity::dash::Filter::Ptr filter);
46+ void setUnityFilter(unity::dash::Filter::Ptr filter) override;
5547
5648private:
49+ void onOptionsChanged(unity::dash::CheckOptionFilter::CheckOptions filter);
50+
5751 unity::dash::CheckOptionFilter::Ptr m_unityCheckOptionFilter;
58− FilterOptions* m_options;
5952 SignalsList m_signals;
60−
61− void onOptionsChanged(unity::dash::CheckOptionFilter::CheckOptions);
53+ GenericOptionsModel* m_options;
6254};
6355
6456Q_DECLARE_METATYPE(CheckOptionFilter*)
plugins/Unity/combinedfilteroption.cppdeleted−139
@@ -1,139 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * Authors:
5− * Pawel Stolowski <pawel.stolowski@canonical.com>
6− *
7− * This program is free software; you can redistribute it and/or modify
8− * it under the terms of the GNU General Public License as published by
9− * the Free Software Foundation; version 3.
10− *
11− * This program is distributed in the hope that it will be useful,
12− * but WITHOUT ANY WARRANTY; without even the implied warranty of
13− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14− * GNU General Public License for more details.
15− *
16− * You should have received a copy of the GNU General Public License
17− * along with this program. If not, see <http://www.gnu.org/licenses/>.
18− */
19−
20−#include "combinedfilteroption.h"
21−
22−#include <libintl.h>
23−
24−CombinedFilterOption::CombinedFilterOption(unity::dash::FilterOption::Ptr unityFilterOption1, unity::dash::FilterOption::Ptr unityFilterOption2, QObject *parent)
25− : AbstractFilterOption(parent),
26− m_active(false),
27− m_requestedActive(false),
28− m_unityFilterOption {nullptr, nullptr}
29−{
30− setUnityFilterOption(unityFilterOption1, unityFilterOption2);
31−}
32−
33−QString CombinedFilterOption::getCombinedId() const
34−{
35− if (m_unityFilterOption[1] != nullptr)
36− return QString::fromStdString(m_unityFilterOption[0]->id() + "-" + m_unityFilterOption[1]->id());
37− return QString::fromStdString(m_unityFilterOption[0]->id());
38−}
39−
40−QString CombinedFilterOption::getCombinedName() const
41−{
42− if (m_unityFilterOption[1] != nullptr) {
43− // TRANSLATORS: this joins two names from a Range filter
44− return QString::fromStdString(gettext("%1 - %2"))
45− .arg(QString::fromStdString(m_unityFilterOption[0]->name()))
46− .arg(QString::fromStdString(m_unityFilterOption[1]->name()));
47− }
48− return QString::fromStdString(m_unityFilterOption[0]->name());
49−}
50−
51−QString CombinedFilterOption::id() const
52−{
53− return getCombinedId();
54−}
55−
56−QString CombinedFilterOption::name() const
57−{
58− return getCombinedName();
59−}
60−
61−QString CombinedFilterOption::iconHint() const
62−{
63− return QString::fromStdString(m_unityFilterOption[0]->icon_hint());
64−}
65−
66−bool CombinedFilterOption::active() const
67−{
68− if (m_unityFilterOption[1] != nullptr)
69− return m_unityFilterOption[0]->active && m_unityFilterOption[1]->active && m_requestedActive;
70− return m_unityFilterOption[0]->active && m_requestedActive;
71−}
72−
73−void CombinedFilterOption::setActive(bool active)
74−{
75− m_requestedActive = active;
76− m_unityFilterOption[0]->active = active;
77− if (m_unityFilterOption[1] != nullptr)
78− m_unityFilterOption[1]->active = active;
79−}
80−
81−void CombinedFilterOption::setInactive(const CombinedFilterOption &otherFilter)
82−{
83− // de-activate underlying unity filter options as long as they don't belong
84− // to otherFilter.
85− if (this != &otherFilter) {
86− m_requestedActive = false;
87− for (int i = 0; i<2; i++) {
88− if (m_unityFilterOption[i] != nullptr) {
89− if (m_unityFilterOption[i]->active &&
90− m_unityFilterOption[i] != otherFilter.m_unityFilterOption[0] &&
91− m_unityFilterOption[i] != otherFilter.m_unityFilterOption[1]) {
92− m_unityFilterOption[i]->active = false;
93− }
94− }
95− }
96− }
97−}
98−
99−void CombinedFilterOption::onIdChanged(const std::string &/* id */)
100−{
101− Q_EMIT idChanged(getCombinedId());
102−}
103−
104−void CombinedFilterOption::onNameChanged(const std::string &/* name */)
105−{
106− Q_EMIT nameChanged(getCombinedName());
107−}
108−
109−void CombinedFilterOption::onIconHintChanged(const std::string &/* iconHint */)
110−{
111− Q_EMIT iconHintChanged(iconHint());
112−}
113−
114−void CombinedFilterOption::onActiveChanged(bool /*active*/)
115−{
116− bool combinedState = CombinedFilterOption::active();
117− if (m_active != combinedState) {
118− m_active = combinedState;
119− Q_EMIT activeChanged(m_active);
120− }
121−}
122−
123−void CombinedFilterOption::setUnityFilterOption(unity::dash::FilterOption::Ptr unityFilterOption1, unity::dash::FilterOption::Ptr unityFilterOption2)
124−{
125− m_signals.disconnectAll();
126−
127− m_unityFilterOption[0] = unityFilterOption1;
128− m_unityFilterOption[1] = unityFilterOption2;
129−
130− /* Property change signals */
131− for (int i=0; i<2; i++) {
132− if (m_unityFilterOption[i] != nullptr) {
133− m_signals << m_unityFilterOption[i]->id.changed.connect(sigc::mem_fun(this, &CombinedFilterOption::onIdChanged))
134− << m_unityFilterOption[i]->name.changed.connect(sigc::mem_fun(this, &CombinedFilterOption::onNameChanged))
135− << m_unityFilterOption[i]->icon_hint.changed.connect(sigc::mem_fun(this,&CombinedFilterOption::onIconHintChanged))
136− << m_unityFilterOption[i]->active.changed.connect(sigc::mem_fun(this, &CombinedFilterOption::onActiveChanged));
137− }
138− }
139−}
plugins/Unity/combinedfilteroption.hdeleted−78
@@ -1,78 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * Authors:
5− * Pawel Stolowski <pawel.stolowski@canonical.com>
6− *
7− * This program is free software; you can redistribute it and/or modify
8− * it under the terms of the GNU General Public License as published by
9− * the Free Software Foundation; version 3.
10− *
11− * This program is distributed in the hope that it will be useful,
12− * but WITHOUT ANY WARRANTY; without even the implied warranty of
13− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14− * GNU General Public License for more details.
15− *
16− * You should have received a copy of the GNU General Public License
17− * along with this program. If not, see <http://www.gnu.org/licenses/>.
18− */
19−
20−#ifndef COMBINEDFILTEROPTION_H
21−#define COMBINEDFILTEROPTION_H
22−
23−// Local
24−#include "abstractfilteroption.h"
25−#include "signalslist.h"
26−
27−// libunity-core
28−#include <UnityCore/Filter.h>
29−
30−/**
31− * Combines one or two Unity's filter options into one.
32− * Becomes active if both of them are active.
33− */
34−class Q_DECL_EXPORT CombinedFilterOption : public AbstractFilterOption
35−{
36− Q_OBJECT
37−
38−public:
39− explicit CombinedFilterOption(unity::dash::FilterOption::Ptr unityFilterOption1,
40− unity::dash::FilterOption::Ptr unityFilterOption2 = nullptr,
41− QObject *parent = nullptr);
42−
43− /* getters */
44− QString id() const override;
45− QString name() const override;
46− QString iconHint() const override;
47− bool active() const override;
48−
49− /* setters */
50− void setActive(bool active) override;
51−
52−private:
53− void onIdChanged(const std::string &id);
54− void onNameChanged(const std::string &name);
55− void onIconHintChanged(const std::string &iconHint);
56− void onActiveChanged(bool active);
57−
58− QString getCombinedId() const;
59− QString getCombinedName() const;
60− void setUnityFilterOption(unity::dash::FilterOption::Ptr unityFilterOption1,
61− unity::dash::FilterOption::Ptr unityFilterOption2 = nullptr);
62−
63− /* De-activate the filter, and also de-activate one or both of the underlying unity's filter options, depending on whether
64− one of them is active in otherFilter. This is used internally by CombinedFilterOptions to ensure only one
65− CombinedFilterOption is active. */
66− void setInactive(const CombinedFilterOption &otherFilter);
67−
68− bool m_active;
69− bool m_requestedActive;
70− unity::dash::FilterOption::Ptr m_unityFilterOption[2];
71− SignalsList m_signals;
72−
73− friend class CombinedFilterOptions;
74−};
75−
76−Q_DECLARE_METATYPE(CombinedFilterOption*)
77−
78−#endif // COMBINEDFILTEROPTION_H
plugins/Unity/combinedfilteroptions.cppdeleted−65
@@ -1,65 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * Authors:
5− * Pawel Stolowski <pawel.stolowski@canonical.com>
6− *
7− * This program is free software; you can redistribute it and/or modify
8− * it under the terms of the GNU General Public License as published by
9− * the Free Software Foundation; version 3.
10− *
11− * This program is distributed in the hope that it will be useful,
12− * but WITHOUT ANY WARRANTY; without even the implied warranty of
13− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14− * GNU General Public License for more details.
15− *
16− * You should have received a copy of the GNU General Public License
17− * along with this program. If not, see <http://www.gnu.org/licenses/>.
18− */
19−
20−#include "combinedfilteroptions.h"
21−#include "combinedfilteroption.h"
22−
23−CombinedFilterOptions::CombinedFilterOptions(const std::vector<unity::dash::FilterOption::Ptr>& list, QObject *parent)
24− : GenericListModel(parent)
25−{
26− initList(list);
27−}
28−
29−void CombinedFilterOptions::initList(const std::vector<unity::dash::FilterOption::Ptr>& list)
30−{
31− // combine options, e.g. A, B, C becomes A-B, B-C, C
32− unsigned int i = 0;
33− while (i < list.size() - 1) {
34− unity::dash::FilterOption::Ptr option1 = list[i];
35− unity::dash::FilterOption::Ptr option2 = list[i+1];
36− auto co = new CombinedFilterOption(option1, option2, this);
37− connect(co, SIGNAL(activeChanged(bool)), this, SLOT(onActiveChanged(bool)));
38− addObject(co);
39− ++i;
40− }
41− if (list.size() > 0) {
42− auto co = new CombinedFilterOption(list[i], nullptr, this);
43− addObject(co);
44− }
45−}
46−
47−void CombinedFilterOptions::onActiveChanged(bool state)
48−{
49− // if option became active, need to disable all other options
50− if (state) {
51− CombinedFilterOption *option = dynamic_cast<CombinedFilterOption*>(QObject::sender());
52− if (option) {
53− Q_FOREACH (auto fo, m_list) {
54− if (option != fo) {
55− CombinedFilterOption *other = dynamic_cast<CombinedFilterOption*>(fo);
56− if (fo) {
57− // note that changing state will result in onActiveChanged signal for that option, but
58− // since it will be 'false', we won't end up in an infinite loop
59− other->setInactive(*option);
60− }
61− }
62− }
63− }
64− }
65−}
plugins/Unity/filter.cpp+1−1
@@ -115,7 +115,7 @@ Filter* Filter::newFromUnityFilter(unity::dash::Filter::Ptr unityFilter)
115115 filter = new MultiRangeFilter;
116116 } else {
117117 qWarning() << "Filter of unknown type: " << typeid(*unityFilter).name();
118− filter = new Filter;
118+ return nullptr;
119119 }
120120
121121 filter->setUnityFilter(unityFilter);
plugins/Unity/filter.h+5
@@ -31,6 +31,8 @@
3131// local
3232#include "signalslist.h"
3333
34+class GenericOptionsModel;
35+
3436class Q_DECL_EXPORT Filter : public QObject
3537{
3638 Q_OBJECT
@@ -42,6 +44,7 @@ class Q_DECL_EXPORT Filter : public QObject
4244 Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged)
4345 Q_PROPERTY(bool collapsed READ collapsed NOTIFY collapsedChanged)
4446 Q_PROPERTY(bool filtering READ filtering NOTIFY filteringChanged)
47+ Q_PROPERTY(GenericOptionsModel* options READ options NOTIFY optionsChanged)
4548
4649public:
4750 explicit Filter(QObject *parent = nullptr);
@@ -54,6 +57,7 @@ public:
5457 bool visible() const;
5558 bool collapsed() const;
5659 bool filtering() const;
60+ virtual GenericOptionsModel* options() const = 0;
5761
5862 Q_INVOKABLE void clear();
5963
@@ -68,6 +72,7 @@ Q_SIGNALS:
6872 void visibleChanged(bool);
6973 void collapsedChanged(bool);
7074 void filteringChanged(bool);
75+ void optionsChanged();
7176
7277protected:
7378 unity::dash::Filter::Ptr m_unityFilter;
plugins/Unity/filteroption.h−4
@@ -23,7 +23,6 @@
2323
2424// Local
2525#include "abstractfilteroption.h"
26−#include "listmodelwrapper.h"
2726#include "signalslist.h"
2827
2928// libunity-core
@@ -59,7 +58,4 @@ private:
5958
6059Q_DECLARE_METATYPE(FilterOption*)
6160
62−typedef ListModelWrapper<FilterOption, unity::dash::FilterOption::Ptr> FilterOptions;
63−Q_DECLARE_METATYPE(FilterOptions*)
64−
6561#endif // FILTEROPTION_H
plugins/Unity/filters.cpp+6−3
@@ -74,7 +74,7 @@ QVariant Filters::data(const QModelIndex& index, int role) const
7474 Filter* filter = m_filters.at(index.row());
7575 switch (role)
7676 {
77− case Filters::RoleId:
77+ case Filters::RoleId:
7878 return filter->id();
7979 case Filters::RoleName:
8080 return filter->name();
@@ -89,8 +89,9 @@ QVariant Filters::data(const QModelIndex& index, int role) const
8989 case Filters::RoleFiltering:
9090 return filter->filtering();
9191 default:
92− return QVariant();
92+ break;
9393 }
94+ return QVariant();
9495}
9596
9697QHash<int, QByteArray> Filters::roleNames() const
@@ -137,7 +138,9 @@ void Filters::addFilter(unity::dash::Filter::Ptr unityFilter, int index)
137138{
138139 beginInsertRows(QModelIndex(), index, index);
139140 Filter* filter = Filter::newFromUnityFilter(unityFilter);
140− m_filters.insert(index, filter);
141+ if (filter != nullptr) {
142+ m_filters.insert(index, filter);
143+ }
141144 endInsertRows();
142145}
143146
plugins/Unity/genericlistmodel.cppdeleted−58
@@ -1,58 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * Authors:
5− * Pawel Stolowski <pawel.stolowski@canonical.com>
6− *
7− * This program is free software; you can redistribute it and/or modify
8− * it under the terms of the GNU General Public License as published by
9− * the Free Software Foundation; version 3.
10− *
11− * This program is distributed in the hope that it will be useful,
12− * but WITHOUT ANY WARRANTY; without even the implied warranty of
13− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14− * GNU General Public License for more details.
15− *
16− * You should have received a copy of the GNU General Public License
17− * along with this program. If not, see <http://www.gnu.org/licenses/>.
18− */
19−
20−#include "genericlistmodel.h"
21−
22−GenericListModel::GenericListModel(QObject *parent)
23− : QAbstractListModel(parent)
24−{
25−}
26−
27−QVariant GenericListModel::data(const QModelIndex& index, int /* role */) const
28−{
29− if (!index.isValid()) {
30− return QVariant();
31− }
32−
33− QObject* item = m_list.at(index.row());
34− return QVariant::fromValue(item);
35−}
36−
37−int GenericListModel::rowCount(const QModelIndex& /* parent */) const
38−{
39− return m_list.count();
40−}
41−
42−void GenericListModel::addObject(QObject *option)
43−{
44− int index = m_list.count();
45− beginInsertRows(QModelIndex(), index, index);
46− m_list.insert(index, option);
47− endInsertRows();
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.hdeleted−50
@@ -1,50 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * Authors:
5− * Pawel Stolowski <pawel.stolowski@canonical.com>
6− *
7− * This program is free software; you can redistribute it and/or modify
8− * it under the terms of the GNU General Public License as published by
9− * the Free Software Foundation; version 3.
10− *
11− * This program is distributed in the hope that it will be useful,
12− * but WITHOUT ANY WARRANTY; without even the implied warranty of
13− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14− * GNU General Public License for more details.
15− *
16− * You should have received a copy of the GNU General Public License
17− * along with this program. If not, see <http://www.gnu.org/licenses/>.
18− */
19−
20−#ifndef GENERICLISTMODEL_H
21−#define GENERICLISTMODEL_H
22−
23−// Qt
24−#include <QObject>
25−#include <QAbstractListModel>
26−
27−/*
28− * TODO: see if it'd be better to use QVariantListModel.
29− */
30−class Q_DECL_EXPORT GenericListModel : public QAbstractListModel
31−{
32− Q_OBJECT
33−
34−public:
35− GenericListModel(QObject *parent = nullptr);
36−
37− QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
38− int rowCount(const QModelIndex& parent = QModelIndex()) const override;
39− void addObject(QObject* option);
40−
41− QList<QObject *>::Iterator optionsBegin();
42− QList<QObject *>::Iterator optionsEnd();
43−
44−protected:
45− QList<QObject *> m_list;
46−};
47−
48−Q_DECLARE_METATYPE(GenericListModel*)
49−
50−#endif // GENERICLISTMODEL_H
plugins/Unity/genericoptionsmodel.cppnew file+155
@@ -0,0 +1,155 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+// self
21+#include "genericoptionsmodel.h"
22+
23+// local
24+#include "abstractfilteroption.h"
25+
26+GenericOptionsModel::GenericOptionsModel(QObject *parent)
27+ : QAbstractListModel(parent)
28+{
29+ setupRoles();
30+}
31+
32+GenericOptionsModel::~GenericOptionsModel()
33+{
34+ Q_FOREACH(auto opt, m_options)
35+ {
36+ opt->deleteLater();
37+ }
38+}
39+
40+void GenericOptionsModel::setupRoles()
41+{
42+ m_roles[GenericOptionsModel::RoleId] = "id";
43+ m_roles[GenericOptionsModel::RoleName] = "name";
44+ m_roles[GenericOptionsModel::RoleIconHint] = "iconHint";
45+ m_roles[GenericOptionsModel::RoleActive] = "active";
46+}
47+
48+QHash<int, QByteArray> GenericOptionsModel::roleNames() const
49+{
50+ return m_roles;
51+}
52+
53+QVariant GenericOptionsModel::data(const QModelIndex& index, int role) const
54+{
55+ if (!index.isValid()) {
56+ return QVariant();
57+ }
58+
59+ auto filterOption = m_options[index.row()];
60+ switch (role)
61+ {
62+ case GenericOptionsModel::RoleId:
63+ return filterOption->id();
64+ case GenericOptionsModel::RoleName:
65+ return filterOption->name();
66+ case GenericOptionsModel::RoleIconHint:
67+ return filterOption->iconHint();
68+ case GenericOptionsModel::RoleActive:
69+ return filterOption->active();
70+ default:
71+ break;
72+ }
73+
74+ return QVariant();
75+}
76+
77+int GenericOptionsModel::rowCount(const QModelIndex& /* parent */) const
78+{
79+ return m_options.size ();
80+}
81+
82+AbstractFilterOption* GenericOptionsModel::getRawOption(QVector<AbstractFilterOption *>::size_type idx) const
83+{
84+ if (idx < m_options.size())
85+ {
86+ return m_options[idx];
87+ }
88+ return nullptr;
89+}
90+
91+void GenericOptionsModel::ensureTheOnlyActive(AbstractFilterOption *activeOption)
92+{
93+ if (activeOption->active()) {
94+ // disable all other options
95+ Q_FOREACH(auto opt, m_options) {
96+ if (opt != activeOption && opt->active()) {
97+ opt->setActive(false);
98+ }
99+ }
100+ }
101+}
102+
103+void GenericOptionsModel::addOption(AbstractFilterOption *option, int index)
104+{
105+ m_options.insert(index, option);
106+
107+ connect(option, SIGNAL(idChanged(const QString &)), this, SLOT(onOptionChanged()));
108+ connect(option, SIGNAL(nameChanged(const QString &)), this, SLOT(onOptionChanged()));
109+ connect(option, SIGNAL(iconHintChanged(const QString &)), this, SLOT(onOptionChanged()));
110+ connect(option, SIGNAL(activeChanged(bool)), this, SLOT(onOptionChanged()));
111+ connect(option, SIGNAL(activeChanged(bool)), this, SLOT(onActiveChanged()));
112+}
113+
114+void GenericOptionsModel::removeOption(int index)
115+{
116+ m_options[index]->deleteLater();
117+ m_options.remove(index);
118+}
119+
120+int GenericOptionsModel::indexOf(const QString &option_id)
121+{
122+ int row = 0;
123+ Q_FOREACH(auto opt, m_options)
124+ {
125+ if (opt->id() == option_id)
126+ {
127+ return row;
128+ }
129+ ++row;
130+ }
131+ return -1;
132+}
133+
134+void GenericOptionsModel::onOptionChanged()
135+{
136+ AbstractFilterOption *option = dynamic_cast<AbstractFilterOption*>(QObject::sender());
137+ if (option)
138+ {
139+ int idx = indexOf(option->id());
140+ if (idx >= 0)
141+ {
142+ QModelIndex optionIndex = index(idx, idx);
143+ Q_EMIT dataChanged(optionIndex, optionIndex);
144+ }
145+ }
146+}
147+
148+void GenericOptionsModel::onActiveChanged()
149+{
150+ AbstractFilterOption *option = dynamic_cast<AbstractFilterOption*>(QObject::sender());
151+ if (option)
152+ {
153+ Q_EMIT activeChanged(option);
154+ }
155+}
plugins/Unity/genericoptionsmodel.hnew file+77
@@ -0,0 +1,77 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+#ifndef GENERICOPTIONSMODEL_H
21+#define GENERICOPTIONSMODEL_H
22+
23+// Qt
24+#include <QObject>
25+#include <QAbstractListModel>
26+#include <QHash>
27+#include <QVector>
28+
29+class AbstractFilterOption;
30+
31+class Q_DECL_EXPORT GenericOptionsModel : public QAbstractListModel
32+{
33+ Q_OBJECT
34+
35+ Q_ENUMS(Roles)
36+
37+Q_SIGNALS:
38+ void activeChanged(AbstractFilterOption *option);
39+
40+public:
41+ GenericOptionsModel(QObject *parent = nullptr);
42+ ~GenericOptionsModel();
43+
44+ enum Roles {
45+ RoleId,
46+ RoleName,
47+ RoleIconHint,
48+ RoleActive
49+ };
50+
51+ QHash<int, QByteArray> roleNames() const override;
52+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
53+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
54+
55+ AbstractFilterOption* getRawOption(QVector<AbstractFilterOption *>::size_type idx) const;
56+
57+public Q_SLOTS:
58+ virtual void ensureTheOnlyActive(AbstractFilterOption *activeOption);
59+
60+protected Q_SLOTS:
61+ void onOptionChanged();
62+ void onActiveChanged();
63+
64+protected:
65+ void addOption(AbstractFilterOption *option, int index);
66+ void removeOption(int index);
67+ int indexOf(const QString &option_id);
68+
69+ QVector<AbstractFilterOption *> m_options;
70+private:
71+ void setupRoles();
72+ QHash<int, QByteArray> m_roles;
73+};
74+
75+Q_DECLARE_METATYPE(GenericOptionsModel*)
76+
77+#endif // GENERICOPTIONSMODEL_H
plugins/Unity/listmodelwrapper.hdeleted−146
@@ -1,146 +0,0 @@
1−/*
2− * Copyright (C) 2011, 2013 Canonical, Ltd.
3− *
4− * Authors:
5− * Florian Boucault <florian.boucault@canonical.com>
6− *
7− * This program is free software; you can redistribute it and/or modify
8− * it under the terms of the GNU General Public License as published by
9− * the Free Software Foundation; version 3.
10− *
11− * This program is distributed in the hope that it will be useful,
12− * but WITHOUT ANY WARRANTY; without even the implied warranty of
13− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14− * GNU General Public License for more details.
15− *
16− * You should have received a copy of the GNU General Public License
17− * along with this program. If not, see <http://www.gnu.org/licenses/>.
18− */
19−
20−#ifndef LISTMODELWRAPPER_H
21−#define LISTMODELWRAPPER_H
22−
23−// Qt
24−#include <QAbstractListModel>
25−#include <QList>
26−
27−#include <sigc++/signal.h>
28−#include <vector>
29−
30−template <class WrapperItem, class ItemClass>
31−class ListModelWrapper : public QAbstractListModel
32−{
33−public:
34− explicit ListModelWrapper(const std::vector<ItemClass>& list,
35− sigc::signal<void, ItemClass> itemAddedSignal,
36− sigc::signal<void, ItemClass> itemRemovedSignal,
37− QObject *parent = nullptr);
38− ~ListModelWrapper();
39−
40− QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
41− int rowCount(const QModelIndex& parent = QModelIndex()) const;
42−
43− const QList<WrapperItem*>& rawList() const;
44−
45−private:
46− void onItemAdded(ItemClass item);
47− void onItemRemoved(ItemClass item);
48− void onItemChanged(ItemClass item);
49−
50− QList<WrapperItem*> m_list;
51− QMap<ItemClass, int> m_indexes;
52−
53− void addItem(ItemClass item, int index);
54− void removeItem(ItemClass item, int index);
55−};
56−
57−
58−template <class WrapperItem, class ItemClass>
59−ListModelWrapper<WrapperItem, ItemClass>::ListModelWrapper(const std::vector<ItemClass>& list,
60− sigc::signal<void, ItemClass> itemAddedSignal,
61− sigc::signal<void, ItemClass> itemRemovedSignal,
62− QObject *parent) :
63− QAbstractListModel(parent)
64−{
65− for (unsigned int i=0; i<list.size(); i++) {
66− addItem(list[i], i);
67− }
68− itemAddedSignal.connect(sigc::mem_fun(this, &ListModelWrapper::onItemAdded));
69− itemRemovedSignal.connect(sigc::mem_fun(this, &ListModelWrapper::onItemRemoved));
70−}
71−
72−template <class WrapperItem, class ItemClass>
73−ListModelWrapper<WrapperItem, ItemClass>::~ListModelWrapper()
74−{
75− m_indexes.clear();
76− while (!m_list.isEmpty()) {
77− delete m_list.takeFirst();
78− }
79−}
80−
81−template <class WrapperItem, class ItemClass>
82−int ListModelWrapper<WrapperItem, ItemClass>::rowCount(const QModelIndex& parent) const
83−{
84− Q_UNUSED(parent)
85−
86− return m_list.count();
87−}
88−
89−template <class WrapperItem, class ItemClass>
90−const QList<WrapperItem*>& ListModelWrapper<WrapperItem, ItemClass>::rawList() const
91−{
92− return m_list;
93−}
94−
95−template <class WrapperItem, class ItemClass>
96−QVariant ListModelWrapper<WrapperItem, ItemClass>::data(const QModelIndex& index, int) const
97−{
98− if (!index.isValid()) {
99− return QVariant();
100− }
101−
102− WrapperItem* item = m_list.at(index.row());
103−
104− return QVariant::fromValue(item);
105−}
106−
107−template <class WrapperItem, class ItemClass>
108−void ListModelWrapper<WrapperItem, ItemClass>::onItemAdded(ItemClass item)
109−{
110− int index = m_list.count();
111− beginInsertRows(QModelIndex(), index, index);
112− addItem(item, index);
113− endInsertRows();
114−}
115−
116−template <class WrapperItem, class ItemClass>
117−void ListModelWrapper<WrapperItem, ItemClass>::onItemRemoved(ItemClass item)
118−{
119− int index = m_indexes[item];
120− beginInsertRows(QModelIndex(), index, index);
121− removeItem(item, index);
122− endInsertRows();
123−}
124−
125−template <class WrapperItem, class ItemClass>
126−void ListModelWrapper<WrapperItem, ItemClass>::onItemChanged(ItemClass item)
127−{
128− QModelIndex itemIndex = index(m_indexes[item]);
129− Q_EMIT dataChanged(itemIndex, itemIndex);
130−}
131−
132−template <class WrapperItem, class ItemClass>
133−void ListModelWrapper<WrapperItem, ItemClass>::addItem(ItemClass item, int index)
134−{
135− m_indexes.insert(item, index);
136− m_list.insert(index, new WrapperItem(item));
137−}
138−
139−template <class WrapperItem, class ItemClass>
140−void ListModelWrapper<WrapperItem, ItemClass>::removeItem(ItemClass item, int index)
141−{
142− m_indexes.remove(item);
143− delete m_list.takeAt(index);
144−}
145−
146−#endif // LISTMODELWRAPPER_H
plugins/Unity/multirangefilter.cpp+9−2
@@ -21,12 +21,15 @@
2121// Self
2222#include "multirangefilter.h"
2323
24+// local
25+#include "unityoptionsmodel.h"
26+
2427MultiRangeFilter::MultiRangeFilter(QObject *parent) :
2528 Filter(parent), m_unityMultiRangeFilter(nullptr), m_options(nullptr)
2629{
2730}
2831
29−CombinedFilterOptions* MultiRangeFilter::options() const
32+GenericOptionsModel* MultiRangeFilter::options() const
3033{
3134 return m_options;
3235}
@@ -47,7 +50,11 @@ void MultiRangeFilter::onOptionsChanged(unity::dash::MultiRangeFilter::Options /
4750 m_options = nullptr;
4851 }
4952
50− m_options = new CombinedFilterOptions(m_unityMultiRangeFilter->options);
53+ m_options = new UnityOptionsModel(this, m_unityMultiRangeFilter->options,
54+ m_unityMultiRangeFilter->option_added,
55+ m_unityMultiRangeFilter->option_removed);
56+
57+ connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), m_options, SLOT(ensureTheOnlyActive(AbstractFilterOption *)));
5158
5259 /* Property change signals */
5360 m_signals << m_unityMultiRangeFilter->options.changed.connect(sigc::mem_fun(this, &MultiRangeFilter::onOptionsChanged));
plugins/Unity/multirangefilter.h+5−9
@@ -31,31 +31,27 @@
3131// Local
3232#include "filter.h"
3333#include "filteroption.h"
34−#include "combinedfilteroptions.h"
3534#include "signalslist.h"
3635
36+class GenericOptionsModel;
37+
3738class Q_DECL_EXPORT MultiRangeFilter : public Filter
3839{
3940 Q_OBJECT
4041
41− Q_PROPERTY(CombinedFilterOptions* options READ options NOTIFY optionsChanged)
42−
4342public:
4443 explicit MultiRangeFilter(QObject *parent = nullptr);
4544
4645 /* getters */
47− CombinedFilterOptions* options() const;
48−
49−Q_SIGNALS:
50− void optionsChanged();
46+ GenericOptionsModel* options() const override;
5147
5248protected:
53− virtual void setUnityFilter(unity::dash::Filter::Ptr filter);
49+ void setUnityFilter(unity::dash::Filter::Ptr filter) override;
5450
5551private:
5652 unity::dash::MultiRangeFilter::Ptr m_unityMultiRangeFilter;
57− CombinedFilterOptions* m_options;
5853 SignalsList m_signals;
54+ GenericOptionsModel* m_options;
5955
6056 void onOptionsChanged(unity::dash::MultiRangeFilter::Options);
6157};
plugins/Unity/radiooptionfilter.cpp+9−15
@@ -3,6 +3,7 @@
33 *
44 * Authors:
55 * Florian Boucault <florian.boucault@canonical.com>
6+ * Pawel Stolowski <pawel.stolowski@canonical.com>
67 *
78 * This program is free software; you can redistribute it and/or modify
89 * it under the terms of the GNU General Public License as published by
@@ -20,26 +21,19 @@
2021// Self
2122#include "radiooptionfilter.h"
2223
24+// local
25+#include "unityoptionsmodel.h"
26+
2327RadioOptionFilter::RadioOptionFilter(QObject *parent) :
2428 Filter(parent), m_unityRadioOptionFilter(nullptr), m_options(nullptr)
2529{
2630}
2731
28−FilterOptions* RadioOptionFilter::options() const
32+GenericOptionsModel* RadioOptionFilter::options() const
2933{
3034 return m_options;
3135}
3236
33−FilterOption* RadioOptionFilter::getOption(const QString& id) const
34−{
35− Q_FOREACH (FilterOption* option, m_options->rawList()) {
36− if (option->id() == id) {
37− return option;
38− }
39− }
40− return nullptr;
41−}
42−
4337void RadioOptionFilter::setUnityFilter(unity::dash::Filter::Ptr filter)
4438{
4539 Filter::setUnityFilter(filter);
@@ -55,10 +49,10 @@ void RadioOptionFilter::onOptionsChanged(unity::dash::RadioOptionFilter::RadioOp
5549 delete m_options;
5650 m_options = nullptr;
5751 }
58− m_options = new FilterOptions(m_unityRadioOptionFilter->options,
59− m_unityRadioOptionFilter->option_added,
60− m_unityRadioOptionFilter->option_removed);
61− /* Property change signals */
52+ m_options = new UnityOptionsModel(this, m_unityRadioOptionFilter->options,
53+ m_unityRadioOptionFilter->option_added,
54+ m_unityRadioOptionFilter->option_removed);
55+
6256 m_signals << m_unityRadioOptionFilter->options.changed.connect(sigc::mem_fun(this, &RadioOptionFilter::onOptionsChanged));
6357
6458 Q_EMIT optionsChanged();
plugins/Unity/radiooptionfilter.h+4−10
@@ -3,6 +3,7 @@
33 *
44 * Authors:
55 * Florian Boucault <florian.boucault@canonical.com>
6+ * Pawel Stolowski <pawel.stolowski@canonical.com>
67 *
78 * This program is free software; you can redistribute it and/or modify
89 * it under the terms of the GNU General Public License as published by
@@ -36,25 +37,18 @@ class Q_DECL_EXPORT RadioOptionFilter : public Filter
3637{
3738 Q_OBJECT
3839
39− Q_PROPERTY(FilterOptions* options READ options NOTIFY optionsChanged)
40−
4140public:
4241 explicit RadioOptionFilter(QObject *parent = nullptr);
4342
4443 /* getters */
45− FilterOptions* options() const;
46−
47− Q_INVOKABLE FilterOption* getOption(const QString& id) const;
48−
49−Q_SIGNALS:
50− void optionsChanged();
44+ GenericOptionsModel* options() const override;
5145
5246protected:
53− virtual void setUnityFilter(unity::dash::Filter::Ptr filter);
47+ void setUnityFilter(unity::dash::Filter::Ptr filter) override;
5448
5549private:
5650 unity::dash::RadioOptionFilter::Ptr m_unityRadioOptionFilter;
57− FilterOptions* m_options;
51+ GenericOptionsModel* m_options;
5852 SignalsList m_signals;
5953
6054 void onOptionsChanged(unity::dash::RadioOptionFilter::RadioOptions);
plugins/Unity/ratingfilteroption.cpp+12−1
@@ -20,7 +20,7 @@
2020#include "ratingfilteroption.h"
2121
2222RatingFilterOption::RatingFilterOption(const QString &id, float value, QObject *parent) :
23− QObject(parent),
23+ AbstractFilterOption(parent),
2424 m_active(false),
2525 m_id(id),
2626 m_value(value)
@@ -32,6 +32,17 @@ QString RatingFilterOption::id() const
3232 return m_id;
3333}
3434
35+
36+QString RatingFilterOption::name() const
37+{
38+ return QString::Null();
39+}
40+
41+QString RatingFilterOption::iconHint() const
42+{
43+ return QString::Null();
44+}
45+
3546float RatingFilterOption::value() const
3647{
3748 return m_value;
plugins/Unity/ratingfilteroption.h+8−9
@@ -20,25 +20,24 @@
2020#ifndef RATINGFILTEROPTION_H
2121#define RATINGFILTEROPTION_H
2222
23−#include <QObject>
23+#include "abstractfilteroption.h"
2424
25−class Q_DECL_EXPORT RatingFilterOption : public QObject
25+class Q_DECL_EXPORT RatingFilterOption : public AbstractFilterOption
2626{
2727 Q_OBJECT
2828
2929public:
30− explicit RatingFilterOption(const QString &id, float ratingValue, QObject *parent = 0);
30+ explicit RatingFilterOption(const QString &id, float ratingValue, QObject *parent = nullptr);
3131
3232 /* getters */
33− QString id() const;
34− bool active() const;
33+ QString id() const override;
34+ QString name() const override;
35+ QString iconHint() const override;
36+ bool active() const override;
3537 float value() const;
3638
3739 /* setters */
38− Q_INVOKABLE void setActive(bool active);
39−
40−Q_SIGNALS:
41− void activeChanged(bool);
40+ void setActive(bool active) override;
4241
4342private:
4443 bool m_active;
plugins/Unity/ratingoptionsmodel.cppnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+// self
21+#include "ratingoptionsmodel.h"
22+
23+// local
24+#include "ratingfilteroption.h"
25+
26+RatingOptionsModel::RatingOptionsModel(QObject *parent) :
27+ GenericOptionsModel(parent)
28+{
29+ for (int i=1; i<=5; i++) {
30+ auto opt = new RatingFilterOption(QString::number(i), i*0.2f, this);
31+ addOption(opt, i-1);
32+ }
33+}
plugins/Unity/combinedfilteroptions.h → plugins/Unity/ratingoptionsmodel.hrenamed+6−21
@@ -17,32 +17,17 @@
1717 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1818 */
1919
20−#ifndef COMBINEDFILTEROPTIONS_H
21−#define COMBINEDFILTEROPTIONS_H
20+#ifndef RATINGOPTIONSMODEL_H
21+#define RATINGOPTIONSMODEL_H
2222
23−// Qt
24−#include <QObject>
23+#include "genericoptionsmodel.h"
2524
26−// libunity-core
27−#include <UnityCore/Filter.h>
28−
29−// local
30−#include "genericlistmodel.h"
31−
32−class CombinedFilterOptions : public GenericListModel
25+class RatingOptionsModel : public GenericOptionsModel
3326{
3427 Q_OBJECT
3528
3629public:
37− CombinedFilterOptions(const std::vector<unity::dash::FilterOption::Ptr>& list, QObject *parent = nullptr);
38−
39−private Q_SLOTS:
40− void onActiveChanged(bool state);
41−
42−private:
43− void initList(const std::vector<unity::dash::FilterOption::Ptr>& list);
30+ RatingOptionsModel(QObject *parent);
4431};
4532
46−Q_DECLARE_METATYPE(CombinedFilterOptions*)
47−
48−#endif // COMBINEDFILTEROPTIONS_H
33+#endif // RATINGOPTIONSMODEL_H
plugins/Unity/ratingsfilter.cpp+24−36
@@ -3,6 +3,7 @@
33 *
44 * Authors:
55 * Florian Boucault <florian.boucault@canonical.com>
6+ * Pawel Stolowski <pawel.stolowski@canonical.com>
67 *
78 * This program is free software; you can redistribute it and/or modify
89 * it under the terms of the GNU General Public License as published by
@@ -21,62 +22,49 @@
2122#include "ratingsfilter.h"
2223
2324// local
24−#include "genericlistmodel.h"
2525#include "ratingfilteroption.h"
26−
27−// Qt
28−#include <QDebug>
26+#include "ratingoptionsmodel.h"
2927
3028RatingsFilter::RatingsFilter(QObject *parent) :
31− Filter(parent), m_unityRatingsFilter(nullptr), m_options(nullptr)
29+ Filter(parent),
30+ m_unityRatingsFilter(nullptr),
31+ m_options(nullptr)
3232{
3333}
3434
35−GenericListModel* RatingsFilter::options() const
35+GenericOptionsModel* RatingsFilter::options() const
3636{
3737 return m_options;
3838}
3939
40−void RatingsFilter::setUnityFilter(unity::dash::Filter::Ptr filter)
40+float RatingsFilter::rating() const
4141{
42− if (m_unityFilter != nullptr) {
43− m_signals.disconnectAll();
42+ if (m_unityRatingsFilter)
43+ {
44+ return m_unityRatingsFilter->rating;
4445 }
46+ return 0.0f;
47+}
4548
49+void RatingsFilter::setUnityFilter(unity::dash::Filter::Ptr filter)
50+{
4651 Filter::setUnityFilter(filter);
4752 m_unityRatingsFilter = std::dynamic_pointer_cast<unity::dash::RatingsFilter>(m_unityFilter);
4853
49− if (m_options) {
50− delete m_options;
51− }
54+ delete m_options;
5255
53− m_options = new GenericListModel(this);
54− for (int i=1; i<=5; i++) {
55− auto opt = new RatingFilterOption(QString::number(i), i*0.2f, this);
56− connect(opt, SIGNAL(activeChanged(bool)), this, SLOT(onActiveChanged()));
57− m_options->addObject(opt);
58− }
56+ m_options = new RatingOptionsModel(this);
57+ connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), m_options, SLOT(ensureTheOnlyActive(AbstractFilterOption *)));
58+ connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), this, SLOT(onActiveChanged(AbstractFilterOption *)));
5959
60− Q_EMIT ratingsChanged();
60+ Q_EMIT optionsChanged();
6161}
6262
63−void RatingsFilter::onActiveChanged()
63+void RatingsFilter::onActiveChanged(AbstractFilterOption *option)
6464{
65− RatingFilterOption *option = dynamic_cast<RatingFilterOption*>(QObject::sender());
66− if (option != nullptr) {
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";
65+ RatingFilterOption *ratingOption = dynamic_cast<RatingFilterOption*>(option);
66+ if (ratingOption != nullptr)
67+ {
68+ m_unityRatingsFilter->rating = ratingOption->active() ? ratingOption->value() : 0.0f;
8169 }
8270}
plugins/Unity/ratingsfilter.h+10−9
@@ -3,6 +3,7 @@
33 *
44 * Authors:
55 * Florian Boucault <florian.boucault@canonical.com>
6+ * Pawel Stolowski <pawel.stolowski@canonical.com>
67 *
78 * This program is free software; you can redistribute it and/or modify
89 * it under the terms of the GNU General Public License as published by
@@ -29,35 +30,35 @@
2930
3031// Local
3132#include "filter.h"
32−#include "signalslist.h"
3333
34−class GenericListModel;
34+class GenericOptionsModel;
35+class AbstractFilterOption;
3536
3637class Q_DECL_EXPORT RatingsFilter : public Filter
3738{
3839 Q_OBJECT
3940
40− Q_PROPERTY(GenericListModel* options READ options NOTIFY ratingsChanged)
41+ Q_PROPERTY(float rating READ rating NOTIFY ratingChanged)
4142
4243public:
4344 explicit RatingsFilter(QObject *parent = nullptr);
4445
4546 /* getters */
46− GenericListModel* options() const;
47+ GenericOptionsModel* options() const override;
48+ float rating() const;
4749
4850Q_SIGNALS:
49− void ratingsChanged();
51+ void ratingChanged(float);
5052
5153protected:
52− virtual void setUnityFilter(unity::dash::Filter::Ptr filter);
54+ void setUnityFilter(unity::dash::Filter::Ptr filter) override;
5355
5456protected Q_SLOTS:
55− void onActiveChanged();
57+ void onActiveChanged(AbstractFilterOption *option);
5658
5759private:
5860 unity::dash::RatingsFilter::Ptr m_unityRatingsFilter;
59− GenericListModel *m_options;
60− SignalsList m_signals;
61+ GenericOptionsModel *m_options;
6162};
6263
6364Q_DECLARE_METATYPE(RatingsFilter*)
plugins/Unity/unityoptionsmodel.cppnew file+67
@@ -0,0 +1,67 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+// self
21+#include "unityoptionsmodel.h"
22+
23+// local
24+#include "filteroption.h"
25+
26+UnityOptionsModel::UnityOptionsModel(QObject *parent,
27+ const std::vector<unity::dash::FilterOption::Ptr> options,
28+ sigc::signal<void, unity::dash::FilterOption::Ptr> optionAdded,
29+ sigc::signal<void, unity::dash::FilterOption::Ptr> optionRemoved) :
30+ GenericOptionsModel(parent)
31+{
32+ setOptions(options, optionAdded, optionRemoved);
33+}
34+
35+void UnityOptionsModel::setOptions(const std::vector<unity::dash::FilterOption::Ptr> options,
36+ sigc::signal<void, unity::dash::FilterOption::Ptr> optionAdded,
37+ sigc::signal<void, unity::dash::FilterOption::Ptr> optionRemoved)
38+{
39+ for (unsigned int i=0; i<options.size(); i++)
40+ {
41+ addOption(new FilterOption(options[i], this), i);
42+ }
43+ optionAdded.connect(sigc::mem_fun(this, &UnityOptionsModel::onOptionAdded));
44+ optionRemoved.connect(sigc::mem_fun(this, &UnityOptionsModel::onOptionRemoved));
45+}
46+
47+void UnityOptionsModel::onOptionAdded(unity::dash::FilterOption::Ptr option)
48+{
49+ int index = m_options.count();
50+ if (index >= 0)
51+ {
52+ beginInsertRows(QModelIndex(), index, index);
53+ addOption(new FilterOption(option, this), index);
54+ endInsertRows();
55+ }
56+}
57+
58+void UnityOptionsModel::onOptionRemoved(unity::dash::FilterOption::Ptr option)
59+{
60+ auto index = indexOf(QString::fromStdString(option->id));
61+ if (index >= 0)
62+ {
63+ beginRemoveRows(QModelIndex(), index, index);
64+ removeOption(index);
65+ endRemoveRows();
66+ }
67+}
plugins/Unity/unityoptionsmodel.hnew file+49
@@ -0,0 +1,49 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+#ifndef UNITYOPTIONSMODEL_H
21+#define UNITYOPTIONSMODEL_H
22+
23+#include "genericoptionsmodel.h"
24+
25+// libunity-core
26+#include <UnityCore/Filter.h>
27+
28+#include <sigc++/signal.h>
29+
30+class UnityOptionsModel : public GenericOptionsModel
31+{
32+ Q_OBJECT
33+
34+public:
35+ UnityOptionsModel(QObject *parent,
36+ const std::vector<unity::dash::FilterOption::Ptr> options,
37+ sigc::signal<void, unity::dash::FilterOption::Ptr> optionAdded,
38+ sigc::signal<void, unity::dash::FilterOption::Ptr> optionRemoved);
39+
40+private:
41+ void setOptions(const std::vector<unity::dash::FilterOption::Ptr> options,
42+ sigc::signal<void, unity::dash::FilterOption::Ptr> optionAdded,
43+ sigc::signal<void, unity::dash::FilterOption::Ptr> optionRemoved);
44+
45+ void onOptionAdded(unity::dash::FilterOption::Ptr option);
46+ void onOptionRemoved(unity::dash::FilterOption::Ptr option);
47+};
48+
49+#endif // UNITYOPTIONSMODEL_H
tests/plugins/Unity/filtersbindingstest.cpp+86−50
@@ -33,11 +33,11 @@
3333// local
3434#include "filter.h"
3535#include "multirangefilter.h"
36−#include "combinedfilteroption.h"
3736#include "checkoptionfilter.h"
3837#include "radiooptionfilter.h"
3938#include "ratingsfilter.h"
4039#include "ratingfilteroption.h"
40+#include "genericoptionsmodel.h"
4141
4242void FiltersBindingsTest::initTestCase()
4343{
@@ -145,9 +145,16 @@ void FiltersBindingsTest::testMultiRangeFilter()
145145 auto options = multi_filter->options();
146146 QCOMPARE(options->rowCount(), 1);
147147
148− QVariant optvar = options->data(options->index(0));
149− CombinedFilterOption* opt1 = optvar.value<CombinedFilterOption*>();
150− QCOMPARE(opt1->id(), QString("opt0"));
148+ auto idx = options->index(0);
149+ QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
150+ QVariant name_var = options->data(idx, GenericOptionsModel::RoleName);
151+ QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
152+ QVariant active_var = options->data(idx, GenericOptionsModel::RoleActive);
153+
154+ QCOMPARE(id_var.toString(), QString("opt0"));
155+ QCOMPARE(name_var.toString(), QString("Option 0"));
156+ QCOMPARE(icon_var.toString(), QString(""));
157+ QCOMPARE(active_var.toBool(), false);
151158
152159 delete multi_filter;
153160 }
@@ -163,12 +170,21 @@ void FiltersBindingsTest::testMultiRangeFilter()
163170 auto options = multi_filter->options();
164171 QCOMPARE(options->rowCount(), 2);
165172
166− QVariant optvar = options->data(options->index(0));
167− CombinedFilterOption* opt1 = optvar.value<CombinedFilterOption*>();
168− QCOMPARE(opt1->id(), QString("opt0-opt1"));
173+ auto idx = options->index(0);
174+ QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
175+ QVariant name_var = options->data(idx, GenericOptionsModel::RoleName);
176+ QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
177+ QVariant active_var = options->data(idx, GenericOptionsModel::RoleActive);
178+
179+ QCOMPARE(id_var.toString(), QString("opt0"));
180+ QCOMPARE(name_var.toString(), QString("Option 0"));
181+ QCOMPARE(icon_var.toString(), QString(""));
182+ QCOMPARE(active_var.toBool(), false);
169183
170− optvar = options->data(options->index(1));
171− CombinedFilterOption* opt2 = optvar.value<CombinedFilterOption*>();
184+ AbstractFilterOption* opt1 = options->getRawOption(0);
185+ QCOMPARE(opt1->id(), QString("opt0"));
186+
187+ AbstractFilterOption* opt2 = options->getRawOption(1);
172188 QCOMPARE(opt2->id(), QString("opt1"));
173189
174190 delete multi_filter;
@@ -185,16 +201,13 @@ void FiltersBindingsTest::testMultiRangeFilter()
185201 auto options = multi_filter->options();
186202 QCOMPARE(options->rowCount(), 3);
187203
188− QVariant optvar = options->data(options->index(0));
189− CombinedFilterOption* opt0 = optvar.value<CombinedFilterOption*>();
190− QCOMPARE(opt0->id(), QString("opt0-opt1"));
204+ AbstractFilterOption* opt0 = options->getRawOption(0);
205+ QCOMPARE(opt0->id(), QString("opt0"));
191206
192− optvar = options->data(options->index(1));
193− CombinedFilterOption* opt1 = optvar.value<CombinedFilterOption*>();
194− QCOMPARE(opt1->id(), QString("opt1-opt2"));
207+ AbstractFilterOption* opt1 = options->getRawOption(1);
208+ QCOMPARE(opt1->id(), QString("opt1"));
195209
196− optvar = options->data(options->index(2));
197− CombinedFilterOption* opt2 = optvar.value<CombinedFilterOption*>();
210+ AbstractFilterOption* opt2 = options->getRawOption(2);
198211 QCOMPARE(opt2->id(), QString("opt2"));
199212
200213 // verify combined filter options are bound to correct underlying unity options
@@ -210,25 +223,21 @@ void FiltersBindingsTest::testMultiRangeFilter()
210223 // test active property changes
211224 QCOMPARE(opt0->active(), false);
212225
213− opt0->setActive(true); // activate 1st combined option
226+ opt0->setActive(true); // activate 1st option
214227 QCOMPARE(opt0spy.count(), 1);
215228 QCOMPARE(opt1spy.count(), 0);
216229 QCOMPARE(opt2spy.count(), 0);
217230 QCOMPARE(opt0->active(), true);
218231 QCOMPARE(opt1->active(), false);
219− QCOMPARE(core_multi_filter->options()[0]->active(), true);
220− QCOMPARE(core_multi_filter->options()[1]->active(), true);
221− QCOMPARE(core_multi_filter->options()[2]->active(), false);
232+ QCOMPARE(opt2->active(), false);
222233
223− opt1->setActive(true); // activate another combined option
234+ opt1->setActive(true);
224235 QCOMPARE(opt0spy.count(), 2);
225236 QCOMPARE(opt1spy.count(), 1);
226237 QCOMPARE(opt2spy.count(), 0);
227238 QCOMPARE(opt0->active(), false); //1st combined option gets deactivated
228239 QCOMPARE(opt1->active(), true);
229− QCOMPARE(core_multi_filter->options()[0]->active(), false);
230− QCOMPARE(core_multi_filter->options()[1]->active(), true); // shared option, stays active
231− QCOMPARE(core_multi_filter->options()[2]->active(), true);
240+ QCOMPARE(opt2->active(), false);
232241
233242 opt1->setActive(false); // and de-activate it
234243 QCOMPARE(opt0spy.count(), 2);
@@ -236,9 +245,7 @@ void FiltersBindingsTest::testMultiRangeFilter()
236245 QCOMPARE(opt2spy.count(), 0);
237246 QCOMPARE(opt0->active(), false);
238247 QCOMPARE(opt1->active(), false);
239− QCOMPARE(core_multi_filter->options()[0]->active(), false);
240− QCOMPARE(core_multi_filter->options()[1]->active(), false);
241− QCOMPARE(core_multi_filter->options()[2]->active(), false);
248+ QCOMPARE(opt2->active(), false);
242249
243250 opt2->setActive(true); // activate another combined option
244251 QCOMPARE(opt0spy.count(), 2);
@@ -247,9 +254,6 @@ void FiltersBindingsTest::testMultiRangeFilter()
247254 QCOMPARE(opt0->active(), false);
248255 QCOMPARE(opt1->active(), false);
249256 QCOMPARE(opt2->active(), true);
250− QCOMPARE(core_multi_filter->options()[0]->active(), false);
251− QCOMPARE(core_multi_filter->options()[1]->active(), false);
252− QCOMPARE(core_multi_filter->options()[2]->active(), true);
253257
254258 delete multi_filter;
255259 }
@@ -280,17 +284,31 @@ void FiltersBindingsTest::testCheckOptionFilter()
280284 QCOMPARE(check_filter->collapsed(), false);
281285 QCOMPARE(check_filter->filtering(), false);
282286
283− QVariant optvar = options->data(options->index(0));
284− FilterOption* opt0 = optvar.value<FilterOption*>();
285− QCOMPARE(opt0->id(), QString("opt0"));
287+ auto idx = options->index(0);
288+ QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
289+ QVariant name_var = options->data(idx, GenericOptionsModel::RoleName);
290+ QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
291+ QVariant active_var = options->data(idx, GenericOptionsModel::RoleActive);
286292
287− optvar = options->data(options->index(1));
288− FilterOption* opt1 = optvar.value<FilterOption*>();
289− QCOMPARE(opt1->id(), QString("opt1"));
293+ QCOMPARE(id_var.toString(), QString("opt0"));
294+ QCOMPARE(name_var.toString(), QString("Option 0"));
295+ QCOMPARE(icon_var.toString(), QString(""));
296+ QCOMPARE(active_var.toBool(), false);
290297
291− optvar = options->data(options->index(2));
292− FilterOption* opt2 = optvar.value<FilterOption*>();
293− QCOMPARE(opt2->id(), QString("opt2"));
298+ idx = options->index(1);
299+ id_var = options->data(idx, GenericOptionsModel::RoleId);
300+ name_var = options->data(idx, GenericOptionsModel::RoleName);
301+ icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
302+ active_var = options->data(idx, GenericOptionsModel::RoleActive);
303+
304+ QCOMPARE(id_var.toString(), QString("opt1"));
305+ QCOMPARE(name_var.toString(), QString("Option 1"));
306+ QCOMPARE(icon_var.toString(), QString(""));
307+ QCOMPARE(active_var.toBool(), false);
308+
309+ AbstractFilterOption* opt0 = options->getRawOption(0);
310+ AbstractFilterOption* opt1 = options->getRawOption(1);
311+ AbstractFilterOption* opt2 = options->getRawOption(2);
294312
295313 QSignalSpy opt0spy(opt0, SIGNAL(activeChanged(bool)));
296314 QSignalSpy opt1spy(opt1, SIGNAL(activeChanged(bool)));
@@ -338,17 +356,31 @@ void FiltersBindingsTest::testRadioOptionFilter()
338356 auto options = radio_filter->options();
339357 QCOMPARE(options->rowCount(), 3);
340358
341− QVariant optvar = options->data(options->index(0));
342− FilterOption* opt0 = optvar.value<FilterOption*>();
343− QCOMPARE(opt0->id(), QString("opt0"));
359+ auto idx = options->index(0);
360+ QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
361+ QVariant name_var = options->data(idx, GenericOptionsModel::RoleName);
362+ QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
363+ QVariant active_var = options->data(idx, GenericOptionsModel::RoleActive);
344364
345− optvar = options->data(options->index(1));
346− FilterOption* opt1 = optvar.value<FilterOption*>();
347− QCOMPARE(opt1->id(), QString("opt1"));
365+ QCOMPARE(id_var.toString(), QString("opt0"));
366+ QCOMPARE(name_var.toString(), QString("Option 0"));
367+ QCOMPARE(icon_var.toString(), QString(""));
368+ QCOMPARE(active_var.toBool(), false);
348369
349− optvar = options->data(options->index(2));
350− FilterOption* opt2 = optvar.value<FilterOption*>();
351− QCOMPARE(opt2->id(), QString("opt2"));
370+ idx = options->index(1);
371+ id_var = options->data(idx, GenericOptionsModel::RoleId);
372+ name_var = options->data(idx, GenericOptionsModel::RoleName);
373+ icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
374+ active_var = options->data(idx, GenericOptionsModel::RoleActive);
375+
376+ QCOMPARE(id_var.toString(), QString("opt1"));
377+ QCOMPARE(name_var.toString(), QString("Option 1"));
378+ QCOMPARE(icon_var.toString(), QString(""));
379+ QCOMPARE(active_var.toBool(), false);
380+
381+ AbstractFilterOption* opt0 = options->getRawOption(0);
382+ AbstractFilterOption* opt1 = options->getRawOption(1);
383+ AbstractFilterOption* opt2 = options->getRawOption(2);
352384
353385 QSignalSpy opt0spy(opt0, SIGNAL(activeChanged(bool)));
354386 QSignalSpy opt1spy(opt1, SIGNAL(activeChanged(bool)));
@@ -398,7 +430,7 @@ void FiltersBindingsTest::testRatingsFilter()
398430
399431 RatingFilterOption* opt[5];
400432 for (int i = 0; i<5; i++) {
401− opt[i] = options->data(options->index(i)).value<RatingFilterOption*>();
433+ opt[i] = dynamic_cast<RatingFilterOption *>(options->getRawOption(i));
402434 }
403435
404436 QSignalSpy opt0spy(opt[0], SIGNAL(activeChanged(bool)));
@@ -410,6 +442,8 @@ void FiltersBindingsTest::testRatingsFilter()
410442 QVERIFY(qAbs(opt[3]->value() - 0.8f) <= 0.0001f);
411443 QVERIFY(qAbs(opt[4]->value() - 1.0f) <= 0.0001f);
412444
445+ QVERIFY(rating_filter->rating() <= 0.0001f); // rating equals zero
446+
413447 // all options initially inactive
414448 for (int i=0; i<5; i++) {
415449 QCOMPARE(opt[i]->active(), false);
@@ -419,6 +453,7 @@ void FiltersBindingsTest::testRatingsFilter()
419453 for (int i=0; i<5; i++) {
420454 opt[i]->setActive(true);
421455 QCOMPARE(opt[i]->active(), true);
456+ QVERIFY(rating_filter->rating() - ((i+1)*0.2f) <= 0.0001f);
422457
423458 // verify that all other options are inactive
424459 for (int j=0; j<5; j++) {
@@ -432,6 +467,7 @@ void FiltersBindingsTest::testRatingsFilter()
432467 QCOMPARE(opt4spy.count(), 1);
433468
434469 opt[4]->setActive(false);
470+ QVERIFY(rating_filter->rating() <= 0.0001f); // rating equals zero
435471 QCOMPARE(opt4spy.count(), 2);
436472 }
437473}