@@ -19,100 +19,21 @@
1919// self
2020#include "fake_categories.h"
2121
22−// local
23−#include "categoryresults.h"
22+#include "fake_resultsmodel.h"
2423
25−#define CATEGORY_COLUMN 2
26−
27−// TODO: use something from libunity once it's public
28−enum CategoryColumn {
29− ID,
30− DISPLAY_NAME,
31− ICON_HINT,
32− RENDERER_NAME,
33− HINTS
34−};
35−
36−Categories::Categories(QObject* parent)
37− : DeeListModel(parent)
24+Categories::Categories(int category_count, QObject* parent)
25+ : QAbstractListModel(parent)
26+ , m_category_count(category_count)
3827{
39− // FIXME: need to clean up unused filters on countChanged
4028 m_roles[Categories::RoleCategoryId] = "categoryId";
4129 m_roles[Categories::RoleName] = "name";
4230 m_roles[Categories::RoleIcon] = "icon";
31+ m_roles[Categories::RoleRawRendererTemplate] = "rawRendererTemplate";
4332 m_roles[Categories::RoleRenderer] = "renderer";
44− m_roles[Categories::RoleContentType] = "contentType";
45− m_roles[Categories::RoleRendererHint] = "rendererHint";
46− m_roles[Categories::RoleHints] = "hints";
33+ m_roles[Categories::RoleComponents] = "components";
34+ m_roles[Categories::RoleProgressSource] = "progressSource";
4735 m_roles[Categories::RoleResults] = "results";
4836 m_roles[Categories::RoleCount] = "count";
49−
50− // TODO This should not be needed but accumulatting the count changes
51− // makes the visualization more stable and also makes crashes on fast
52− // change of the search term harder to reproduce
53− m_timer.setSingleShot(true);
54− m_timer.setInterval(50);
55− connect(&m_timer, SIGNAL(timeout()), this, SLOT(onEmitCountChanged()));
56−}
57−
58−DeeListModel*
59−Categories::getFilter(int index) const
60−{
61− if (!m_filters.contains(index)) {
62− auto results = new CategoryResults ();
63− results->setCategoryIndex(index);
64− connect(results, SIGNAL(countChanged()), this, SLOT(onCountChanged()));
65−
66− unsigned cat_index = static_cast<unsigned>(index);
67− auto model = getResultsForCategory(cat_index);
68− results->setModel(model);
69−
70− m_filters.insert(index, results);
71− }
72−
73− return m_filters[index];
74−}
75−
76−void
77−Categories::onCountChanged()
78−{
79− DeeListModel* filter = qobject_cast<DeeListModel*>(sender());
80− if (filter) {
81− m_timerFilters << filter;
82− m_timer.start();
83− }
84−}
85−
86−void Categories::onRowCountChanged()
87−{
88− QAbstractItemModel* model = qobject_cast<QAbstractItemModel*>(sender());
89− // find the corresponding category index
90− for (auto iter = m_overriddenCategories.begin(); iter != m_overriddenCategories.end(); ++iter) {
91− if (iter.value() == model) {
92− for (int i = 0; i < rowCount(); i++) {
93− auto id = data(index(i), RoleCategoryId).toString();
94− if (id != iter.key()) continue;
95− QVector<int> roles;
96− roles.append(RoleCount);
97− QModelIndex changedIndex = index(i);
98− Q_EMIT dataChanged(changedIndex, changedIndex, roles);
99− break;
100− }
101− }
102− }
103−}
104−
105−void
106−Categories::onEmitCountChanged()
107−{
108− QVector<int> roles;
109− roles.append(Categories::RoleCount);
110− Q_FOREACH(DeeListModel* results, m_timerFilters) {
111− auto cat_results = qobject_cast<CategoryResults*>(results);
112− QModelIndex changedIndex = index(cat_results->categoryIndex());
113− Q_EMIT dataChanged(changedIndex, changedIndex, roles);
114− }
115− m_timerFilters.clear();
11637}
11738
11839QHash<int, QByteArray>
@@ -121,93 +42,11 @@ Categories::roleNames() const
12142 return m_roles;
12243}
12344
124−void Categories::onOverrideModelDestroyed()
45+int Categories::rowCount(const QModelIndex& /*parent*/) const
12546{
126− QObject* model = sender();
127− auto iter = m_overriddenCategories.begin();
128− while (iter != m_overriddenCategories.end()) {
129− if (iter.value() == model) {
130− iter = m_overriddenCategories.erase(iter);
131− continue;
132− }
133− ++iter;
134− }
47+ return m_category_count;
13548}
13649
137−void Categories::overrideResults(const QString& categoryId, QAbstractItemModel* model)
138−{
139− m_overriddenCategories[categoryId] = model;
140− // watch the model
141− connect(model, &QObject::destroyed, this, &Categories::onOverrideModelDestroyed);
142− connect(model, &QAbstractItemModel::rowsInserted, this, &Categories::onRowCountChanged);
143− connect(model, &QAbstractItemModel::rowsRemoved, this, &Categories::onRowCountChanged);
144− connect(model, &QAbstractItemModel::modelReset, this, &Categories::onRowCountChanged);
145−
146− // emit the dataChanged signal if the category is already in the model
147− for (int i = 0; i < rowCount(); i++) {
148− auto id = data(index(i), RoleCategoryId).toString();
149− if (id != categoryId) continue;
150− QVector<int> roles;
151− roles.append(RoleCount);
152− roles.append(RoleResults);
153− QModelIndex changedIndex = index(i);
154− Q_EMIT dataChanged(changedIndex, changedIndex, roles);
155− break;
156− }
157−}
158−
159−void Categories::setResultModel(DeeModel* model)
160−{
161− // FIXME: should ref it
162− m_dee_results = model;
163−}
164−
165−
166−static void category_filter_map_func (DeeModel* orig_model,
167− DeeFilterModel* filter_model,
168− gpointer user_data)
169−{
170− DeeModelIter* iter;
171− DeeModelIter* end;
172− unsigned index = GPOINTER_TO_UINT(user_data);
173−
174− iter = dee_model_get_first_iter(orig_model);
175− end = dee_model_get_last_iter(orig_model);
176− while (iter != end) {
177− unsigned category_index = dee_model_get_uint32(orig_model, iter, CATEGORY_COLUMN);
178− if (index == category_index) {
179− dee_filter_model_append_iter(filter_model, iter);
180− }
181− iter = dee_model_next(orig_model, iter);
182− }
183−}
184−
185−static gboolean category_filter_notify_func (DeeModel* orig_model,
186− DeeModelIter* orig_iter,
187− DeeFilterModel* filter_model,
188− gpointer user_data)
189−{
190− unsigned index = GPOINTER_TO_UINT(user_data);
191− unsigned category_index = dee_model_get_uint32(orig_model, orig_iter, CATEGORY_COLUMN);
192−
193− if (index != category_index)
194− return FALSE;
195−
196− dee_filter_model_insert_iter_with_original_order(filter_model, orig_iter);
197− return TRUE;
198−}
199−
200−DeeModel* Categories::getResultsForCategory(unsigned cat_index) const
201−{
202− DeeFilter filter;
203− filter.map_func = category_filter_map_func;
204− filter.map_notify = category_filter_notify_func;
205− filter.destroy = nullptr;
206− filter.userdata = GUINT_TO_POINTER(cat_index);
207−
208− DeeModel* filtered_model = dee_filter_model_new(m_dee_results, &filter);
209− return filtered_model;
210−}
21150
21251QVariant
21352Categories::data(const QModelIndex& index, int role) const
@@ -216,44 +55,46 @@ Categories::data(const QModelIndex& index, int role) const
21655 return QVariant();
21756 }
21857
58+ ResultsModel *resultsModel = m_resultsModels[index.row()];
59+ if (!resultsModel) {
60+ resultsModel = new ResultsModel(15, index.row());
61+ m_resultsModels[index.row()] = resultsModel;
62+ }
21963 switch (role) {
22064 case RoleCategoryId:
221− return DeeListModel::data(index, CategoryColumn::ID);
65+ return QString("%1").arg(index.row());
22266 case RoleName:
223− return DeeListModel::data(index, CategoryColumn::DISPLAY_NAME);
67+ return QString("Category %1").arg(index.row());
22468 case RoleIcon:
225− return DeeListModel::data(index, CategoryColumn::ICON_HINT);
69+ return "gtk-apply";
70+ case RoleRawRendererTemplate:
71+ qFatal("Using un-implemented RoleRawRendererTemplate Categories role");
72+ return QVariant();
22673 case RoleRenderer:
227− return DeeListModel::data(index, CategoryColumn::RENDERER_NAME);
228− case RoleContentType:
22974 {
230− auto hints = DeeListModel::data(index, CategoryColumn::HINTS).toHash();
231− return hints.contains("content-type") ? hints["content-type"] : QVariant(QString("default"));
75+ QVariantMap map;
76+ map["category-layout"] = index.row() % 2 == 0 ? "grid" : "carousel";
77+ map["card-size"] = "small";
78+ return map;
23279 }
233− case RoleRendererHint:
80+ case RoleComponents:
23481 {
235− auto hints = DeeListModel::data(index, CategoryColumn::HINTS).toHash();
236− return hints.contains("renderer-hint") ? hints["renderer-hint"] : QVariant(QString());
82+ QVariantMap map, artMap;
83+ artMap["aspect-ratio"] = "1.0";
84+ artMap["field"] = "art";
85+ map["art"] = artMap;
86+ map["title"] = "HOLA";
87+ return map;
23788 }
238− case RoleHints:
239− return DeeListModel::data(index, CategoryColumn::HINTS);
89+ case RoleProgressSource:
90+ qFatal("Using un-implemented RoleProgressSource Categories role");
91+ return QVariant();
24092 case RoleResults:
241− if (m_overriddenCategories.size() > 0)
242− {
243− auto id = DeeListModel::data(index, CategoryColumn::ID).toString();
244− if (m_overriddenCategories.find(id) != m_overriddenCategories.end())
245− return QVariant::fromValue(m_overriddenCategories[id]);
246− }
247− return QVariant::fromValue(getFilter(index.row()));
93+ return QVariant::fromValue(resultsModel);
24894 case RoleCount:
249− if (m_overriddenCategories.size() > 0)
250− {
251− auto id = DeeListModel::data(index, CategoryColumn::ID).toString();
252− if (m_overriddenCategories.find(id) != m_overriddenCategories.end())
253− return QVariant::fromValue(m_overriddenCategories[id]->rowCount());
254− }
255− return QVariant::fromValue(getFilter(index.row())->rowCount());
95+ return resultsModel->rowCount();
25696 default:
97+ qFatal("Using un-implemented Categories role");
25798 return QVariant();
25899 }
259100}