Merge lp:~stolowski/unity-scopes-shell/favoriting-fixes into lp:unity-scopes-shell
- favoriting-fixes
- Merge into trunk
Proposed by
Paweł Stołowski
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Marcus Tomlinson | ||||||||
Approved revision: | 341 | ||||||||
Merged at revision: | 346 | ||||||||
Proposed branch: | lp:~stolowski/unity-scopes-shell/favoriting-fixes | ||||||||
Merge into: | lp:unity-scopes-shell | ||||||||
Diff against target: |
626 lines (+309/-126) 7 files modified
src/Unity/CMakeLists.txt (+1/-0) src/Unity/favorites.cpp (+160/-0) src/Unity/favorites.h (+63/-0) src/Unity/scope.cpp (+4/-4) src/Unity/scope.h (+2/-2) src/Unity/scopes.cpp (+76/-118) src/Unity/scopes.h (+3/-2) |
||||||||
To merge this branch: | bzr merge lp:~stolowski/unity-scopes-shell/favoriting-fixes | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Marcus Tomlinson (community) | Approve | ||
Review via email: mp+302253@code.launchpad.net |
Commit message
Optimize scope favoriting. Make sure click scope is favorited back if reinstalled.
Description of the change
Optimize and refactor scope favoriting. Make sure click scope is favorited back if reinstalled.
The optimization is mostly achieved by temporarily disabling gesttings signals when storing an updated list of favorites.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/Unity/CMakeLists.txt' | |||
2 | --- src/Unity/CMakeLists.txt 2016-06-02 08:49:55 +0000 | |||
3 | +++ src/Unity/CMakeLists.txt 2016-08-10 07:21:23 +0000 | |||
4 | @@ -20,6 +20,7 @@ | |||
5 | 20 | collectors.cpp | 20 | collectors.cpp |
6 | 21 | department.cpp | 21 | department.cpp |
7 | 22 | departmentnode.cpp | 22 | departmentnode.cpp |
8 | 23 | favorites.cpp | ||
9 | 23 | filters.cpp | 24 | filters.cpp |
10 | 24 | filtergroupwidget.cpp | 25 | filtergroupwidget.cpp |
11 | 25 | optionselectorfilter.cpp | 26 | optionselectorfilter.cpp |
12 | 26 | 27 | ||
13 | === added file 'src/Unity/favorites.cpp' | |||
14 | --- src/Unity/favorites.cpp 1970-01-01 00:00:00 +0000 | |||
15 | +++ src/Unity/favorites.cpp 2016-08-10 07:21:23 +0000 | |||
16 | @@ -0,0 +1,160 @@ | |||
17 | 1 | /* | ||
18 | 2 | * Copyright (C) 2016 Canonical, Ltd. | ||
19 | 3 | * | ||
20 | 4 | * Authors: | ||
21 | 5 | * Pawel Stolowski <pawel.stolowski@canonical.com> | ||
22 | 6 | * | ||
23 | 7 | * This program is free software; you can redistribute it and/or modify | ||
24 | 8 | * it under the terms of the GNU General Public License as published by | ||
25 | 9 | * the Free Software Foundation; version 3. | ||
26 | 10 | * | ||
27 | 11 | * This program is distributed in the hope that it will be useful, | ||
28 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
29 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
30 | 14 | * GNU General Public License for more details. | ||
31 | 15 | * | ||
32 | 16 | * You should have received a copy of the GNU General Public License | ||
33 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
34 | 18 | */ | ||
35 | 19 | |||
36 | 20 | #include <QGSettings> | ||
37 | 21 | #include <QVariant> | ||
38 | 22 | #include <QDebug> | ||
39 | 23 | #include <unity/scopes/CannedQuery.h> | ||
40 | 24 | #include <unity/UnityExceptions.h> | ||
41 | 25 | #include <algorithm> | ||
42 | 26 | #include "favorites.h" | ||
43 | 27 | |||
44 | 28 | namespace scopes_ng | ||
45 | 29 | { | ||
46 | 30 | |||
47 | 31 | Favorites::Favorites(QObject *parent, QGSettings *dashSettings) | ||
48 | 32 | : QObject(parent), | ||
49 | 33 | m_dashSettings(dashSettings) | ||
50 | 34 | { | ||
51 | 35 | if (m_dashSettings) { | ||
52 | 36 | readFavoritesFromGSettings(); | ||
53 | 37 | QObject::connect(m_dashSettings, &QGSettings::changed, this, &Favorites::dashSettingsChanged); | ||
54 | 38 | } | ||
55 | 39 | } | ||
56 | 40 | |||
57 | 41 | void Favorites::readFavoritesFromGSettings() | ||
58 | 42 | { | ||
59 | 43 | m_favoriteScopes.clear(); | ||
60 | 44 | m_positionLookup.clear(); | ||
61 | 45 | |||
62 | 46 | int pos = 0 ; | ||
63 | 47 | auto const favs = m_dashSettings->get(QStringLiteral("favoriteScopes")).toList(); | ||
64 | 48 | for (auto const fv: favs) { | ||
65 | 49 | try | ||
66 | 50 | { | ||
67 | 51 | auto const query = unity::scopes::CannedQuery::from_uri(fv.toString().toStdString()); | ||
68 | 52 | auto scopeId = QString::fromStdString(query.scope_id()); | ||
69 | 53 | m_favoriteScopes.append(scopeId); | ||
70 | 54 | m_positionLookup[scopeId] = pos++; | ||
71 | 55 | } | ||
72 | 56 | catch (const unity::InvalidArgumentException &e) | ||
73 | 57 | { | ||
74 | 58 | qWarning() << "Invalid canned query '" << fv.toString() << "'" << QString::fromStdString(e.what()); | ||
75 | 59 | } | ||
76 | 60 | } | ||
77 | 61 | } | ||
78 | 62 | |||
79 | 63 | Favorites::~Favorites() | ||
80 | 64 | { | ||
81 | 65 | } | ||
82 | 66 | |||
83 | 67 | int Favorites::setFavorite(QString const& scopeId, bool value) | ||
84 | 68 | { | ||
85 | 69 | if (!value) { | ||
86 | 70 | int pos = position(scopeId); | ||
87 | 71 | if (pos >= 0) { | ||
88 | 72 | m_favoriteScopes.removeAt(pos); | ||
89 | 73 | m_positionLookup.remove(scopeId); | ||
90 | 74 | for (int i = pos; i<m_favoriteScopes.size(); i++) { | ||
91 | 75 | m_positionLookup[m_favoriteScopes[i]] = i; | ||
92 | 76 | } | ||
93 | 77 | Q_ASSERT(m_favoriteScopes.size() == m_positionLookup.size()); | ||
94 | 78 | storeFavorites(); | ||
95 | 79 | return pos; | ||
96 | 80 | } | ||
97 | 81 | } else { | ||
98 | 82 | int pos = position(scopeId); | ||
99 | 83 | if (pos < 0) { | ||
100 | 84 | m_favoriteScopes.push_back(scopeId); | ||
101 | 85 | pos = m_favoriteScopes.size() - 1; | ||
102 | 86 | m_positionLookup[scopeId] = pos; | ||
103 | 87 | } | ||
104 | 88 | Q_ASSERT(m_favoriteScopes.size() == m_positionLookup.size()); | ||
105 | 89 | storeFavorites(); | ||
106 | 90 | return pos; | ||
107 | 91 | } | ||
108 | 92 | |||
109 | 93 | return -1; | ||
110 | 94 | } | ||
111 | 95 | |||
112 | 96 | void Favorites::moveFavoriteTo(QString const& scopeId, int pos) | ||
113 | 97 | { | ||
114 | 98 | int oldPos = position(scopeId); | ||
115 | 99 | if (oldPos >= 0) { | ||
116 | 100 | m_favoriteScopes.move(oldPos, pos); | ||
117 | 101 | auto const range = std::minmax(oldPos, pos); | ||
118 | 102 | for (int i = range.first; i<=range.second; i++) { | ||
119 | 103 | m_positionLookup[m_favoriteScopes[i]] = i; | ||
120 | 104 | } | ||
121 | 105 | } else { | ||
122 | 106 | qWarning() << "Favorites::moveFavoriteTo: no such scope" << scopeId; | ||
123 | 107 | } | ||
124 | 108 | |||
125 | 109 | storeFavorites(); | ||
126 | 110 | |||
127 | 111 | Q_ASSERT(m_favoriteScopes.size() == m_positionLookup.size()); | ||
128 | 112 | } | ||
129 | 113 | |||
130 | 114 | QStringList Favorites::getFavorites() | ||
131 | 115 | { | ||
132 | 116 | return m_favoriteScopes; | ||
133 | 117 | } | ||
134 | 118 | |||
135 | 119 | bool Favorites::hasScope(QString const& scopeId) const | ||
136 | 120 | { | ||
137 | 121 | return m_positionLookup.find(scopeId) != m_positionLookup.end(); | ||
138 | 122 | } | ||
139 | 123 | |||
140 | 124 | int Favorites::position(QString const& scopeId) const | ||
141 | 125 | { | ||
142 | 126 | auto it = m_positionLookup.find(scopeId); | ||
143 | 127 | if (it != m_positionLookup.end()) { | ||
144 | 128 | return it.value(); | ||
145 | 129 | } | ||
146 | 130 | return -1; | ||
147 | 131 | } | ||
148 | 132 | |||
149 | 133 | void Favorites::dashSettingsChanged(QString const &key) | ||
150 | 134 | { | ||
151 | 135 | if (key != QLatin1String("favoriteScopes")) { | ||
152 | 136 | return; | ||
153 | 137 | } | ||
154 | 138 | readFavoritesFromGSettings(); | ||
155 | 139 | Q_EMIT favoritesChanged(); | ||
156 | 140 | } | ||
157 | 141 | |||
158 | 142 | void Favorites::storeFavorites() | ||
159 | 143 | { | ||
160 | 144 | if (m_dashSettings) { | ||
161 | 145 | QStringList cannedQueries; | ||
162 | 146 | for (auto const& fav: m_favoriteScopes) | ||
163 | 147 | { | ||
164 | 148 | const QString query = "scope://" + fav; | ||
165 | 149 | cannedQueries.push_back(query); | ||
166 | 150 | } | ||
167 | 151 | |||
168 | 152 | QObject::disconnect(m_dashSettings, &QGSettings::changed, this, &Favorites::dashSettingsChanged); | ||
169 | 153 | m_dashSettings->set(QStringLiteral("favoriteScopes"), QVariant(cannedQueries)); | ||
170 | 154 | QObject::connect(m_dashSettings, &QGSettings::changed, this, &Favorites::dashSettingsChanged); | ||
171 | 155 | } | ||
172 | 156 | } | ||
173 | 157 | |||
174 | 158 | } // namespace scopes_ng | ||
175 | 159 | |||
176 | 160 | #include <favorites.moc> | ||
177 | 0 | 161 | ||
178 | === added file 'src/Unity/favorites.h' | |||
179 | --- src/Unity/favorites.h 1970-01-01 00:00:00 +0000 | |||
180 | +++ src/Unity/favorites.h 2016-08-10 07:21:23 +0000 | |||
181 | @@ -0,0 +1,63 @@ | |||
182 | 1 | /* | ||
183 | 2 | * Copyright (C) 2016 Canonical, Ltd. | ||
184 | 3 | * | ||
185 | 4 | * Authors: | ||
186 | 5 | * Pawel Stolowski <pawel.stolowski@canonical.com> | ||
187 | 6 | * | ||
188 | 7 | * This program is free software; you can redistribute it and/or modify | ||
189 | 8 | * it under the terms of the GNU General Public License as published by | ||
190 | 9 | * the Free Software Foundation; version 3. | ||
191 | 10 | * | ||
192 | 11 | * This program is distributed in the hope that it will be useful, | ||
193 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
194 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
195 | 14 | * GNU General Public License for more details. | ||
196 | 15 | * | ||
197 | 16 | * You should have received a copy of the GNU General Public License | ||
198 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
199 | 18 | */ | ||
200 | 19 | |||
201 | 20 | #ifndef NG_FAVORITES_H | ||
202 | 21 | #define NG_FAVORITES_H | ||
203 | 22 | |||
204 | 23 | #include <QStringList> | ||
205 | 24 | #include <QObject> | ||
206 | 25 | #include <QPointer> | ||
207 | 26 | #include <QMap> | ||
208 | 27 | |||
209 | 28 | class QGSettings; | ||
210 | 29 | |||
211 | 30 | namespace scopes_ng | ||
212 | 31 | { | ||
213 | 32 | |||
214 | 33 | class Q_DECL_EXPORT Favorites : public QObject | ||
215 | 34 | { | ||
216 | 35 | Q_OBJECT | ||
217 | 36 | public: | ||
218 | 37 | Favorites(QObject *parent, QGSettings *dashSettings); | ||
219 | 38 | ~Favorites(); | ||
220 | 39 | |||
221 | 40 | int setFavorite(QString const& scopeId, bool value); | ||
222 | 41 | void moveFavoriteTo(QString const& scopeId, int pos); | ||
223 | 42 | bool hasScope(QString const& scopeId) const; | ||
224 | 43 | int position(QString const& scopeId) const; | ||
225 | 44 | QStringList getFavorites(); | ||
226 | 45 | void storeFavorites(); | ||
227 | 46 | |||
228 | 47 | Q_SIGNALS: | ||
229 | 48 | void favoritesChanged(); | ||
230 | 49 | |||
231 | 50 | private Q_SLOTS: | ||
232 | 51 | void dashSettingsChanged(QString const &key); | ||
233 | 52 | |||
234 | 53 | private: | ||
235 | 54 | void readFavoritesFromGSettings(); | ||
236 | 55 | |||
237 | 56 | QPointer<QGSettings> m_dashSettings; | ||
238 | 57 | QStringList m_favoriteScopes; | ||
239 | 58 | QMap<QString, int> m_positionLookup; | ||
240 | 59 | }; | ||
241 | 60 | |||
242 | 61 | } // namespace scopes_ng | ||
243 | 62 | |||
244 | 63 | #endif // NG_SCOPES_H | ||
245 | 0 | 64 | ||
246 | === modified file 'src/Unity/scope.cpp' | |||
247 | --- src/Unity/scope.cpp 2016-06-24 14:03:59 +0000 | |||
248 | +++ src/Unity/scope.cpp 2016-08-10 07:21:23 +0000 | |||
249 | @@ -75,13 +75,13 @@ | |||
250 | 75 | const int RESULTS_TTL_LARGE = 3600000; // 1 hour | 75 | const int RESULTS_TTL_LARGE = 3600000; // 1 hour |
251 | 76 | const int SEARCH_CARDINALITY = 300; // maximum number of results accepted from a single scope | 76 | const int SEARCH_CARDINALITY = 300; // maximum number of results accepted from a single scope |
252 | 77 | 77 | ||
254 | 78 | Scope::Ptr Scope::newInstance(scopes_ng::Scopes* parent) | 78 | Scope::Ptr Scope::newInstance(scopes_ng::Scopes* parent, bool favorite) |
255 | 79 | { | 79 | { |
257 | 80 | auto scope = Scope::Ptr(new Scope(parent), &QObject::deleteLater); | 80 | auto scope = Scope::Ptr(new Scope(parent, favorite), &QObject::deleteLater); |
258 | 81 | return scope; | 81 | return scope; |
259 | 82 | } | 82 | } |
260 | 83 | 83 | ||
262 | 84 | Scope::Scope(scopes_ng::Scopes* parent) : | 84 | Scope::Scope(scopes_ng::Scopes* parent, bool favorite) : |
263 | 85 | m_query_id(0) | 85 | m_query_id(0) |
264 | 86 | , m_formFactor(QStringLiteral("phone")) | 86 | , m_formFactor(QStringLiteral("phone")) |
265 | 87 | , m_activeFiltersCount(0) | 87 | , m_activeFiltersCount(0) |
266 | @@ -91,7 +91,7 @@ | |||
267 | 91 | , m_resultsDirty(false) | 91 | , m_resultsDirty(false) |
268 | 92 | , m_delayedSearchProcessing(false) | 92 | , m_delayedSearchProcessing(false) |
269 | 93 | , m_hasNavigation(false) | 93 | , m_hasNavigation(false) |
271 | 94 | , m_favorite(false) | 94 | , m_favorite(favorite) |
272 | 95 | , m_initialQueryDone(false) | 95 | , m_initialQueryDone(false) |
273 | 96 | , m_childScopesDirty(true) | 96 | , m_childScopesDirty(true) |
274 | 97 | , m_searchController(new CollectionController) | 97 | , m_searchController(new CollectionController) |
275 | 98 | 98 | ||
276 | === modified file 'src/Unity/scope.h' | |||
277 | --- src/Unity/scope.h 2016-06-23 09:27:45 +0000 | |||
278 | +++ src/Unity/scope.h 2016-08-10 07:21:23 +0000 | |||
279 | @@ -110,7 +110,7 @@ | |||
280 | 110 | public: | 110 | public: |
281 | 111 | typedef QSharedPointer<Scope> Ptr; | 111 | typedef QSharedPointer<Scope> Ptr; |
282 | 112 | 112 | ||
284 | 113 | static Scope::Ptr newInstance(scopes_ng::Scopes* parent); | 113 | static Scope::Ptr newInstance(scopes_ng::Scopes* parent, bool favorite = false); |
285 | 114 | 114 | ||
286 | 115 | virtual ~Scope(); | 115 | virtual ~Scope(); |
287 | 116 | 116 | ||
288 | @@ -205,7 +205,7 @@ | |||
289 | 205 | void previewModelDestroyed(QObject *obj); | 205 | void previewModelDestroyed(QObject *obj); |
290 | 206 | 206 | ||
291 | 207 | protected: | 207 | protected: |
293 | 208 | explicit Scope(scopes_ng::Scopes* parent); | 208 | explicit Scope(scopes_ng::Scopes* parent, bool favorite = false); |
294 | 209 | 209 | ||
295 | 210 | void setStatus(unity::shell::scopes::ScopeInterface::Status status); | 210 | void setStatus(unity::shell::scopes::ScopeInterface::Status status); |
296 | 211 | void invalidateLastSearch(); | 211 | void invalidateLastSearch(); |
297 | 212 | 212 | ||
298 | === modified file 'src/Unity/scopes.cpp' | |||
299 | --- src/Unity/scopes.cpp 2016-06-23 12:53:21 +0000 | |||
300 | +++ src/Unity/scopes.cpp 2016-08-10 07:21:23 +0000 | |||
301 | @@ -24,6 +24,7 @@ | |||
302 | 24 | #include "scope.h" | 24 | #include "scope.h" |
303 | 25 | #include "overviewscope.h" | 25 | #include "overviewscope.h" |
304 | 26 | #include "ubuntulocationservice.h" | 26 | #include "ubuntulocationservice.h" |
305 | 27 | #include "favorites.h" | ||
306 | 27 | 28 | ||
307 | 28 | // Qt | 29 | // Qt |
308 | 29 | #include <QDebug> | 30 | #include <QDebug> |
309 | @@ -126,10 +127,8 @@ | |||
310 | 126 | QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/com/canonical/unity/scopes"), QStringLiteral("com.canonical.unity.scopes"), QStringLiteral("InvalidateResults"), this, SLOT(invalidateScopeResults(QString))); | 127 | QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/com/canonical/unity/scopes"), QStringLiteral("com.canonical.unity.scopes"), QStringLiteral("InvalidateResults"), this, SLOT(invalidateScopeResults(QString))); |
311 | 127 | 128 | ||
312 | 128 | m_dashSettings = QGSettings::isSchemaInstalled("com.canonical.Unity.Dash") ? new QGSettings("com.canonical.Unity.Dash", QByteArray(), this) : nullptr; | 129 | m_dashSettings = QGSettings::isSchemaInstalled("com.canonical.Unity.Dash") ? new QGSettings("com.canonical.Unity.Dash", QByteArray(), this) : nullptr; |
317 | 129 | if (m_dashSettings) | 130 | m_favoriteScopes = new Favorites(this, m_dashSettings); |
318 | 130 | { | 131 | QObject::connect(m_favoriteScopes, &Favorites::favoritesChanged, this, &Scopes::favoritesChanged); |
315 | 131 | QObject::connect(m_dashSettings, &QGSettings::changed, this, &Scopes::dashSettingsChanged); | ||
316 | 132 | } | ||
319 | 133 | 132 | ||
320 | 134 | m_overviewScope = OverviewScope::newInstance(this); | 133 | m_overviewScope = OverviewScope::newInstance(this); |
321 | 135 | 134 | ||
322 | @@ -427,57 +426,41 @@ | |||
323 | 427 | 426 | ||
324 | 428 | void Scopes::processFavoriteScopes() | 427 | void Scopes::processFavoriteScopes() |
325 | 429 | { | 428 | { |
326 | 429 | qDebug() << "Scopes::processFavoriteScopes()"; | ||
327 | 430 | |||
328 | 430 | if (m_noFavorites) { | 431 | if (m_noFavorites) { |
329 | 431 | return; | 432 | return; |
330 | 432 | } | 433 | } |
331 | 433 | 434 | ||
332 | 434 | // | 435 | // |
333 | 435 | // read the favoriteScopes array value from gsettings. | ||
334 | 436 | // process it and turn its values into scope ids. | ||
335 | 437 | // create new Scope objects or remove existing according to the list of favorities. | 436 | // create new Scope objects or remove existing according to the list of favorities. |
336 | 438 | // notify about scopes model changes accordingly. | 437 | // notify about scopes model changes accordingly. |
337 | 439 | if (m_dashSettings) { | 438 | if (m_dashSettings) { |
341 | 440 | QStringList newFavorites; | 439 | for (auto const& fv: m_favoriteScopes->getFavorites()) |
339 | 441 | QMap<QString, int> favScopesLut; | ||
340 | 442 | for (auto const& fv: m_dashSettings->get(QStringLiteral("favoriteScopes")).toList()) | ||
342 | 443 | { | 440 | { |
374 | 444 | int pos = 0; | 441 | // favorited scope not installed? |
375 | 445 | try | 442 | if (m_cachedMetadata.find(fv) == m_cachedMetadata.end()) |
376 | 446 | { | 443 | { |
377 | 447 | auto const query = unity::scopes::CannedQuery::from_uri(fv.toString().toStdString()); | 444 | qDebug() << "Favorited scope" << fv << "is no longer available, un-favoriting"; |
378 | 448 | const QString id = QString::fromStdString(query.scope_id()); | 445 | m_favoriteScopes->setFavorite(fv, false); |
379 | 449 | 446 | } | |
380 | 450 | if (m_cachedMetadata.find(id) != m_cachedMetadata.end()) | 447 | } |
381 | 451 | { | 448 | |
382 | 452 | newFavorites.push_back(id); | 449 | // special-case clickscope; append it to favorites if it was uninstalled (and in consequence removed from favorites) - see LP: #1603186 |
383 | 453 | pos = newFavorites.size() - 1; | 450 | if (m_cachedMetadata.contains(CLICK_SCOPE_ID) && !m_favoriteScopes->hasScope(CLICK_SCOPE_ID)) { |
384 | 454 | favScopesLut[id] = pos; | 451 | qDebug() << "Favoriting" << CLICK_SCOPE_ID; |
385 | 455 | } | 452 | m_favoriteScopes->setFavorite(CLICK_SCOPE_ID, true); |
386 | 456 | else | 453 | } |
387 | 457 | { | 454 | |
388 | 458 | // If a scope that was favorited no longer exists, unfavorite it in m_dashSettings | 455 | QSet<QString> scopesInTheModel; |
358 | 459 | setFavorite(id, false); | ||
359 | 460 | } | ||
360 | 461 | } | ||
361 | 462 | catch (const InvalidArgumentException &e) | ||
362 | 463 | { | ||
363 | 464 | qWarning() << "Invalid canned query '" << fv.toString() << "'" << QString::fromStdString(e.what()); | ||
364 | 465 | } | ||
365 | 466 | } | ||
366 | 467 | |||
367 | 468 | // this prevents further processing if we get called back when calling scope->setFavorite() below | ||
368 | 469 | if (m_favoriteScopes == newFavorites) | ||
369 | 470 | return; | ||
370 | 471 | |||
371 | 472 | m_favoriteScopes = newFavorites; | ||
372 | 473 | |||
373 | 474 | QSet<QString> oldScopes; | ||
389 | 475 | int row = 0; | 456 | int row = 0; |
390 | 476 | // remove un-favorited scopes | 457 | // remove un-favorited scopes |
391 | 477 | for (auto it = m_scopes.begin(); it != m_scopes.end();) | 458 | for (auto it = m_scopes.begin(); it != m_scopes.end();) |
392 | 478 | { | 459 | { |
394 | 479 | if (!favScopesLut.contains((*it)->id())) | 460 | if (!m_favoriteScopes->hasScope((*it)->id())) |
395 | 480 | { | 461 | { |
396 | 462 | qDebug() << "Scope" << (*it)->id() << "is no longer favorited, removing"; | ||
397 | 463 | |||
398 | 481 | beginRemoveRows(QModelIndex(), row, row); | 464 | beginRemoveRows(QModelIndex(), row, row); |
399 | 482 | Scope::Ptr toDelete = *it; | 465 | Scope::Ptr toDelete = *it; |
400 | 483 | toDelete->setFavorite(false); | 466 | toDelete->setFavorite(false); |
401 | @@ -490,7 +473,7 @@ | |||
402 | 490 | } | 473 | } |
403 | 491 | else | 474 | else |
404 | 492 | { | 475 | { |
406 | 493 | oldScopes.insert((*it)->id()); | 476 | scopesInTheModel.insert((*it)->id()); |
407 | 494 | ++it; | 477 | ++it; |
408 | 495 | ++row; | 478 | ++row; |
409 | 496 | } | 479 | } |
410 | @@ -498,41 +481,35 @@ | |||
411 | 498 | 481 | ||
412 | 499 | // add new favorites | 482 | // add new favorites |
413 | 500 | row = 0; | 483 | row = 0; |
415 | 501 | for (auto favIt = m_favoriteScopes.begin(); favIt != m_favoriteScopes.end(); ) | 484 | for (auto const& fv: m_favoriteScopes->getFavorites()) |
416 | 502 | { | 485 | { |
419 | 503 | auto const fav = *favIt; | 486 | if (!scopesInTheModel.contains(fv)) |
418 | 504 | if (!oldScopes.contains(fav)) | ||
420 | 505 | { | 487 | { |
422 | 506 | auto it = m_cachedMetadata.find(fav); | 488 | auto it = m_cachedMetadata.find(fv); |
423 | 507 | if (it != m_cachedMetadata.end()) | 489 | if (it != m_cachedMetadata.end()) |
424 | 508 | { | 490 | { |
426 | 509 | Scope::Ptr scope = Scope::newInstance(this); | 491 | qDebug() << "Scope" << fv << "is favorited, adding to scopes model"; |
427 | 492 | |||
428 | 493 | Scope::Ptr scope = Scope::newInstance(this, true); | ||
429 | 510 | connect(scope.data(), SIGNAL(isActiveChanged()), this, SLOT(prepopulateNextScopes())); | 494 | connect(scope.data(), SIGNAL(isActiveChanged()), this, SLOT(prepopulateNextScopes())); |
430 | 511 | scope->setScopeData(*(it.value())); | 495 | scope->setScopeData(*(it.value())); |
431 | 512 | scope->setFavorite(true); | ||
432 | 513 | beginInsertRows(QModelIndex(), row, row); | 496 | beginInsertRows(QModelIndex(), row, row); |
433 | 514 | m_scopes.insert(row, scope); | 497 | m_scopes.insert(row, scope); |
434 | 515 | endInsertRows(); | 498 | endInsertRows(); |
435 | 516 | } | 499 | } |
436 | 517 | else | ||
437 | 518 | { | ||
438 | 519 | qWarning() << "No such scope:" << fav; | ||
439 | 520 | favIt = m_favoriteScopes.erase(favIt); | ||
440 | 521 | continue; | ||
441 | 522 | } | ||
442 | 523 | } | 500 | } |
443 | 524 | ++row; | 501 | ++row; |
444 | 525 | ++favIt; | ||
445 | 526 | } | 502 | } |
446 | 527 | 503 | ||
448 | 528 | // iterate over results, move rows if positions changes | 504 | // iterate over results, move rows if positions changed |
449 | 529 | for (int i = 0; i<m_scopes.size(); ) | 505 | for (int i = 0; i<m_scopes.size(); ) |
450 | 530 | { | 506 | { |
451 | 531 | auto scope = m_scopes.at(i); | 507 | auto scope = m_scopes.at(i); |
452 | 532 | const QString id = scope->id(); | 508 | const QString id = scope->id(); |
455 | 533 | if (favScopesLut.contains(id)) { | 509 | int pos = m_favoriteScopes->position(id); |
456 | 534 | int pos = favScopesLut[id]; | 510 | if (pos >= 0) { |
457 | 535 | if (pos != i) { | 511 | if (pos != i) { |
458 | 512 | qDebug() << "Moving scope" << id << "to row" << pos << "to match position in favorites"; | ||
459 | 536 | beginMoveRows(QModelIndex(), i, i, QModelIndex(), pos + (pos > i ? 1 : 0)); | 513 | beginMoveRows(QModelIndex(), i, i, QModelIndex(), pos + (pos > i ? 1 : 0)); |
460 | 537 | m_scopes.move(i, pos); | 514 | m_scopes.move(i, pos); |
461 | 538 | endMoveRows(); | 515 | endMoveRows(); |
462 | @@ -544,17 +521,13 @@ | |||
463 | 544 | } | 521 | } |
464 | 545 | } | 522 | } |
465 | 546 | 523 | ||
467 | 547 | void Scopes::dashSettingsChanged(QString const& key) | 524 | void Scopes::favoritesChanged() |
468 | 548 | { | 525 | { |
469 | 549 | if (key != QLatin1String("favoriteScopes")) { | ||
470 | 550 | return; | ||
471 | 551 | } | ||
472 | 552 | |||
473 | 553 | processFavoriteScopes(); | 526 | processFavoriteScopes(); |
474 | 554 | 527 | ||
475 | 555 | if (m_overviewScope) | 528 | if (m_overviewScope) |
476 | 556 | { | 529 | { |
478 | 557 | m_overviewScope->updateFavorites(m_favoriteScopes); | 530 | m_overviewScope->updateFavorites(m_favoriteScopes->getFavorites()); |
479 | 558 | } | 531 | } |
480 | 559 | } | 532 | } |
481 | 560 | 533 | ||
482 | @@ -675,7 +648,7 @@ | |||
483 | 675 | 648 | ||
484 | 676 | QStringList Scopes::getFavoriteIds() const | 649 | QStringList Scopes::getFavoriteIds() const |
485 | 677 | { | 650 | { |
487 | 678 | return m_favoriteScopes; | 651 | return m_favoriteScopes->getFavorites(); |
488 | 679 | } | 652 | } |
489 | 680 | 653 | ||
490 | 681 | void Scopes::setFavorite(QString const& scopeId, bool value) | 654 | void Scopes::setFavorite(QString const& scopeId, bool value) |
491 | @@ -685,32 +658,39 @@ | |||
492 | 685 | qWarning() << "Cannot unfavorite" << scopeId; | 658 | qWarning() << "Cannot unfavorite" << scopeId; |
493 | 686 | return; | 659 | return; |
494 | 687 | } | 660 | } |
496 | 688 | if (m_dashSettings) | 661 | |
497 | 662 | int row = m_favoriteScopes->setFavorite(scopeId, value); | ||
498 | 663 | if (row >= 0) | ||
499 | 689 | { | 664 | { |
524 | 690 | QStringList cannedQueries; | 665 | if (value) { |
525 | 691 | bool changed = false; | 666 | auto it = m_cachedMetadata.find(scopeId); |
526 | 692 | 667 | if (it != m_cachedMetadata.end()) | |
527 | 693 | for (auto const& fav: m_favoriteScopes) | 668 | { |
528 | 694 | { | 669 | Scope::Ptr scope = Scope::newInstance(this, true); |
529 | 695 | if (value == false && fav == scopeId) { | 670 | connect(scope.data(), SIGNAL(isActiveChanged()), this, SLOT(prepopulateNextScopes())); |
530 | 696 | changed = true; | 671 | scope->setScopeData(*(it.value())); |
531 | 697 | continue; // skip it | 672 | beginInsertRows(QModelIndex(), row, row); |
532 | 698 | } | 673 | m_scopes.insert(row, scope); |
533 | 699 | // TODO: use CannedQuery::to_uri() when we really support them | 674 | endInsertRows(); |
534 | 700 | const QString query = "scope://" + fav; | 675 | } else { |
535 | 701 | cannedQueries.push_back(query); | 676 | qWarning() << "setFavorite: unknown scope" << scopeId; |
536 | 702 | } | 677 | } |
537 | 703 | 678 | } else { | |
538 | 704 | if (value && !m_favoriteScopes.contains(scopeId)) { | 679 | for (auto it = m_scopes.begin(); it != m_scopes.end(); it++) |
539 | 705 | const QString query = "scope://" + scopeId; | 680 | { |
540 | 706 | cannedQueries.push_back(query); | 681 | if ((*it)->id() == scopeId) { |
541 | 707 | changed = true; | 682 | beginRemoveRows(QModelIndex(), row, row); |
542 | 708 | } | 683 | Scope::Ptr toDelete = *it; |
543 | 709 | 684 | toDelete->setFavorite(false); | |
544 | 710 | if (changed) { | 685 | // we need to delay actual deletion of Scope object so that shell can animate it |
545 | 711 | // update gsettings entry | 686 | m_scopesToDelete.push_back(toDelete); |
546 | 712 | // note: this will trigger notification, so that new favorites are processed by processFavoriteScopes | 687 | // if the timer is already active, we just wait a bit longer, which is no problem |
547 | 713 | m_dashSettings->set(QStringLiteral("favoriteScopes"), QVariant(cannedQueries)); | 688 | m_scopesToDeleteTimer.start(); |
548 | 689 | it = m_scopes.erase(it); | ||
549 | 690 | endRemoveRows(); | ||
550 | 691 | break; | ||
551 | 692 | } | ||
552 | 693 | } | ||
553 | 714 | } | 694 | } |
554 | 715 | } | 695 | } |
555 | 716 | } | 696 | } |
556 | @@ -737,34 +717,12 @@ | |||
557 | 737 | 717 | ||
558 | 738 | void Scopes::moveFavoriteTo(QString const& scopeId, int index) | 718 | void Scopes::moveFavoriteTo(QString const& scopeId, int index) |
559 | 739 | { | 719 | { |
588 | 740 | if (m_dashSettings) | 720 | int oldPos = m_favoriteScopes->position(scopeId); |
589 | 741 | { | 721 | if (oldPos != index) { |
590 | 742 | QStringList cannedQueries; | 722 | m_favoriteScopes->moveFavoriteTo(scopeId, index); |
591 | 743 | bool found = false; | 723 | beginMoveRows(QModelIndex(), oldPos, oldPos, QModelIndex(), index + (index > oldPos ? 1 : 0)); |
592 | 744 | 724 | m_scopes.move(oldPos, index); | |
593 | 745 | int i = 0; | 725 | endMoveRows(); |
566 | 746 | for (auto const& fav: m_favoriteScopes) | ||
567 | 747 | { | ||
568 | 748 | if (fav == scopeId) { | ||
569 | 749 | if (index == i) | ||
570 | 750 | return; // same position | ||
571 | 751 | found = true; | ||
572 | 752 | } else { | ||
573 | 753 | const QString query = "scope://" + fav; | ||
574 | 754 | cannedQueries.push_back(query); | ||
575 | 755 | } | ||
576 | 756 | |||
577 | 757 | ++i; | ||
578 | 758 | } | ||
579 | 759 | |||
580 | 760 | if (found) { | ||
581 | 761 | // insert scopeId at new position | ||
582 | 762 | const QString query = "scope://" + scopeId; | ||
583 | 763 | cannedQueries.insert(index, query); | ||
584 | 764 | // update gsettings entry | ||
585 | 765 | // note: this will trigger notification, so that new favorites are processed by processFavoriteScopes | ||
586 | 766 | m_dashSettings->set(QStringLiteral("favoriteScopes"), QVariant(cannedQueries)); | ||
587 | 767 | } | ||
594 | 768 | } | 726 | } |
595 | 769 | } | 727 | } |
596 | 770 | 728 | ||
597 | 771 | 729 | ||
598 | === modified file 'src/Unity/scopes.h' | |||
599 | --- src/Unity/scopes.h 2016-06-10 13:41:37 +0000 | |||
600 | +++ src/Unity/scopes.h 2016-08-10 07:21:23 +0000 | |||
601 | @@ -47,6 +47,7 @@ | |||
602 | 47 | class UbuntuLocationService; | 47 | class UbuntuLocationService; |
603 | 48 | class LocationAccessHelper; | 48 | class LocationAccessHelper; |
604 | 49 | class Scope; | 49 | class Scope; |
605 | 50 | class Favorites; | ||
606 | 50 | class OverviewScope; | 51 | class OverviewScope; |
607 | 51 | 52 | ||
608 | 52 | class Q_DECL_EXPORT Scopes : public unity::shell::scopes::ScopesInterface | 53 | class Q_DECL_EXPORT Scopes : public unity::shell::scopes::ScopesInterface |
609 | @@ -92,7 +93,7 @@ | |||
610 | 92 | virtual QString readPartnerId(); | 93 | virtual QString readPartnerId(); |
611 | 93 | 94 | ||
612 | 94 | private Q_SLOTS: | 95 | private Q_SLOTS: |
614 | 95 | void dashSettingsChanged(QString const &key); | 96 | void favoritesChanged(); |
615 | 96 | void processFavoriteScopes(); | 97 | void processFavoriteScopes(); |
616 | 97 | void populateScopes(); | 98 | void populateScopes(); |
617 | 98 | void discoveryFinished(); | 99 | void discoveryFinished(); |
618 | @@ -117,7 +118,7 @@ | |||
619 | 117 | QList<QSharedPointer<Scope>> m_scopes; | 118 | QList<QSharedPointer<Scope>> m_scopes; |
620 | 118 | QList<QSharedPointer<Scope>> m_scopesToDelete; | 119 | QList<QSharedPointer<Scope>> m_scopesToDelete; |
621 | 119 | bool m_noFavorites; | 120 | bool m_noFavorites; |
623 | 120 | QStringList m_favoriteScopes; | 121 | Favorites* m_favoriteScopes; |
624 | 121 | QGSettings* m_dashSettings; | 122 | QGSettings* m_dashSettings; |
625 | 122 | QMap<QString, unity::scopes::ScopeMetadata::SPtr> m_cachedMetadata; | 123 | QMap<QString, unity::scopes::ScopeMetadata::SPtr> m_cachedMetadata; |
626 | 123 | QSharedPointer<OverviewScope> m_overviewScope; | 124 | QSharedPointer<OverviewScope> m_overviewScope; |
Outstanding work Pawel. +1