@@ -90,9 +90,37 @@ void Categories::onCategoriesModelChanged(unity::glib::Object<DeeModel> model)
9090 delete model;
9191 }
9292 m_results.clear();
93+ m_categoryOrder.clear();
94+
9395 setModel(model);
9496}
9597
98+void Categories::onCategoryOrderChanged(const std::vector<unsigned int>& cat_order)
99+{
100+ for (unsigned int pos = 0; pos<cat_order.size(); pos++)
101+ {
102+ unsigned int cat = cat_order[pos];
103+ const int old_pos = m_categoryOrder.indexOf(cat);
104+
105+ if (old_pos < 0) {
106+ qWarning() << "No such category index:" << cat;
107+ continue;
108+ }
109+
110+ if (static_cast<int>(pos) != old_pos) {
111+ int target_pos = pos;
112+ if (target_pos > old_pos)
113+ target_pos++;
114+ const bool status = beginMoveRows(QModelIndex(), old_pos, old_pos, QModelIndex(), target_pos);
115+ if (status)
116+ m_categoryOrder.move(old_pos, pos);
117+ else
118+ qWarning() << "beginMoveRows failed:" << old_pos << target_pos;
119+ endMoveRows();
120+ }
121+ }
122+}
123+
96124void
97125Categories::setUnityScope(const unity::dash::Scope::Ptr& scope)
98126{
@@ -101,9 +129,9 @@ Categories::setUnityScope(const unity::dash::Scope::Ptr& scope)
101129 // no need to call this, we'll get notified
102130 //setModel(m_unityScope->categories()->model());
103131
104− m_categoriesChangedConnection.disconnect();
105− m_categoriesChangedConnection =
106− m_unityScope->categories()->model.changed.connect(sigc::mem_fun(this, &Categories::onCategoriesModelChanged));
132+ m_signals.disconnectAll();
133+ m_signals << m_unityScope->categories()->model.changed.connect(sigc::mem_fun(this, &Categories::onCategoriesModelChanged));
134+ m_signals << m_unityScope->category_order.changed.connect(sigc::mem_fun(this, &Categories::onCategoryOrderChanged));
107135}
108136
109137void
@@ -111,7 +139,9 @@ Categories::onCountChanged()
111139{
112140 CategoryResults* results = qobject_cast<CategoryResults*>(sender());
113141 if (results) {
114− m_updatedCategories << results->categoryIndex();
142+ if (!m_updatedCategories.contains(results->categoryIndex())) {
143+ m_updatedCategories << results->categoryIndex();
144+ }
115145 m_timer.start();
116146 }
117147}
@@ -142,7 +172,8 @@ Categories::onEmitCountChanged()
142172 roles.append(Categories::RoleCount);
143173 Q_FOREACH(int categoryIndex, m_updatedCategories) {
144174 if (!m_results.contains(categoryIndex)) continue;
145− QModelIndex changedIndex = index(categoryIndex);
175+ const int realIndex = m_categoryOrder.indexOf(categoryIndex);
176+ const QModelIndex changedIndex = index(realIndex);
146177 Q_EMIT dataChanged(changedIndex, changedIndex, roles);
147178 }
148179 m_updatedCategories.clear();
@@ -196,48 +227,70 @@ Categories::data(const QModelIndex& index, int role) const
196227 return QVariant();
197228 }
198229
230+ if (m_categoryOrder.size() != rowCount())
231+ {
232+ // populate category order vector with 0..n
233+ m_categoryOrder.clear();
234+ const unsigned int lim = rowCount();
235+ for (unsigned int i = 0; i<lim; i++) {
236+ m_categoryOrder.append(i);
237+ }
238+ }
239+
240+ int realRow = index.row();
241+ if (index.row() < m_categoryOrder.size()) {
242+ realRow = m_categoryOrder[index.row()];
243+ } else {
244+ qWarning() << "Invalid index" << index.row();
245+ return QVariant();
246+ }
247+
248+ const QModelIndex realIndex = createIndex(realRow, index.column());
249+
199250 switch (role) {
200251 case RoleCategoryId:
201− return DeeListModel::data(index, CategoryColumn::ID);
252+ return DeeListModel::data(realIndex, CategoryColumn::ID);
202253 case RoleName:
203− return DeeListModel::data(index, CategoryColumn::DISPLAY_NAME);
254+ return DeeListModel::data(realIndex, CategoryColumn::DISPLAY_NAME);
204255 case RoleIcon:
205− return DeeListModel::data(index, CategoryColumn::ICON_HINT);
256+ return DeeListModel::data(realIndex, CategoryColumn::ICON_HINT);
206257 case RoleRenderer:
207− return DeeListModel::data(index, CategoryColumn::RENDERER_NAME);
258+ return DeeListModel::data(realIndex, CategoryColumn::RENDERER_NAME);
208259 case RoleContentType:
209260 {
210− auto hints = DeeListModel::data(index, CategoryColumn::HINTS).toHash();
261+ auto hints = DeeListModel::data(realIndex, CategoryColumn::HINTS).toHash();
211262 return hints.contains("content-type") ? hints["content-type"] : QVariant(QString("default"));
212263 }
213264 case RoleRendererHint:
214265 {
215− auto hints = DeeListModel::data(index, CategoryColumn::HINTS).toHash();
266+ auto hints = DeeListModel::data(realIndex, CategoryColumn::HINTS).toHash();
216267 return hints.contains("renderer-hint") ? hints["renderer-hint"] : QVariant(QString());
217268 }
218269 case RoleProgressSource:
219270 {
220− auto hints = DeeListModel::data(index, CategoryColumn::HINTS).toHash();
271+ auto hints = DeeListModel::data(realIndex, CategoryColumn::HINTS).toHash();
221272 return hints.contains("progress-source") ? hints["progress-source"] : QVariant();
222273 }
223274 case RoleHints:
224− return DeeListModel::data(index, CategoryColumn::HINTS);
275+ return DeeListModel::data(realIndex, CategoryColumn::HINTS);
225276 case RoleResults:
226277 if (m_overriddenCategories.size() > 0)
227278 {
228− auto id = DeeListModel::data(index, CategoryColumn::ID).toString();
279+ auto id = DeeListModel::data(realIndex, CategoryColumn::ID).toString();
229280 if (m_overriddenCategories.find(id) != m_overriddenCategories.end())
230281 return QVariant::fromValue(m_overriddenCategories[id]);
231282 }
232− return QVariant::fromValue(getResults(index.row()));
283+ return QVariant::fromValue(getResults(realRow));
233284 case RoleCount:
234285 if (m_overriddenCategories.size() > 0)
235286 {
236− auto id = DeeListModel::data(index, CategoryColumn::ID).toString();
287+ auto id = DeeListModel::data(realIndex, CategoryColumn::ID).toString();
237288 if (m_overriddenCategories.find(id) != m_overriddenCategories.end())
289+ {
238290 return QVariant::fromValue(m_overriddenCategories[id]->rowCount());
291+ }
239292 }
240− return QVariant::fromValue(getResults(index.row())->rowCount());
293+ return QVariant::fromValue(getResults(realRow)->rowCount());
241294 default:
242295 return QVariant();
243296 }