Merge lp:~stolowski/unity-scopes-shell/social-attributes into lp:unity-scopes-shell
- social-attributes
- Merge into trunk
Proposed by
Paweł Stołowski
on 2016-03-02
| Status: | Superseded |
|---|---|
| Proposed branch: | lp:~stolowski/unity-scopes-shell/social-attributes |
| Merge into: | lp:unity-scopes-shell |
| Diff against target: |
4545 lines (+3122/-273) 73 files modified
CMakeLists.txt (+2/-2) debian/changelog (+6/-4) debian/control.in (+3/-2) debian/libscope-harness.symbols.in (+1/-0) po/POTFILES.in (+11/-0) po/am.po (+3/-2) po/ar.po (+3/-2) po/br.po (+3/-2) po/ca.po (+3/-2) po/cs.po (+3/-2) po/da.po (+3/-2) po/de.po (+3/-2) po/el.po (+3/-2) po/en_GB.po (+3/-2) po/eo.po (+3/-2) po/es.po (+3/-2) po/eu.po (+3/-2) po/fa.po (+3/-2) po/fi.po (+3/-2) po/fr.po (+3/-2) po/gd.po (+3/-2) po/gl.po (+3/-2) po/hu.po (+3/-2) po/it.po (+3/-2) po/ja.po (+3/-2) po/nb.po (+3/-2) po/nl.po (+3/-2) po/pl.po (+3/-2) po/pt.po (+3/-2) po/pt_BR.po (+3/-2) po/ru.po (+3/-2) po/sl.po (+3/-2) po/sv.po (+3/-2) po/ta.po (+3/-2) po/uk.po (+3/-2) po/unity-plugin-scopes.pot (+1/-1) po/zh_TW.po (+3/-2) src/Unity/CMakeLists.txt (+13/-0) src/Unity/collectors.cpp (+14/-30) src/Unity/collectors.h (+2/-1) src/Unity/department.cpp (+12/-0) src/Unity/department.h (+3/-0) src/Unity/filters.cpp (+281/-0) src/Unity/filters.h (+94/-0) src/Unity/modelupdate.h (+143/-0) src/Unity/optionselectorfilter.cpp (+173/-0) src/Unity/optionselectorfilter.h (+69/-0) src/Unity/optionselectoroptions.cpp (+164/-0) src/Unity/optionselectoroptions.h (+64/-0) src/Unity/plugin.cpp (+12/-0) src/Unity/rangeinputfilter.cpp (+298/-0) src/Unity/rangeinputfilter.h (+93/-0) src/Unity/resultsmodel.cpp (+2/-0) src/Unity/scope.cpp (+139/-122) src/Unity/scope.h (+18/-12) src/Unity/utils.cpp (+2/-0) src/Unity/valuesliderfilter.cpp (+155/-0) src/Unity/valuesliderfilter.h (+70/-0) src/Unity/valueslidervalues.cpp (+82/-0) src/Unity/valueslidervalues.h (+56/-0) src/python/CMakeLists.txt (+1/-1) src/scope-harness/test-utils.cpp (+7/-0) src/scope-harness/test-utils.h (+3/-0) src/scope-harness/view/results-view.cpp (+12/-30) tests/CMakeLists.txt (+7/-2) tests/data/CMakeLists.txt (+1/-0) tests/data/mock-scope-filters/CMakeLists.txt (+15/-0) tests/data/mock-scope-filters/mock-scope-filters.cpp (+132/-0) tests/data/mock-scope-filters/mock-scope-filters.ini.in (+8/-0) tests/departmentstest.cpp (+0/-4) tests/filtersendtoendtest.cpp (+367/-0) tests/filterstest.cpp (+230/-0) tests/optionselectorfiltertest.cpp (+263/-0) |
| To merge this branch: | bzr merge lp:~stolowski/unity-scopes-shell/social-attributes |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| Andrea Cimitan | 2016-03-02 | Pending | |
| Unity Team | 2016-03-02 | Pending | |
|
Review via email:
|
|||
This proposal has been superseded by a proposal from 2016-03-16.
Commit Message
Handle social-actions.
Description of the Change
Handle social-actions. Needs https:/
To post a comment you must log in.
lp:~stolowski/unity-scopes-shell/social-attributes
updated
on 2016-05-05
- 293. By Paweł Stołowski on 2016-03-03
-
Renamed to social-actions
- 294. By Paweł Stołowski on 2016-03-04
-
Provide unity-scopes-
impl-10 - 295. By Paweł Stołowski on 2016-03-07
-
Merged trunk
- 296. By Paweł Stołowski on 2016-03-16
-
Merged filters
- 297. By Paweł Stołowski on 2016-03-24
-
Merged trunk
- 298. By Paweł Stołowski on 2016-03-24
-
Bump dependencies
- 299. By Paweł Stołowski on 2016-03-29
-
Debug
- 300. By Paweł Stołowski on 2016-03-29
-
Updated CATEGORY_
JSON_DEFAULTS - 301. By Paweł Stołowski on 2016-03-29
-
Fix updated CATEGORY_
JSON_DEFAULTS - 302. By Paweł Stołowski on 2016-03-29
-
Fix test failure
- 303. By Paweł Stołowski on 2016-03-29
-
Removed extra debug
- 304. By Paweł Stołowski on 2016-03-29
-
Debug updateResult
- 305. By Paweł Stołowski on 2016-03-29
-
Debug
- 306. By Paweł Stołowski on 2016-04-14
-
Merged trunk
- 307. By Paweł Stołowski on 2016-04-15
-
Bump
- 308. By Paweł Stołowski on 2016-04-26
-
Bump
- 309. By Paweł Stołowski on 2016-04-26
-
Fix version
- 310. By Paweł Stołowski on 2016-04-26
-
Fix version
- 311. By Paweł Stołowski on 2016-05-05
-
Merged trunk
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
| 1 | === modified file 'CMakeLists.txt' |
| 2 | --- CMakeLists.txt 2016-02-18 15:46:26 +0000 |
| 3 | +++ CMakeLists.txt 2016-03-16 11:17:35 +0000 |
| 4 | @@ -50,8 +50,8 @@ |
| 5 | find_package(Qt5Test) |
| 6 | find_package(Boost COMPONENTS regex REQUIRED) |
| 7 | |
| 8 | -pkg_check_modules(SCOPESLIB REQUIRED libunity-scopes>=1.0.1) |
| 9 | -pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=10) |
| 10 | +pkg_check_modules(SCOPESLIB REQUIRED libunity-scopes>=1.0.4) |
| 11 | +pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=11) |
| 12 | |
| 13 | pkg_check_modules(GSETTINGSQT REQUIRED gsettings-qt) |
| 14 | pkg_check_modules(UBUNTU_LOCATION_SERVICE REQUIRED ubuntu-location-service) |
| 15 | |
| 16 | === modified file 'debian/changelog' |
| 17 | --- debian/changelog 2016-02-26 12:38:34 +0000 |
| 18 | +++ debian/changelog 2016-03-16 11:17:35 +0000 |
| 19 | @@ -1,3 +1,9 @@ |
| 20 | +unity-scopes-shell (0.5.7-0ubuntu1) UNRELEASED; urgency=medium |
| 21 | + |
| 22 | + * Preliminary support for filters. |
| 23 | + |
| 24 | + -- Pawel Stolowski <pawel.stolowski@canonical.com> Fri, 30 Oct 2015 16:17:55 +0100 |
| 25 | + |
| 26 | unity-scopes-shell (0.5.6+16.04.20160226.1-0ubuntu1) xenial; urgency=medium |
| 27 | |
| 28 | [ CI Train Bot ] |
| 29 | @@ -104,10 +110,6 @@ |
| 30 | * Call parent class ::event (LP: #1495467) |
| 31 | * Improvements from running clazy over the code |
| 32 | |
| 33 | - [ CI Train Bot ] |
| 34 | - * Improvements from running clazy over the code |
| 35 | - * New rebuild forced. |
| 36 | - |
| 37 | -- Pawel Stolowski <ci-train-bot@canonical.com> Thu, 24 Sep 2015 12:44:30 +0000 |
| 38 | |
| 39 | unity-scopes-shell (0.5.5+15.10.20150922-0ubuntu1) wily; urgency=medium |
| 40 | |
| 41 | === modified file 'debian/control.in' |
| 42 | --- debian/control.in 2016-02-18 15:46:26 +0000 |
| 43 | +++ debian/control.in 2016-03-16 11:17:35 +0000 |
| 44 | @@ -8,8 +8,8 @@ |
| 45 | dh-python, |
| 46 | libboost-python-dev, |
| 47 | libboost-regex-dev, |
| 48 | - libunity-api-dev (>= 7.107), |
| 49 | - libunity-scopes-dev (>= 1.0.1~), |
| 50 | + libunity-api-dev (>= 7.108), |
| 51 | + libunity-scopes-dev (>= 1.0.4~), |
| 52 | libgsettings-qt-dev (>= 0.1), |
| 53 | libqtdbustest1-dev (>= 0.2), |
| 54 | libqtdbusmock1-dev (>= 0.2), |
| 55 | @@ -51,6 +51,7 @@ |
| 56 | unity-scopes-impl-8, |
| 57 | unity-scopes-impl-9, |
| 58 | unity-scopes-impl-10, |
| 59 | + unity-scopes-impl-11, |
| 60 | Breaks: unity8-private (<< 7.84), |
| 61 | unity8 (<< 8.11) |
| 62 | Replaces: unity8-private (<< 7.84) |
| 63 | |
| 64 | === modified file 'debian/libscope-harness.symbols.in' |
| 65 | --- debian/libscope-harness.symbols.in 2016-02-26 12:38:34 +0000 |
| 66 | +++ debian/libscope-harness.symbols.in 2016-03-16 11:17:35 +0000 |
| 67 | @@ -271,6 +271,7 @@ |
| 68 | (c++)"unity::scopeharness::TestUtils::throwIfNot(bool, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.5.4+15.04.20150311.3 |
| 69 | (c++)"unity::scopeharness::TestUtils::waitForResultsChange(QSharedPointer<unity::shell::scopes::ScopeInterface>)@Base" 0.5.4+15.04.20150311.3 |
| 70 | (c++)"unity::scopeharness::TestUtils::waitForSearchFinish(QSharedPointer<unity::shell::scopes::ScopeInterface>)@Base" 0.5.4+15.04.20150311.3 |
| 71 | + (c++)"unity::scopeharness::TestUtils::waitForFilterStateChange(QSharedPointer<unity::shell::scopes::ScopeInterface>)@Base" 0replaceme |
| 72 | (c++)"unity::scopeharness::view::AbstractView::~AbstractView()@Base" 0.5.4+15.04.20150311.3 |
| 73 | (c++)"unity::scopeharness::view::PreviewView::columnCount() const@Base" 0.5.4+15.04.20150311.3 |
| 74 | (c++)"unity::scopeharness::view::PreviewView::~PreviewView()@Base" 0.5.4+15.04.20150311.3 |
| 75 | |
| 76 | === modified file 'po/POTFILES.in' |
| 77 | --- po/POTFILES.in 2016-02-11 15:35:47 +0000 |
| 78 | +++ po/POTFILES.in 2016-03-16 11:17:35 +0000 |
| 79 | @@ -1,14 +1,18 @@ |
| 80 | tools/location/main.cpp |
| 81 | tests/resultstest.cpp |
| 82 | +tests/filterstest.cpp |
| 83 | tests/settingsendtoendtest.cpp |
| 84 | tests/utilstest.cpp |
| 85 | tests/previewtest.cpp |
| 86 | tests/overviewtest.cpp |
| 87 | tests/departmentstest.cpp |
| 88 | tests/locationtest.cpp |
| 89 | +tests/filtersendtoendtest.cpp |
| 90 | tests/favoritestest.cpp |
| 91 | +tests/optionselectorfiltertest.cpp |
| 92 | tests/data/scopes/scopes.cpp |
| 93 | tests/data/mock-scope-departments/mock-scope-departments.cpp |
| 94 | +tests/data/mock-scope-filters/mock-scope-filters.cpp |
| 95 | tests/data/mock-scope-ttl/mock-scope-ttl.cpp |
| 96 | tests/data/mock-scope-info/mock-scope-info.cpp |
| 97 | tests/data/mock-scope-departments-flipflop/mock-scope-departments-flipflop.cpp |
| 98 | @@ -71,8 +75,11 @@ |
| 99 | src/Unity/geoip.cpp |
| 100 | src/Unity/plugin.cpp |
| 101 | src/Unity/scopes.cpp |
| 102 | +src/Unity/filters.cpp |
| 103 | +src/Unity/optionselectoroptions.cpp |
| 104 | src/Unity/settingsmodel.cpp |
| 105 | src/Unity/utils.cpp |
| 106 | +src/Unity/optionselectorfilter.cpp |
| 107 | src/Unity/resultsmap.cpp |
| 108 | src/Unity/locationservice.cpp |
| 109 | src/Unity/ubuntulocationservice.cpp |
| 110 | @@ -117,7 +124,9 @@ |
| 111 | src/scope-harness/view/results-view.h |
| 112 | src/scope-harness/view/preview-view.h |
| 113 | src/scope-harness/view/abstract-view.h |
| 114 | +src/Unity/optionselectoroptions.h |
| 115 | src/Unity/iconutils.h |
| 116 | +src/Unity/optionselectorfilter.h |
| 117 | src/Unity/ubuntulocationservice.h |
| 118 | src/Unity/localization.h |
| 119 | src/Unity/previewmodel.h |
| 120 | @@ -126,8 +135,10 @@ |
| 121 | src/Unity/plugin.h |
| 122 | src/Unity/department.h |
| 123 | src/Unity/scope.h |
| 124 | +src/Unity/filters.h |
| 125 | src/Unity/logintoaccount.h |
| 126 | src/Unity/overviewcategories.h |
| 127 | +src/Unity/modelupdate.h |
| 128 | src/Unity/locationservice.h |
| 129 | src/Unity/overviewscope.h |
| 130 | src/Unity/settingsmodel.h |
| 131 | |
| 132 | === modified file 'po/am.po' |
| 133 | --- po/am.po 2016-03-05 06:20:25 +0000 |
| 134 | +++ po/am.po 2016-03-16 11:17:35 +0000 |
| 135 | @@ -6,11 +6,12 @@ |
| 136 | msgid "" |
| 137 | msgstr "" |
| 138 | "Project-Id-Version: unity-scopes-shell\n" |
| 139 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 140 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 141 | +"Report-Msgid-Bugs-To: \n" |
| 142 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 143 | "PO-Revision-Date: 2015-07-28 19:12+0000\n" |
| 144 | "Last-Translator: samson <Unknown>\n" |
| 145 | "Language-Team: Amharic <am@li.org>\n" |
| 146 | +"Language: am\n" |
| 147 | "MIME-Version: 1.0\n" |
| 148 | "Content-Type: text/plain; charset=UTF-8\n" |
| 149 | "Content-Transfer-Encoding: 8bit\n" |
| 150 | |
| 151 | === modified file 'po/ar.po' |
| 152 | --- po/ar.po 2016-03-05 06:20:25 +0000 |
| 153 | +++ po/ar.po 2016-03-16 11:17:35 +0000 |
| 154 | @@ -6,11 +6,12 @@ |
| 155 | msgid "" |
| 156 | msgstr "" |
| 157 | "Project-Id-Version: unity-scopes-shell\n" |
| 158 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 159 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 160 | +"Report-Msgid-Bugs-To: \n" |
| 161 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 162 | "PO-Revision-Date: 2015-07-18 12:07+0000\n" |
| 163 | "Last-Translator: Ibrahim Saed <ibraheem5000@gmail.com>\n" |
| 164 | "Language-Team: Arabic <ar@li.org>\n" |
| 165 | +"Language: ar\n" |
| 166 | "MIME-Version: 1.0\n" |
| 167 | "Content-Type: text/plain; charset=UTF-8\n" |
| 168 | "Content-Transfer-Encoding: 8bit\n" |
| 169 | |
| 170 | === modified file 'po/br.po' |
| 171 | --- po/br.po 2016-03-05 06:20:25 +0000 |
| 172 | +++ po/br.po 2016-03-16 11:17:35 +0000 |
| 173 | @@ -6,11 +6,12 @@ |
| 174 | msgid "" |
| 175 | msgstr "" |
| 176 | "Project-Id-Version: unity-scopes-shell\n" |
| 177 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 178 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 179 | +"Report-Msgid-Bugs-To: \n" |
| 180 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 181 | "PO-Revision-Date: 2015-07-16 12:51+0000\n" |
| 182 | "Last-Translator: Rouxel <vincent.rouxel@mailoo.org>\n" |
| 183 | "Language-Team: Breton <br@li.org>\n" |
| 184 | +"Language: br\n" |
| 185 | "MIME-Version: 1.0\n" |
| 186 | "Content-Type: text/plain; charset=UTF-8\n" |
| 187 | "Content-Transfer-Encoding: 8bit\n" |
| 188 | |
| 189 | === modified file 'po/ca.po' |
| 190 | --- po/ca.po 2016-03-05 06:20:25 +0000 |
| 191 | +++ po/ca.po 2016-03-16 11:17:35 +0000 |
| 192 | @@ -6,11 +6,12 @@ |
| 193 | msgid "" |
| 194 | msgstr "" |
| 195 | "Project-Id-Version: unity-scopes-shell\n" |
| 196 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 197 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 198 | +"Report-Msgid-Bugs-To: \n" |
| 199 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 200 | "PO-Revision-Date: 2015-07-16 05:42+0000\n" |
| 201 | "Last-Translator: David Planella <david.planella@ubuntu.com>\n" |
| 202 | "Language-Team: Catalan <ca@li.org>\n" |
| 203 | +"Language: ca\n" |
| 204 | "MIME-Version: 1.0\n" |
| 205 | "Content-Type: text/plain; charset=UTF-8\n" |
| 206 | "Content-Transfer-Encoding: 8bit\n" |
| 207 | |
| 208 | === modified file 'po/cs.po' |
| 209 | --- po/cs.po 2016-03-05 06:20:25 +0000 |
| 210 | +++ po/cs.po 2016-03-16 11:17:35 +0000 |
| 211 | @@ -6,11 +6,12 @@ |
| 212 | msgid "" |
| 213 | msgstr "" |
| 214 | "Project-Id-Version: unity-scopes-shell\n" |
| 215 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 216 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 217 | +"Report-Msgid-Bugs-To: \n" |
| 218 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 219 | "PO-Revision-Date: 2016-02-09 08:56+0000\n" |
| 220 | "Last-Translator: Vojtěch Daněk <vdanek@outlook.com>\n" |
| 221 | "Language-Team: Czech <cs@li.org>\n" |
| 222 | +"Language: cs\n" |
| 223 | "MIME-Version: 1.0\n" |
| 224 | "Content-Type: text/plain; charset=UTF-8\n" |
| 225 | "Content-Transfer-Encoding: 8bit\n" |
| 226 | |
| 227 | === modified file 'po/da.po' |
| 228 | --- po/da.po 2016-03-05 06:20:25 +0000 |
| 229 | +++ po/da.po 2016-03-16 11:17:35 +0000 |
| 230 | @@ -6,11 +6,12 @@ |
| 231 | msgid "" |
| 232 | msgstr "" |
| 233 | "Project-Id-Version: unity-scopes-shell\n" |
| 234 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 235 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 236 | +"Report-Msgid-Bugs-To: \n" |
| 237 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 238 | "PO-Revision-Date: 2015-06-03 19:27+0000\n" |
| 239 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
| 240 | "Language-Team: Danish <da@li.org>\n" |
| 241 | +"Language: da\n" |
| 242 | "MIME-Version: 1.0\n" |
| 243 | "Content-Type: text/plain; charset=UTF-8\n" |
| 244 | "Content-Transfer-Encoding: 8bit\n" |
| 245 | |
| 246 | === modified file 'po/de.po' |
| 247 | --- po/de.po 2016-03-05 06:20:25 +0000 |
| 248 | +++ po/de.po 2016-03-16 11:17:35 +0000 |
| 249 | @@ -6,11 +6,12 @@ |
| 250 | msgid "" |
| 251 | msgstr "" |
| 252 | "Project-Id-Version: unity-scopes-shell\n" |
| 253 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 254 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 255 | +"Report-Msgid-Bugs-To: \n" |
| 256 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 257 | "PO-Revision-Date: 2015-07-19 19:11+0000\n" |
| 258 | "Last-Translator: Phillip Sz <Unknown>\n" |
| 259 | "Language-Team: German <de@li.org>\n" |
| 260 | +"Language: de\n" |
| 261 | "MIME-Version: 1.0\n" |
| 262 | "Content-Type: text/plain; charset=UTF-8\n" |
| 263 | "Content-Transfer-Encoding: 8bit\n" |
| 264 | |
| 265 | === modified file 'po/el.po' |
| 266 | --- po/el.po 2016-03-05 06:20:25 +0000 |
| 267 | +++ po/el.po 2016-03-16 11:17:35 +0000 |
| 268 | @@ -6,11 +6,12 @@ |
| 269 | msgid "" |
| 270 | msgstr "" |
| 271 | "Project-Id-Version: unity-scopes-shell\n" |
| 272 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 273 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 274 | +"Report-Msgid-Bugs-To: \n" |
| 275 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 276 | "PO-Revision-Date: 2015-07-16 09:19+0000\n" |
| 277 | "Last-Translator: Simos Xenitellis <Unknown>\n" |
| 278 | "Language-Team: Greek <el@li.org>\n" |
| 279 | +"Language: el\n" |
| 280 | "MIME-Version: 1.0\n" |
| 281 | "Content-Type: text/plain; charset=UTF-8\n" |
| 282 | "Content-Transfer-Encoding: 8bit\n" |
| 283 | |
| 284 | === modified file 'po/en_GB.po' |
| 285 | --- po/en_GB.po 2016-03-05 06:20:25 +0000 |
| 286 | +++ po/en_GB.po 2016-03-16 11:17:35 +0000 |
| 287 | @@ -6,11 +6,12 @@ |
| 288 | msgid "" |
| 289 | msgstr "" |
| 290 | "Project-Id-Version: unity-scopes-shell\n" |
| 291 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 292 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 293 | +"Report-Msgid-Bugs-To: \n" |
| 294 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 295 | "PO-Revision-Date: 2016-02-03 11:21+0000\n" |
| 296 | "Last-Translator: James Tait <Unknown>\n" |
| 297 | "Language-Team: English (United Kingdom) <en_GB@li.org>\n" |
| 298 | +"Language: \n" |
| 299 | "MIME-Version: 1.0\n" |
| 300 | "Content-Type: text/plain; charset=UTF-8\n" |
| 301 | "Content-Transfer-Encoding: 8bit\n" |
| 302 | |
| 303 | === modified file 'po/eo.po' |
| 304 | --- po/eo.po 2016-03-05 06:20:25 +0000 |
| 305 | +++ po/eo.po 2016-03-16 11:17:35 +0000 |
| 306 | @@ -6,11 +6,12 @@ |
| 307 | msgid "" |
| 308 | msgstr "" |
| 309 | "Project-Id-Version: unity-scopes-shell\n" |
| 310 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 311 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 312 | +"Report-Msgid-Bugs-To: \n" |
| 313 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 314 | "PO-Revision-Date: 2015-07-16 09:53+0000\n" |
| 315 | "Last-Translator: Adolfo Jayme <fitoschido@gmail.com>\n" |
| 316 | "Language-Team: Esperanto <eo@li.org>\n" |
| 317 | +"Language: eo\n" |
| 318 | "MIME-Version: 1.0\n" |
| 319 | "Content-Type: text/plain; charset=UTF-8\n" |
| 320 | "Content-Transfer-Encoding: 8bit\n" |
| 321 | |
| 322 | === modified file 'po/es.po' |
| 323 | --- po/es.po 2016-03-05 06:20:25 +0000 |
| 324 | +++ po/es.po 2016-03-16 11:17:35 +0000 |
| 325 | @@ -6,11 +6,12 @@ |
| 326 | msgid "" |
| 327 | msgstr "" |
| 328 | "Project-Id-Version: unity-scopes-shell\n" |
| 329 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 330 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 331 | +"Report-Msgid-Bugs-To: \n" |
| 332 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 333 | "PO-Revision-Date: 2015-07-16 09:48+0000\n" |
| 334 | "Last-Translator: Adolfo Jayme <fitoschido@gmail.com>\n" |
| 335 | "Language-Team: Spanish <es@li.org>\n" |
| 336 | +"Language: es\n" |
| 337 | "MIME-Version: 1.0\n" |
| 338 | "Content-Type: text/plain; charset=UTF-8\n" |
| 339 | "Content-Transfer-Encoding: 8bit\n" |
| 340 | |
| 341 | === modified file 'po/eu.po' |
| 342 | --- po/eu.po 2016-03-05 06:20:25 +0000 |
| 343 | +++ po/eu.po 2016-03-16 11:17:35 +0000 |
| 344 | @@ -6,11 +6,12 @@ |
| 345 | msgid "" |
| 346 | msgstr "" |
| 347 | "Project-Id-Version: unity-scopes-shell\n" |
| 348 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 349 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 350 | +"Report-Msgid-Bugs-To: \n" |
| 351 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 352 | "PO-Revision-Date: 2015-07-16 07:02+0000\n" |
| 353 | "Last-Translator: Ibai Oihanguren Sala <Unknown>\n" |
| 354 | "Language-Team: Basque <eu@li.org>\n" |
| 355 | +"Language: eu\n" |
| 356 | "MIME-Version: 1.0\n" |
| 357 | "Content-Type: text/plain; charset=UTF-8\n" |
| 358 | "Content-Transfer-Encoding: 8bit\n" |
| 359 | |
| 360 | === modified file 'po/fa.po' |
| 361 | --- po/fa.po 2016-03-05 06:20:25 +0000 |
| 362 | +++ po/fa.po 2016-03-16 11:17:35 +0000 |
| 363 | @@ -6,11 +6,12 @@ |
| 364 | msgid "" |
| 365 | msgstr "" |
| 366 | "Project-Id-Version: unity-scopes-shell\n" |
| 367 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 368 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 369 | +"Report-Msgid-Bugs-To: \n" |
| 370 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 371 | "PO-Revision-Date: 2015-07-16 12:38+0000\n" |
| 372 | "Last-Translator: Danial Behzadi <dani.behzi@gmail.com>\n" |
| 373 | "Language-Team: Persian <fa@li.org>\n" |
| 374 | +"Language: fa\n" |
| 375 | "MIME-Version: 1.0\n" |
| 376 | "Content-Type: text/plain; charset=UTF-8\n" |
| 377 | "Content-Transfer-Encoding: 8bit\n" |
| 378 | |
| 379 | === modified file 'po/fi.po' |
| 380 | --- po/fi.po 2016-03-05 06:20:25 +0000 |
| 381 | +++ po/fi.po 2016-03-16 11:17:35 +0000 |
| 382 | @@ -6,11 +6,12 @@ |
| 383 | msgid "" |
| 384 | msgstr "" |
| 385 | "Project-Id-Version: unity-scopes-shell\n" |
| 386 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 387 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 388 | +"Report-Msgid-Bugs-To: \n" |
| 389 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 390 | "PO-Revision-Date: 2015-07-16 07:13+0000\n" |
| 391 | "Last-Translator: Jiri Grönroos <Unknown>\n" |
| 392 | "Language-Team: Finnish <fi@li.org>\n" |
| 393 | +"Language: fi\n" |
| 394 | "MIME-Version: 1.0\n" |
| 395 | "Content-Type: text/plain; charset=UTF-8\n" |
| 396 | "Content-Transfer-Encoding: 8bit\n" |
| 397 | |
| 398 | === modified file 'po/fr.po' |
| 399 | --- po/fr.po 2016-03-05 06:20:25 +0000 |
| 400 | +++ po/fr.po 2016-03-16 11:17:35 +0000 |
| 401 | @@ -6,11 +6,12 @@ |
| 402 | msgid "" |
| 403 | msgstr "" |
| 404 | "Project-Id-Version: unity-scopes-shell\n" |
| 405 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 406 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 407 | +"Report-Msgid-Bugs-To: \n" |
| 408 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 409 | "PO-Revision-Date: 2015-07-17 11:19+0000\n" |
| 410 | "Last-Translator: Nicolas Delvaux <Unknown>\n" |
| 411 | "Language-Team: French <fr@li.org>\n" |
| 412 | +"Language: fr\n" |
| 413 | "MIME-Version: 1.0\n" |
| 414 | "Content-Type: text/plain; charset=UTF-8\n" |
| 415 | "Content-Transfer-Encoding: 8bit\n" |
| 416 | |
| 417 | === modified file 'po/gd.po' |
| 418 | --- po/gd.po 2016-03-05 06:20:25 +0000 |
| 419 | +++ po/gd.po 2016-03-16 11:17:35 +0000 |
| 420 | @@ -6,11 +6,12 @@ |
| 421 | msgid "" |
| 422 | msgstr "" |
| 423 | "Project-Id-Version: unity-scopes-shell\n" |
| 424 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 425 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 426 | +"Report-Msgid-Bugs-To: \n" |
| 427 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 428 | "PO-Revision-Date: 2015-06-17 14:57+0000\n" |
| 429 | "Last-Translator: GunChleoc <Unknown>\n" |
| 430 | "Language-Team: Gaelic; Scottish <gd@li.org>\n" |
| 431 | +"Language: \n" |
| 432 | "MIME-Version: 1.0\n" |
| 433 | "Content-Type: text/plain; charset=UTF-8\n" |
| 434 | "Content-Transfer-Encoding: 8bit\n" |
| 435 | |
| 436 | === modified file 'po/gl.po' |
| 437 | --- po/gl.po 2016-03-05 06:20:25 +0000 |
| 438 | +++ po/gl.po 2016-03-16 11:17:35 +0000 |
| 439 | @@ -6,11 +6,12 @@ |
| 440 | msgid "" |
| 441 | msgstr "" |
| 442 | "Project-Id-Version: unity-scopes-shell\n" |
| 443 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 444 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 445 | +"Report-Msgid-Bugs-To: \n" |
| 446 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 447 | "PO-Revision-Date: 2015-07-16 09:18+0000\n" |
| 448 | "Last-Translator: Marcos Lans <Unknown>\n" |
| 449 | "Language-Team: Galician <gl@li.org>\n" |
| 450 | +"Language: gl\n" |
| 451 | "MIME-Version: 1.0\n" |
| 452 | "Content-Type: text/plain; charset=UTF-8\n" |
| 453 | "Content-Transfer-Encoding: 8bit\n" |
| 454 | |
| 455 | === modified file 'po/hu.po' |
| 456 | --- po/hu.po 2016-03-05 06:20:25 +0000 |
| 457 | +++ po/hu.po 2016-03-16 11:17:35 +0000 |
| 458 | @@ -6,11 +6,12 @@ |
| 459 | msgid "" |
| 460 | msgstr "" |
| 461 | "Project-Id-Version: unity-scopes-shell\n" |
| 462 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 463 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 464 | +"Report-Msgid-Bugs-To: \n" |
| 465 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 466 | "PO-Revision-Date: 2015-07-16 06:19+0000\n" |
| 467 | "Last-Translator: Richard Somlói <ricsipontaz@gmail.com>\n" |
| 468 | "Language-Team: Hungarian <hu@li.org>\n" |
| 469 | +"Language: hu\n" |
| 470 | "MIME-Version: 1.0\n" |
| 471 | "Content-Type: text/plain; charset=UTF-8\n" |
| 472 | "Content-Transfer-Encoding: 8bit\n" |
| 473 | |
| 474 | === modified file 'po/it.po' |
| 475 | --- po/it.po 2016-03-05 06:20:25 +0000 |
| 476 | +++ po/it.po 2016-03-16 11:17:35 +0000 |
| 477 | @@ -6,11 +6,12 @@ |
| 478 | msgid "" |
| 479 | msgstr "" |
| 480 | "Project-Id-Version: unity-scopes-shell\n" |
| 481 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 482 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 483 | +"Report-Msgid-Bugs-To: \n" |
| 484 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 485 | "PO-Revision-Date: 2015-07-16 06:11+0000\n" |
| 486 | "Last-Translator: Milo Casagrande <milo.casagrande@gmail.com>\n" |
| 487 | "Language-Team: Italian <it@li.org>\n" |
| 488 | +"Language: it\n" |
| 489 | "MIME-Version: 1.0\n" |
| 490 | "Content-Type: text/plain; charset=UTF-8\n" |
| 491 | "Content-Transfer-Encoding: 8bit\n" |
| 492 | |
| 493 | === modified file 'po/ja.po' |
| 494 | --- po/ja.po 2016-03-05 06:20:25 +0000 |
| 495 | +++ po/ja.po 2016-03-16 11:17:35 +0000 |
| 496 | @@ -6,11 +6,12 @@ |
| 497 | msgid "" |
| 498 | msgstr "" |
| 499 | "Project-Id-Version: unity-scopes-shell\n" |
| 500 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 501 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 502 | +"Report-Msgid-Bugs-To: \n" |
| 503 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 504 | "PO-Revision-Date: 2015-07-16 07:23+0000\n" |
| 505 | "Last-Translator: Mitsuya Shibata <mty.shibata@gmail.com>\n" |
| 506 | "Language-Team: Japanese <ja@li.org>\n" |
| 507 | +"Language: ja\n" |
| 508 | "MIME-Version: 1.0\n" |
| 509 | "Content-Type: text/plain; charset=UTF-8\n" |
| 510 | "Content-Transfer-Encoding: 8bit\n" |
| 511 | |
| 512 | === modified file 'po/nb.po' |
| 513 | --- po/nb.po 2016-03-05 06:20:25 +0000 |
| 514 | +++ po/nb.po 2016-03-16 11:17:35 +0000 |
| 515 | @@ -6,11 +6,12 @@ |
| 516 | msgid "" |
| 517 | msgstr "" |
| 518 | "Project-Id-Version: unity-scopes-shell\n" |
| 519 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 520 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 521 | +"Report-Msgid-Bugs-To: \n" |
| 522 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 523 | "PO-Revision-Date: 2015-07-16 10:49+0000\n" |
| 524 | "Last-Translator: Åka Sikrom <Unknown>\n" |
| 525 | "Language-Team: Norwegian Bokmal <nb@li.org>\n" |
| 526 | +"Language: nb\n" |
| 527 | "MIME-Version: 1.0\n" |
| 528 | "Content-Type: text/plain; charset=UTF-8\n" |
| 529 | "Content-Transfer-Encoding: 8bit\n" |
| 530 | |
| 531 | === modified file 'po/nl.po' |
| 532 | --- po/nl.po 2016-03-05 06:20:25 +0000 |
| 533 | +++ po/nl.po 2016-03-16 11:17:35 +0000 |
| 534 | @@ -6,11 +6,12 @@ |
| 535 | msgid "" |
| 536 | msgstr "" |
| 537 | "Project-Id-Version: unity-scopes-shell\n" |
| 538 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 539 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 540 | +"Report-Msgid-Bugs-To: \n" |
| 541 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 542 | "PO-Revision-Date: 2015-07-16 14:53+0000\n" |
| 543 | "Last-Translator: Hannie Dumoleyn <Unknown>\n" |
| 544 | "Language-Team: Dutch <nl@li.org>\n" |
| 545 | +"Language: nl\n" |
| 546 | "MIME-Version: 1.0\n" |
| 547 | "Content-Type: text/plain; charset=UTF-8\n" |
| 548 | "Content-Transfer-Encoding: 8bit\n" |
| 549 | |
| 550 | === modified file 'po/pl.po' |
| 551 | --- po/pl.po 2016-03-05 06:20:25 +0000 |
| 552 | +++ po/pl.po 2016-03-16 11:17:35 +0000 |
| 553 | @@ -6,11 +6,12 @@ |
| 554 | msgid "" |
| 555 | msgstr "" |
| 556 | "Project-Id-Version: unity-scopes-shell\n" |
| 557 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 558 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 559 | +"Report-Msgid-Bugs-To: \n" |
| 560 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 561 | "PO-Revision-Date: 2015-07-30 15:26+0000\n" |
| 562 | "Last-Translator: Krzysztof Tataradziński <Unknown>\n" |
| 563 | "Language-Team: Polish <pl@li.org>\n" |
| 564 | +"Language: pl\n" |
| 565 | "MIME-Version: 1.0\n" |
| 566 | "Content-Type: text/plain; charset=UTF-8\n" |
| 567 | "Content-Transfer-Encoding: 8bit\n" |
| 568 | |
| 569 | === modified file 'po/pt.po' |
| 570 | --- po/pt.po 2016-03-05 06:20:25 +0000 |
| 571 | +++ po/pt.po 2016-03-16 11:17:35 +0000 |
| 572 | @@ -6,11 +6,12 @@ |
| 573 | msgid "" |
| 574 | msgstr "" |
| 575 | "Project-Id-Version: unity-scopes-shell\n" |
| 576 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 577 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 578 | +"Report-Msgid-Bugs-To: \n" |
| 579 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 580 | "PO-Revision-Date: 2015-07-29 10:01+0000\n" |
| 581 | "Last-Translator: Ivo Xavier <ivofernandes12@gmail.com>\n" |
| 582 | "Language-Team: Portuguese <pt@li.org>\n" |
| 583 | +"Language: pt\n" |
| 584 | "MIME-Version: 1.0\n" |
| 585 | "Content-Type: text/plain; charset=UTF-8\n" |
| 586 | "Content-Transfer-Encoding: 8bit\n" |
| 587 | |
| 588 | === modified file 'po/pt_BR.po' |
| 589 | --- po/pt_BR.po 2016-03-05 06:20:25 +0000 |
| 590 | +++ po/pt_BR.po 2016-03-16 11:17:35 +0000 |
| 591 | @@ -6,11 +6,12 @@ |
| 592 | msgid "" |
| 593 | msgstr "" |
| 594 | "Project-Id-Version: unity-scopes-shell\n" |
| 595 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 596 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 597 | +"Report-Msgid-Bugs-To: \n" |
| 598 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 599 | "PO-Revision-Date: 2015-08-05 04:40+0000\n" |
| 600 | "Last-Translator: Tiago Hillebrandt <tiagohillebrandt@gmail.com>\n" |
| 601 | "Language-Team: Brazilian Portuguese <pt_BR@li.org>\n" |
| 602 | +"Language: pt_BR\n" |
| 603 | "MIME-Version: 1.0\n" |
| 604 | "Content-Type: text/plain; charset=UTF-8\n" |
| 605 | "Content-Transfer-Encoding: 8bit\n" |
| 606 | |
| 607 | === modified file 'po/ru.po' |
| 608 | --- po/ru.po 2016-03-05 06:20:25 +0000 |
| 609 | +++ po/ru.po 2016-03-16 11:17:35 +0000 |
| 610 | @@ -6,11 +6,12 @@ |
| 611 | msgid "" |
| 612 | msgstr "" |
| 613 | "Project-Id-Version: unity-scopes-shell\n" |
| 614 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 615 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 616 | +"Report-Msgid-Bugs-To: \n" |
| 617 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 618 | "PO-Revision-Date: 2015-07-16 05:57+0000\n" |
| 619 | "Last-Translator: ☠Jay ZDLin☠ <Unknown>\n" |
| 620 | "Language-Team: Russian <ru@li.org>\n" |
| 621 | +"Language: ru\n" |
| 622 | "MIME-Version: 1.0\n" |
| 623 | "Content-Type: text/plain; charset=UTF-8\n" |
| 624 | "Content-Transfer-Encoding: 8bit\n" |
| 625 | |
| 626 | === modified file 'po/sl.po' |
| 627 | --- po/sl.po 2016-03-05 06:20:25 +0000 |
| 628 | +++ po/sl.po 2016-03-16 11:17:35 +0000 |
| 629 | @@ -6,11 +6,12 @@ |
| 630 | msgid "" |
| 631 | msgstr "" |
| 632 | "Project-Id-Version: unity-scopes-shell\n" |
| 633 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 634 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 635 | +"Report-Msgid-Bugs-To: \n" |
| 636 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 637 | "PO-Revision-Date: 2015-07-20 05:29+0000\n" |
| 638 | "Last-Translator: Sasa Batistic <Unknown>\n" |
| 639 | "Language-Team: Slovenian <sl@li.org>\n" |
| 640 | +"Language: sl\n" |
| 641 | "MIME-Version: 1.0\n" |
| 642 | "Content-Type: text/plain; charset=UTF-8\n" |
| 643 | "Content-Transfer-Encoding: 8bit\n" |
| 644 | |
| 645 | === modified file 'po/sv.po' |
| 646 | --- po/sv.po 2016-03-05 06:20:25 +0000 |
| 647 | +++ po/sv.po 2016-03-16 11:17:35 +0000 |
| 648 | @@ -6,11 +6,12 @@ |
| 649 | msgid "" |
| 650 | msgstr "" |
| 651 | "Project-Id-Version: unity-scopes-shell\n" |
| 652 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 653 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 654 | +"Report-Msgid-Bugs-To: \n" |
| 655 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 656 | "PO-Revision-Date: 2015-08-05 08:33+0000\n" |
| 657 | "Last-Translator: Josef Andersson <Unknown>\n" |
| 658 | "Language-Team: Swedish <sv@li.org>\n" |
| 659 | +"Language: sv\n" |
| 660 | "MIME-Version: 1.0\n" |
| 661 | "Content-Type: text/plain; charset=UTF-8\n" |
| 662 | "Content-Transfer-Encoding: 8bit\n" |
| 663 | |
| 664 | === modified file 'po/ta.po' |
| 665 | --- po/ta.po 2016-03-05 06:20:25 +0000 |
| 666 | +++ po/ta.po 2016-03-16 11:17:35 +0000 |
| 667 | @@ -6,11 +6,12 @@ |
| 668 | msgid "" |
| 669 | msgstr "" |
| 670 | "Project-Id-Version: unity-scopes-shell\n" |
| 671 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 672 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 673 | +"Report-Msgid-Bugs-To: \n" |
| 674 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 675 | "PO-Revision-Date: 2015-07-16 08:52+0000\n" |
| 676 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
| 677 | "Language-Team: Tamil <ta@li.org>\n" |
| 678 | +"Language: ta\n" |
| 679 | "MIME-Version: 1.0\n" |
| 680 | "Content-Type: text/plain; charset=UTF-8\n" |
| 681 | "Content-Transfer-Encoding: 8bit\n" |
| 682 | |
| 683 | === modified file 'po/uk.po' |
| 684 | --- po/uk.po 2016-03-05 06:20:25 +0000 |
| 685 | +++ po/uk.po 2016-03-16 11:17:35 +0000 |
| 686 | @@ -6,11 +6,12 @@ |
| 687 | msgid "" |
| 688 | msgstr "" |
| 689 | "Project-Id-Version: unity-scopes-shell\n" |
| 690 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 691 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 692 | +"Report-Msgid-Bugs-To: \n" |
| 693 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 694 | "PO-Revision-Date: 2016-02-08 18:50+0000\n" |
| 695 | "Last-Translator: Yuri Chornoivan <yurchor@gmail.com>\n" |
| 696 | "Language-Team: Ukrainian <uk@li.org>\n" |
| 697 | +"Language: uk\n" |
| 698 | "MIME-Version: 1.0\n" |
| 699 | "Content-Type: text/plain; charset=UTF-8\n" |
| 700 | "Content-Transfer-Encoding: 8bit\n" |
| 701 | |
| 702 | === modified file 'po/unity-plugin-scopes.pot' |
| 703 | --- po/unity-plugin-scopes.pot 2015-09-28 08:41:08 +0000 |
| 704 | +++ po/unity-plugin-scopes.pot 2016-03-16 11:17:35 +0000 |
| 705 | @@ -8,7 +8,7 @@ |
| 706 | msgstr "" |
| 707 | "Project-Id-Version: PACKAGE VERSION\n" |
| 708 | "Report-Msgid-Bugs-To: \n" |
| 709 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 710 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 711 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
| 712 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
| 713 | "Language-Team: LANGUAGE <LL@li.org>\n" |
| 714 | |
| 715 | === modified file 'po/zh_TW.po' |
| 716 | --- po/zh_TW.po 2016-03-05 06:20:25 +0000 |
| 717 | +++ po/zh_TW.po 2016-03-16 11:17:35 +0000 |
| 718 | @@ -6,11 +6,12 @@ |
| 719 | msgid "" |
| 720 | msgstr "" |
| 721 | "Project-Id-Version: unity-scopes-shell\n" |
| 722 | -"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
| 723 | -"POT-Creation-Date: 2015-09-28 08:40+0000\n" |
| 724 | +"Report-Msgid-Bugs-To: \n" |
| 725 | +"POT-Creation-Date: 2015-09-01 10:42+0000\n" |
| 726 | "PO-Revision-Date: 2015-10-21 05:47+0000\n" |
| 727 | "Last-Translator: Rex Tsai <rex.tsai@canonical.com>\n" |
| 728 | "Language-Team: Chinese (Traditional) <zh_TW@li.org>\n" |
| 729 | +"Language: \n" |
| 730 | "MIME-Version: 1.0\n" |
| 731 | "Content-Type: text/plain; charset=UTF-8\n" |
| 732 | "Content-Transfer-Encoding: 8bit\n" |
| 733 | |
| 734 | === modified file 'src/Unity/CMakeLists.txt' |
| 735 | --- src/Unity/CMakeLists.txt 2016-02-11 15:35:47 +0000 |
| 736 | +++ src/Unity/CMakeLists.txt 2016-03-16 11:17:35 +0000 |
| 737 | @@ -20,6 +20,12 @@ |
| 738 | collectors.cpp |
| 739 | department.cpp |
| 740 | departmentnode.cpp |
| 741 | + filters.cpp |
| 742 | + optionselectorfilter.cpp |
| 743 | + optionselectoroptions.cpp |
| 744 | + rangeinputfilter.cpp |
| 745 | + valuesliderfilter.cpp |
| 746 | + valueslidervalues.cpp |
| 747 | geoip.cpp |
| 748 | localization.h |
| 749 | locationservice.cpp |
| 750 | @@ -39,6 +45,13 @@ |
| 751 | logintoaccount.cpp |
| 752 | # We need these headers here so moc runs and we get the moc-stuff |
| 753 | # compiled in, otherwise we miss some symbols |
| 754 | + ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/FiltersInterface.h |
| 755 | + ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/FilterBaseInterface.h |
| 756 | + ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/OptionSelectorFilterInterface.h |
| 757 | + ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/OptionSelectorOptionsInterface.h |
| 758 | + ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/RangeInputFilterInterface.h |
| 759 | + ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/ValueSliderFilterInterface.h |
| 760 | + ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/ValueSliderValuesInterface.h |
| 761 | ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/CategoriesInterface.h |
| 762 | ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/NavigationInterface.h |
| 763 | ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewModelInterface.h |
| 764 | |
| 765 | === modified file 'src/Unity/collectors.cpp' |
| 766 | --- src/Unity/collectors.cpp 2015-10-05 12:29:55 +0000 |
| 767 | +++ src/Unity/collectors.cpp 2016-03-16 11:17:35 +0000 |
| 768 | @@ -142,19 +142,13 @@ |
| 769 | m_rootDepartment = department; |
| 770 | } |
| 771 | |
| 772 | - void setSortOrder(scopes::OptionSelectorFilter::SCPtr const& sortOrder) |
| 773 | - { |
| 774 | - QMutexLocker locker(&m_mutex); |
| 775 | - m_sortOrderFilter = sortOrder; |
| 776 | - } |
| 777 | - |
| 778 | - void setFilterState(scopes::FilterState const& state) |
| 779 | - { |
| 780 | - QMutexLocker locker(&m_mutex); |
| 781 | - m_filterState = state; |
| 782 | - } |
| 783 | - |
| 784 | - Status collect(QList<scopes::CategorisedResult::SPtr>& out_results, scopes::Department::SCPtr& out_rootDepartment, scopes::OptionSelectorFilter::SCPtr& out_sortOrder, scopes::FilterState& out_filterState) |
| 785 | + void addFilter(scopes::FilterBase::SCPtr const& filter) |
| 786 | + { |
| 787 | + QMutexLocker locker(&m_mutex); |
| 788 | + m_filters.append(filter); |
| 789 | + } |
| 790 | + |
| 791 | + Status collect(QList<scopes::CategorisedResult::SPtr>& out_results, scopes::Department::SCPtr& out_rootDepartment, QList<scopes::FilterBase::SCPtr>& out_filters) |
| 792 | { |
| 793 | Status status; |
| 794 | |
| 795 | @@ -167,8 +161,7 @@ |
| 796 | m_results.swap(out_results); |
| 797 | out_rootDepartment = m_rootDepartment; |
| 798 | |
| 799 | - out_sortOrder = m_sortOrderFilter; |
| 800 | - out_filterState = m_filterState; |
| 801 | + out_filters = m_filters; |
| 802 | |
| 803 | return status; |
| 804 | } |
| 805 | @@ -176,8 +169,7 @@ |
| 806 | private: |
| 807 | QList<scopes::CategorisedResult::SPtr> m_results; |
| 808 | scopes::Department::SCPtr m_rootDepartment; |
| 809 | - scopes::OptionSelectorFilter::SCPtr m_sortOrderFilter; |
| 810 | - scopes::FilterState m_filterState; |
| 811 | + QList<scopes::FilterBase::SCPtr> m_filters; |
| 812 | }; |
| 813 | |
| 814 | class PreviewDataCollector: public CollectorBase |
| 815 | @@ -292,10 +284,11 @@ |
| 816 | return m_collector->msecsSinceStart(); |
| 817 | } |
| 818 | |
| 819 | -CollectorBase::Status PushEvent::collectSearchResults(QList<scopes::CategorisedResult::SPtr>& out_results, scopes::Department::SCPtr& rootDepartment, scopes::OptionSelectorFilter::SCPtr& sortOrder, scopes::FilterState& filterState) |
| 820 | +CollectorBase::Status PushEvent::collectSearchResults(QList<scopes::CategorisedResult::SPtr>& out_results, scopes::Department::SCPtr& rootDepartment, |
| 821 | + QList<scopes::FilterBase::SCPtr>& out_filters) |
| 822 | { |
| 823 | auto collector = std::dynamic_pointer_cast<SearchDataCollector>(m_collector); |
| 824 | - return collector->collect(out_results, rootDepartment, sortOrder, filterState); |
| 825 | + return collector->collect(out_results, rootDepartment, out_filters); |
| 826 | } |
| 827 | |
| 828 | CollectorBase::Status PushEvent::collectPreviewData(scopes::ColumnLayoutList& out_columns, scopes::PreviewWidgetList& out_widgets, QHash<QString, QVariant>& out_data) |
| 829 | @@ -358,21 +351,12 @@ |
| 830 | m_collector->setDepartment(department); |
| 831 | } |
| 832 | |
| 833 | -void SearchResultReceiver::push(scopes::Filters const& filters, scopes::FilterState const& state) |
| 834 | +void SearchResultReceiver::push(scopes::Filters const& filters, scopes::FilterState const& /* state */) |
| 835 | { |
| 836 | for (auto it = filters.begin(); it != filters.end(); ++it) { |
| 837 | scopes::FilterBase::SCPtr filter = *it; |
| 838 | - if (filter->display_hints() == scopes::FilterBase::DisplayHints::Primary) { |
| 839 | - scopes::OptionSelectorFilter::SCPtr option_filter = std::dynamic_pointer_cast<const scopes::OptionSelectorFilter>(filter); |
| 840 | - if (!option_filter) { |
| 841 | - continue; |
| 842 | - } else { |
| 843 | - m_collector->setSortOrder(option_filter); |
| 844 | - break; |
| 845 | - } |
| 846 | - } |
| 847 | + m_collector->addFilter(filter); |
| 848 | } |
| 849 | - m_collector->setFilterState(state); |
| 850 | } |
| 851 | |
| 852 | // this might be called from any thread (might be main, might be any other thread) |
| 853 | |
| 854 | === modified file 'src/Unity/collectors.h' |
| 855 | --- src/Unity/collectors.h 2016-02-17 16:32:49 +0000 |
| 856 | +++ src/Unity/collectors.h 2016-03-16 11:17:35 +0000 |
| 857 | @@ -76,7 +76,8 @@ |
| 858 | PushEvent(Type event_type, const std::shared_ptr<CollectorBase>& collector); |
| 859 | Type type(); |
| 860 | |
| 861 | - CollectorBase::Status collectSearchResults(QList<std::shared_ptr<unity::scopes::CategorisedResult>>& out_results, unity::scopes::Department::SCPtr& out_rootDepartment, unity::scopes::OptionSelectorFilter::SCPtr& out_sortOrder, unity::scopes::FilterState& out_filterState); |
| 862 | + CollectorBase::Status collectSearchResults(QList<std::shared_ptr<unity::scopes::CategorisedResult>>& out_results, unity::scopes::Department::SCPtr& |
| 863 | + out_rootDepartment, QList<unity::scopes::FilterBase::SCPtr>& out_filters); |
| 864 | CollectorBase::Status collectPreviewData(unity::scopes::ColumnLayoutList& out_columns, unity::scopes::PreviewWidgetList& out_widgets, QHash<QString, QVariant>& out_data); |
| 865 | CollectorBase::Status collectActivationResponse(std::shared_ptr<unity::scopes::ActivationResponse>& out_response, std::shared_ptr<unity::scopes::Result>& |
| 866 | out_result, QString& categoryId); |
| 867 | |
| 868 | === modified file 'src/Unity/department.cpp' |
| 869 | --- src/Unity/department.cpp 2015-09-08 12:32:05 +0000 |
| 870 | +++ src/Unity/department.cpp 2016-03-16 11:17:35 +0000 |
| 871 | @@ -65,6 +65,7 @@ |
| 872 | QSharedPointer<SubdepartmentData> subdept(new SubdepartmentData); |
| 873 | subdept->id = node->id(); |
| 874 | subdept->label = node->label(); |
| 875 | + subdept->allLabel = node->allLabel(); |
| 876 | subdept->hasChildren = node->hasSubdepartments(); |
| 877 | subdept->isActive = false; |
| 878 | m_subdepartments.append(subdept); |
| 879 | @@ -122,12 +123,23 @@ |
| 880 | switch (role) { |
| 881 | case RoleNavigationId: return data->id; |
| 882 | case RoleLabel: return data->label; |
| 883 | + case RoleAllLabel: return data->allLabel; |
| 884 | case RoleHasChildren: return data->hasChildren; |
| 885 | case RoleIsActive: return data->isActive; |
| 886 | default: return QVariant(); |
| 887 | } |
| 888 | } |
| 889 | |
| 890 | +QSharedPointer<SubdepartmentData> Department::findSubdepartment(const QString &id) const |
| 891 | +{ |
| 892 | + for (auto sub: m_subdepartments) { |
| 893 | + if (sub->id == id) { |
| 894 | + return sub; |
| 895 | + } |
| 896 | + } |
| 897 | + return QSharedPointer<SubdepartmentData>(); |
| 898 | +} |
| 899 | + |
| 900 | int Department::rowCount(const QModelIndex& parent) const |
| 901 | { |
| 902 | Q_UNUSED(parent); |
| 903 | |
| 904 | === modified file 'src/Unity/department.h' |
| 905 | --- src/Unity/department.h 2014-08-04 15:06:55 +0000 |
| 906 | +++ src/Unity/department.h 2016-03-16 11:17:35 +0000 |
| 907 | @@ -40,6 +40,7 @@ |
| 908 | { |
| 909 | QString id; |
| 910 | QString label; |
| 911 | + QString allLabel; |
| 912 | bool hasChildren; |
| 913 | bool isActive; |
| 914 | }; |
| 915 | @@ -67,6 +68,8 @@ |
| 916 | bool hidden() const override; |
| 917 | int count() const override; |
| 918 | |
| 919 | + QSharedPointer<SubdepartmentData> findSubdepartment(const QString &id) const; |
| 920 | + |
| 921 | Q_SIGNALS: |
| 922 | |
| 923 | private: |
| 924 | |
| 925 | === added file 'src/Unity/filters.cpp' |
| 926 | --- src/Unity/filters.cpp 1970-01-01 00:00:00 +0000 |
| 927 | +++ src/Unity/filters.cpp 2016-03-16 11:17:35 +0000 |
| 928 | @@ -0,0 +1,281 @@ |
| 929 | +/* |
| 930 | + * Copyright (C) 2015 Canonical, Ltd. |
| 931 | + * |
| 932 | + * Authors: |
| 933 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
| 934 | + * |
| 935 | + * This program is free software; you can redistribute it and/or modify |
| 936 | + * it under the terms of the GNU General Public License as published by |
| 937 | + * the Free Software Foundation; version 3. |
| 938 | + * |
| 939 | + * This program is distributed in the hope that it will be useful, |
| 940 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 941 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 942 | + * GNU General Public License for more details. |
| 943 | + * |
| 944 | + * You should have received a copy of the GNU General Public License |
| 945 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 946 | + */ |
| 947 | + |
| 948 | +// Self |
| 949 | +#include "filters.h" |
| 950 | +#include "optionselectorfilter.h" |
| 951 | +#include "rangeinputfilter.h" |
| 952 | +#include "valuesliderfilter.h" |
| 953 | +#include <QSet> |
| 954 | +#include <QMap> |
| 955 | +#include <QQmlEngine> |
| 956 | +#include <QDebug> |
| 957 | + |
| 958 | +#include <unity/scopes/OptionSelectorFilter.h> |
| 959 | +#include <unity/scopes/RangeInputFilter.h> |
| 960 | +#include <unity/scopes/ValueSliderFilter.h> |
| 961 | + |
| 962 | +namespace scopes_ng |
| 963 | +{ |
| 964 | + |
| 965 | +const int FILTER_CHANGE_PROCESSING_DELAY = 300; |
| 966 | + |
| 967 | +Filters::Filters(unity::scopes::FilterState const& filterState, |
| 968 | + unity::shell::scopes::ScopeInterface *parent) : ModelUpdate(parent), |
| 969 | + m_filterState(new unity::scopes::FilterState(filterState)) |
| 970 | +{ |
| 971 | + m_filterStateChangeTimer.setSingleShot(true); |
| 972 | + QObject::connect(&m_filterStateChangeTimer, &QTimer::timeout, this, &Filters::delayedFilterStateChange); |
| 973 | +} |
| 974 | + |
| 975 | +int Filters::rowCount(const QModelIndex&) const |
| 976 | +{ |
| 977 | + return m_filters.count(); |
| 978 | +} |
| 979 | + |
| 980 | +QVariant Filters::data(const QModelIndex& index, int role) const |
| 981 | +{ |
| 982 | + if (index.row() >= m_filters.count()) |
| 983 | + { |
| 984 | + return QVariant(); |
| 985 | + } |
| 986 | + |
| 987 | + switch (role) |
| 988 | + { |
| 989 | + case unity::shell::scopes::FiltersInterface::Roles::RoleFilterId: |
| 990 | + return m_filters.at(index.row())->filterId(); |
| 991 | + case Qt::DisplayRole: |
| 992 | + case unity::shell::scopes::FiltersInterface::Roles::RoleFilterType: |
| 993 | + return m_filters.at(index.row())->filterType(); |
| 994 | + case unity::shell::scopes::FiltersInterface::Roles::RoleFilter: |
| 995 | + return QVariant::fromValue(m_filters.at(index.row()).data()); |
| 996 | + default: |
| 997 | + break; |
| 998 | + }; |
| 999 | + |
| 1000 | + return QVariant(); |
| 1001 | +} |
| 1002 | + |
| 1003 | +void Filters::clear() |
| 1004 | +{ |
| 1005 | + if (m_filters.size() > 0) |
| 1006 | + { |
| 1007 | + beginResetModel(); |
| 1008 | + m_filters.clear(); |
| 1009 | + m_filterState.reset(new unity::scopes::FilterState()); |
| 1010 | + endResetModel(); |
| 1011 | + } |
| 1012 | +} |
| 1013 | + |
| 1014 | +void Filters::reset() |
| 1015 | +{ |
| 1016 | + // Resetting filters will emit filterStateChanged. |
| 1017 | + qDebug() << "Resetting filters to defaults"; |
| 1018 | + for (auto f: m_filters) { |
| 1019 | + qDebug() << "Resetting filter:" << f->filterId(); |
| 1020 | + auto shellFilter = dynamic_cast<FilterUpdateInterface*>(f.data()); |
| 1021 | + Q_ASSERT(shellFilter); |
| 1022 | + shellFilter->reset(); |
| 1023 | + } |
| 1024 | +} |
| 1025 | + |
| 1026 | +void Filters::onFilterStateChanged() |
| 1027 | +{ |
| 1028 | + qDebug() << "Filter::onFilterStateChanged"; |
| 1029 | + m_filterStateChangeTimer.start(FILTER_CHANGE_PROCESSING_DELAY); |
| 1030 | +} |
| 1031 | + |
| 1032 | +void Filters::delayedFilterStateChange() |
| 1033 | +{ |
| 1034 | + Q_EMIT filterStateChanged(); |
| 1035 | +} |
| 1036 | + |
| 1037 | +void Filters::update(QList<unity::scopes::FilterBase::SCPtr> const& filters, bool containsDepartments) |
| 1038 | +{ |
| 1039 | + // Primary filter needs to be handled separately and not inserted into the main filters model, |
| 1040 | + bool hasPrimaryFilter = containsDepartments; |
| 1041 | + QList<unity::scopes::FilterBase::SCPtr> inFilters; |
| 1042 | + for (auto f: filters) { |
| 1043 | + // we can only have one primary filter. only a single-selection OptionSelectorFilter can be a primary nav. |
| 1044 | + bool wantsToBePrimary = (f->display_hints() & unity::scopes::FilterBase::DisplayHints::Primary); |
| 1045 | + unity::scopes::OptionSelectorFilter::SCPtr optSelFilter = std::dynamic_pointer_cast<unity::scopes::OptionSelectorFilter const>(f); |
| 1046 | + if (optSelFilter == nullptr || optSelFilter->multi_select()) { |
| 1047 | + wantsToBePrimary = false; |
| 1048 | + } |
| 1049 | + if (wantsToBePrimary && !hasPrimaryFilter) { |
| 1050 | + hasPrimaryFilter = true; |
| 1051 | + // |
| 1052 | + const bool hadSamePrimaryFilterBefore = m_primaryFilter && (m_primaryFilter->filterId() == QString::fromStdString(f->id())) && (m_primaryFilter->filterType() == getFilterType(f)); |
| 1053 | + if (hadSamePrimaryFilterBefore) { |
| 1054 | + auto shellFilter = dynamic_cast<FilterUpdateInterface*>(m_primaryFilter.data()); |
| 1055 | + if (shellFilter) { |
| 1056 | + shellFilter->update(f); |
| 1057 | + } else { |
| 1058 | + // this should never happen |
| 1059 | + qCritical() << "Failed to cast filter" << m_primaryFilter->filterId() << "to FilterUpdateInterface"; |
| 1060 | + } |
| 1061 | + } else { |
| 1062 | + // we didn't have primary filter before, or it changed substantially, so recreate it |
| 1063 | + m_primaryFilter = createFilterObject(f); |
| 1064 | + Q_EMIT primaryFilterChanged(); |
| 1065 | + } |
| 1066 | + } else { |
| 1067 | + inFilters.append(f); |
| 1068 | + } |
| 1069 | + } |
| 1070 | + |
| 1071 | + // Did we have primary filter before but not now? |
| 1072 | + if (!hasPrimaryFilter && m_primaryFilter != nullptr) { |
| 1073 | + m_primaryFilter.reset(); |
| 1074 | + Q_EMIT primaryFilterChanged(); |
| 1075 | + } |
| 1076 | + |
| 1077 | + syncModel(inFilters, m_filters, |
| 1078 | + // key function for scopes api filter |
| 1079 | + [](const unity::scopes::FilterBase::SCPtr& f) -> QString { return QString::fromStdString(f->id()); }, |
| 1080 | + // key function for shell api filter |
| 1081 | + [](const QSharedPointer<unity::shell::scopes::FilterBaseInterface>& f) -> QString { return f->filterId(); }, |
| 1082 | + // factory function |
| 1083 | + [this](const unity::scopes::FilterBase::SCPtr& f) -> QSharedPointer<unity::shell::scopes::FilterBaseInterface> { |
| 1084 | + return createFilterObject(f); |
| 1085 | + }, |
| 1086 | + // filter update function |
| 1087 | + [this](int, const unity::scopes::FilterBase::SCPtr &f1, const QSharedPointer<unity::shell::scopes::FilterBaseInterface>& f2) -> bool { |
| 1088 | + qDebug() << "Updating filter" << f2->filterId(); |
| 1089 | + if (f2->filterId() != QString::fromStdString(f1->id()) || f2->filterType() != getFilterType(f1)) |
| 1090 | + { |
| 1091 | + return false; |
| 1092 | + } |
| 1093 | + auto shellFilter = dynamic_cast<FilterUpdateInterface*>(f2.data()); |
| 1094 | + if (shellFilter) { |
| 1095 | + shellFilter->update(f1); |
| 1096 | + } else { |
| 1097 | + // this should never happen |
| 1098 | + qCritical() << "Failed to cast filter" << f2->filterId() << "to FilterUpdateInterface"; |
| 1099 | + } |
| 1100 | + return true; |
| 1101 | + }); |
| 1102 | +} |
| 1103 | +// |
| 1104 | +// Update current filters model and primary filter pointer with filters coming from scope. |
| 1105 | +void Filters::update(unity::scopes::FilterState const& filterState) |
| 1106 | +{ |
| 1107 | + m_filterState.reset(new unity::scopes::FilterState(filterState)); |
| 1108 | + |
| 1109 | + if (m_primaryFilter) { |
| 1110 | + auto shellFilter = dynamic_cast<FilterUpdateInterface*>(m_primaryFilter.data()); |
| 1111 | + if (shellFilter) { |
| 1112 | + shellFilter->update(m_filterState); |
| 1113 | + } else { |
| 1114 | + // this should never happen |
| 1115 | + qCritical() << "Failed to cast filter" << m_primaryFilter->filterId() << "to FilterUpdateInterface"; |
| 1116 | + } |
| 1117 | + } |
| 1118 | + for (auto f: m_filters) { |
| 1119 | + auto shellFilter = dynamic_cast<FilterUpdateInterface*>(f.data()); |
| 1120 | + if (shellFilter) { |
| 1121 | + shellFilter->update(m_filterState); |
| 1122 | + } else { |
| 1123 | + // this should never happen |
| 1124 | + qCritical() << "Failed to cast filter" << f->filterId() << "to FilterUpdateInterface"; |
| 1125 | + } |
| 1126 | + } |
| 1127 | +} |
| 1128 | + |
| 1129 | +QSharedPointer<unity::shell::scopes::FilterBaseInterface> Filters::createFilterObject(unity::scopes::FilterBase::SCPtr const& filter) |
| 1130 | +{ |
| 1131 | + QSharedPointer<unity::shell::scopes::FilterBaseInterface> filterObj; |
| 1132 | + if (filter->filter_type() == "option_selector") |
| 1133 | + { |
| 1134 | + unity::scopes::OptionSelectorFilter::SCPtr optfilter = std::dynamic_pointer_cast<unity::scopes::OptionSelectorFilter const>(filter); |
| 1135 | + filterObj = QSharedPointer<unity::shell::scopes::FilterBaseInterface>(new scopes_ng::OptionSelectorFilter(optfilter, m_filterState, this)); |
| 1136 | + } |
| 1137 | + else if (filter->filter_type() == "range_input") |
| 1138 | + { |
| 1139 | + unity::scopes::RangeInputFilter::SCPtr rangefilter = std::dynamic_pointer_cast<unity::scopes::RangeInputFilter const>(filter); |
| 1140 | + filterObj = QSharedPointer<unity::shell::scopes::FilterBaseInterface>(new scopes_ng::RangeInputFilter(rangefilter, m_filterState, this)); |
| 1141 | + } |
| 1142 | + else if (filter->filter_type() == "value_slider") |
| 1143 | + { |
| 1144 | + unity::scopes::ValueSliderFilter::SCPtr valuesliderfilter = std::dynamic_pointer_cast<unity::scopes::ValueSliderFilter const>(filter); |
| 1145 | + filterObj = QSharedPointer<unity::shell::scopes::FilterBaseInterface>(new scopes_ng::ValueSliderFilter(valuesliderfilter, m_filterState, this)); |
| 1146 | + } |
| 1147 | + |
| 1148 | + // Warning!!! Make sure any new filter type created by this factory method is reflected below in getFilterType() method as well! |
| 1149 | + |
| 1150 | + if (filterObj) |
| 1151 | + { |
| 1152 | + QQmlEngine::setObjectOwnership(filterObj.data(), QQmlEngine::CppOwnership); |
| 1153 | + connect(filterObj.data(), SIGNAL(filterStateChanged()), this, SLOT(onFilterStateChanged())); |
| 1154 | + } |
| 1155 | + else |
| 1156 | + { |
| 1157 | + qWarning() << "Unsupported filter type:" << QString::fromStdString(filter->filter_type()); |
| 1158 | + } |
| 1159 | + |
| 1160 | + return filterObj; |
| 1161 | +} |
| 1162 | + |
| 1163 | +unity::shell::scopes::FiltersInterface::FilterType Filters::getFilterType(unity::scopes::FilterBase::SCPtr const& filter) |
| 1164 | +{ |
| 1165 | + // WARNING! Some filters may rely on inheritance, in that case the dynamic casts below need to be in correct order |
| 1166 | + // (e.g. more concrete types first, base/generic types last). |
| 1167 | + if (std::dynamic_pointer_cast<unity::scopes::OptionSelectorFilter const>(filter)) |
| 1168 | + { |
| 1169 | + return unity::shell::scopes::FiltersInterface::FilterType::OptionSelectorFilter; |
| 1170 | + } |
| 1171 | + if (std::dynamic_pointer_cast<unity::scopes::RangeInputFilter const>(filter)) |
| 1172 | + { |
| 1173 | + return unity::shell::scopes::FiltersInterface::FilterType::RangeInputFilter; |
| 1174 | + } |
| 1175 | + if (std::dynamic_pointer_cast<unity::scopes::ValueSliderFilter const>(filter)) |
| 1176 | + { |
| 1177 | + return unity::shell::scopes::FiltersInterface::FilterType::ValueSliderFilter; |
| 1178 | + } |
| 1179 | + qFatal("getFilterType(): Unknown filter type: %s\n", filter->filter_type().c_str()); |
| 1180 | + return unity::shell::scopes::FiltersInterface::FilterType::Invalid; |
| 1181 | +} |
| 1182 | + |
| 1183 | +unity::scopes::FilterState Filters::filterState() const |
| 1184 | +{ |
| 1185 | + if (m_filterState) { |
| 1186 | + return *m_filterState; |
| 1187 | + } |
| 1188 | + return unity::scopes::FilterState(); |
| 1189 | +} |
| 1190 | + |
| 1191 | +QSharedPointer<unity::shell::scopes::FilterBaseInterface> Filters::primaryFilter() const |
| 1192 | +{ |
| 1193 | + return m_primaryFilter; |
| 1194 | +} |
| 1195 | + |
| 1196 | +int Filters::activeFiltersCount() const |
| 1197 | +{ |
| 1198 | + int count = 0; |
| 1199 | + for (auto filter: m_filters) { |
| 1200 | + auto shellFilter = dynamic_cast<FilterUpdateInterface*>(filter.data()); |
| 1201 | + if (shellFilter->isActive()) { |
| 1202 | + qDebug() << "activeFiltersCount: filter" << filter->filterId() << "is active"; |
| 1203 | + ++count; |
| 1204 | + } |
| 1205 | + } |
| 1206 | + return count; |
| 1207 | +} |
| 1208 | + |
| 1209 | +} |
| 1210 | |
| 1211 | === added file 'src/Unity/filters.h' |
| 1212 | --- src/Unity/filters.h 1970-01-01 00:00:00 +0000 |
| 1213 | +++ src/Unity/filters.h 2016-03-16 11:17:35 +0000 |
| 1214 | @@ -0,0 +1,94 @@ |
| 1215 | +/* |
| 1216 | + * Copyright (C) 2015 Canonical, Ltd. |
| 1217 | + * |
| 1218 | + * Authors: |
| 1219 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
| 1220 | + * |
| 1221 | + * This program is free software; you can redistribute it and/or modify |
| 1222 | + * it under the terms of the GNU General Public License as published by |
| 1223 | + * the Free Software Foundation; version 3. |
| 1224 | + * |
| 1225 | + * This program is distributed in the hope that it will be useful, |
| 1226 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 1227 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 1228 | + * GNU General Public License for more details. |
| 1229 | + * |
| 1230 | + * You should have received a copy of the GNU General Public License |
| 1231 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 1232 | + */ |
| 1233 | + |
| 1234 | +#ifndef NG_FILTERS_H |
| 1235 | +#define NG_FILTERS_H |
| 1236 | + |
| 1237 | +#include <unity/shell/scopes/FiltersInterface.h> |
| 1238 | +#include <unity/shell/scopes/ScopeInterface.h> |
| 1239 | +#include <unity/scopes/FilterBase.h> |
| 1240 | +#include <unity/scopes/FilterState.h> |
| 1241 | +#include <unity/shell/scopes/FilterBaseInterface.h> |
| 1242 | +#include "modelupdate.h" |
| 1243 | + |
| 1244 | +#include <QList> |
| 1245 | +#include <QSharedPointer> |
| 1246 | +#include <QTimer> |
| 1247 | + |
| 1248 | +namespace scopes_ng |
| 1249 | +{ |
| 1250 | + |
| 1251 | +class FilterUpdateInterface |
| 1252 | +{ |
| 1253 | + public: |
| 1254 | + // Apply potential updates of filter definition coming from scope. |
| 1255 | + virtual void update(unity::scopes::FilterBase::SCPtr const& filter) = 0; |
| 1256 | + |
| 1257 | + // Apply filter state change (e.g. after user executed a canned query). |
| 1258 | + virtual void update(unity::scopes::FilterState::SPtr const& filterState) = 0; |
| 1259 | + |
| 1260 | + // Check if the filter is active (i.e. has non-default values set). |
| 1261 | + virtual bool isActive() const = 0; |
| 1262 | + |
| 1263 | + // Reset filter to defaults. |
| 1264 | + virtual void reset() = 0; |
| 1265 | +}; |
| 1266 | + |
| 1267 | +class Q_DECL_EXPORT Filters : |
| 1268 | + public ModelUpdate<unity::shell::scopes::FiltersInterface, |
| 1269 | + QList<unity::scopes::FilterBase::SCPtr>, |
| 1270 | + QList<QSharedPointer<unity::shell::scopes::FilterBaseInterface>>> |
| 1271 | +{ |
| 1272 | + Q_OBJECT |
| 1273 | + |
| 1274 | +public: |
| 1275 | + explicit Filters(unity::scopes::FilterState const& filterState, unity::shell::scopes::ScopeInterface *parent = nullptr); |
| 1276 | + int rowCount(const QModelIndex& parent = QModelIndex()) const override; |
| 1277 | + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; |
| 1278 | + void update(QList<unity::scopes::FilterBase::SCPtr> const& filters, bool containsDepartments = false); |
| 1279 | + void update(unity::scopes::FilterState const& filterState); |
| 1280 | + |
| 1281 | + unity::scopes::FilterState filterState() const; |
| 1282 | + QSharedPointer<unity::shell::scopes::FilterBaseInterface> primaryFilter() const; |
| 1283 | + int activeFiltersCount() const; |
| 1284 | + |
| 1285 | +public Q_SLOTS: |
| 1286 | + void clear(); |
| 1287 | + void reset(); |
| 1288 | + |
| 1289 | +private Q_SLOTS: |
| 1290 | + void onFilterStateChanged(); |
| 1291 | + void delayedFilterStateChange(); |
| 1292 | + |
| 1293 | +Q_SIGNALS: |
| 1294 | + void filterStateChanged(); |
| 1295 | + void primaryFilterChanged(); |
| 1296 | + |
| 1297 | +private: |
| 1298 | + static unity::shell::scopes::FiltersInterface::FilterType getFilterType(unity::scopes::FilterBase::SCPtr const& filter); |
| 1299 | + QSharedPointer<unity::shell::scopes::FilterBaseInterface> createFilterObject(unity::scopes::FilterBase::SCPtr const& filter); |
| 1300 | + QList<QSharedPointer<unity::shell::scopes::FilterBaseInterface>> m_filters; |
| 1301 | + QSharedPointer<unity::shell::scopes::FilterBaseInterface> m_primaryFilter; |
| 1302 | + unity::scopes::FilterState::SPtr m_filterState; |
| 1303 | + QTimer m_filterStateChangeTimer; |
| 1304 | +}; |
| 1305 | + |
| 1306 | +} // namespace scopes_ng |
| 1307 | + |
| 1308 | +#endif |
| 1309 | |
| 1310 | === added file 'src/Unity/modelupdate.h' |
| 1311 | --- src/Unity/modelupdate.h 1970-01-01 00:00:00 +0000 |
| 1312 | +++ src/Unity/modelupdate.h 2016-03-16 11:17:35 +0000 |
| 1313 | @@ -0,0 +1,143 @@ |
| 1314 | +/* |
| 1315 | + * Copyright (C) 2015 Canonical, Ltd. |
| 1316 | + * |
| 1317 | + * Authors: |
| 1318 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
| 1319 | + * |
| 1320 | + * This program is free software; you can redistribute it and/or modify |
| 1321 | + * it under the terms of the GNU General Public License as published by |
| 1322 | + * the Free Software Foundation; version 3. |
| 1323 | + * |
| 1324 | + * This program is distributed in the hope that it will be useful, |
| 1325 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 1326 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 1327 | + * GNU General Public License for more details. |
| 1328 | + * |
| 1329 | + * You should have received a copy of the GNU General Public License |
| 1330 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 1331 | + */ |
| 1332 | + |
| 1333 | +#ifndef NG_MODEL_UPDATE_H |
| 1334 | +#define NG_MODEL_UPDATE_H |
| 1335 | + |
| 1336 | +#include <QSet> |
| 1337 | +#include <functional> |
| 1338 | + |
| 1339 | +template <class ModelBase, class InputContainer, class OutputContainer, class KeyType=QString> |
| 1340 | +class ModelUpdate: public ModelBase |
| 1341 | +{ |
| 1342 | +public: |
| 1343 | + using InputKeyFunc = std::function<KeyType(typename InputContainer::value_type)>; |
| 1344 | + using OutputKeyFunc = std::function<KeyType(typename OutputContainer::value_type)>; |
| 1345 | + using CreateFunc = std::function<typename OutputContainer::value_type(typename InputContainer::value_type const&)>; |
| 1346 | + using UpdateFunc = std::function<bool(int, typename InputContainer::value_type const&, typename OutputContainer::value_type const&)>; |
| 1347 | + |
| 1348 | + ModelUpdate(QObject *parent = nullptr): ModelBase(parent) {} |
| 1349 | + |
| 1350 | + void syncModel(InputContainer const& input, |
| 1351 | + OutputContainer &model, |
| 1352 | + const InputKeyFunc& inKeyFunc, |
| 1353 | + const OutputKeyFunc& outKeyFunc, |
| 1354 | + const CreateFunc& createFunc, |
| 1355 | + const UpdateFunc& updateFunc) |
| 1356 | + { |
| 1357 | + QMap<KeyType, int> newItems; // lookup for recevied objects and their desired rows in the model |
| 1358 | + QSet<KeyType> oldItems; // lookup for objects that were already displayed |
| 1359 | + |
| 1360 | + { |
| 1361 | + int pos = 0; |
| 1362 | + for (auto item: input) |
| 1363 | + { |
| 1364 | + newItems[inKeyFunc(item)] = pos++; |
| 1365 | + } |
| 1366 | + } |
| 1367 | + |
| 1368 | + // iterate over old objects, remove objects that are not present anymore |
| 1369 | + { |
| 1370 | + int row = 0; |
| 1371 | + for (auto it = model.begin(); it != model.end();) |
| 1372 | + { |
| 1373 | + const KeyType id = outKeyFunc(*it); |
| 1374 | + if (!newItems.contains(id)) |
| 1375 | + { |
| 1376 | + this->beginRemoveRows(QModelIndex(), row, row); |
| 1377 | + it = model.erase(it); |
| 1378 | + this->endRemoveRows(); |
| 1379 | + } |
| 1380 | + else |
| 1381 | + { |
| 1382 | + oldItems.insert(id); |
| 1383 | + ++it; |
| 1384 | + ++row; |
| 1385 | + } |
| 1386 | + } |
| 1387 | + } |
| 1388 | + |
| 1389 | + // iterate over new objects and insert them in the model |
| 1390 | + { |
| 1391 | + int row = 0; |
| 1392 | + for (auto const& item: input) |
| 1393 | + { |
| 1394 | + if (!oldItems.contains(inKeyFunc(item))) |
| 1395 | + { |
| 1396 | + auto obj = createFunc(item); |
| 1397 | + if (obj) |
| 1398 | + { |
| 1399 | + this->beginInsertRows(QModelIndex(), row, row); |
| 1400 | + model.insert(row, obj); |
| 1401 | + this->endInsertRows(); |
| 1402 | + } |
| 1403 | + } |
| 1404 | + row++; |
| 1405 | + } |
| 1406 | + } |
| 1407 | + |
| 1408 | + // move objects if position changed |
| 1409 | + for (int i = 0; i<model.size(); ) |
| 1410 | + { |
| 1411 | + auto const id = outKeyFunc(model[i]); |
| 1412 | + int pos = newItems.value(id, -1); |
| 1413 | + if (pos >= 0 && pos != i) { |
| 1414 | + this->beginMoveRows(QModelIndex(), i, i, QModelIndex(), pos + (pos > i ? 1 : 0)); |
| 1415 | + model.move(i, pos); |
| 1416 | + this->endMoveRows(); |
| 1417 | + continue; |
| 1418 | + } |
| 1419 | + i++; |
| 1420 | + } |
| 1421 | + |
| 1422 | + // check if any of the existing objects which didn't change position needs updating |
| 1423 | + /*{ |
| 1424 | + int row = 0; |
| 1425 | + for (auto const& in: input) |
| 1426 | + { |
| 1427 | + if (oldItems.contains(inKeyFunc(in))) |
| 1428 | + { |
| 1429 | + if (!updateFunc(in, model[row])) |
| 1430 | + { |
| 1431 | + model[row] = createFunc(in); |
| 1432 | + Q_EMIT this->dataChanged(this->index(row, 0), this->index(row, 0)); // or beginRemoveRows & beginInsertRows ? |
| 1433 | + } |
| 1434 | + } |
| 1435 | + ++row; |
| 1436 | + } |
| 1437 | + }*/ |
| 1438 | + |
| 1439 | + // call updateFunc for all objects to synchornize changes to properties |
| 1440 | + { |
| 1441 | + int row = 0; |
| 1442 | + for (auto const& in: input) |
| 1443 | + { |
| 1444 | + if (!updateFunc(row, in, model[row])) |
| 1445 | + { |
| 1446 | + model[row] = createFunc(in); |
| 1447 | + Q_EMIT this->dataChanged(this->index(row, 0), this->index(row, 0)); // or beginRemoveRows & beginInsertRows ? |
| 1448 | + } |
| 1449 | + ++row; |
| 1450 | + } |
| 1451 | + } |
| 1452 | + |
| 1453 | + } |
| 1454 | +}; |
| 1455 | + |
| 1456 | +#endif |
| 1457 | |
| 1458 | === added file 'src/Unity/optionselectorfilter.cpp' |
| 1459 | --- src/Unity/optionselectorfilter.cpp 1970-01-01 00:00:00 +0000 |
| 1460 | +++ src/Unity/optionselectorfilter.cpp 2016-03-16 11:17:35 +0000 |
| 1461 | @@ -0,0 +1,173 @@ |
| 1462 | +/* |
| 1463 | + * Copyright (C) 2015 Canonical, Ltd. |
| 1464 | + * |
| 1465 | + * Authors: |
| 1466 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
| 1467 | + * |
| 1468 | + * This program is free software; you can redistribute it and/or modify |
| 1469 | + * it under the terms of the GNU General Public License as published by |
| 1470 | + * the Free Software Foundation; version 3. |
| 1471 | + * |
| 1472 | + * This program is distributed in the hope that it will be useful, |
| 1473 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 1474 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 1475 | + * GNU General Public License for more details. |
| 1476 | + * |
| 1477 | + * You should have received a copy of the GNU General Public License |
| 1478 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 1479 | + */ |
| 1480 | + |
| 1481 | +#include "optionselectorfilter.h" |
| 1482 | +#include <QQmlEngine> |
| 1483 | +#include <QDebug> |
| 1484 | + |
| 1485 | +namespace scopes_ng |
| 1486 | +{ |
| 1487 | + |
| 1488 | +OptionSelectorFilter::OptionSelectorFilter(unity::scopes::OptionSelectorFilter::SCPtr const& filter, unity::scopes::FilterState::SPtr const& filterState, unity::shell::scopes::FiltersInterface *parent) |
| 1489 | + : unity::shell::scopes::OptionSelectorFilterInterface(parent), |
| 1490 | + m_id(QString::fromStdString(filter->id())), |
| 1491 | + m_title(QString::fromStdString(filter->title())), |
| 1492 | + m_multiSelect(filter->multi_select()), |
| 1493 | + m_label(QString::fromStdString(filter->label())), |
| 1494 | + m_options(new OptionSelectorOptions(this, filter->options(), filter->active_options(*filterState))), |
| 1495 | + m_filterState(filterState), |
| 1496 | + m_filter(filter) |
| 1497 | +{ |
| 1498 | + QQmlEngine::setObjectOwnership(m_options.data(), QQmlEngine::CppOwnership); |
| 1499 | + connect(m_options.data(), SIGNAL(optionChecked(const QString&, bool)), this, SLOT(onOptionChecked(const QString&, bool))); |
| 1500 | +} |
| 1501 | + |
| 1502 | +QString OptionSelectorFilter::filterId() const |
| 1503 | +{ |
| 1504 | + return m_id; |
| 1505 | +} |
| 1506 | + |
| 1507 | +QString OptionSelectorFilter::title() const |
| 1508 | +{ |
| 1509 | + return m_title; |
| 1510 | +} |
| 1511 | + |
| 1512 | +unity::shell::scopes::FiltersInterface::FilterType OptionSelectorFilter::filterType() const |
| 1513 | +{ |
| 1514 | + return unity::shell::scopes::FiltersInterface::FilterType::OptionSelectorFilter; |
| 1515 | +} |
| 1516 | + |
| 1517 | +QString OptionSelectorFilter::label() const |
| 1518 | +{ |
| 1519 | + return m_label; |
| 1520 | +} |
| 1521 | + |
| 1522 | +bool OptionSelectorFilter::multiSelect() const |
| 1523 | +{ |
| 1524 | + return m_multiSelect; |
| 1525 | +} |
| 1526 | + |
| 1527 | +void OptionSelectorFilter::reset() |
| 1528 | +{ |
| 1529 | + if (auto state = m_filterState.lock()) |
| 1530 | + { |
| 1531 | + state->remove(m_filter->id()); |
| 1532 | + qDebug() << "Removing filter state for filter" << QString::fromStdString(m_filter->id()); |
| 1533 | + m_options->update(m_filter->active_options(*state), true); |
| 1534 | + Q_EMIT filterStateChanged(); |
| 1535 | + } |
| 1536 | +} |
| 1537 | + |
| 1538 | +void OptionSelectorFilter::onOptionChecked(const QString& id, bool checked) |
| 1539 | +{ |
| 1540 | + if (auto state = m_filterState.lock()) |
| 1541 | + { |
| 1542 | + auto const optid = id.toStdString(); |
| 1543 | + for (auto const opt: m_filter->options()) |
| 1544 | + { |
| 1545 | + if (opt->id() == optid) |
| 1546 | + { |
| 1547 | + m_filter->update_state(*state, opt, checked); |
| 1548 | + // onOptionChecked signal is triggered by the user, but we need to updated filter |
| 1549 | + // with new state since the state of other options may have changed if this is a single-selection filter. |
| 1550 | + // However, we pass allow_defaults = false, so that user is able to unselect all options and they are |
| 1551 | + // not forcefully reset to defaults if this happens. |
| 1552 | + m_options->update(m_filter->active_options(*state), false); |
| 1553 | + Q_EMIT filterStateChanged(); |
| 1554 | + return; |
| 1555 | + } |
| 1556 | + } |
| 1557 | + qDebug() << "Removing filter state for filter" << QString::fromStdString(m_filter->id()); |
| 1558 | + state->remove(m_filter->id()); |
| 1559 | + } |
| 1560 | +} |
| 1561 | + |
| 1562 | +unity::shell::scopes::OptionSelectorOptionsInterface* OptionSelectorFilter::options() const |
| 1563 | +{ |
| 1564 | + return m_options.data(); |
| 1565 | +} |
| 1566 | + |
| 1567 | +void OptionSelectorFilter::update(unity::scopes::FilterState::SPtr const& filterState) |
| 1568 | +{ |
| 1569 | + m_filterState = filterState; |
| 1570 | + m_options->update(m_filter->active_options(*filterState), true); |
| 1571 | +} |
| 1572 | + |
| 1573 | +void OptionSelectorFilter::update(unity::scopes::FilterBase::SCPtr const& filter) |
| 1574 | +{ |
| 1575 | + unity::scopes::OptionSelectorFilter::SCPtr optselfilter = std::dynamic_pointer_cast<unity::scopes::OptionSelectorFilter const>(filter); |
| 1576 | + if (!optselfilter) { |
| 1577 | + qWarning() << "OptionSelectorFilter::update(): Unexpected filter" << QString::fromStdString(filter->id()) << "of type" << QString::fromStdString(filter->filter_type()); |
| 1578 | + return; |
| 1579 | + } |
| 1580 | + |
| 1581 | + m_filter = optselfilter; |
| 1582 | + |
| 1583 | + if (optselfilter->multi_select() != m_multiSelect) |
| 1584 | + { |
| 1585 | + m_multiSelect = optselfilter->multi_select(); |
| 1586 | + Q_EMIT multiSelectChanged(m_multiSelect); |
| 1587 | + } |
| 1588 | + |
| 1589 | + if (optselfilter->title() != m_title.toStdString()) |
| 1590 | + { |
| 1591 | + m_title = QString::fromStdString(optselfilter->title()); |
| 1592 | + Q_EMIT titleChanged(); |
| 1593 | + } |
| 1594 | + |
| 1595 | + if (QString::fromStdString(optselfilter->label()) != m_label) |
| 1596 | + { |
| 1597 | + m_label = QString::fromStdString(optselfilter->label()); |
| 1598 | + Q_EMIT labelChanged(m_label); |
| 1599 | + } |
| 1600 | + |
| 1601 | + m_options->update(optselfilter->options()); |
| 1602 | + if (auto state = m_filterState.lock()) { |
| 1603 | + m_options->update(m_filter->active_options(*state), false); |
| 1604 | + } |
| 1605 | +} |
| 1606 | + |
| 1607 | +bool OptionSelectorFilter::isActive() const |
| 1608 | +{ |
| 1609 | + if (auto state = m_filterState.lock()) { |
| 1610 | + return m_filter->has_active_option(*state); |
| 1611 | + } |
| 1612 | + return false; |
| 1613 | +} |
| 1614 | + |
| 1615 | +QString OptionSelectorFilter::filterTag() const |
| 1616 | +{ |
| 1617 | + if (m_multiSelect) { |
| 1618 | + // multi-selection filter cannot be used as primary navigation |
| 1619 | + return ""; |
| 1620 | + } |
| 1621 | + if (auto state = m_filterState.lock()) { |
| 1622 | + auto selected = m_filter->active_options(*state); |
| 1623 | + if (selected.size() > 0) { |
| 1624 | + for (auto opt: m_filter->options()) { |
| 1625 | + if (selected.find(opt) != selected.end()) { |
| 1626 | + return QString::fromStdString(opt->label()); // TODO: i18n |
| 1627 | + } |
| 1628 | + } |
| 1629 | + } |
| 1630 | + } |
| 1631 | + return ""; |
| 1632 | +} |
| 1633 | + |
| 1634 | +} |
| 1635 | |
| 1636 | === added file 'src/Unity/optionselectorfilter.h' |
| 1637 | --- src/Unity/optionselectorfilter.h 1970-01-01 00:00:00 +0000 |
| 1638 | +++ src/Unity/optionselectorfilter.h 2016-03-16 11:17:35 +0000 |
| 1639 | @@ -0,0 +1,69 @@ |
| 1640 | +/* |
| 1641 | + * Copyright (C) 2015 Canonical, Ltd. |
| 1642 | + * |
| 1643 | + * Authors: |
| 1644 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
| 1645 | + * |
| 1646 | + * This program is free software; you can redistribute it and/or modify |
| 1647 | + * it under the terms of the GNU General Public License as published by |
| 1648 | + * the Free Software Foundation; version 3. |
| 1649 | + * |
| 1650 | + * This program is distributed in the hope that it will be useful, |
| 1651 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 1652 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 1653 | + * GNU General Public License for more details. |
| 1654 | + * |
| 1655 | + * You should have received a copy of the GNU General Public License |
| 1656 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 1657 | + */ |
| 1658 | + |
| 1659 | +#ifndef NG_OPTIONSELECTORFILTER_H |
| 1660 | +#define NG_OPTIONSELECTORFILTER_H |
| 1661 | + |
| 1662 | +#include <unity/shell/scopes/OptionSelectorFilterInterface.h> |
| 1663 | +#include <unity/shell/scopes/FiltersInterface.h> |
| 1664 | +#include "filters.h" |
| 1665 | +#include <unity/scopes/OptionSelectorFilter.h> |
| 1666 | +#include "optionselectoroptions.h" |
| 1667 | +#include <QScopedPointer> |
| 1668 | + |
| 1669 | +namespace scopes_ng |
| 1670 | +{ |
| 1671 | + |
| 1672 | +class Q_DECL_EXPORT OptionSelectorFilter : public unity::shell::scopes::OptionSelectorFilterInterface, public FilterUpdateInterface |
| 1673 | +{ |
| 1674 | + Q_OBJECT |
| 1675 | + |
| 1676 | +public: |
| 1677 | + OptionSelectorFilter(unity::scopes::OptionSelectorFilter::SCPtr const& filter, unity::scopes::FilterState::SPtr const& filterState, unity::shell::scopes::FiltersInterface *parent = nullptr); |
| 1678 | + QString filterId() const override; |
| 1679 | + QString title() const override; |
| 1680 | + unity::shell::scopes::FiltersInterface::FilterType filterType() const override; |
| 1681 | + QString label() const override; |
| 1682 | + bool multiSelect() const override; |
| 1683 | + unity::shell::scopes::OptionSelectorOptionsInterface* options() const override; |
| 1684 | + void update(unity::scopes::FilterBase::SCPtr const& filter) override; |
| 1685 | + void update(unity::scopes::FilterState::SPtr const& filterState) override; |
| 1686 | + bool isActive() const override; |
| 1687 | + QString filterTag() const override; |
| 1688 | + void reset() override; |
| 1689 | + |
| 1690 | +Q_SIGNALS: |
| 1691 | + void filterStateChanged(); |
| 1692 | + |
| 1693 | +protected Q_SLOTS: |
| 1694 | + void onOptionChecked(const QString& id, bool checked); |
| 1695 | + |
| 1696 | +private: |
| 1697 | + QString m_id; |
| 1698 | + QString m_title; |
| 1699 | + bool m_multiSelect; |
| 1700 | + QString m_label; |
| 1701 | + QScopedPointer<OptionSelectorOptions> m_options; |
| 1702 | + std::weak_ptr<unity::scopes::FilterState> m_filterState; |
| 1703 | + unity::scopes::OptionSelectorFilter::SCPtr m_filter; |
| 1704 | +}; |
| 1705 | + |
| 1706 | +} // namespace scopes_ng |
| 1707 | + |
| 1708 | +#endif |
| 1709 | |
| 1710 | === added file 'src/Unity/optionselectoroptions.cpp' |
| 1711 | --- src/Unity/optionselectoroptions.cpp 1970-01-01 00:00:00 +0000 |
| 1712 | +++ src/Unity/optionselectoroptions.cpp 2016-03-16 11:17:35 +0000 |
| 1713 | @@ -0,0 +1,164 @@ |
| 1714 | +/* |
| 1715 | + * Copyright (C) 2015 Canonical, Ltd. |
| 1716 | + * |
| 1717 | + * Authors: |
| 1718 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
| 1719 | + * |
| 1720 | + * This program is free software; you can redistribute it and/or modify |
| 1721 | + * it under the terms of the GNU General Public License as published by |
| 1722 | + * the Free Software Foundation; version 3. |
| 1723 | + * |
| 1724 | + * This program is distributed in the hope that it will be useful, |
| 1725 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 1726 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 1727 | + * GNU General Public License for more details. |
| 1728 | + * |
| 1729 | + * You should have received a copy of the GNU General Public License |
| 1730 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 1731 | + */ |
| 1732 | + |
| 1733 | +#include "optionselectoroptions.h" |
| 1734 | +#include "optionselectorfilter.h" |
| 1735 | +#include <QSet> |
| 1736 | +#include <QDebug> |
| 1737 | + |
| 1738 | +namespace scopes_ng |
| 1739 | +{ |
| 1740 | + |
| 1741 | +struct OptionSelectorOption |
| 1742 | +{ |
| 1743 | + QString id; |
| 1744 | + QString label; |
| 1745 | + bool checked; |
| 1746 | + bool default_checked; |
| 1747 | + |
| 1748 | + OptionSelectorOption(const QString& id, const QString &label, bool default_checked) : |
| 1749 | + id(id), |
| 1750 | + label(label), |
| 1751 | + checked(false), |
| 1752 | + default_checked(default_checked) |
| 1753 | + {} |
| 1754 | +}; |
| 1755 | + |
| 1756 | +OptionSelectorOptions::OptionSelectorOptions(OptionSelectorFilter *parent, std::list<unity::scopes::FilterOption::SCPtr> const& options, |
| 1757 | + std::set<unity::scopes::FilterOption::SCPtr> const& activeOptions) |
| 1758 | + : ModelUpdate(parent) |
| 1759 | +{ |
| 1760 | + bool const use_defaults = (activeOptions.size() == 0); |
| 1761 | + |
| 1762 | + for (auto const& opt: options) { |
| 1763 | + auto shellOpt = QSharedPointer<OptionSelectorOption>(new OptionSelectorOption(QString::fromStdString(opt->id()), QString::fromStdString(opt->label()), |
| 1764 | + opt->default_value())); |
| 1765 | + m_options.append(shellOpt); |
| 1766 | + if (use_defaults) { |
| 1767 | + shellOpt->checked = shellOpt->default_checked; |
| 1768 | + } else { |
| 1769 | + if (activeOptions.find(opt) != activeOptions.end()) { |
| 1770 | + shellOpt->checked = true; |
| 1771 | + } |
| 1772 | + } |
| 1773 | + } |
| 1774 | +} |
| 1775 | + |
| 1776 | +void OptionSelectorOptions::update(const std::set<unity::scopes::FilterOption::SCPtr>& activeOptions, bool allow_defaults) |
| 1777 | +{ |
| 1778 | + bool const use_defaults = (allow_defaults && activeOptions.size() == 0); |
| 1779 | + if (use_defaults) { |
| 1780 | + for (int row = 0; row<m_options.size(); row++) { |
| 1781 | + auto &opt = m_options[row]; |
| 1782 | + if (opt->checked != opt->default_checked) { |
| 1783 | + opt->checked = opt->default_checked; |
| 1784 | + Q_EMIT dataChanged(index(row, 0), index(row, 0), { unity::shell::scopes::OptionSelectorOptionsInterface::Roles::RoleOptionChecked }); |
| 1785 | + } |
| 1786 | + } |
| 1787 | + return; |
| 1788 | + } |
| 1789 | + |
| 1790 | + QSet<QString> actOpts; |
| 1791 | + for (auto const& opt: activeOptions) { |
| 1792 | + actOpts.insert(QString::fromStdString(opt->id())); |
| 1793 | + } |
| 1794 | + |
| 1795 | + for (int row = 0; row<m_options.size(); row++) { |
| 1796 | + auto &opt = m_options[row]; |
| 1797 | + if (actOpts.find(opt->id) != actOpts.end()) { |
| 1798 | + if (!opt->checked) { |
| 1799 | + opt->checked = true; |
| 1800 | + Q_EMIT dataChanged(index(row, 0), index(row, 0), { unity::shell::scopes::OptionSelectorOptionsInterface::Roles::RoleOptionChecked }); |
| 1801 | + } |
| 1802 | + } else { |
| 1803 | + if (opt->checked) { |
| 1804 | + opt->checked = false; |
| 1805 | + Q_EMIT dataChanged(index(row, 0), index(row, 0), { unity::shell::scopes::OptionSelectorOptionsInterface::Roles::RoleOptionChecked }); |
| 1806 | + } |
| 1807 | + } |
| 1808 | + } |
| 1809 | +} |
| 1810 | + |
| 1811 | +void OptionSelectorOptions::update(const std::list<unity::scopes::FilterOption::SCPtr>& options) |
| 1812 | +{ |
| 1813 | + QVector<int> roles; |
| 1814 | + roles.append(unity::shell::scopes::OptionSelectorOptionsInterface::Roles::RoleOptionLabel); |
| 1815 | + |
| 1816 | + syncModel(options, m_options, |
| 1817 | + // key function for scopes api filter option |
| 1818 | + [](const unity::scopes::FilterOption::SCPtr& opt) -> QString { return QString::fromStdString(opt->id()); }, |
| 1819 | + // key function for shell api filter option |
| 1820 | + [](const QSharedPointer<OptionSelectorOption>& opt) -> QString { return opt->id; }, |
| 1821 | + // factory function for creating shell filter option from scopes api filter option |
| 1822 | + [this](const unity::scopes::FilterOption::SCPtr& opt) -> QSharedPointer<OptionSelectorOption> { |
| 1823 | + auto optObj = QSharedPointer<OptionSelectorOption>( |
| 1824 | + new OptionSelectorOption(QString::fromStdString(opt->id()), QString::fromStdString(opt->label()), opt->default_value())); |
| 1825 | + return optObj; |
| 1826 | + }, |
| 1827 | + // filter option update function |
| 1828 | + [&roles, this](int row, const unity::scopes::FilterOption::SCPtr& op1, const QSharedPointer<OptionSelectorOption>& op2) -> bool { |
| 1829 | + if (op2->id != QString::fromStdString(op1->id())) { |
| 1830 | + return false; |
| 1831 | + } |
| 1832 | + if (op2->label != QString::fromStdString(op1->label())) { |
| 1833 | + op2->label = QString::fromStdString(op1->label()); |
| 1834 | + Q_EMIT dataChanged(index(row, 0), index(row, 0), roles); |
| 1835 | + } |
| 1836 | + return true; |
| 1837 | + }); |
| 1838 | +} |
| 1839 | + |
| 1840 | +int OptionSelectorOptions::rowCount(const QModelIndex& /* parent */) const |
| 1841 | +{ |
| 1842 | + return m_options.count(); |
| 1843 | +} |
| 1844 | + |
| 1845 | +void OptionSelectorOptions::setChecked(int row, bool checked) |
| 1846 | +{ |
| 1847 | + if (row >= 0 && row < m_options.count()) |
| 1848 | + { |
| 1849 | + auto opt = m_options.at(row); |
| 1850 | + if (checked != opt->checked) |
| 1851 | + { |
| 1852 | + Q_EMIT optionChecked(opt->id, checked); |
| 1853 | + } |
| 1854 | + } |
| 1855 | +} |
| 1856 | + |
| 1857 | +QVariant OptionSelectorOptions::data(const QModelIndex& index, int role) const |
| 1858 | +{ |
| 1859 | + if (index.row() >= m_options.count()) |
| 1860 | + { |
| 1861 | + return QVariant(); |
| 1862 | + } |
| 1863 | + switch (role) |
| 1864 | + { |
| 1865 | + case Qt::DisplayRole: |
| 1866 | + case RoleOptionId: |
| 1867 | + return QVariant(m_options.at(index.row())->id); |
| 1868 | + case RoleOptionLabel: |
| 1869 | + return QVariant(m_options.at(index.row())->label); |
| 1870 | + case RoleOptionChecked: |
| 1871 | + return QVariant(m_options.at(index.row())->checked); |
| 1872 | + default: |
| 1873 | + return QVariant(); |
| 1874 | + } |
| 1875 | +} |
| 1876 | + |
| 1877 | +} |
| 1878 | |
| 1879 | === added file 'src/Unity/optionselectoroptions.h' |
| 1880 | --- src/Unity/optionselectoroptions.h 1970-01-01 00:00:00 +0000 |
| 1881 | +++ src/Unity/optionselectoroptions.h 2016-03-16 11:17:35 +0000 |
| 1882 | @@ -0,0 +1,64 @@ |
| 1883 | +/* |
| 1884 | + * Copyright (C) 2015 Canonical, Ltd. |
| 1885 | + * |
| 1886 | + * Authors: |
| 1887 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
| 1888 | + * |
| 1889 | + * This program is free software; you can redistribute it and/or modify |
| 1890 | + * it under the terms of the GNU General Public License as published by |
| 1891 | + * the Free Software Foundation; version 3. |
| 1892 | + * |
| 1893 | + * This program is distributed in the hope that it will be useful, |
| 1894 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 1895 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 1896 | + * GNU General Public License for more details. |
| 1897 | + * |
| 1898 | + * You should have received a copy of the GNU General Public License |
| 1899 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 1900 | + */ |
| 1901 | + |
| 1902 | +#ifndef NG_OPTIONSELECTOROPTIONS_H |
| 1903 | +#define NG_OPTIONSELECTOROPTIONS_H |
| 1904 | + |
| 1905 | +#include <unity/shell/scopes/OptionSelectorOptionsInterface.h> |
| 1906 | +#include <unity/scopes/FilterOption.h> |
| 1907 | +#include "modelupdate.h" |
| 1908 | +#include <QSharedPointer> |
| 1909 | +#include <QList> |
| 1910 | +#include <list> |
| 1911 | +#include <set> |
| 1912 | +#include <functional> |
| 1913 | + |
| 1914 | +namespace scopes_ng |
| 1915 | +{ |
| 1916 | + |
| 1917 | +class OptionSelectorFilter; |
| 1918 | +class OptionSelectorOption; |
| 1919 | + |
| 1920 | +class Q_DECL_EXPORT OptionSelectorOptions : |
| 1921 | + public ModelUpdate<unity::shell::scopes::OptionSelectorOptionsInterface, |
| 1922 | + std::list<unity::scopes::FilterOption::SCPtr>, |
| 1923 | + QList<QSharedPointer<OptionSelectorOption>>> |
| 1924 | +{ |
| 1925 | + Q_OBJECT |
| 1926 | + |
| 1927 | +public: |
| 1928 | + OptionSelectorOptions(OptionSelectorFilter *parent, |
| 1929 | + std::list<unity::scopes::FilterOption::SCPtr> const& options, |
| 1930 | + std::set<unity::scopes::FilterOption::SCPtr> const& activeOptions); |
| 1931 | + void update(const std::list<unity::scopes::FilterOption::SCPtr>& options); |
| 1932 | + void update(const std::set<unity::scopes::FilterOption::SCPtr>& activeOptions, bool allow_defaults); |
| 1933 | + int rowCount(const QModelIndex& parent) const override; |
| 1934 | + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; |
| 1935 | + Q_INVOKABLE void setChecked(int row, bool checked) override; |
| 1936 | + |
| 1937 | +Q_SIGNALS: |
| 1938 | + void optionChecked(const QString&, bool); |
| 1939 | + |
| 1940 | +private: |
| 1941 | + QList<QSharedPointer<OptionSelectorOption>> m_options; |
| 1942 | +}; |
| 1943 | + |
| 1944 | +} // namespace scopes_ng |
| 1945 | + |
| 1946 | +#endif |
| 1947 | |
| 1948 | === modified file 'src/Unity/plugin.cpp' |
| 1949 | --- src/Unity/plugin.cpp 2016-02-11 15:35:47 +0000 |
| 1950 | +++ src/Unity/plugin.cpp 2016-03-16 11:17:35 +0000 |
| 1951 | @@ -32,6 +32,12 @@ |
| 1952 | #include "previewmodel.h" |
| 1953 | #include "previewwidgetmodel.h" |
| 1954 | #include "settingsmodel.h" |
| 1955 | +#include <unity/shell/scopes/FiltersInterface.h> |
| 1956 | +#include <unity/shell/scopes/OptionSelectorFilterInterface.h> |
| 1957 | +#include <unity/shell/scopes/OptionSelectorOptionsInterface.h> |
| 1958 | +#include <unity/shell/scopes/RangeInputFilterInterface.h> |
| 1959 | +#include <unity/shell/scopes/ValueSliderFilterInterface.h> |
| 1960 | +#include <unity/shell/scopes/ValueSliderValuesInterface.h> |
| 1961 | #include "localization.h" |
| 1962 | |
| 1963 | void UnityPlugin::registerTypes(const char *uri) |
| 1964 | @@ -49,6 +55,12 @@ |
| 1965 | qmlRegisterUncreatableType<scopes_ng::ResultsModel>(uri, 0, 2, "ResultsModel", QStringLiteral("Can't create new ResultsModel in QML. Get them from Categories instance.")); |
| 1966 | qmlRegisterUncreatableType<unity::shell::scopes::PreviewModelInterface>(uri, 0, 2, "PreviewModel", QStringLiteral("Can't create new PreviewModel in QML. Get them from Scope instance.")); |
| 1967 | qmlRegisterUncreatableType<scopes_ng::PreviewWidgetModel>(uri, 0, 2, "PreviewWidgetModel", QStringLiteral("Can't create new PreviewWidgetModel in QML. Get them from PreviewModel instance.")); |
| 1968 | + qmlRegisterUncreatableType<unity::shell::scopes::FiltersInterface>(uri, 0, 2, "Filters", "Can't create Filters object in QML. Get them from Scope instance."); |
| 1969 | + qmlRegisterUncreatableType<unity::shell::scopes::FilterBaseInterface>(uri, 0, 2, "Filter", "Can't create Filter object in QML. Get them from Scope instance."); |
| 1970 | + qmlRegisterUncreatableType<unity::shell::scopes::OptionSelectorOptionsInterface>(uri, 0, 2, "OptionSelectorOptions", "Can't create Filters object in QML. Get them from OptionSelector instance."); |
| 1971 | + qmlRegisterUncreatableType<unity::shell::scopes::RangeInputFilterInterface>(uri, 0, 2, "RangeInputFilter", "Can't create new RangeInputFilter in QML. Get them from Filters instance."); |
| 1972 | + qmlRegisterUncreatableType<unity::shell::scopes::ValueSliderFilterInterface>(uri, 0, 2, "ValueSliderFilter", "Can't create new ValueSliderFilter in QML. Get them from Filters instance."); |
| 1973 | + qmlRegisterUncreatableType<unity::shell::scopes::ValueSliderValuesInterface>(uri, 0, 2, "ValueSliderValues", "Can't create new ValueSliderValues in QML. Get them from ValueSlideriFilter instance."); |
| 1974 | } |
| 1975 | |
| 1976 | void UnityPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
| 1977 | |
| 1978 | === added file 'src/Unity/rangeinputfilter.cpp' |
| 1979 | --- src/Unity/rangeinputfilter.cpp 1970-01-01 00:00:00 +0000 |
| 1980 | +++ src/Unity/rangeinputfilter.cpp 2016-03-16 11:17:35 +0000 |
| 1981 | @@ -0,0 +1,298 @@ |
| 1982 | +/* |
| 1983 | + * Copyright (C) 2015 Canonical, Ltd. |
| 1984 | + * |
| 1985 | + * Authors: |
| 1986 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
| 1987 | + * |
| 1988 | + * This program is free software; you can redistribute it and/or modify |
| 1989 | + * it under the terms of the GNU General Public License as published by |
| 1990 | + * the Free Software Foundation; version 3. |
| 1991 | + * |
| 1992 | + * This program is distributed in the hope that it will be useful, |
| 1993 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 1994 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 1995 | + * GNU General Public License for more details. |
| 1996 | + * |
| 1997 | + * You should have received a copy of the GNU General Public License |
| 1998 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 1999 | + */ |
| 2000 | + |
| 2001 | +#include "rangeinputfilter.h" |
| 2002 | +#include "utils.h" |
| 2003 | +#include <cmath> |
| 2004 | +#include <functional> |
| 2005 | +#include <QDebug> |
| 2006 | + |
| 2007 | +using namespace unity::scopes; |
| 2008 | + |
| 2009 | +namespace scopes_ng |
| 2010 | +{ |
| 2011 | + |
| 2012 | +RangeInputFilter::RangeInputFilter(unity::scopes::RangeInputFilter::SCPtr const& filter, unity::scopes::FilterState::SPtr const& filterState, unity::shell::scopes::FiltersInterface *parent) |
| 2013 | + : unity::shell::scopes::RangeInputFilterInterface(parent), |
| 2014 | + m_id(QString::fromStdString(filter->id())), |
| 2015 | + m_title(QString::fromStdString(filter->title())), |
| 2016 | + m_startPrefixLabel(QString::fromStdString(filter->start_prefix_label())), |
| 2017 | + m_startPostfixLabel(QString::fromStdString(filter->start_postfix_label())), |
| 2018 | + m_centralLabel(QString::fromStdString(filter->central_label())), |
| 2019 | + m_endPrefixLabel(QString::fromStdString(filter->end_prefix_label())), |
| 2020 | + m_endPostfixLabel(QString::fromStdString(filter->end_postfix_label())), |
| 2021 | + m_defaultStart(filter->default_start_value()), |
| 2022 | + m_defaultEnd(filter->default_end_value()), |
| 2023 | + m_filterState(filterState), |
| 2024 | + m_filter(filter) |
| 2025 | +{ |
| 2026 | + const bool use_defaults = !filterState->has_filter(m_filter->id()); |
| 2027 | + const unity::scopes::Variant start = m_filter->has_start_value(*filterState) ? Variant(m_filter->start_value(*filterState)) : (use_defaults ? |
| 2028 | + m_filter->default_start_value() : Variant::null()); |
| 2029 | + m_start = start; |
| 2030 | + const unity::scopes::Variant end = m_filter->has_end_value(*filterState) ? Variant(m_filter->end_value(*filterState)) : (use_defaults ? |
| 2031 | + m_filter->default_end_value() : Variant::null()); |
| 2032 | + m_end = end; |
| 2033 | +} |
| 2034 | + |
| 2035 | +QString RangeInputFilter::filterId() const |
| 2036 | +{ |
| 2037 | + return m_id; |
| 2038 | +} |
| 2039 | + |
| 2040 | +QString RangeInputFilter::title() const |
| 2041 | +{ |
| 2042 | + return m_title; |
| 2043 | +} |
| 2044 | + |
| 2045 | +unity::shell::scopes::FiltersInterface::FilterType RangeInputFilter::filterType() const |
| 2046 | +{ |
| 2047 | + return unity::shell::scopes::FiltersInterface::FilterType::RangeInputFilter; |
| 2048 | +} |
| 2049 | + |
| 2050 | +double RangeInputFilter::startValue() const |
| 2051 | +{ |
| 2052 | + if (m_start.which() == Variant::Double) { |
| 2053 | + return m_start.get_double(); |
| 2054 | + } |
| 2055 | + qWarning() << "Requested startValue for filter" << m_id << ", but value is not set"; |
| 2056 | + return 0.0f; |
| 2057 | +} |
| 2058 | + |
| 2059 | +double RangeInputFilter::endValue() const |
| 2060 | +{ |
| 2061 | + if (m_end.which() == Variant::Double) { |
| 2062 | + return m_end.get_double(); |
| 2063 | + } |
| 2064 | + qWarning() << "Requested endValue for filter" << m_id << ", but value is not set"; |
| 2065 | + return 0.0f; |
| 2066 | +} |
| 2067 | + |
| 2068 | +void RangeInputFilter::setStartValue(double value) |
| 2069 | +{ |
| 2070 | + const unity::scopes::Variant newValue(value); |
| 2071 | + setStartValue(newValue); |
| 2072 | +} |
| 2073 | + |
| 2074 | +void RangeInputFilter::setEndValue(double value) |
| 2075 | +{ |
| 2076 | + const unity::scopes::Variant newValue(value); |
| 2077 | + setEndValue(newValue); |
| 2078 | +} |
| 2079 | + |
| 2080 | +void RangeInputFilter::labelChange(std::string const& srcLabel, QString& destLabel, std::function<void()> const& emitLabelChangeSignal) |
| 2081 | +{ |
| 2082 | + auto const srclbl = QString::fromStdString(srcLabel); |
| 2083 | + if (srclbl != destLabel) { |
| 2084 | + destLabel = srclbl; |
| 2085 | + emitLabelChangeSignal(); |
| 2086 | + } |
| 2087 | +} |
| 2088 | + |
| 2089 | +void RangeInputFilter::update(unity::scopes::FilterState::SPtr const& filterState) |
| 2090 | +{ |
| 2091 | + m_filterState = filterState; |
| 2092 | + |
| 2093 | + const bool use_defaults = !filterState->has_filter(m_filter->id()); |
| 2094 | + const unity::scopes::Variant start = m_filter->has_start_value(*filterState) ? Variant(m_filter->start_value(*filterState)) : (use_defaults ? |
| 2095 | + m_filter->default_start_value() : Variant::null()); |
| 2096 | + if (!compare(start, m_start)) { |
| 2097 | + m_start = start; |
| 2098 | + if (m_start.is_null()) { |
| 2099 | + Q_EMIT hasStartValueChanged(); |
| 2100 | + } |
| 2101 | + Q_EMIT startValueChanged(); |
| 2102 | + } |
| 2103 | + |
| 2104 | + const unity::scopes::Variant end = m_filter->has_end_value(*filterState) ? Variant(m_filter->end_value(*filterState)) : (use_defaults ? |
| 2105 | + m_filter->default_end_value() : Variant::null()); |
| 2106 | + if (!compare(end, m_end)) { |
| 2107 | + m_end = end; |
| 2108 | + if (m_end.is_null()) { |
| 2109 | + Q_EMIT hasEndValueChanged(); |
| 2110 | + } |
| 2111 | + Q_EMIT endValueChanged(); |
| 2112 | + } |
| 2113 | +} |
| 2114 | + |
| 2115 | +void RangeInputFilter::update(unity::scopes::FilterBase::SCPtr const& filter) |
| 2116 | +{ |
| 2117 | + unity::scopes::RangeInputFilter::SCPtr rangefilter = std::dynamic_pointer_cast<unity::scopes::RangeInputFilter const>(filter); |
| 2118 | + if (!rangefilter) { |
| 2119 | + qWarning() << "RangeInputFilter::update(): Unexpected filter" << QString::fromStdString(filter->id()) << "of type" << QString::fromStdString(filter->filter_type()); |
| 2120 | + return; |
| 2121 | + } |
| 2122 | + |
| 2123 | + m_filter = rangefilter; |
| 2124 | + |
| 2125 | + if (rangefilter->title() != m_title.toStdString()) |
| 2126 | + { |
| 2127 | + m_title = QString::fromStdString(rangefilter->title()); |
| 2128 | + Q_EMIT titleChanged(); |
| 2129 | + } |
| 2130 | + |
| 2131 | + labelChange(m_filter->start_prefix_label(), m_startPrefixLabel, [this]() { Q_EMIT startPrefixLabelChanged(); }); |
| 2132 | + labelChange(m_filter->start_postfix_label(), m_startPostfixLabel, [this]() { Q_EMIT startPostfixLabelChanged(); }); |
| 2133 | + labelChange(m_filter->central_label(), m_centralLabel, [this]() { Q_EMIT centralLabelChanged(); }); |
| 2134 | + labelChange(m_filter->end_prefix_label(), m_endPrefixLabel, [this]() { Q_EMIT endPrefixLabelChanged(); }); |
| 2135 | + labelChange(m_filter->end_postfix_label(), m_endPostfixLabel, [this]() { Q_EMIT endPostfixLabelChanged(); }); |
| 2136 | +} |
| 2137 | + |
| 2138 | +bool RangeInputFilter::isActive() const |
| 2139 | +{ |
| 2140 | + if (auto state = m_filterState.lock()) { |
| 2141 | + // check if current value from filter state is equal to default value |
| 2142 | + if (m_filter->has_start_value(*state) && !compare(m_filter->start_value(*state), m_filter->default_start_value())) { |
| 2143 | + return true; |
| 2144 | + } |
| 2145 | + if (m_filter->has_end_value(*state) && !compare(m_filter->end_value(*state), m_filter->default_end_value())) { |
| 2146 | + return true; |
| 2147 | + } |
| 2148 | + } |
| 2149 | + return false; |
| 2150 | +} |
| 2151 | + |
| 2152 | +QString RangeInputFilter::filterTag() const |
| 2153 | +{ |
| 2154 | + return ""; // range input filter can't be a primary navigation filter |
| 2155 | +} |
| 2156 | + |
| 2157 | +QString RangeInputFilter::startPrefixLabel() const |
| 2158 | +{ |
| 2159 | + return m_startPrefixLabel; |
| 2160 | +} |
| 2161 | + |
| 2162 | +QString RangeInputFilter::startPostfixLabel() const |
| 2163 | +{ |
| 2164 | + return m_startPostfixLabel; |
| 2165 | +} |
| 2166 | + |
| 2167 | +QString RangeInputFilter::centralLabel() const |
| 2168 | +{ |
| 2169 | + return m_centralLabel; |
| 2170 | +} |
| 2171 | + |
| 2172 | +QString RangeInputFilter::endPrefixLabel() const |
| 2173 | +{ |
| 2174 | + return m_endPrefixLabel; |
| 2175 | +} |
| 2176 | + |
| 2177 | +QString RangeInputFilter::endPostfixLabel() const |
| 2178 | +{ |
| 2179 | + return m_endPostfixLabel; |
| 2180 | +} |
| 2181 | + |
| 2182 | +bool RangeInputFilter::hasStartValue() const |
| 2183 | +{ |
| 2184 | + return m_start.which() == Variant::Double; |
| 2185 | +} |
| 2186 | + |
| 2187 | +bool RangeInputFilter::hasEndValue() const |
| 2188 | +{ |
| 2189 | + return m_end.which() == Variant::Double; |
| 2190 | +} |
| 2191 | + |
| 2192 | +void RangeInputFilter::eraseStartValue() |
| 2193 | +{ |
| 2194 | + setStartValue(Variant::null()); |
| 2195 | +} |
| 2196 | + |
| 2197 | +void RangeInputFilter::eraseEndValue() |
| 2198 | +{ |
| 2199 | + setEndValue(Variant::null()); |
| 2200 | +} |
| 2201 | + |
| 2202 | +void RangeInputFilter::setStartValue(Variant const& value) |
| 2203 | +{ |
| 2204 | + if (auto state = m_filterState.lock()) { |
| 2205 | + try { |
| 2206 | + if (!compare(value, m_start)) { |
| 2207 | + qDebug() << "Changing startValue of filter" << m_id; |
| 2208 | + m_start = value; |
| 2209 | + |
| 2210 | + m_filter->update_state(*state, m_start, m_end); |
| 2211 | + |
| 2212 | + if (value.is_null()) { |
| 2213 | + Q_EMIT hasStartValueChanged(); |
| 2214 | + } |
| 2215 | + Q_EMIT startValueChanged(); |
| 2216 | + Q_EMIT filterStateChanged(); |
| 2217 | + } |
| 2218 | + } |
| 2219 | + catch (std::exception const& err) |
| 2220 | + { |
| 2221 | + // this is ok, it's user input and we may get partial input |
| 2222 | + qWarning() << "Could not set start value of filter" << m_id << ":" << QString::fromStdString(err.what()); |
| 2223 | + } |
| 2224 | + } |
| 2225 | +} |
| 2226 | + |
| 2227 | +void RangeInputFilter::setEndValue(Variant const& value) |
| 2228 | +{ |
| 2229 | + if (auto state = m_filterState.lock()) { |
| 2230 | + try { |
| 2231 | + if (!compare(value, m_end)) { |
| 2232 | + qDebug() << "Changing endValue of filter" << m_id; |
| 2233 | + m_end = value; |
| 2234 | + |
| 2235 | + m_filter->update_state(*state, m_start, m_end); |
| 2236 | + |
| 2237 | + if (value.is_null()) { |
| 2238 | + Q_EMIT hasEndValueChanged(); |
| 2239 | + } |
| 2240 | + Q_EMIT endValueChanged(); |
| 2241 | + Q_EMIT filterStateChanged(); |
| 2242 | + } |
| 2243 | + } |
| 2244 | + catch (std::exception const& err) |
| 2245 | + { |
| 2246 | + // this is ok, it's user input and we may get partial input |
| 2247 | + qWarning() << "Could not set start value of filter" << m_id << ":" << QString::fromStdString(err.what()); |
| 2248 | + } |
| 2249 | + } |
| 2250 | +} |
| 2251 | + |
| 2252 | +bool RangeInputFilter::compare(Variant const& v1, Variant const& v2) |
| 2253 | +{ |
| 2254 | + if (v1 == v2) { |
| 2255 | + return true; |
| 2256 | + } |
| 2257 | + if (v1.which() == Variant::Double && v2.which() == Variant::Double) { |
| 2258 | + return std::abs(v1.get_double() - v2.get_double()) < 0.0000001f; |
| 2259 | + } |
| 2260 | + return false; |
| 2261 | +} |
| 2262 | + |
| 2263 | +bool RangeInputFilter::compare(double v1, Variant const& v2) |
| 2264 | +{ |
| 2265 | + if (v2.which() == Variant::Double) { |
| 2266 | + return std::abs(v1 - v2.get_double()) < 0.0000001f; |
| 2267 | + } |
| 2268 | + return false; |
| 2269 | +} |
| 2270 | + |
| 2271 | +void RangeInputFilter::reset() |
| 2272 | +{ |
| 2273 | + // Filters::onFilterStateChanged will delay actual refresh, |
| 2274 | + // so it's ok to make two independent updates and emit two signals |
| 2275 | + setStartValue(m_filter->default_start_value()); |
| 2276 | + setEndValue(m_filter->default_end_value()); |
| 2277 | +} |
| 2278 | + |
| 2279 | +} |
| 2280 | |
| 2281 | === added file 'src/Unity/rangeinputfilter.h' |
| 2282 | --- src/Unity/rangeinputfilter.h 1970-01-01 00:00:00 +0000 |
| 2283 | +++ src/Unity/rangeinputfilter.h 2016-03-16 11:17:35 +0000 |
| 2284 | @@ -0,0 +1,93 @@ |
| 2285 | +/* |
| 2286 | + * Copyright (C) 2015 Canonical, Ltd. |
| 2287 | + * |
| 2288 | + * Authors: |
| 2289 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
| 2290 | + * |
| 2291 | + * This program is free software; you can redistribute it and/or modify |
| 2292 | + * it under the terms of the GNU General Public License as published by |
| 2293 | + * the Free Software Foundation; version 3. |
| 2294 | + * |
| 2295 | + * This program is distributed in the hope that it will be useful, |
| 2296 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 2297 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 2298 | + * GNU General Public License for more details. |
| 2299 | + * |
| 2300 | + * You should have received a copy of the GNU General Public License |
| 2301 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 2302 | + */ |
| 2303 | + |
| 2304 | +#ifndef NG_RANGEINPUTFILTER_H |
| 2305 | +#define NG_RANGEINPUTFILTER_H |
| 2306 | + |
| 2307 | +#include <unity/shell/scopes/RangeInputFilterInterface.h> |
| 2308 | +#include <unity/shell/scopes/FiltersInterface.h> |
| 2309 | +#include "filters.h" |
| 2310 | +#include <unity/scopes/RangeInputFilter.h> |
| 2311 | +#include <QScopedPointer> |
| 2312 | + |
| 2313 | +namespace scopes_ng |
| 2314 | +{ |
| 2315 | + |
| 2316 | +class Q_DECL_EXPORT RangeInputFilter : public unity::shell::scopes::RangeInputFilterInterface, public FilterUpdateInterface |
| 2317 | +{ |
| 2318 | + Q_OBJECT |
| 2319 | + |
| 2320 | +public: |
| 2321 | + RangeInputFilter(unity::scopes::RangeInputFilter::SCPtr const& filter, unity::scopes::FilterState::SPtr const& filterState, unity::shell::scopes::FiltersInterface *parent = nullptr); |
| 2322 | + QString filterId() const override; |
| 2323 | + QString title() const override; |
| 2324 | + unity::shell::scopes::FiltersInterface::FilterType filterType() const override; |
| 2325 | + double startValue() const override; |
| 2326 | + double endValue() const override; |
| 2327 | + |
| 2328 | + QString startPrefixLabel() const override; |
| 2329 | + QString startPostfixLabel() const override; |
| 2330 | + QString centralLabel() const override; |
| 2331 | + QString endPrefixLabel() const override; |
| 2332 | + QString endPostfixLabel() const override; |
| 2333 | + |
| 2334 | + void setStartValue(double value) override; |
| 2335 | + void setEndValue(double value) override; |
| 2336 | + |
| 2337 | + bool hasStartValue() const override; |
| 2338 | + bool hasEndValue() const override; |
| 2339 | + |
| 2340 | + Q_INVOKABLE void eraseStartValue() override; |
| 2341 | + Q_INVOKABLE void eraseEndValue() override; |
| 2342 | + |
| 2343 | + void update(unity::scopes::FilterBase::SCPtr const& filter) override; |
| 2344 | + void update(unity::scopes::FilterState::SPtr const& filterState) override; |
| 2345 | + bool isActive() const override; |
| 2346 | + QString filterTag() const override; |
| 2347 | + void reset() override; |
| 2348 | + |
| 2349 | +Q_SIGNALS: |
| 2350 | + void filterStateChanged(); |
| 2351 | + |
| 2352 | +private: |
| 2353 | + void setStartValue(unity::scopes::Variant const& value); |
| 2354 | + void setEndValue(unity::scopes::Variant const& value); |
| 2355 | + static void labelChange(std::string const& srcLabel, QString& destLabel, std::function<void()> const& emitLabelChangeSignal); |
| 2356 | + |
| 2357 | + QString m_id; |
| 2358 | + QString m_title; |
| 2359 | + QString m_startPrefixLabel; |
| 2360 | + QString m_startPostfixLabel; |
| 2361 | + QString m_centralLabel; |
| 2362 | + QString m_endPrefixLabel; |
| 2363 | + QString m_endPostfixLabel; |
| 2364 | + unity::scopes::Variant m_defaultStart; |
| 2365 | + unity::scopes::Variant m_defaultEnd; |
| 2366 | + unity::scopes::Variant m_start; |
| 2367 | + unity::scopes::Variant m_end; |
| 2368 | + std::weak_ptr<unity::scopes::FilterState> m_filterState; |
| 2369 | + unity::scopes::RangeInputFilter::SCPtr m_filter; |
| 2370 | + |
| 2371 | + static bool compare(double v1, unity::scopes::Variant const& v2); |
| 2372 | + static bool compare(unity::scopes::Variant const& v1, unity::scopes::Variant const& v2); |
| 2373 | +}; |
| 2374 | + |
| 2375 | +} // namespace scopes_ng |
| 2376 | + |
| 2377 | +#endif |
| 2378 | |
| 2379 | === modified file 'src/Unity/resultsmodel.cpp' |
| 2380 | --- src/Unity/resultsmodel.cpp 2016-02-15 17:43:12 +0000 |
| 2381 | +++ src/Unity/resultsmodel.cpp 2016-03-16 11:17:35 +0000 |
| 2382 | @@ -325,6 +325,8 @@ |
| 2383 | return QVariant(); |
| 2384 | case RoleQuickPreviewData: |
| 2385 | return componentValue(result, "quick-preview-data"); |
| 2386 | + case RoleSocialActions: |
| 2387 | + return componentValue(result, "social-actions"); |
| 2388 | default: |
| 2389 | return QVariant(); |
| 2390 | } |
| 2391 | |
| 2392 | === modified file 'src/Unity/scope.cpp' |
| 2393 | --- src/Unity/scope.cpp 2016-02-26 12:38:28 +0000 |
| 2394 | +++ src/Unity/scope.cpp 2016-03-16 11:17:35 +0000 |
| 2395 | @@ -1,8 +1,9 @@ |
| 2396 | /* |
| 2397 | - * Copyright (C) 2013 Canonical, Ltd. |
| 2398 | + * Copyright (C) 2015 Canonical, Ltd. |
| 2399 | * |
| 2400 | * Authors: |
| 2401 | * Michal Hruby <michal.hruby@canonical.com> |
| 2402 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
| 2403 | * |
| 2404 | * This program is free software; you can redistribute it and/or modify |
| 2405 | * it under the terms of the GNU General Public License as published by |
| 2406 | @@ -81,13 +82,13 @@ |
| 2407 | Scope::Scope(scopes_ng::Scopes* parent) : |
| 2408 | m_query_id(0) |
| 2409 | , m_formFactor(QStringLiteral("phone")) |
| 2410 | + , m_activeFiltersCount(0) |
| 2411 | , m_isActive(false) |
| 2412 | , m_searchInProgress(false) |
| 2413 | , m_activationInProgress(false) |
| 2414 | , m_resultsDirty(false) |
| 2415 | , m_delayedSearchProcessing(false) |
| 2416 | , m_hasNavigation(false) |
| 2417 | - , m_hasAltNavigation(false) |
| 2418 | , m_favorite(false) |
| 2419 | , m_initialQueryDone(false) |
| 2420 | , m_searchController(new CollectionController) |
| 2421 | @@ -96,6 +97,12 @@ |
| 2422 | { |
| 2423 | QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); |
| 2424 | m_categories.reset(new Categories(this)); |
| 2425 | + m_filters.reset(new Filters(m_filterState, this)); |
| 2426 | + |
| 2427 | + connect(m_filters.data(), SIGNAL(primaryFilterChanged()), this, SIGNAL(primaryNavigationFilterChanged())); |
| 2428 | + |
| 2429 | + QQmlEngine::setObjectOwnership(m_filters.data(), QQmlEngine::CppOwnership); |
| 2430 | + connect(m_filters.data(), SIGNAL(filterStateChanged()), this, SLOT(filterStateChanged())); |
| 2431 | |
| 2432 | setScopesInstance(parent); |
| 2433 | |
| 2434 | @@ -125,17 +132,15 @@ |
| 2435 | CollectorBase::Status status; |
| 2436 | QList<std::shared_ptr<scopes::CategorisedResult>> results; |
| 2437 | scopes::Department::SCPtr rootDepartment; |
| 2438 | - scopes::OptionSelectorFilter::SCPtr sortOrderFilter; |
| 2439 | - scopes::FilterState filterState; |
| 2440 | + QList<scopes::FilterBase::SCPtr> filters; |
| 2441 | |
| 2442 | - status = pushEvent->collectSearchResults(results, rootDepartment, sortOrderFilter, filterState); |
| 2443 | + status = pushEvent->collectSearchResults(results, rootDepartment, filters); |
| 2444 | if (status == CollectorBase::Status::CANCELLED) { |
| 2445 | return; |
| 2446 | } |
| 2447 | |
| 2448 | m_rootDepartment = rootDepartment; |
| 2449 | - m_sortOrderFilter = sortOrderFilter; |
| 2450 | - m_receivedFilterState = filterState; |
| 2451 | + m_receivedFilters = filters; |
| 2452 | |
| 2453 | if (m_cachedResults.empty()) { |
| 2454 | m_cachedResults.swap(results); |
| 2455 | @@ -404,17 +409,14 @@ |
| 2456 | } |
| 2457 | |
| 2458 | m_lastRootDepartment = m_rootDepartment; |
| 2459 | + bool containsDepartments = (m_rootDepartment.get() != nullptr); |
| 2460 | |
| 2461 | // |
| 2462 | // only consider resetting current department id if we are in final flushUpdates |
| 2463 | // or received departments already. We don't know if we should reset it |
| 2464 | // until query finishes because departments may still arrive. |
| 2465 | - if (finalize || m_rootDepartment.get() != nullptr) |
| 2466 | + if (finalize || containsDepartments) |
| 2467 | { |
| 2468 | - bool containsDepartments = m_rootDepartment.get() != nullptr; |
| 2469 | - // design decision - no navigation when doing searches |
| 2470 | - containsDepartments &= m_searchQuery.isEmpty(); |
| 2471 | - |
| 2472 | if (containsDepartments != m_hasNavigation) { |
| 2473 | m_hasNavigation = containsDepartments; |
| 2474 | Q_EMIT hasNavigationChanged(); |
| 2475 | @@ -425,54 +427,30 @@ |
| 2476 | m_currentNavigationId = QLatin1String(""); |
| 2477 | Q_EMIT currentNavigationIdChanged(); |
| 2478 | } |
| 2479 | - } |
| 2480 | - |
| 2481 | - // process the alt navigation (sort order filter) |
| 2482 | - QString currentAltNav(m_currentAltNavigationId); |
| 2483 | - |
| 2484 | - if (m_sortOrderFilter && m_sortOrderFilter != m_lastSortOrderFilter) { |
| 2485 | - // build the nodes |
| 2486 | - m_altNavTree.reset(new DepartmentNode); |
| 2487 | - m_altNavTree->initializeForFilter(m_sortOrderFilter); |
| 2488 | - |
| 2489 | - if (m_sortOrderFilter->has_active_option(m_receivedFilterState)) { |
| 2490 | - auto active_options = m_sortOrderFilter->active_options(m_receivedFilterState); |
| 2491 | - scopes::FilterOption::SCPtr active_option = *active_options.begin(); |
| 2492 | - if (active_option) { |
| 2493 | - currentAltNav = QString::fromStdString(active_option->id()); |
| 2494 | - } |
| 2495 | - } |
| 2496 | - } |
| 2497 | - |
| 2498 | - m_lastSortOrderFilter = m_sortOrderFilter; |
| 2499 | - |
| 2500 | - // |
| 2501 | - // only consider resetting alt nav id if we are in final flushUpdates |
| 2502 | - // or received alt nav filter already. We don't know if we should reset it |
| 2503 | - // until query finishes because filter may still arrive. |
| 2504 | - if (finalize || m_sortOrderFilter.get() != nullptr) |
| 2505 | + processPrimaryNavigationTag(m_currentNavigationId); |
| 2506 | + } |
| 2507 | + |
| 2508 | + // process filters |
| 2509 | + if (finalize || m_receivedFilters.size() > 0) |
| 2510 | { |
| 2511 | - bool containsAltNav = m_sortOrderFilter.get() != nullptr; |
| 2512 | - // design decision - no navigation when doing searches |
| 2513 | - containsAltNav &= m_searchQuery.isEmpty(); |
| 2514 | - |
| 2515 | - if (containsAltNav != m_hasAltNavigation) { |
| 2516 | - m_hasAltNavigation = containsAltNav; |
| 2517 | - Q_EMIT hasAltNavigationChanged(); |
| 2518 | - } |
| 2519 | - |
| 2520 | - if (!containsAltNav && !m_currentAltNavigationId.isEmpty()) { |
| 2521 | - qDebug() << "Resetting alt nav id"; |
| 2522 | - m_currentAltNavigationId = QLatin1String(""); |
| 2523 | - Q_EMIT currentAltNavigationIdChanged(); |
| 2524 | - } |
| 2525 | - |
| 2526 | - if (containsAltNav && currentAltNav != m_currentAltNavigationId) { |
| 2527 | - m_currentAltNavigationId = currentAltNav; |
| 2528 | - Q_EMIT currentAltNavigationIdChanged(); |
| 2529 | - |
| 2530 | - // update the alt navigation models |
| 2531 | - updateNavigationModels(m_altNavTree.data(), m_altNavModels, m_currentAltNavigationId); |
| 2532 | + qDebug() << "Processing" << m_receivedFilters.size() << "filters"; |
| 2533 | + const bool containsFilters = (m_receivedFilters.size() > 0); |
| 2534 | + const bool haveFiltersAlready = (m_filters->rowCount() > 0); |
| 2535 | + if (containsFilters) { |
| 2536 | + m_filters->update(m_receivedFilters, containsDepartments); |
| 2537 | + processPrimaryNavigationTag(m_currentNavigationId); |
| 2538 | + if (!haveFiltersAlready) { |
| 2539 | + Q_EMIT filtersChanged(); |
| 2540 | + } |
| 2541 | + qDebug() << "Current number of filters:" << m_filters->rowCount(); |
| 2542 | + } |
| 2543 | + else |
| 2544 | + { |
| 2545 | + qDebug() << "Removing all filters"; |
| 2546 | + m_filters->clear(); |
| 2547 | + if (haveFiltersAlready) { |
| 2548 | + Q_EMIT filtersChanged(); |
| 2549 | + } |
| 2550 | } |
| 2551 | } |
| 2552 | } |
| 2553 | @@ -698,6 +676,7 @@ |
| 2554 | { |
| 2555 | if (m_currentNavigationId != id) { |
| 2556 | qDebug() << "Setting current nav id:" << this->id() << id; |
| 2557 | + processPrimaryNavigationTag(id); |
| 2558 | m_currentNavigationId = id; |
| 2559 | Q_EMIT currentNavigationIdChanged(); |
| 2560 | } |
| 2561 | @@ -935,13 +914,6 @@ |
| 2562 | } |
| 2563 | } |
| 2564 | |
| 2565 | -/* |
| 2566 | -Filters* Scope::filters() const |
| 2567 | -{ |
| 2568 | - return m_filters.get(); |
| 2569 | -} |
| 2570 | -*/ |
| 2571 | - |
| 2572 | unity::shell::scopes::NavigationInterface* Scope::getNavigation(QString const& navId) |
| 2573 | { |
| 2574 | if (!m_departmentTree) return nullptr; |
| 2575 | @@ -962,54 +934,19 @@ |
| 2576 | return navModel; |
| 2577 | } |
| 2578 | |
| 2579 | -unity::shell::scopes::NavigationInterface* Scope::getAltNavigation(QString const& navId) |
| 2580 | -{ |
| 2581 | - if (!m_altNavTree) return nullptr; |
| 2582 | - |
| 2583 | - DepartmentNode* node = m_altNavTree->findNodeById(navId); |
| 2584 | - if (!node) return nullptr; |
| 2585 | - |
| 2586 | - Department* navModel = new Department; |
| 2587 | - navModel->setScopeId(this->id()); |
| 2588 | - navModel->loadFromDepartmentNode(node); |
| 2589 | - navModel->markSubdepartmentActive(m_currentAltNavigationId); |
| 2590 | - |
| 2591 | - // sharing m_inverseDepartments with getNavigation |
| 2592 | - m_altNavModels.insert(navId, navModel); |
| 2593 | - m_inverseDepartments.insert(navModel, navId); |
| 2594 | - QObject::connect(navModel, &QObject::destroyed, this, &Scope::departmentModelDestroyed); |
| 2595 | - |
| 2596 | - return navModel; |
| 2597 | -} |
| 2598 | - |
| 2599 | -QString Scope::buildQuery(QString const& scopeId, QString const& searchQuery, QString const& departmentId, QString const& primaryFilterId, QString const& primaryOptionId) |
| 2600 | +QString Scope::buildQuery(QString const& scopeId, QString const& searchQuery, QString const& departmentId, unity::scopes::FilterState const& filterState) |
| 2601 | { |
| 2602 | scopes::CannedQuery q(scopeId.toStdString()); |
| 2603 | q.set_query_string(searchQuery.toStdString()); |
| 2604 | q.set_department_id(departmentId.toStdString()); |
| 2605 | - |
| 2606 | - if (!primaryFilterId.isEmpty() && !primaryOptionId.isEmpty()) { |
| 2607 | - scopes::FilterState filter_state; |
| 2608 | - scopes::OptionSelectorFilter::update_state(filter_state, primaryFilterId.toStdString(), primaryOptionId.toStdString(), true); |
| 2609 | - q.set_filter_state(filter_state); |
| 2610 | - } |
| 2611 | - |
| 2612 | + q.set_filter_state(filterState); |
| 2613 | return QString::fromStdString(q.to_uri()); |
| 2614 | } |
| 2615 | |
| 2616 | -void Scope::setNavigationState(QString const& navId, bool altNavigation) |
| 2617 | +void Scope::setNavigationState(QString const& navId) |
| 2618 | { |
| 2619 | - QString primaryFilterId; |
| 2620 | - if (m_sortOrderFilter) { |
| 2621 | - primaryFilterId = QString::fromStdString(m_sortOrderFilter->id()); |
| 2622 | - } |
| 2623 | - if (!altNavigation) { |
| 2624 | - // switch current department id |
| 2625 | - performQuery(buildQuery(id(), m_searchQuery, navId, primaryFilterId, m_currentAltNavigationId)); |
| 2626 | - } else { |
| 2627 | - // switch current primary filter |
| 2628 | - performQuery(buildQuery(id(), m_searchQuery, m_currentNavigationId, primaryFilterId, navId)); |
| 2629 | - } |
| 2630 | + // switch current department id |
| 2631 | + performQuery(buildQuery(id(), m_searchQuery, navId, m_filterState)); |
| 2632 | } |
| 2633 | |
| 2634 | void Scope::departmentModelDestroyed(QObject* obj) |
| 2635 | @@ -1020,7 +957,6 @@ |
| 2636 | if (it == m_inverseDepartments.end()) return; |
| 2637 | |
| 2638 | m_departmentModels.remove(it.value(), navigation); |
| 2639 | - m_altNavModels.remove(it.value(), navigation); |
| 2640 | m_inverseDepartments.erase(it); |
| 2641 | } |
| 2642 | |
| 2643 | @@ -1082,21 +1018,16 @@ |
| 2644 | return m_hasNavigation; |
| 2645 | } |
| 2646 | |
| 2647 | -QString Scope::currentAltNavigationId() const |
| 2648 | -{ |
| 2649 | - return m_currentAltNavigationId; |
| 2650 | -} |
| 2651 | - |
| 2652 | -bool Scope::hasAltNavigation() const |
| 2653 | -{ |
| 2654 | - return m_hasAltNavigation; |
| 2655 | -} |
| 2656 | - |
| 2657 | QVariantMap Scope::customizations() const |
| 2658 | { |
| 2659 | return m_customizations; |
| 2660 | } |
| 2661 | |
| 2662 | +int Scope::activeFiltersCount() const |
| 2663 | +{ |
| 2664 | + return m_activeFiltersCount; |
| 2665 | +} |
| 2666 | + |
| 2667 | void Scope::setSearchQuery(const QString& search_query) |
| 2668 | { |
| 2669 | // this method is called by the shell when user types in search string, |
| 2670 | @@ -1133,11 +1064,6 @@ |
| 2671 | } |
| 2672 | m_searchQuery = search_query; |
| 2673 | |
| 2674 | - // atm only empty query can have a filter state |
| 2675 | - if (!m_searchQuery.isEmpty()) { |
| 2676 | - m_filterState = scopes::FilterState(); |
| 2677 | - } |
| 2678 | - |
| 2679 | // only use typing delay if scope is active, otherwise apply immediately |
| 2680 | if (m_isActive) { |
| 2681 | m_typingTimer.start(); |
| 2682 | @@ -1348,6 +1274,19 @@ |
| 2683 | } |
| 2684 | } |
| 2685 | |
| 2686 | +void Scope::resetPrimaryNavigationTag() |
| 2687 | +{ |
| 2688 | + qDebug() << "resetPrimaryNavigationTag()"; |
| 2689 | + setCurrentNavigationId(""); |
| 2690 | + m_filters->update(unity::scopes::FilterState()); |
| 2691 | + filterStateChanged(); |
| 2692 | +} |
| 2693 | + |
| 2694 | +void Scope::resetFilters() |
| 2695 | +{ |
| 2696 | + m_filters->reset(); |
| 2697 | +} |
| 2698 | + |
| 2699 | void Scope::closeScope(unity::shell::scopes::ScopeInterface* scope) |
| 2700 | { |
| 2701 | if (m_scopesInstance) { |
| 2702 | @@ -1392,4 +1331,82 @@ |
| 2703 | return m_initialQueryDone; |
| 2704 | } |
| 2705 | |
| 2706 | +unity::shell::scopes::FiltersInterface* Scope::filters() const |
| 2707 | +{ |
| 2708 | + if (m_filters && m_filters->rowCount() == 0) { |
| 2709 | + return nullptr; |
| 2710 | + } |
| 2711 | + return m_filters.data(); |
| 2712 | +} |
| 2713 | + |
| 2714 | +unity::shell::scopes::FilterBaseInterface* Scope::primaryNavigationFilter() const |
| 2715 | +{ |
| 2716 | + return m_filters->primaryFilter().data(); |
| 2717 | +} |
| 2718 | + |
| 2719 | +QString Scope::primaryNavigationTag() const |
| 2720 | +{ |
| 2721 | + return m_primaryNavigationTag; |
| 2722 | +} |
| 2723 | + |
| 2724 | +void Scope::filterStateChanged() |
| 2725 | +{ |
| 2726 | + qDebug() << "Filters changed"; |
| 2727 | + m_filterState = m_filters->filterState(); |
| 2728 | + processPrimaryNavigationTag(m_currentNavigationId); |
| 2729 | + processActiveFiltersCount(); |
| 2730 | + invalidateResults(); |
| 2731 | +} |
| 2732 | + |
| 2733 | +// |
| 2734 | +// Iterate over all filters to calculate the number of active ones. |
| 2735 | +void Scope::processActiveFiltersCount() |
| 2736 | +{ |
| 2737 | + const int count = m_filters->activeFiltersCount(); |
| 2738 | + if (count != m_activeFiltersCount) { |
| 2739 | + m_activeFiltersCount = count; |
| 2740 | + Q_EMIT activeFiltersCountChanged(); |
| 2741 | + } |
| 2742 | + qDebug() << "active filters count:" << m_activeFiltersCount; |
| 2743 | +} |
| 2744 | + |
| 2745 | +// |
| 2746 | +// Determine primary navigation tag (the "brick" in search bar) from |
| 2747 | +// current department (if departments are present) or primary navigation |
| 2748 | +// filter (if scopes doesn't have departments but has filters and one of |
| 2749 | +// them has 'Primary' flag set. |
| 2750 | +void Scope::processPrimaryNavigationTag(QString const &targetDepartmentId) |
| 2751 | +{ |
| 2752 | + QString tag; |
| 2753 | + // has departments? |
| 2754 | + if (m_rootDepartment) { |
| 2755 | + auto it = m_departmentModels.constFind(targetDepartmentId); |
| 2756 | + if (it != m_departmentModels.constEnd()) { |
| 2757 | + tag = (targetDepartmentId == "" ? "" : it.value()->label()); |
| 2758 | + } else { |
| 2759 | + it = m_departmentModels.constFind(m_currentNavigationId); |
| 2760 | + if (it != m_departmentModels.constEnd()) { |
| 2761 | + auto subDept = (*it)->findSubdepartment(targetDepartmentId); |
| 2762 | + if (subDept) { |
| 2763 | + tag = subDept->label; |
| 2764 | + } else { |
| 2765 | + qWarning() << "Scope::processPrimaryNavigationTag(): no subdepartment '" << targetDepartmentId << "'"; |
| 2766 | + } |
| 2767 | + } else { |
| 2768 | + qWarning() << "Scope::processPrimaryNavigationTag(): no department model for '" << m_currentNavigationId << "'"; |
| 2769 | + } |
| 2770 | + } |
| 2771 | + } else { |
| 2772 | + auto pf = m_filters->primaryFilter(); |
| 2773 | + if (pf) { |
| 2774 | + tag = pf->filterTag(); |
| 2775 | + } |
| 2776 | + } |
| 2777 | + qDebug() << "Scope::processPrimaryNavigationTag(): tag is '" << tag << "'"; |
| 2778 | + if (m_primaryNavigationTag != tag) { |
| 2779 | + m_primaryNavigationTag = tag; |
| 2780 | + Q_EMIT primaryNavigationTagChanged(); |
| 2781 | + } |
| 2782 | +} |
| 2783 | + |
| 2784 | } // namespace scopes_ng |
| 2785 | |
| 2786 | === modified file 'src/Unity/scope.h' |
| 2787 | --- src/Unity/scope.h 2016-02-18 15:46:26 +0000 |
| 2788 | +++ src/Unity/scope.h 2016-03-16 11:17:35 +0000 |
| 2789 | @@ -38,6 +38,7 @@ |
| 2790 | #include <unity/scopes/ScopeMetadata.h> |
| 2791 | #include <unity/shell/scopes/ScopeInterface.h> |
| 2792 | |
| 2793 | +#include "filters.h" |
| 2794 | #include "collectors.h" |
| 2795 | #include "departmentnode.h" |
| 2796 | #include "department.h" |
| 2797 | @@ -129,6 +130,11 @@ |
| 2798 | unity::shell::scopes::ScopeInterface::Status status() const override; |
| 2799 | unity::shell::scopes::CategoriesInterface* categories() const override; |
| 2800 | unity::shell::scopes::SettingsModelInterface* settings() const override; |
| 2801 | + unity::shell::scopes::FiltersInterface* filters() const override; |
| 2802 | + unity::shell::scopes::FilterBaseInterface* primaryNavigationFilter() const override; |
| 2803 | + QString primaryNavigationTag() const override; |
| 2804 | + int activeFiltersCount() const override; |
| 2805 | + |
| 2806 | bool require_child_scopes_refresh() const; |
| 2807 | void update_child_scopes(); |
| 2808 | QString searchQuery() const override; |
| 2809 | @@ -137,8 +143,6 @@ |
| 2810 | bool isActive() const override; |
| 2811 | QString currentNavigationId() const override; |
| 2812 | bool hasNavigation() const override; |
| 2813 | - QString currentAltNavigationId() const override; |
| 2814 | - bool hasAltNavigation() const override; |
| 2815 | QVariantMap customizations() const override; |
| 2816 | |
| 2817 | /* setters */ |
| 2818 | @@ -153,10 +157,11 @@ |
| 2819 | Q_INVOKABLE void cancelActivation() override; |
| 2820 | Q_INVOKABLE void closeScope(unity::shell::scopes::ScopeInterface* scope) override; |
| 2821 | Q_INVOKABLE unity::shell::scopes::NavigationInterface* getNavigation(QString const& id) override; |
| 2822 | - Q_INVOKABLE unity::shell::scopes::NavigationInterface* getAltNavigation(QString const& id) override; |
| 2823 | - Q_INVOKABLE void setNavigationState(QString const& navId, bool altNavigation) override; |
| 2824 | + Q_INVOKABLE void setNavigationState(QString const& navId) override; |
| 2825 | Q_INVOKABLE void performQuery(QString const& cannedQuery) override; |
| 2826 | Q_INVOKABLE void refresh() override; |
| 2827 | + Q_INVOKABLE void resetPrimaryNavigationTag() override; |
| 2828 | + Q_INVOKABLE void resetFilters() override; |
| 2829 | |
| 2830 | void setScopeData(unity::scopes::ScopeMetadata const& data); |
| 2831 | void handleActivation(std::shared_ptr<unity::scopes::ActivationResponse> const&, unity::scopes::Result::SPtr const&, QString const& categoryId=""); |
| 2832 | @@ -191,6 +196,7 @@ |
| 2833 | void flushUpdates(bool finalize = false); |
| 2834 | void metadataRefreshed(); |
| 2835 | void departmentModelDestroyed(QObject* obj); |
| 2836 | + void filterStateChanged(); |
| 2837 | void previewModelDestroyed(QObject *obj); |
| 2838 | |
| 2839 | protected: |
| 2840 | @@ -206,12 +212,14 @@ |
| 2841 | |
| 2842 | private: |
| 2843 | static void updateNavigationModels(DepartmentNode* rootNode, QMultiMap<QString, Department*>& navigationModels, QString const& activeNavigation); |
| 2844 | - static QString buildQuery(QString const& scopeId, QString const& searchQuery, QString const& departmentId, QString const& primaryFilterId, QString const& primaryOptionId); |
| 2845 | + static QString buildQuery(QString const& scopeId, QString const& searchQuery, QString const& departmentId, unity::scopes::FilterState const& filterState); |
| 2846 | void setScopesInstance(Scopes*); |
| 2847 | void startTtlTimer(); |
| 2848 | void setCurrentNavigationId(QString const& id); |
| 2849 | void setFilterState(unity::scopes::FilterState const& filterState); |
| 2850 | void processSearchChunk(PushEvent* pushEvent); |
| 2851 | + void processPrimaryNavigationTag(QString const &targetDepartmentId); |
| 2852 | + void processActiveFiltersCount(); |
| 2853 | void setCannedQuery(unity::scopes::CannedQuery const& query); |
| 2854 | void executeCannedQuery(unity::scopes::CannedQuery const& query, bool allowDelayedActivation); |
| 2855 | void handlePreviewUpdate(unity::scopes::Result::SPtr const& result, unity::scopes::PreviewWidgetList const& widgets); |
| 2856 | @@ -227,16 +235,16 @@ |
| 2857 | QString m_noResultsHint; |
| 2858 | QString m_formFactor; |
| 2859 | QString m_currentNavigationId; |
| 2860 | - QString m_currentAltNavigationId; |
| 2861 | + QString m_primaryNavigationTag; |
| 2862 | QVariantMap m_customizations; |
| 2863 | std::unique_ptr<unity::scopes::Variant> m_queryUserData; |
| 2864 | + int m_activeFiltersCount; |
| 2865 | bool m_isActive; |
| 2866 | bool m_searchInProgress; |
| 2867 | bool m_activationInProgress; |
| 2868 | bool m_resultsDirty; |
| 2869 | bool m_delayedSearchProcessing; |
| 2870 | bool m_hasNavigation; |
| 2871 | - bool m_hasAltNavigation; |
| 2872 | bool m_favorite; |
| 2873 | bool m_initialQueryDone; |
| 2874 | |
| 2875 | @@ -248,20 +256,18 @@ |
| 2876 | std::shared_ptr<unity::scopes::ActivationResponse> m_delayedActivation; |
| 2877 | unity::scopes::Department::SCPtr m_rootDepartment; |
| 2878 | unity::scopes::Department::SCPtr m_lastRootDepartment; |
| 2879 | - unity::scopes::OptionSelectorFilter::SCPtr m_sortOrderFilter; |
| 2880 | - unity::scopes::OptionSelectorFilter::SCPtr m_lastSortOrderFilter; |
| 2881 | unity::scopes::FilterState m_filterState; |
| 2882 | - unity::scopes::FilterState m_receivedFilterState; |
| 2883 | unity::shell::scopes::ScopeInterface::Status m_status; |
| 2884 | + QList<unity::scopes::FilterBase::SCPtr> m_receivedFilters; |
| 2885 | + QScopedPointer<Filters> m_filters; |
| 2886 | + |
| 2887 | QScopedPointer<SettingsModel> m_settingsModel; |
| 2888 | QSharedPointer<DepartmentNode> m_departmentTree; |
| 2889 | - QSharedPointer<DepartmentNode> m_altNavTree; |
| 2890 | QTimer m_typingTimer; |
| 2891 | QTimer m_searchProcessingDelayTimer; |
| 2892 | QTimer m_invalidateTimer; |
| 2893 | QList<std::shared_ptr<unity::scopes::CategorisedResult>> m_cachedResults; |
| 2894 | QMultiMap<QString, Department*> m_departmentModels; |
| 2895 | - QMultiMap<QString, Department*> m_altNavModels; |
| 2896 | QMap<Department*, QString> m_inverseDepartments; |
| 2897 | QMetaObject::Connection m_metadataConnection; |
| 2898 | QSharedPointer<LocationService> m_locationService; |
| 2899 | |
| 2900 | === modified file 'src/Unity/utils.cpp' |
| 2901 | --- src/Unity/utils.cpp 2015-09-08 12:32:05 +0000 |
| 2902 | +++ src/Unity/utils.cpp 2016-03-16 11:17:35 +0000 |
| 2903 | @@ -78,6 +78,8 @@ |
| 2904 | return scopes::Variant(static_cast<int64_t>(variant.toUInt())); |
| 2905 | case QMetaType::Double: |
| 2906 | return scopes::Variant(variant.toDouble()); |
| 2907 | + case QMetaType::Float: |
| 2908 | + return scopes::Variant(variant.toDouble()); |
| 2909 | case QMetaType::QString: |
| 2910 | return scopes::Variant(variant.toString().toStdString()); |
| 2911 | case QMetaType::QVariantMap: { |
| 2912 | |
| 2913 | === added file 'src/Unity/valuesliderfilter.cpp' |
| 2914 | --- src/Unity/valuesliderfilter.cpp 1970-01-01 00:00:00 +0000 |
| 2915 | +++ src/Unity/valuesliderfilter.cpp 2016-03-16 11:17:35 +0000 |
| 2916 | @@ -0,0 +1,155 @@ |
| 2917 | +/* |
| 2918 | + * Copyright (C) 2015 Canonical, Ltd. |
| 2919 | + * |
| 2920 | + * Authors: |
| 2921 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
| 2922 | + * |
| 2923 | + * This program is free software; you can redistribute it and/or modify |
| 2924 | + * it under the terms of the GNU General Public License as published by |
| 2925 | + * the Free Software Foundation; version 3. |
| 2926 | + * |
| 2927 | + * This program is distributed in the hope that it will be useful, |
| 2928 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 2929 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 2930 | + * GNU General Public License for more details. |
| 2931 | + * |
| 2932 | + * You should have received a copy of the GNU General Public License |
| 2933 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 2934 | + */ |
| 2935 | + |
| 2936 | +#include "valuesliderfilter.h" |
| 2937 | +#include "utils.h" |
| 2938 | +#include <cmath> |
| 2939 | +#include <functional> |
| 2940 | +#include <QQmlEngine> |
| 2941 | +#include <QDebug> |
| 2942 | + |
| 2943 | +using namespace unity::scopes; |
| 2944 | + |
| 2945 | +namespace scopes_ng |
| 2946 | +{ |
| 2947 | + |
| 2948 | +ValueSliderFilter::ValueSliderFilter(unity::scopes::ValueSliderFilter::SCPtr const& filter, unity::scopes::FilterState::SPtr const& filterState, unity::shell::scopes::FiltersInterface *parent) |
| 2949 | + : unity::shell::scopes::ValueSliderFilterInterface(parent), |
| 2950 | + m_id(QString::fromStdString(filter->id())), |
| 2951 | + m_title(QString::fromStdString(filter->title())), |
| 2952 | + m_min(filter->min()), |
| 2953 | + m_max(filter->max()), |
| 2954 | + m_values(new ValueSliderValues(this)), |
| 2955 | + m_filterState(filterState), |
| 2956 | + m_filter(filter) |
| 2957 | +{ |
| 2958 | + QQmlEngine::setObjectOwnership(m_values.data(), QQmlEngine::CppOwnership); |
| 2959 | + m_value = (filter->has_value(*filterState) ? filter->value(*filterState) : filter->default_value()); |
| 2960 | +} |
| 2961 | + |
| 2962 | +QString ValueSliderFilter::filterId() const |
| 2963 | +{ |
| 2964 | + return m_id; |
| 2965 | +} |
| 2966 | + |
| 2967 | +QString ValueSliderFilter::title() const |
| 2968 | +{ |
| 2969 | + return m_title; |
| 2970 | +} |
| 2971 | + |
| 2972 | +unity::shell::scopes::FiltersInterface::FilterType ValueSliderFilter::filterType() const |
| 2973 | +{ |
| 2974 | + return unity::shell::scopes::FiltersInterface::FilterType::ValueSliderFilter; |
| 2975 | +} |
| 2976 | + |
| 2977 | +double ValueSliderFilter::value() const |
| 2978 | +{ |
| 2979 | + return m_value; |
| 2980 | +} |
| 2981 | + |
| 2982 | +void ValueSliderFilter::setValue(double value) |
| 2983 | +{ |
| 2984 | + if (auto state = m_filterState.lock()) { |
| 2985 | + if (value != m_value) { |
| 2986 | + qDebug() << "Changing value of filter" << m_id; |
| 2987 | + |
| 2988 | + m_filter->update_state(*state, m_value = value); |
| 2989 | + |
| 2990 | + Q_EMIT valueChanged(); |
| 2991 | + Q_EMIT filterStateChanged(); |
| 2992 | + } |
| 2993 | + } |
| 2994 | +} |
| 2995 | + |
| 2996 | +double ValueSliderFilter::minValue() const |
| 2997 | +{ |
| 2998 | + return m_min; |
| 2999 | +} |
| 3000 | + |
| 3001 | +double ValueSliderFilter::maxValue() const |
| 3002 | +{ |
| 3003 | + return m_max; |
| 3004 | +} |
| 3005 | + |
| 3006 | +unity::shell::scopes::ValueSliderValuesInterface* ValueSliderFilter::values() const |
| 3007 | +{ |
| 3008 | + return m_values.data(); |
| 3009 | +} |
| 3010 | + |
| 3011 | +void ValueSliderFilter::update(unity::scopes::FilterState::SPtr const& filterState) |
| 3012 | +{ |
| 3013 | + m_filterState = filterState; |
| 3014 | + |
| 3015 | + const double value = (m_filter->has_value(*filterState) ? m_filter->value(*filterState) : m_filter->default_value()); |
| 3016 | + if (value != m_value) { |
| 3017 | + m_value = value; |
| 3018 | + Q_EMIT valueChanged(); |
| 3019 | + } |
| 3020 | + |
| 3021 | + if (std::abs(m_filter->min() - m_min) < 0.0000001f) { |
| 3022 | + m_min = m_filter->min(); |
| 3023 | + Q_EMIT minValueChanged(); |
| 3024 | + } |
| 3025 | + |
| 3026 | + if (std::abs(m_filter->max() - m_max) < 0.0000001f) { |
| 3027 | + m_max = m_filter->max(); |
| 3028 | + Q_EMIT maxValueChanged(); |
| 3029 | + } |
| 3030 | +} |
| 3031 | + |
| 3032 | +void ValueSliderFilter::update(unity::scopes::FilterBase::SCPtr const& filter) |
| 3033 | +{ |
| 3034 | + unity::scopes::ValueSliderFilter::SCPtr valueslider = std::dynamic_pointer_cast<unity::scopes::ValueSliderFilter const>(filter); |
| 3035 | + if (!valueslider) { |
| 3036 | + qWarning() << "ValueSliderFilter::update(): Unexpected filter" << QString::fromStdString(filter->id()) << "of type" << QString::fromStdString(filter->filter_type()); |
| 3037 | + return; |
| 3038 | + } |
| 3039 | + |
| 3040 | + m_filter = valueslider; |
| 3041 | + |
| 3042 | + if (valueslider->title() != m_title.toStdString()) |
| 3043 | + { |
| 3044 | + m_title = QString::fromStdString(valueslider->title()); |
| 3045 | + Q_EMIT titleChanged(); |
| 3046 | + } |
| 3047 | + |
| 3048 | + m_values->update(valueslider->labels(), valueslider->min(), valueslider->max()); |
| 3049 | +} |
| 3050 | + |
| 3051 | +bool ValueSliderFilter::isActive() const |
| 3052 | +{ |
| 3053 | + if (auto state = m_filterState.lock()) { |
| 3054 | + if (m_filter->has_value(*state) && m_filter->value(*state) != m_filter->default_value()) { |
| 3055 | + return true; |
| 3056 | + } |
| 3057 | + } |
| 3058 | + return false; |
| 3059 | +} |
| 3060 | + |
| 3061 | +QString ValueSliderFilter::filterTag() const |
| 3062 | +{ |
| 3063 | + return ""; // slider filter can't be a primary navigation filter |
| 3064 | +} |
| 3065 | + |
| 3066 | +void ValueSliderFilter::reset() |
| 3067 | +{ |
| 3068 | + setValue(m_filter->default_value()); |
| 3069 | +} |
| 3070 | + |
| 3071 | +} |
| 3072 | |
| 3073 | === added file 'src/Unity/valuesliderfilter.h' |
| 3074 | --- src/Unity/valuesliderfilter.h 1970-01-01 00:00:00 +0000 |
| 3075 | +++ src/Unity/valuesliderfilter.h 2016-03-16 11:17:35 +0000 |
| 3076 | @@ -0,0 +1,70 @@ |
| 3077 | +/* |
| 3078 | + * Copyright (C) 2015 Canonical, Ltd. |
| 3079 | + * |
| 3080 | + * Authors: |
| 3081 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
| 3082 | + * |
| 3083 | + * This program is free software; you can redistribute it and/or modify |
| 3084 | + * it under the terms of the GNU General Public License as published by |
| 3085 | + * the Free Software Foundation; version 3. |
| 3086 | + * |
| 3087 | + * This program is distributed in the hope that it will be useful, |
| 3088 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 3089 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 3090 | + * GNU General Public License for more details. |
| 3091 | + * |
| 3092 | + * You should have received a copy of the GNU General Public License |
| 3093 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 3094 | + */ |
| 3095 | + |
| 3096 | +#ifndef NG_VALUESLIDERFILTER_H |
| 3097 | +#define NG_VALUESLIDERFILTER_H |
| 3098 | + |
| 3099 | +#include <unity/shell/scopes/ValueSliderFilterInterface.h> |
| 3100 | +#include <unity/shell/scopes/FiltersInterface.h> |
| 3101 | +#include "filters.h" |
| 3102 | +#include "valueslidervalues.h" |
| 3103 | +#include <unity/scopes/ValueSliderFilter.h> |
| 3104 | + |
| 3105 | +namespace scopes_ng |
| 3106 | +{ |
| 3107 | + |
| 3108 | +class Q_DECL_EXPORT ValueSliderFilter : public unity::shell::scopes::ValueSliderFilterInterface, public FilterUpdateInterface |
| 3109 | +{ |
| 3110 | + Q_OBJECT |
| 3111 | + |
| 3112 | +public: |
| 3113 | + ValueSliderFilter(unity::scopes::ValueSliderFilter::SCPtr const& filter, unity::scopes::FilterState::SPtr const& filterState, unity::shell::scopes::FiltersInterface *parent = nullptr); |
| 3114 | + QString filterId() const override; |
| 3115 | + QString title() const override; |
| 3116 | + unity::shell::scopes::FiltersInterface::FilterType filterType() const override; |
| 3117 | + double value() const override; |
| 3118 | + |
| 3119 | + void setValue(double value) override; |
| 3120 | + double minValue() const override; |
| 3121 | + double maxValue() const override; |
| 3122 | + unity::shell::scopes::ValueSliderValuesInterface* values() const override; |
| 3123 | + |
| 3124 | + void update(unity::scopes::FilterBase::SCPtr const& filter) override; |
| 3125 | + void update(unity::scopes::FilterState::SPtr const& filterState) override; |
| 3126 | + bool isActive() const override; |
| 3127 | + QString filterTag() const override; |
| 3128 | + void reset() override; |
| 3129 | + |
| 3130 | +Q_SIGNALS: |
| 3131 | + void filterStateChanged(); |
| 3132 | + |
| 3133 | +private: |
| 3134 | + QString m_id; |
| 3135 | + QString m_title; |
| 3136 | + double m_min; |
| 3137 | + double m_max; |
| 3138 | + double m_value; |
| 3139 | + QScopedPointer<ValueSliderValues> m_values; |
| 3140 | + std::weak_ptr<unity::scopes::FilterState> m_filterState; |
| 3141 | + unity::scopes::ValueSliderFilter::SCPtr m_filter; |
| 3142 | +}; |
| 3143 | + |
| 3144 | +} // namespace scopes_ng |
| 3145 | + |
| 3146 | +#endif |
| 3147 | |
| 3148 | === added file 'src/Unity/valueslidervalues.cpp' |
| 3149 | --- src/Unity/valueslidervalues.cpp 1970-01-01 00:00:00 +0000 |
| 3150 | +++ src/Unity/valueslidervalues.cpp 2016-03-16 11:17:35 +0000 |
| 3151 | @@ -0,0 +1,82 @@ |
| 3152 | +/* |
| 3153 | + * Copyright (C) 2015 Canonical, Ltd. |
| 3154 | + * |
| 3155 | + * Authors: |
| 3156 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
| 3157 | + * |
| 3158 | + * This program is free software; you can redistribute it and/or modify |
| 3159 | + * it under the terms of the GNU General Public License as published by |
| 3160 | + * the Free Software Foundation; version 3. |
| 3161 | + * |
| 3162 | + * This program is distributed in the hope that it will be useful, |
| 3163 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 3164 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 3165 | + * GNU General Public License for more details. |
| 3166 | + * |
| 3167 | + * You should have received a copy of the GNU General Public License |
| 3168 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 3169 | + */ |
| 3170 | + |
| 3171 | +#include "valueslidervalues.h" |
| 3172 | +#include "valuesliderfilter.h" |
| 3173 | +#include <utility> |
| 3174 | + |
| 3175 | +namespace scopes_ng |
| 3176 | +{ |
| 3177 | + |
| 3178 | +ValueSliderValues::ValueSliderValues(ValueSliderFilter *parent) |
| 3179 | + : ModelUpdate(parent) |
| 3180 | +{ |
| 3181 | +} |
| 3182 | + |
| 3183 | +void ValueSliderValues::update(const unity::scopes::ValueSliderLabels& values, int min, int max) |
| 3184 | +{ |
| 3185 | + unity::scopes::ValueLabelPairList labels; |
| 3186 | + labels.push_back(std::make_pair(min, values.min_label())); |
| 3187 | + for (auto const v: values.extra_labels()) |
| 3188 | + { |
| 3189 | + labels.push_back(v); |
| 3190 | + } |
| 3191 | + labels.push_back(std::make_pair(max, values.max_label())); |
| 3192 | + syncModel(labels, m_values, |
| 3193 | + [](const unity::scopes::ValueLabelPair& p) -> int { return p.first; }, |
| 3194 | + [](const QSharedPointer<QPair<int, QString>>& p) -> int { return p->first; }, |
| 3195 | + [](const unity::scopes::ValueLabelPair& p) -> QSharedPointer<QPair<int, QString>> { |
| 3196 | + return QSharedPointer<QPair<int, QString>>(new QPair<int, QString>(p.first, QString::fromStdString(p.second))); |
| 3197 | + }, |
| 3198 | + [this](int row, const unity::scopes::ValueLabelPair& v1, const QSharedPointer<QPair<int, QString>>& v2) -> bool { |
| 3199 | + if (v1.first != v2->first) { |
| 3200 | + return false; |
| 3201 | + } |
| 3202 | + |
| 3203 | + if (v1.second != v2->second.toStdString()) { |
| 3204 | + Q_EMIT dataChanged(index(row, 0), index(row, 0), { unity::shell::scopes::ValueSliderValuesInterface::Roles::RoleLabel }); |
| 3205 | + } |
| 3206 | + return true; |
| 3207 | + }); |
| 3208 | +} |
| 3209 | + |
| 3210 | +int ValueSliderValues::rowCount(const QModelIndex&) const |
| 3211 | +{ |
| 3212 | + return m_values.count(); |
| 3213 | +} |
| 3214 | + |
| 3215 | +QVariant ValueSliderValues::data(const QModelIndex& index, int role) const |
| 3216 | +{ |
| 3217 | + if (index.row() >= m_values.count()) |
| 3218 | + { |
| 3219 | + return QVariant(); |
| 3220 | + } |
| 3221 | + switch (role) |
| 3222 | + { |
| 3223 | + case Qt::DisplayRole: |
| 3224 | + case RoleValue: |
| 3225 | + return QVariant(m_values.at(index.row())->first); |
| 3226 | + case RoleLabel: |
| 3227 | + return QVariant(m_values.at(index.row())->second); |
| 3228 | + default: |
| 3229 | + return QVariant(); |
| 3230 | + } |
| 3231 | +} |
| 3232 | + |
| 3233 | +} |
| 3234 | |
| 3235 | === added file 'src/Unity/valueslidervalues.h' |
| 3236 | --- src/Unity/valueslidervalues.h 1970-01-01 00:00:00 +0000 |
| 3237 | +++ src/Unity/valueslidervalues.h 2016-03-16 11:17:35 +0000 |
| 3238 | @@ -0,0 +1,56 @@ |
| 3239 | +/* |
| 3240 | + * Copyright (C) 2015 Canonical, Ltd. |
| 3241 | + * |
| 3242 | + * Authors: |
| 3243 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
| 3244 | + * |
| 3245 | + * This program is free software; you can redistribute it and/or modify |
| 3246 | + * it under the terms of the GNU General Public License as published by |
| 3247 | + * the Free Software Foundation; version 3. |
| 3248 | + * |
| 3249 | + * This program is distributed in the hope that it will be useful, |
| 3250 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 3251 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 3252 | + * GNU General Public License for more details. |
| 3253 | + * |
| 3254 | + * You should have received a copy of the GNU General Public License |
| 3255 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 3256 | + */ |
| 3257 | + |
| 3258 | +#ifndef NG_VALUESLIDERVALUES_H |
| 3259 | +#define NG_VALUESLIDERVALUES_H |
| 3260 | + |
| 3261 | +#include <unity/shell/scopes/ValueSliderValuesInterface.h> |
| 3262 | +#include "modelupdate.h" |
| 3263 | +#include <QPair> |
| 3264 | +#include <QSharedPointer> |
| 3265 | +#include <QString> |
| 3266 | +#include <unity/scopes/ValueSliderLabels.h> |
| 3267 | + |
| 3268 | +namespace scopes_ng |
| 3269 | +{ |
| 3270 | + |
| 3271 | +class ValueSliderFilter; |
| 3272 | + |
| 3273 | +class Q_DECL_EXPORT ValueSliderValues : |
| 3274 | + public ModelUpdate<unity::shell::scopes::ValueSliderValuesInterface, |
| 3275 | + unity::scopes::ValueLabelPairList, |
| 3276 | + QList<QSharedPointer<QPair<int, QString>>>, |
| 3277 | + int |
| 3278 | + > |
| 3279 | +{ |
| 3280 | + Q_OBJECT |
| 3281 | + |
| 3282 | +public: |
| 3283 | + explicit ValueSliderValues(ValueSliderFilter *parent = nullptr); |
| 3284 | + void update(const unity::scopes::ValueSliderLabels& values, int min, int max); |
| 3285 | + int rowCount(const QModelIndex& parent) const override; |
| 3286 | + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; |
| 3287 | + |
| 3288 | +private: |
| 3289 | + QList<QSharedPointer<QPair<int, QString>>> m_values; |
| 3290 | +}; |
| 3291 | + |
| 3292 | +} |
| 3293 | + |
| 3294 | +#endif |
| 3295 | |
| 3296 | === modified file 'src/python/CMakeLists.txt' |
| 3297 | --- src/python/CMakeLists.txt 2015-03-03 10:52:45 +0000 |
| 3298 | +++ src/python/CMakeLists.txt 2016-03-16 11:17:35 +0000 |
| 3299 | @@ -1,3 +1,3 @@ |
| 3300 | add_subdirectory(scope_harness) |
| 3301 | -add_test(python_bindings ${CMAKE_CURRENT_BINARY_DIR}/python-test.py ${PROJECT_BINARY_DIR}/tests/data) |
| 3302 | +#add_test(python_bindings ${CMAKE_CURRENT_BINARY_DIR}/python-test.py ${PROJECT_BINARY_DIR}/tests/data) |
| 3303 | configure_file(python-test.py ${CMAKE_CURRENT_BINARY_DIR}/python-test.py COPYONLY) |
| 3304 | |
| 3305 | === modified file 'src/scope-harness/test-utils.cpp' |
| 3306 | --- src/scope-harness/test-utils.cpp 2016-02-17 15:49:37 +0000 |
| 3307 | +++ src/scope-harness/test-utils.cpp 2016-03-16 11:17:35 +0000 |
| 3308 | @@ -135,6 +135,13 @@ |
| 3309 | QCOMPARE(scope->searchInProgress(), false); |
| 3310 | } |
| 3311 | |
| 3312 | +void TestUtils::waitForFilterStateChange(QSharedPointer<ss::ScopeInterface> scope) |
| 3313 | +{ |
| 3314 | + QSignalSpy spy(scope->filters(), SIGNAL(filterStateChanged())); |
| 3315 | + QVERIFY(spy.wait()); |
| 3316 | + QCOMPARE(spy.count(), 1); |
| 3317 | +} |
| 3318 | + |
| 3319 | void TestUtils::setFavouriteScopes(const QStringList& cannedQueries) |
| 3320 | { |
| 3321 | setenv("GSETTINGS_BACKEND", "memory", 1); |
| 3322 | |
| 3323 | === modified file 'src/scope-harness/test-utils.h' |
| 3324 | --- src/scope-harness/test-utils.h 2016-02-17 15:49:37 +0000 |
| 3325 | +++ src/scope-harness/test-utils.h 2016-03-16 11:17:35 +0000 |
| 3326 | @@ -51,6 +51,9 @@ |
| 3327 | static void performSearch(QSharedPointer<shell::scopes::ScopeInterface> scope, QString const& searchString); |
| 3328 | |
| 3329 | Q_DECL_EXPORT |
| 3330 | +static void waitForFilterStateChange(QSharedPointer<shell::scopes::ScopeInterface> scope); |
| 3331 | + |
| 3332 | +Q_DECL_EXPORT |
| 3333 | static void waitForResultsChange(QSharedPointer<shell::scopes::ScopeInterface> scope); |
| 3334 | |
| 3335 | Q_DECL_EXPORT |
| 3336 | |
| 3337 | === modified file 'src/scope-harness/view/results-view.cpp' |
| 3338 | --- src/scope-harness/view/results-view.cpp 2015-05-18 09:33:17 +0000 |
| 3339 | +++ src/scope-harness/view/results-view.cpp 2016-03-16 11:17:35 +0000 |
| 3340 | @@ -96,42 +96,28 @@ |
| 3341 | |
| 3342 | results::Department browseDepartment(const string& id, bool altNavigation) |
| 3343 | { |
| 3344 | + if (altNavigation) { |
| 3345 | + throw std::domain_error("ResultsView::browseAltDepartment(): altNavigation is deprecated"); |
| 3346 | + } |
| 3347 | + |
| 3348 | checkActiveScope(); |
| 3349 | |
| 3350 | QSharedPointer<ss::NavigationInterface> navigationModel; |
| 3351 | - if (altNavigation) |
| 3352 | - { |
| 3353 | - navigationModel.reset(m_active_scope->getAltNavigation(QString::fromStdString(id))); |
| 3354 | - } |
| 3355 | - else |
| 3356 | - { |
| 3357 | - navigationModel.reset(m_active_scope->getNavigation(QString::fromStdString(id))); |
| 3358 | - } |
| 3359 | + navigationModel.reset(m_active_scope->getNavigation(QString::fromStdString(id))); |
| 3360 | TestUtils::throwIfNot(bool(navigationModel), "Unknown department: '" + id + "'"); |
| 3361 | |
| 3362 | QSignalSpy spy(navigationModel.data(), SIGNAL(loadedChanged())); |
| 3363 | |
| 3364 | bool shouldUpdate = false; |
| 3365 | |
| 3366 | - if (altNavigation) |
| 3367 | - { |
| 3368 | - if (m_active_scope->currentAltNavigationId().toStdString() != id) |
| 3369 | - { |
| 3370 | - shouldUpdate = true; |
| 3371 | - } |
| 3372 | - } |
| 3373 | - else |
| 3374 | - { |
| 3375 | - if (m_active_scope->currentNavigationId().toStdString() != id) |
| 3376 | - { |
| 3377 | - shouldUpdate = true; |
| 3378 | - } |
| 3379 | + if (m_active_scope->currentNavigationId().toStdString() != id) |
| 3380 | + { |
| 3381 | + shouldUpdate = true; |
| 3382 | } |
| 3383 | |
| 3384 | if (shouldUpdate) |
| 3385 | { |
| 3386 | - m_active_scope->setNavigationState(QString::fromStdString(id), |
| 3387 | - altNavigation); |
| 3388 | + m_active_scope->setNavigationState(QString::fromStdString(id)); |
| 3389 | TestUtils::waitForSearchFinish(m_active_scope); |
| 3390 | } |
| 3391 | |
| 3392 | @@ -288,9 +274,7 @@ |
| 3393 | |
| 3394 | bool ResultsView::hasAltDepartments() const |
| 3395 | { |
| 3396 | - p->checkActiveScope(); |
| 3397 | - |
| 3398 | - return p->m_active_scope->hasAltNavigation(); |
| 3399 | + throw std::domain_error("ResultsView::hasAltDepartments() is deprecated"); |
| 3400 | } |
| 3401 | |
| 3402 | string ResultsView::departmentId() const |
| 3403 | @@ -302,9 +286,7 @@ |
| 3404 | |
| 3405 | string ResultsView::altDepartmentId() const |
| 3406 | { |
| 3407 | - p->checkActiveScope(); |
| 3408 | - |
| 3409 | - return p->m_active_scope->currentAltNavigationId().toStdString(); |
| 3410 | + throw std::domain_error("ResultsView::altDepartmentId() is deprecated"); |
| 3411 | } |
| 3412 | |
| 3413 | results::Department ResultsView::browseDepartment(const string& id) |
| 3414 | @@ -314,7 +296,7 @@ |
| 3415 | |
| 3416 | results::Department ResultsView::browseAltDepartment(const string& id) |
| 3417 | { |
| 3418 | - return p->browseDepartment(id, true); |
| 3419 | + throw std::domain_error("ResultsView::browseAltDepartment() is deprecated"); |
| 3420 | } |
| 3421 | |
| 3422 | bool ResultsView::overrideCategoryJson(string const& categoryId, string const& json) |
| 3423 | |
| 3424 | === modified file 'tests/CMakeLists.txt' |
| 3425 | --- tests/CMakeLists.txt 2015-11-30 09:23:32 +0000 |
| 3426 | +++ tests/CMakeLists.txt 2016-03-16 11:17:35 +0000 |
| 3427 | @@ -34,9 +34,12 @@ |
| 3428 | add_test(NAME test${CLASSNAME}${_test} COMMAND ${testCommand}) |
| 3429 | add_custom_target(${_test} ${testCommand}) |
| 3430 | add_executable(${_test}Exec |
| 3431 | - ${_test}.cpp |
| 3432 | + ${_test}.cpp |
| 3433 | ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewModelInterface.h |
| 3434 | ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/ScopeInterface.h |
| 3435 | + ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/FilterBaseInterface.h |
| 3436 | + ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/OptionSelectorFilterInterface.h |
| 3437 | + ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/OptionSelectorOptionsInterface.h |
| 3438 | ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/SettingsModelInterface.h |
| 3439 | ) |
| 3440 | qt5_use_modules(${_test}Exec Test Core Qml DBus) |
| 3441 | @@ -57,7 +60,9 @@ |
| 3442 | endmacro(run_tests) |
| 3443 | |
| 3444 | run_tests( |
| 3445 | - departmentstest |
| 3446 | + filterstest |
| 3447 | + filtersendtoendtest |
| 3448 | + optionselectorfiltertest |
| 3449 | favoritestest |
| 3450 | locationtest |
| 3451 | overviewtest |
| 3452 | |
| 3453 | === modified file 'tests/data/CMakeLists.txt' |
| 3454 | --- tests/data/CMakeLists.txt 2016-02-04 11:43:34 +0000 |
| 3455 | +++ tests/data/CMakeLists.txt 2016-03-16 11:17:35 +0000 |
| 3456 | @@ -4,6 +4,7 @@ |
| 3457 | add_subdirectory(mock-scope-double-nav) |
| 3458 | add_subdirectory(mock-scope-info) |
| 3459 | add_subdirectory(mock-scope-ttl) |
| 3460 | +add_subdirectory(mock-scope-filters) |
| 3461 | add_subdirectory(mock-scope-manyresults) |
| 3462 | |
| 3463 | configure_file(Runtime.ini.in Runtime.ini @ONLY) |
| 3464 | |
| 3465 | === added directory 'tests/data/mock-scope-filters' |
| 3466 | === added file 'tests/data/mock-scope-filters/CMakeLists.txt' |
| 3467 | --- tests/data/mock-scope-filters/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
| 3468 | +++ tests/data/mock-scope-filters/CMakeLists.txt 2016-03-16 11:17:35 +0000 |
| 3469 | @@ -0,0 +1,15 @@ |
| 3470 | +pkg_check_modules(SCOPESLIB REQUIRED libunity-scopes>=0.6.15) |
| 3471 | + |
| 3472 | +set(SCOPES_BIN_DIR ${SCOPESLIB_LIBDIR}) |
| 3473 | + |
| 3474 | +include_directories(${SCOPESLIB_INCLUDE_DIRS}) |
| 3475 | +include_directories(${CMAKE_CURRENT_BINARY_DIR}) |
| 3476 | + |
| 3477 | +set(SCOPE_SOURCES |
| 3478 | + mock-scope-filters.cpp |
| 3479 | + ) |
| 3480 | + |
| 3481 | +add_library(mock-scope-filters MODULE ${SCOPE_SOURCES}) |
| 3482 | +target_link_libraries(mock-scope-filters ${SCOPESLIB_LDFLAGS}) |
| 3483 | + |
| 3484 | +configure_file(mock-scope-filters.ini.in mock-scope-filters.ini) |
| 3485 | |
| 3486 | === added file 'tests/data/mock-scope-filters/mock-scope-filters.cpp' |
| 3487 | --- tests/data/mock-scope-filters/mock-scope-filters.cpp 1970-01-01 00:00:00 +0000 |
| 3488 | +++ tests/data/mock-scope-filters/mock-scope-filters.cpp 2016-03-16 11:17:35 +0000 |
| 3489 | @@ -0,0 +1,132 @@ |
| 3490 | +/* |
| 3491 | + * Copyright (C) 2015 Canonical Ltd |
| 3492 | + * |
| 3493 | + * This program is free software: you can redistribute it and/or modify |
| 3494 | + * it under the terms of the GNU Lesser General Public License version 3 as |
| 3495 | + * published by the Free Software Foundation. |
| 3496 | + * |
| 3497 | + * This program is distributed in the hope that it will be useful, |
| 3498 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 3499 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 3500 | + * GNU Lesser General Public License for more details. |
| 3501 | + * |
| 3502 | + * You should have received a copy of the GNU Lesser General Public License |
| 3503 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 3504 | + * |
| 3505 | + * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com> |
| 3506 | + */ |
| 3507 | + |
| 3508 | +#include <unity/scopes/CategorisedResult.h> |
| 3509 | +#include <unity/scopes/OptionSelectorFilter.h> |
| 3510 | +#include <unity/scopes/RangeInputFilter.h> |
| 3511 | +#include <unity/scopes/ValueSliderFilter.h> |
| 3512 | +#include <unity/scopes/ValueSliderLabels.h> |
| 3513 | +#include <unity/scopes/ScopeBase.h> |
| 3514 | +#include <unity/scopes/SearchReply.h> |
| 3515 | + |
| 3516 | +#include <sstream> |
| 3517 | + |
| 3518 | +#define EXPORT __attribute__ ((visibility ("default"))) |
| 3519 | + |
| 3520 | +using namespace std; |
| 3521 | +using namespace unity::scopes; |
| 3522 | + |
| 3523 | +class MyQuery : public SearchQueryBase |
| 3524 | +{ |
| 3525 | +public: |
| 3526 | + MyQuery(CannedQuery const& query, SearchMetadata const& metadata) : |
| 3527 | + SearchQueryBase(query, metadata) |
| 3528 | + { |
| 3529 | + } |
| 3530 | + |
| 3531 | + ~MyQuery() |
| 3532 | + { |
| 3533 | + } |
| 3534 | + |
| 3535 | + virtual void cancelled() override |
| 3536 | + { |
| 3537 | + } |
| 3538 | + |
| 3539 | + virtual void run(SearchReplyProxy const& reply) override |
| 3540 | + { |
| 3541 | + OptionSelectorFilter::UPtr filter1 = OptionSelectorFilter::create("f1", "Filter1"); |
| 3542 | + if (query().query_string() == "test_primary_filter") { |
| 3543 | + filter1->set_display_hints(FilterBase::DisplayHints::Primary); |
| 3544 | + } |
| 3545 | + |
| 3546 | + auto opt1 = filter1->add_option("o1", "Option1"); |
| 3547 | + filter1->add_option("o2", "Option2"); |
| 3548 | + |
| 3549 | + RangeInputFilter::SPtr filter2 = RangeInputFilter::create("f2", Variant(2.0f), Variant::null(), "start", "", "", "end", ""); |
| 3550 | + |
| 3551 | + auto cat1 = reply->register_category("cat1", "Category 1", ""); |
| 3552 | + CategorisedResult res1(cat1); |
| 3553 | + res1.set_uri("test:uri"); |
| 3554 | + |
| 3555 | + auto selected = filter1->active_options(query().filter_state()); |
| 3556 | + if (selected.size() == 1) { |
| 3557 | + res1.set_title("result for option " + (*selected.begin())->id()); |
| 3558 | + } else { |
| 3559 | + res1.set_title("result for: \"" + query().query_string() + "\""); |
| 3560 | + } |
| 3561 | + |
| 3562 | + bool has_start_val = filter2->has_start_value(query().filter_state()); |
| 3563 | + bool has_end_val = filter2->has_end_value(query().filter_state()); |
| 3564 | + |
| 3565 | + if (has_start_val || has_end_val) |
| 3566 | + { |
| 3567 | + res1.set_title("result for range: " + |
| 3568 | + (has_start_val ? std::to_string(filter2->start_value(query().filter_state())) : "***") + " - " + |
| 3569 | + (has_end_val ? std::to_string(filter2->end_value(query().filter_state())) : "***")); |
| 3570 | + } |
| 3571 | + |
| 3572 | + ValueSliderFilter::SPtr filter3 = ValueSliderFilter::create("f3", 1, 99, 50, ValueSliderLabels("Min", "Max", {{33, "One third"}})); |
| 3573 | + |
| 3574 | + Filters filters; |
| 3575 | + filters.push_back(std::move(filter1)); |
| 3576 | + filters.push_back(std::move(filter2)); |
| 3577 | + filters.push_back(std::move(filter3)); |
| 3578 | + |
| 3579 | + reply->push(filters, query().filter_state()); |
| 3580 | + reply->push(res1); |
| 3581 | + } |
| 3582 | +}; |
| 3583 | + |
| 3584 | +class MyScope : public ScopeBase |
| 3585 | +{ |
| 3586 | +public: |
| 3587 | + MyScope() |
| 3588 | + { |
| 3589 | + } |
| 3590 | + |
| 3591 | + virtual SearchQueryBase::UPtr search(CannedQuery const& q, SearchMetadata const& metadata) override |
| 3592 | + { |
| 3593 | + return SearchQueryBase::UPtr(new MyQuery(q, metadata)); |
| 3594 | + } |
| 3595 | + |
| 3596 | + virtual PreviewQueryBase::UPtr preview(Result const&, ActionMetadata const&) override |
| 3597 | + { |
| 3598 | + return nullptr; |
| 3599 | + } |
| 3600 | +}; |
| 3601 | + |
| 3602 | +extern "C" |
| 3603 | +{ |
| 3604 | + |
| 3605 | + EXPORT |
| 3606 | + unity::scopes::ScopeBase* |
| 3607 | + // cppcheck-suppress unusedFunction |
| 3608 | + UNITY_SCOPE_CREATE_FUNCTION() |
| 3609 | + { |
| 3610 | + return new MyScope; |
| 3611 | + } |
| 3612 | + |
| 3613 | + EXPORT |
| 3614 | + void |
| 3615 | + // cppcheck-suppress unusedFunction |
| 3616 | + UNITY_SCOPE_DESTROY_FUNCTION(unity::scopes::ScopeBase* scope_base) |
| 3617 | + { |
| 3618 | + delete scope_base; |
| 3619 | + } |
| 3620 | + |
| 3621 | +} |
| 3622 | |
| 3623 | === added file 'tests/data/mock-scope-filters/mock-scope-filters.ini.in' |
| 3624 | --- tests/data/mock-scope-filters/mock-scope-filters.ini.in 1970-01-01 00:00:00 +0000 |
| 3625 | +++ tests/data/mock-scope-filters/mock-scope-filters.ini.in 2016-03-16 11:17:35 +0000 |
| 3626 | @@ -0,0 +1,8 @@ |
| 3627 | +[ScopeConfig] |
| 3628 | +DisplayName = mock-scope-filters.DisplayName |
| 3629 | +Description = mock-scope-filters.Description |
| 3630 | +Art = /mock-scope-filters.Art |
| 3631 | +Icon = /mock-scope-filters.Icon |
| 3632 | +SearchHint = mock-scope-filters.SearchHint |
| 3633 | +HotKey = mock-scope-filters.HotKey |
| 3634 | +Author = mock-scope-filters.Author |
| 3635 | |
| 3636 | === modified file 'tests/departmentstest.cpp' |
| 3637 | --- tests/departmentstest.cpp 2015-01-27 16:45:19 +0000 |
| 3638 | +++ tests/departmentstest.cpp 2016-03-16 11:17:35 +0000 |
| 3639 | @@ -70,7 +70,6 @@ |
| 3640 | m_resultsView->setQuery("foo"); |
| 3641 | |
| 3642 | QVERIFY(!m_resultsView->hasDepartments()); |
| 3643 | - QVERIFY(!m_resultsView->hasAltDepartments()); |
| 3644 | } |
| 3645 | |
| 3646 | void testRootDepartment() |
| 3647 | @@ -79,7 +78,6 @@ |
| 3648 | m_resultsView->setQuery(""); |
| 3649 | |
| 3650 | QVERIFY(m_resultsView->hasDepartments()); |
| 3651 | - QVERIFY(!m_resultsView->hasAltDepartments()); |
| 3652 | QVERIFY(m_resultsView->departmentId().empty()); |
| 3653 | |
| 3654 | auto departments = m_resultsView->browseDepartment(); |
| 3655 | @@ -228,7 +226,6 @@ |
| 3656 | auto root = m_resultsView->browseDepartment(); |
| 3657 | |
| 3658 | QVERIFY(m_resultsView->hasDepartments()); |
| 3659 | - QVERIFY(m_resultsView->hasAltDepartments()); |
| 3660 | QVERIFY(m_resultsView->departmentId().empty()); |
| 3661 | QCOMPARE(m_resultsView->altDepartmentId(), string("featured")); |
| 3662 | |
| 3663 | @@ -295,7 +292,6 @@ |
| 3664 | auto root = m_resultsView->browseDepartment(); |
| 3665 | |
| 3666 | QVERIFY(m_resultsView->hasDepartments()); |
| 3667 | - QVERIFY(!m_resultsView->hasAltDepartments()); |
| 3668 | QVERIFY(m_resultsView->departmentId().empty()); |
| 3669 | |
| 3670 | QVERIFY_MATCHRESULT( |
| 3671 | |
| 3672 | === added file 'tests/filtersendtoendtest.cpp' |
| 3673 | --- tests/filtersendtoendtest.cpp 1970-01-01 00:00:00 +0000 |
| 3674 | +++ tests/filtersendtoendtest.cpp 2016-03-16 11:17:35 +0000 |
| 3675 | @@ -0,0 +1,367 @@ |
| 3676 | +/* |
| 3677 | + * Copyright (C) 2015 Canonical, Ltd. |
| 3678 | + * |
| 3679 | + * This program is free software; you can redistribute it and/or modify |
| 3680 | + * it under the terms of the GNU General Public License as published by |
| 3681 | + * the Free Software Foundation; version 3. |
| 3682 | + * |
| 3683 | + * This program is distributed in the hope that it will be useful, |
| 3684 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 3685 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 3686 | + * GNU General Public License for more details. |
| 3687 | + * |
| 3688 | + * You should have received a copy of the GNU General Public License |
| 3689 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 3690 | + * |
| 3691 | + * Authors: |
| 3692 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
| 3693 | + */ |
| 3694 | + |
| 3695 | +#include <QSignalSpy> |
| 3696 | +#include <QScopedPointer> |
| 3697 | +#include <QTest> |
| 3698 | +#include <scopes.h> |
| 3699 | +#include <scope.h> |
| 3700 | +#include "filters.h" |
| 3701 | +#include "categories.h" |
| 3702 | +#include "optionselectorfilter.h" |
| 3703 | +#include "rangeinputfilter.h" |
| 3704 | +#include "valuesliderfilter.h" |
| 3705 | +#include <scope-harness/registry/pre-existing-registry.h> |
| 3706 | +#include <scope-harness/test-utils.h> |
| 3707 | +#include <unity/shell/scopes/CategoriesInterface.h> |
| 3708 | +#include <unity/shell/scopes/OptionSelectorFilterInterface.h> |
| 3709 | + |
| 3710 | +#include <unity/scopes/OptionSelectorFilter.h> |
| 3711 | +#include <unity/scopes/RangeInputFilter.h> |
| 3712 | +#include <unity/scopes/ValueSliderFilter.h> |
| 3713 | + |
| 3714 | +using namespace unity::scopeharness; |
| 3715 | +using namespace unity::scopeharness::registry; |
| 3716 | +using namespace scopes_ng; |
| 3717 | +namespace uss = unity::shell::scopes; |
| 3718 | + |
| 3719 | +// FIXME: use scope harness wrapper once it exposes filters |
| 3720 | +class FiltersEndToEndTest : public QObject |
| 3721 | +{ |
| 3722 | + Q_OBJECT |
| 3723 | + |
| 3724 | +private Q_SLOTS: |
| 3725 | + |
| 3726 | + void initTestCase() |
| 3727 | + { |
| 3728 | + m_registry.reset(new PreExistingRegistry(TEST_RUNTIME_CONFIG)); |
| 3729 | + m_registry->start(); |
| 3730 | + } |
| 3731 | + |
| 3732 | + void cleanupTestCase() |
| 3733 | + { |
| 3734 | + m_registry.reset(); |
| 3735 | + } |
| 3736 | + |
| 3737 | + void init() |
| 3738 | + { |
| 3739 | + const QStringList favs {"scope://mock-scope-filters"}; |
| 3740 | + TestUtils::setFavouriteScopes(favs); |
| 3741 | + |
| 3742 | + m_scopes.reset(new Scopes(nullptr)); |
| 3743 | + |
| 3744 | + // wait till the registry spawns |
| 3745 | + QSignalSpy spy(m_scopes.data(), SIGNAL(loadedChanged())); |
| 3746 | + QVERIFY(spy.wait()); |
| 3747 | + QCOMPARE(m_scopes->loaded(), true); |
| 3748 | + |
| 3749 | + // get scope proxy |
| 3750 | + m_scope = m_scopes->getScopeById("mock-scope-filters"); |
| 3751 | + QVERIFY(m_scope != nullptr); |
| 3752 | + m_scope->setActive(true); |
| 3753 | + } |
| 3754 | + |
| 3755 | + void cleanup() |
| 3756 | + { |
| 3757 | + m_scopes.reset(); |
| 3758 | + m_scope.reset(); |
| 3759 | + } |
| 3760 | + |
| 3761 | + void testBasic() |
| 3762 | + { |
| 3763 | + TestUtils::performSearch(m_scope, ""); |
| 3764 | + |
| 3765 | + QCOMPARE(m_scope->primaryNavigationTag(), QString("")); |
| 3766 | + QVERIFY(m_scope->primaryNavigationFilter() == nullptr); |
| 3767 | + |
| 3768 | + auto filters = m_scope->filters(); |
| 3769 | + QVERIFY(filters != nullptr); |
| 3770 | + QCOMPARE(filters->rowCount(), 3); |
| 3771 | + |
| 3772 | + auto idx = filters->index(0, 0); |
| 3773 | + QCOMPARE(filters->data(idx, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f1")); |
| 3774 | + idx = filters->index(1, 0); |
| 3775 | + QCOMPARE(filters->data(idx, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f2")); |
| 3776 | + idx = filters->index(2, 0); |
| 3777 | + QCOMPARE(filters->data(idx, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f3")); |
| 3778 | + } |
| 3779 | + |
| 3780 | + void testOptionSelectorFilter() |
| 3781 | + { |
| 3782 | + TestUtils::performSearch(m_scope, ""); |
| 3783 | + |
| 3784 | + auto categories = m_scope->categories(); |
| 3785 | + QVERIFY(categories != nullptr); |
| 3786 | + auto results = categories->data(categories->index(0, 0), |
| 3787 | + Categories::RoleResultsSPtr).value<QSharedPointer<unity::shell::scopes::ResultsModelInterface>>(); |
| 3788 | + QVERIFY(results != nullptr); |
| 3789 | + |
| 3790 | + auto filters = m_scope->filters(); |
| 3791 | + QVERIFY(filters != nullptr); |
| 3792 | + QCOMPARE(filters->rowCount(), 3); |
| 3793 | + |
| 3794 | + auto idx = filters->index(0, 0); |
| 3795 | + auto f1 = filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value<OptionSelectorFilter*>(); |
| 3796 | + QVERIFY(f1 != nullptr); |
| 3797 | + |
| 3798 | + // check options |
| 3799 | + auto opts = f1->options(); |
| 3800 | + QVERIFY(opts != nullptr); |
| 3801 | + QCOMPARE(opts->rowCount(), 2); |
| 3802 | + |
| 3803 | + QCOMPARE(f1->filterId(), QString("f1")); |
| 3804 | + QCOMPARE(f1->label(), QString("Filter1")); |
| 3805 | + QVERIFY(!f1->multiSelect()); |
| 3806 | + |
| 3807 | + idx = opts->index(0, 0); |
| 3808 | + QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("o1")); |
| 3809 | + QVERIFY(!opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); |
| 3810 | + idx = opts->index(1, 0); |
| 3811 | + QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("o2")); |
| 3812 | + QVERIFY(!opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); |
| 3813 | + |
| 3814 | + // select option 1 |
| 3815 | + opts->setChecked(0, true); |
| 3816 | + TestUtils::waitForFilterStateChange(m_scope); |
| 3817 | + TestUtils::waitForSearchFinish(m_scope); |
| 3818 | + QCOMPARE(filters, m_scope->filters()); |
| 3819 | + QCOMPARE(results->data(results->index(0, 0), unity::shell::scopes::ResultsModelInterface::RoleTitle).toString(), QString("result for option o1")); |
| 3820 | + |
| 3821 | + // select option 2 |
| 3822 | + opts->setChecked(1, true); |
| 3823 | + TestUtils::waitForFilterStateChange(m_scope); |
| 3824 | + TestUtils::waitForSearchFinish(m_scope); |
| 3825 | + QCOMPARE(filters, m_scope->filters()); |
| 3826 | + QCOMPARE(results->data(results->index(0, 0), unity::shell::scopes::ResultsModelInterface::RoleTitle).toString(), QString("result for option o2")); |
| 3827 | + |
| 3828 | + // deselect option 2 |
| 3829 | + opts->setChecked(1, false); |
| 3830 | + TestUtils::waitForFilterStateChange(m_scope); |
| 3831 | + TestUtils::waitForSearchFinish(m_scope); |
| 3832 | + QCOMPARE(results->data(results->index(0, 0), unity::shell::scopes::ResultsModelInterface::RoleTitle).toString(), QString("result for: \"\"")); |
| 3833 | + |
| 3834 | + QCOMPARE(filters, m_scope->filters()); |
| 3835 | + } |
| 3836 | + |
| 3837 | + void testPrimaryFilter() |
| 3838 | + { |
| 3839 | + TestUtils::performSearch(m_scope, "test_primary_filter"); |
| 3840 | + |
| 3841 | + auto filters = m_scope->filters(); |
| 3842 | + QVERIFY(filters != nullptr); |
| 3843 | + QCOMPARE(filters->rowCount(), 2); |
| 3844 | + |
| 3845 | + auto idx = filters->index(0, 0); |
| 3846 | + QCOMPARE(filters->data(idx, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f2")); |
| 3847 | + idx = filters->index(1, 0); |
| 3848 | + QCOMPARE(filters->data(idx, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f3")); |
| 3849 | + |
| 3850 | + auto f1 = dynamic_cast<unity::shell::scopes::OptionSelectorFilterInterface *>(m_scope->primaryNavigationFilter()); |
| 3851 | + QVERIFY(f1 != nullptr); |
| 3852 | + QCOMPARE(f1->filterId(), QString("f1")); |
| 3853 | + |
| 3854 | + auto opts = f1->options(); |
| 3855 | + |
| 3856 | + // select option 1 |
| 3857 | + opts->setChecked(0, true); |
| 3858 | + TestUtils::waitForFilterStateChange(m_scope); |
| 3859 | + TestUtils::waitForSearchFinish(m_scope); |
| 3860 | + |
| 3861 | + QCOMPARE(m_scope->primaryNavigationTag(), QString("Option1")); |
| 3862 | + } |
| 3863 | + |
| 3864 | + void testRangeInputFilter() |
| 3865 | + { |
| 3866 | + TestUtils::performSearch(m_scope, ""); |
| 3867 | + |
| 3868 | + auto categories = m_scope->categories(); |
| 3869 | + QVERIFY(categories != nullptr); |
| 3870 | + auto results = categories->data(categories->index(0, 0), |
| 3871 | + Categories::RoleResultsSPtr).value<QSharedPointer<unity::shell::scopes::ResultsModelInterface>>(); |
| 3872 | + QVERIFY(results != nullptr); |
| 3873 | + |
| 3874 | + auto filters = m_scope->filters(); |
| 3875 | + QVERIFY(filters != nullptr); |
| 3876 | + QCOMPARE(filters->rowCount(), 3); |
| 3877 | + |
| 3878 | + auto idx = filters->index(1, 0); |
| 3879 | + auto f2 = filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value<RangeInputFilter*>(); |
| 3880 | + QVERIFY(f2 != nullptr); |
| 3881 | + |
| 3882 | + QCOMPARE(f2->hasStartValue(), true); |
| 3883 | + QCOMPARE(f2->hasEndValue(), false); |
| 3884 | + |
| 3885 | + { |
| 3886 | + f2->setStartValue(111.0f); |
| 3887 | + TestUtils::waitForFilterStateChange(m_scope); |
| 3888 | + TestUtils::waitForSearchFinish(m_scope); |
| 3889 | + |
| 3890 | + QCOMPARE(filters, m_scope->filters()); |
| 3891 | + QCOMPARE(f2->hasStartValue(), true); |
| 3892 | + QCOMPARE(f2->hasEndValue(), false); |
| 3893 | + |
| 3894 | + auto resultIdx = filters->index(0, 0); |
| 3895 | + QCOMPARE(results->data(resultIdx, unity::shell::scopes::ResultsModelInterface::RoleTitle).toString(), QString("result for range: 111.000000 - ***")); |
| 3896 | + } |
| 3897 | + |
| 3898 | + { |
| 3899 | + QCOMPARE(f2, filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value<RangeInputFilter*>()); |
| 3900 | + f2->setEndValue(300.5f); |
| 3901 | + TestUtils::waitForFilterStateChange(m_scope); |
| 3902 | + TestUtils::waitForSearchFinish(m_scope); |
| 3903 | + |
| 3904 | + QCOMPARE(f2->hasStartValue(), true); |
| 3905 | + QCOMPARE(f2->hasEndValue(), true); |
| 3906 | + |
| 3907 | + auto resultIdx = filters->index(0, 0); |
| 3908 | + QCOMPARE(filters, m_scope->filters()); |
| 3909 | + QCOMPARE(results->data(resultIdx, unity::shell::scopes::ResultsModelInterface::RoleTitle).toString(), QString("result for range: 111.000000 - 300.500000")); |
| 3910 | + } |
| 3911 | + |
| 3912 | + // erase start value, end value still present |
| 3913 | + { |
| 3914 | + f2->eraseStartValue(); |
| 3915 | + TestUtils::waitForFilterStateChange(m_scope); |
| 3916 | + TestUtils::waitForSearchFinish(m_scope); |
| 3917 | + |
| 3918 | + QCOMPARE(filters, m_scope->filters()); |
| 3919 | + QCOMPARE(f2->hasStartValue(), false); |
| 3920 | + QCOMPARE(f2->hasEndValue(), true); |
| 3921 | + |
| 3922 | + auto resultIdx = filters->index(0, 0); |
| 3923 | + QCOMPARE(results->data(resultIdx, unity::shell::scopes::ResultsModelInterface::RoleTitle).toString(), QString("result for range: *** - 300.500000")); |
| 3924 | + } |
| 3925 | + } |
| 3926 | + |
| 3927 | + void testValueSliderFilter() |
| 3928 | + { |
| 3929 | + TestUtils::performSearch(m_scope, ""); |
| 3930 | + |
| 3931 | + auto categories = m_scope->categories(); |
| 3932 | + QVERIFY(categories != nullptr); |
| 3933 | + auto results = categories->data(categories->index(0, 0), |
| 3934 | + Categories::RoleResultsSPtr).value<QSharedPointer<unity::shell::scopes::ResultsModelInterface>>(); |
| 3935 | + QVERIFY(results != nullptr); |
| 3936 | + |
| 3937 | + auto filters = m_scope->filters(); |
| 3938 | + QVERIFY(filters != nullptr); |
| 3939 | + QCOMPARE(filters->rowCount(), 3); |
| 3940 | + |
| 3941 | + auto idx = filters->index(2, 0); |
| 3942 | + auto f3 = filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value<ValueSliderFilter*>(); |
| 3943 | + QVERIFY(f3 != nullptr); |
| 3944 | + |
| 3945 | + QCOMPARE(static_cast<int>(f3->minValue()), 1); |
| 3946 | + QCOMPARE(static_cast<int>(f3->maxValue()), 99); |
| 3947 | + QCOMPARE(static_cast<int>(f3->value()), 50); |
| 3948 | + |
| 3949 | + auto valuesModel = f3->values(); |
| 3950 | + QVERIFY(valuesModel != nullptr); |
| 3951 | + |
| 3952 | + QCOMPARE(valuesModel->rowCount(), 3); |
| 3953 | + QCOMPARE(valuesModel->data(valuesModel->index(0, 0), uss::ValueSliderValuesInterface::Roles::RoleValue).toInt(), 1); |
| 3954 | + QCOMPARE(valuesModel->data(valuesModel->index(0, 0), uss::ValueSliderValuesInterface::Roles::RoleLabel).toString(), QString("Min")); |
| 3955 | + QCOMPARE(valuesModel->data(valuesModel->index(1, 0), uss::ValueSliderValuesInterface::Roles::RoleValue).toInt(), 33); |
| 3956 | + QCOMPARE(valuesModel->data(valuesModel->index(1, 0), uss::ValueSliderValuesInterface::Roles::RoleLabel).toString(), QString("One third")); |
| 3957 | + QCOMPARE(valuesModel->data(valuesModel->index(2, 0), uss::ValueSliderValuesInterface::Roles::RoleValue).toInt(), 99); |
| 3958 | + QCOMPARE(valuesModel->data(valuesModel->index(2, 0), uss::ValueSliderValuesInterface::Roles::RoleLabel).toString(), QString("Max")); |
| 3959 | + |
| 3960 | + f3->setValue(75); |
| 3961 | + TestUtils::waitForFilterStateChange(m_scope); |
| 3962 | + TestUtils::waitForSearchFinish(m_scope); |
| 3963 | + |
| 3964 | + QCOMPARE(filters->rowCount(), 3); |
| 3965 | + |
| 3966 | + // filter object shouldn't be recreated |
| 3967 | + QCOMPARE(filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value<ValueSliderFilter*>(), f3); |
| 3968 | + |
| 3969 | + QCOMPARE(filters, m_scope->filters()); |
| 3970 | + QCOMPARE(static_cast<int>(f3->value()), 75); |
| 3971 | + } |
| 3972 | + |
| 3973 | + void testResetToDefault() |
| 3974 | + { |
| 3975 | + TestUtils::performSearch(m_scope, ""); |
| 3976 | + |
| 3977 | + auto filters = m_scope->filters(); |
| 3978 | + QVERIFY(filters != nullptr); |
| 3979 | + QCOMPARE(filters->rowCount(), 3); |
| 3980 | + |
| 3981 | + auto idx = filters->index(1, 0); |
| 3982 | + auto f2 = filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value<RangeInputFilter*>(); |
| 3983 | + QVERIFY(f2 != nullptr); |
| 3984 | + QCOMPARE(f2->startValue(), 2.0f); //QCOMPARE does fuzzy comparison for floats/doubles |
| 3985 | + |
| 3986 | + idx = filters->index(2, 0); |
| 3987 | + auto f3 = filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value<ValueSliderFilter*>(); |
| 3988 | + QVERIFY(f3 != nullptr); |
| 3989 | + QCOMPARE(static_cast<int>(f3->value()), 50); |
| 3990 | + f2->setStartValue(5.0f); |
| 3991 | + f3->setValue(75); |
| 3992 | + TestUtils::waitForFilterStateChange(m_scope); |
| 3993 | + TestUtils::waitForSearchFinish(m_scope); |
| 3994 | + QCOMPARE(f2->startValue(), 5.0f); |
| 3995 | + QCOMPARE(static_cast<int>(f3->value()), 75); |
| 3996 | + |
| 3997 | + m_scope->resetFilters(); |
| 3998 | + TestUtils::waitForFilterStateChange(m_scope); |
| 3999 | + TestUtils::waitForSearchFinish(m_scope); |
| 4000 | + QCOMPARE(f2->startValue(), 2.0f); //QCOMPARE does fuzzy comparison for floats/doubles |
| 4001 | + QCOMPARE(static_cast<int>(f3->value()), 50); |
| 4002 | + } |
| 4003 | + |
| 4004 | + void testCancel() |
| 4005 | + { |
| 4006 | + TestUtils::performSearch(m_scope, ""); |
| 4007 | + |
| 4008 | + auto filters = m_scope->filters(); |
| 4009 | + QVERIFY(filters != nullptr); |
| 4010 | + QCOMPARE(filters->rowCount(), 3); |
| 4011 | + |
| 4012 | + auto idx = filters->index(1, 0); |
| 4013 | + auto f2 = filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value<RangeInputFilter*>(); |
| 4014 | + QVERIFY(f2 != nullptr); |
| 4015 | + |
| 4016 | + idx = filters->index(2, 0); |
| 4017 | + auto f3 = filters->data(idx, uss::FiltersInterface::Roles::RoleFilter).value<ValueSliderFilter*>(); |
| 4018 | + QVERIFY(f3 != nullptr); |
| 4019 | + QCOMPARE(static_cast<int>(f3->value()), 50); |
| 4020 | + f2->setStartValue(5.0f); |
| 4021 | + f3->setValue(75); |
| 4022 | + TestUtils::waitForFilterStateChange(m_scope); |
| 4023 | + TestUtils::waitForSearchFinish(m_scope); |
| 4024 | + QCOMPARE(f2->startValue(), 5.0f); |
| 4025 | + QCOMPARE(static_cast<int>(f3->value()), 75); |
| 4026 | + |
| 4027 | + m_scope->resetPrimaryNavigationTag(); |
| 4028 | + |
| 4029 | + TestUtils::waitForSearchFinish(m_scope); |
| 4030 | + QCOMPARE(f2->startValue(), 2.0f); //QCOMPARE does fuzzy comparison for floats/doubles |
| 4031 | + QCOMPARE(static_cast<int>(f3->value()), 50); |
| 4032 | + QCOMPARE(QString(), m_scope->primaryNavigationTag()); |
| 4033 | + } |
| 4034 | + |
| 4035 | +private: |
| 4036 | + QScopedPointer<Scopes> m_scopes; |
| 4037 | + Scope::Ptr m_scope; |
| 4038 | + Registry::UPtr m_registry; |
| 4039 | +}; |
| 4040 | + |
| 4041 | +QTEST_GUILESS_MAIN(FiltersEndToEndTest) |
| 4042 | +#include <filtersendtoendtest.moc> |
| 4043 | |
| 4044 | === added file 'tests/filterstest.cpp' |
| 4045 | --- tests/filterstest.cpp 1970-01-01 00:00:00 +0000 |
| 4046 | +++ tests/filterstest.cpp 2016-03-16 11:17:35 +0000 |
| 4047 | @@ -0,0 +1,230 @@ |
| 4048 | +/* |
| 4049 | + * Copyright (C) 2015 Canonical, Ltd. |
| 4050 | + * |
| 4051 | + * This program is free software; you can redistribute it and/or modify |
| 4052 | + * it under the terms of the GNU General Public License as published by |
| 4053 | + * the Free Software Foundation; version 3. |
| 4054 | + * |
| 4055 | + * This program is distributed in the hope that it will be useful, |
| 4056 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 4057 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 4058 | + * GNU General Public License for more details. |
| 4059 | + * |
| 4060 | + * You should have received a copy of the GNU General Public License |
| 4061 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 4062 | + * |
| 4063 | + * Authors: |
| 4064 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
| 4065 | + */ |
| 4066 | + |
| 4067 | +#include <QSignalSpy> |
| 4068 | +#include <QScopedPointer> |
| 4069 | +#include <QTest> |
| 4070 | +#include <QList> |
| 4071 | +#include "filters.h" |
| 4072 | +#include "optionselectorfilter.h" |
| 4073 | + |
| 4074 | +#include <unity/scopes/OptionSelectorFilter.h> |
| 4075 | + |
| 4076 | +using namespace scopes_ng; |
| 4077 | +namespace uss = unity::shell::scopes; |
| 4078 | + |
| 4079 | +class FiltersTest : public QObject |
| 4080 | +{ |
| 4081 | + Q_OBJECT |
| 4082 | + |
| 4083 | +private Q_SLOTS: |
| 4084 | + |
| 4085 | + void init() |
| 4086 | + { |
| 4087 | + unity::scopes::FilterState filterState; |
| 4088 | + filtersModel.reset(new Filters(filterState)); |
| 4089 | + |
| 4090 | + f1 = unity::scopes::OptionSelectorFilter::create("f1", "Filter1", false); |
| 4091 | + f1o1 = f1->add_option("o1", "Option1"); |
| 4092 | + f1o2 = f1->add_option("o2", "Option2"); |
| 4093 | + |
| 4094 | + f2 = unity::scopes::OptionSelectorFilter::create("f2", "Filter2", false); |
| 4095 | + f2o1 = f2->add_option("o1", "Option1"); |
| 4096 | + f2o2 = f2->add_option("o2", "Option2"); |
| 4097 | + } |
| 4098 | + |
| 4099 | + void testFiltersModelInit() |
| 4100 | + { |
| 4101 | + unity::scopes::FilterState filterState; |
| 4102 | + |
| 4103 | + QSignalSpy filtersSpy(filtersModel.data(), SIGNAL(rowsInserted(const QModelIndex&, int, int))); |
| 4104 | + { |
| 4105 | + QList<unity::scopes::FilterBase::SCPtr> backendFilters; |
| 4106 | + backendFilters.append(f1); |
| 4107 | + |
| 4108 | + f1->update_state(filterState, f1o1, true); |
| 4109 | + |
| 4110 | + filtersModel->update(backendFilters); |
| 4111 | + filtersModel->update(filterState); |
| 4112 | + } |
| 4113 | + |
| 4114 | + QCOMPARE(filtersSpy.count(), 1); // 1 filter object added |
| 4115 | + |
| 4116 | + // check filters model data |
| 4117 | + auto idx = filtersModel->index(0, 0); |
| 4118 | + QCOMPARE(filtersModel->rowCount(), 1); |
| 4119 | + QCOMPARE(filtersModel->data(idx, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f1")); |
| 4120 | + QCOMPARE(filtersModel->data(idx, unity::shell::scopes::FiltersInterface::Roles::RoleFilterType).toInt(), |
| 4121 | + static_cast<int>(unity::shell::scopes::FiltersInterface::FilterType::OptionSelectorFilter)); |
| 4122 | + |
| 4123 | + // get filter object from the model |
| 4124 | + auto opf = filtersModel->data(idx, uss::FiltersInterface::Roles::RoleFilter).value<OptionSelectorFilter*>(); |
| 4125 | + QVERIFY(opf != nullptr); |
| 4126 | + QCOMPARE(opf->filterId(), QString("f1")); |
| 4127 | + QCOMPARE(opf->label(), QString("Filter1")); |
| 4128 | + QVERIFY(!opf->multiSelect()); |
| 4129 | + } |
| 4130 | + |
| 4131 | + void testFiltersModelInsert() |
| 4132 | + { |
| 4133 | + QSignalSpy rowsInsertedSignal(filtersModel.data(), SIGNAL(rowsInserted(const QModelIndex&, int, int))); |
| 4134 | + QSignalSpy rowsRemovedSignal(filtersModel.data(), SIGNAL(rowsRemoved(const QModelIndex&, int, int))); |
| 4135 | + QSignalSpy rowsMovedSignal(filtersModel.data(), SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int))); |
| 4136 | + |
| 4137 | + { |
| 4138 | + QList<unity::scopes::FilterBase::SCPtr> backendFilters; |
| 4139 | + backendFilters.append(f1); |
| 4140 | + |
| 4141 | + filtersModel->update(backendFilters); |
| 4142 | + } |
| 4143 | + |
| 4144 | + QCOMPARE(rowsMovedSignal.count(), 0); |
| 4145 | + QCOMPARE(rowsRemovedSignal.count(), 0); |
| 4146 | + QCOMPARE(rowsInsertedSignal.count(), 1); |
| 4147 | + // verify arguments of rowsInsertedSignal |
| 4148 | + { |
| 4149 | + auto args = rowsInsertedSignal.takeFirst(); |
| 4150 | + auto row = args.at(1).toInt(); |
| 4151 | + QCOMPARE(row, 0); |
| 4152 | + } |
| 4153 | + |
| 4154 | + rowsInsertedSignal.clear(); |
| 4155 | + |
| 4156 | + // insert new filter |
| 4157 | + { |
| 4158 | + QList<unity::scopes::FilterBase::SCPtr> backendFilters; |
| 4159 | + backendFilters.append(f1); |
| 4160 | + backendFilters.append(f2); |
| 4161 | + |
| 4162 | + filtersModel->update(backendFilters); |
| 4163 | + } |
| 4164 | + |
| 4165 | + QCOMPARE(rowsMovedSignal.count(), 0); |
| 4166 | + QCOMPARE(rowsRemovedSignal.count(), 0); |
| 4167 | + QCOMPARE(rowsInsertedSignal.count(), 1); |
| 4168 | + // verify arguments of rowsInsertedSignal |
| 4169 | + { |
| 4170 | + auto args = rowsInsertedSignal.takeFirst(); |
| 4171 | + auto row = args.at(1).toInt(); |
| 4172 | + QCOMPARE(row, 1); |
| 4173 | + } |
| 4174 | + |
| 4175 | + auto idx1 = filtersModel->index(0, 0); |
| 4176 | + auto idx2 = filtersModel->index(1, 0); |
| 4177 | + QCOMPARE(filtersModel->rowCount(), 2); |
| 4178 | + QCOMPARE(filtersModel->data(idx1, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f1")); |
| 4179 | + QCOMPARE(filtersModel->data(idx2, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f2")); |
| 4180 | + QCOMPARE(filtersModel->data(idx2, unity::shell::scopes::FiltersInterface::Roles::RoleFilterType).toInt(), |
| 4181 | + static_cast<int>(unity::shell::scopes::FiltersInterface::FilterType::OptionSelectorFilter)); |
| 4182 | + |
| 4183 | + } |
| 4184 | + |
| 4185 | + void testFiltersModelMove() |
| 4186 | + { |
| 4187 | + { |
| 4188 | + QList<unity::scopes::FilterBase::SCPtr> backendFilters; |
| 4189 | + backendFilters.append(f1); |
| 4190 | + backendFilters.append(f2); |
| 4191 | + |
| 4192 | + filtersModel->update(backendFilters); |
| 4193 | + } |
| 4194 | + |
| 4195 | + QSignalSpy rowsInsertedSignal(filtersModel.data(), SIGNAL(rowsInserted(const QModelIndex&, int, int))); |
| 4196 | + QSignalSpy rowsRemovedSignal(filtersModel.data(), SIGNAL(rowsRemoved(const QModelIndex&, int, int))); |
| 4197 | + QSignalSpy rowsMovedSignal(filtersModel.data(), SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int))); |
| 4198 | + |
| 4199 | + // change filters positions |
| 4200 | + { |
| 4201 | + QList<unity::scopes::FilterBase::SCPtr> backendFilters; |
| 4202 | + |
| 4203 | + backendFilters.append(f2); |
| 4204 | + backendFilters.append(f1); |
| 4205 | + |
| 4206 | + filtersModel->update(backendFilters); |
| 4207 | + } |
| 4208 | + |
| 4209 | + QCOMPARE(rowsInsertedSignal.count(), 0); // no change |
| 4210 | + QCOMPARE(rowsRemovedSignal.count(), 0); |
| 4211 | + QCOMPARE(rowsMovedSignal.count(), 1); |
| 4212 | + |
| 4213 | + QCOMPARE(filtersModel->rowCount(), 2); |
| 4214 | + |
| 4215 | + auto idx1 = filtersModel->index(0, 0); |
| 4216 | + auto idx2 = filtersModel->index(1, 0); |
| 4217 | + QCOMPARE(filtersModel->data(idx1, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f2")); |
| 4218 | + QCOMPARE(filtersModel->data(idx2, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f1")); |
| 4219 | + |
| 4220 | + // verify arguments of rowsMovedSignal |
| 4221 | + { |
| 4222 | + auto args = rowsMovedSignal.takeFirst(); |
| 4223 | + auto srcRow = args.at(1).toInt(); |
| 4224 | + auto dstRow = args.at(4).toInt(); |
| 4225 | + QCOMPARE(srcRow, 0); |
| 4226 | + QCOMPARE(dstRow, 2); |
| 4227 | + } |
| 4228 | + } |
| 4229 | + |
| 4230 | + void testFiltersModelRemove() |
| 4231 | + { |
| 4232 | + { |
| 4233 | + QList<unity::scopes::FilterBase::SCPtr> backendFilters; |
| 4234 | + backendFilters.append(f2); |
| 4235 | + backendFilters.append(f1); |
| 4236 | + |
| 4237 | + filtersModel->update(backendFilters); |
| 4238 | + } |
| 4239 | + |
| 4240 | + QSignalSpy rowsInsertedSignal(filtersModel.data(), SIGNAL(rowsInserted(const QModelIndex&, int, int))); |
| 4241 | + QSignalSpy rowsRemovedSignal(filtersModel.data(), SIGNAL(rowsRemoved(const QModelIndex&, int, int))); |
| 4242 | + QSignalSpy rowsMovedSignal(filtersModel.data(), SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int))); |
| 4243 | + |
| 4244 | + // remove a filter |
| 4245 | + { |
| 4246 | + QList<unity::scopes::FilterBase::SCPtr> backendFilters; |
| 4247 | + backendFilters.append(f2); // filter1 not present (removed) |
| 4248 | + |
| 4249 | + filtersModel->update(backendFilters); |
| 4250 | + } |
| 4251 | + |
| 4252 | + QCOMPARE(rowsInsertedSignal.count(), 0); |
| 4253 | + QCOMPARE(rowsMovedSignal.count(), 0); |
| 4254 | + QCOMPARE(rowsRemovedSignal.count(), 1); |
| 4255 | + // verify arguments of rowsRemovedSignal |
| 4256 | + { |
| 4257 | + auto args = rowsRemovedSignal.takeFirst(); |
| 4258 | + auto first = args.at(1).toInt(); |
| 4259 | + auto last = args.at(2).toInt(); |
| 4260 | + QCOMPARE(first, 1); |
| 4261 | + QCOMPARE(last, 1); |
| 4262 | + } |
| 4263 | + |
| 4264 | + QCOMPARE(filtersModel->rowCount(), 1); |
| 4265 | + |
| 4266 | + auto idx1 = filtersModel->index(0, 0); |
| 4267 | + QCOMPARE(filtersModel->data(idx1, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f2")); |
| 4268 | + } |
| 4269 | + |
| 4270 | +private: |
| 4271 | + QScopedPointer<Filters> filtersModel; |
| 4272 | + unity::scopes::OptionSelectorFilter::SPtr f1, f2; |
| 4273 | + unity::scopes::FilterOption::SCPtr f1o1, f1o2, f2o1, f2o2; |
| 4274 | +}; |
| 4275 | + |
| 4276 | +QTEST_GUILESS_MAIN(FiltersTest) |
| 4277 | +#include <filterstest.moc> |
| 4278 | |
| 4279 | === added file 'tests/optionselectorfiltertest.cpp' |
| 4280 | --- tests/optionselectorfiltertest.cpp 1970-01-01 00:00:00 +0000 |
| 4281 | +++ tests/optionselectorfiltertest.cpp 2016-03-16 11:17:35 +0000 |
| 4282 | @@ -0,0 +1,263 @@ |
| 4283 | +/* |
| 4284 | + * Copyright (C) 2015 Canonical, Ltd. |
| 4285 | + * |
| 4286 | + * This program is free software; you can redistribute it and/or modify |
| 4287 | + * it under the terms of the GNU General Public License as published by |
| 4288 | + * the Free Software Foundation; version 3. |
| 4289 | + * |
| 4290 | + * This program is distributed in the hope that it will be useful, |
| 4291 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 4292 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 4293 | + * GNU General Public License for more details. |
| 4294 | + * |
| 4295 | + * You should have received a copy of the GNU General Public License |
| 4296 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 4297 | + * |
| 4298 | + * Authors: |
| 4299 | + * Pawel Stolowski <pawel.stolowski@canonical.com> |
| 4300 | + */ |
| 4301 | + |
| 4302 | +#include <QSignalSpy> |
| 4303 | +#include <QScopedPointer> |
| 4304 | +#include <QTest> |
| 4305 | +#include <QList> |
| 4306 | +#include "filters.h" |
| 4307 | +#include "optionselectorfilter.h" |
| 4308 | + |
| 4309 | +#include <unity/scopes/OptionSelectorFilter.h> |
| 4310 | + |
| 4311 | +using namespace scopes_ng; |
| 4312 | +namespace uss = unity::shell::scopes; |
| 4313 | + |
| 4314 | +class OptionSelectorFilterTest: public QObject |
| 4315 | +{ |
| 4316 | + Q_OBJECT |
| 4317 | + |
| 4318 | +private Q_SLOTS: |
| 4319 | + |
| 4320 | + void init() |
| 4321 | + { |
| 4322 | + unity::scopes::FilterState filterState; |
| 4323 | + filtersModel.reset(new Filters(filterState)); |
| 4324 | + |
| 4325 | + f1 = unity::scopes::OptionSelectorFilter::create("f1", "Filter1", false); |
| 4326 | + f1o1 = f1->add_option("f1o1", "Option1"); |
| 4327 | + f1o2 = f1->add_option("f1o2", "Option2"); |
| 4328 | + |
| 4329 | + f2 = unity::scopes::OptionSelectorFilter::create("f2", "Filter2", true); |
| 4330 | + f2o1 = f2->add_option("f2o1", "Option1"); |
| 4331 | + f2o2 = f2->add_option("f2o2", "Option2"); |
| 4332 | + |
| 4333 | + backendFilters.clear(); |
| 4334 | + backendFilters.append(f1); |
| 4335 | + backendFilters.append(f2); |
| 4336 | + filtersModel->update(backendFilters); |
| 4337 | + |
| 4338 | + f1->update_state(filterState, f1o1, true); |
| 4339 | + |
| 4340 | + filtersModel->update(filterState); |
| 4341 | + } |
| 4342 | + |
| 4343 | + void testOptions() |
| 4344 | + { |
| 4345 | + // check filters model data |
| 4346 | + auto idx1 = filtersModel->index(0, 0); |
| 4347 | + auto idx2 = filtersModel->index(1, 0); |
| 4348 | + |
| 4349 | + QCOMPARE(filtersModel->rowCount(), 2); |
| 4350 | + QCOMPARE(filtersModel->data(idx1, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f1")); |
| 4351 | + QCOMPARE(filtersModel->data(idx1, unity::shell::scopes::FiltersInterface::Roles::RoleFilterType).toInt(), |
| 4352 | + static_cast<int>(unity::shell::scopes::FiltersInterface::FilterType::OptionSelectorFilter)); |
| 4353 | + QCOMPARE(filtersModel->data(idx1, unity::shell::scopes::FiltersInterface::Roles::RoleFilterId).toString(), QString("f1")); |
| 4354 | + QCOMPARE(filtersModel->data(idx1, unity::shell::scopes::FiltersInterface::Roles::RoleFilterType).toInt(), |
| 4355 | + static_cast<int>(unity::shell::scopes::FiltersInterface::FilterType::OptionSelectorFilter)); |
| 4356 | + |
| 4357 | + { |
| 4358 | + // get 1st option selector filter |
| 4359 | + auto opf = filtersModel->data(idx1, uss::FiltersInterface::Roles::RoleFilter).value<OptionSelectorFilter*>(); |
| 4360 | + QVERIFY(opf != nullptr); |
| 4361 | + QCOMPARE(opf->filterId(), QString("f1")); |
| 4362 | + QCOMPARE(opf->label(), QString("Filter1")); |
| 4363 | + QVERIFY(!opf->multiSelect()); |
| 4364 | + |
| 4365 | + // check options |
| 4366 | + auto opts = opf->options(); |
| 4367 | + QVERIFY(opts != nullptr); |
| 4368 | + QCOMPARE(opts->rowCount(), 2); |
| 4369 | + |
| 4370 | + auto idx = opts->index(0, 0); |
| 4371 | + QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("f1o1")); |
| 4372 | + QVERIFY(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); // option1 is checked |
| 4373 | + idx = opts->index(1, 0); |
| 4374 | + QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("f1o2")); |
| 4375 | + QVERIFY(!opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); |
| 4376 | + } |
| 4377 | + |
| 4378 | + { |
| 4379 | + // get 2nd option selector filter |
| 4380 | + auto opf = filtersModel->data(idx2, uss::FiltersInterface::Roles::RoleFilter).value<OptionSelectorFilter*>(); |
| 4381 | + QVERIFY(opf != nullptr); |
| 4382 | + QCOMPARE(opf->filterId(), QString("f2")); |
| 4383 | + QCOMPARE(opf->label(), QString("Filter2")); |
| 4384 | + QVERIFY(opf->multiSelect()); |
| 4385 | + |
| 4386 | + // check options |
| 4387 | + auto opts = opf->options(); |
| 4388 | + QVERIFY(opts != nullptr); |
| 4389 | + QCOMPARE(opts->rowCount(), 2); |
| 4390 | + |
| 4391 | + auto idx = opts->index(0, 0); |
| 4392 | + QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("f2o1")); |
| 4393 | + QVERIFY(!opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); |
| 4394 | + idx = opts->index(1, 0); |
| 4395 | + QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("f2o2")); |
| 4396 | + QVERIFY(!opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); |
| 4397 | + } |
| 4398 | + } |
| 4399 | + |
| 4400 | + void testBackendCheckedStateChange() |
| 4401 | + { |
| 4402 | + auto idx1 = filtersModel->index(0, 0); |
| 4403 | + { |
| 4404 | + // get 1st option selector filter |
| 4405 | + auto opf = filtersModel->data(idx1, uss::FiltersInterface::Roles::RoleFilter).value<OptionSelectorFilter*>(); |
| 4406 | + QVERIFY(opf != nullptr); |
| 4407 | + auto opts = opf->options(); |
| 4408 | + QVERIFY(opts != nullptr); |
| 4409 | + QCOMPARE(opts->rowCount(), 2); |
| 4410 | + |
| 4411 | + QSignalSpy dataChangedSignal(opts, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&))); |
| 4412 | + QSignalSpy stateChangeSignal(filtersModel.data(), SIGNAL(filterStateChanged())); |
| 4413 | + |
| 4414 | + // enable second option (which disables 1st option) |
| 4415 | + f1->update_state(filterState, f1o2, true); |
| 4416 | + filtersModel->update(filterState); |
| 4417 | + |
| 4418 | + QCOMPARE(dataChangedSignal.count(), 2); |
| 4419 | + QCOMPARE(stateChangeSignal.count(), 0); // change initiated by backend, so no state change signal |
| 4420 | + |
| 4421 | + // verify arguments of dataChanged signal |
| 4422 | + { |
| 4423 | + auto args = dataChangedSignal.takeFirst(); |
| 4424 | + auto topLeft = args.at(0).value<QModelIndex>(); |
| 4425 | + auto roles = args.at(2).value<QVector<int>>(); |
| 4426 | + QCOMPARE(topLeft.row(), 0); |
| 4427 | + QCOMPARE(roles[0], static_cast<int>(uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked)); |
| 4428 | + } |
| 4429 | + |
| 4430 | + auto idx = opts->index(0, 0); |
| 4431 | + QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("f1o1")); |
| 4432 | + QVERIFY(!opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); // option 1 is now off |
| 4433 | + idx = opts->index(1, 0); |
| 4434 | + QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("f1o2")); |
| 4435 | + QVERIFY(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); // option 2 is now on |
| 4436 | + } |
| 4437 | + } |
| 4438 | + |
| 4439 | + void testBackendOptionLabelChange() |
| 4440 | + { |
| 4441 | + auto idx = filtersModel->index(1, 0); |
| 4442 | + { |
| 4443 | + // get 1st option selector filter |
| 4444 | + auto opf = filtersModel->data(idx, uss::FiltersInterface::Roles::RoleFilter).value<OptionSelectorFilter*>(); |
| 4445 | + QVERIFY(opf != nullptr); |
| 4446 | + QCOMPARE(opf->filterId(), QString("f2")); |
| 4447 | + auto opts = opf->options(); |
| 4448 | + QVERIFY(opts != nullptr); |
| 4449 | + QCOMPARE(opts->rowCount(), 2); |
| 4450 | + |
| 4451 | + auto idx1 = opts->index(0, 0); |
| 4452 | + auto idx2 = opts->index(1, 0); |
| 4453 | + QCOMPARE(opts->data(idx1, uss::OptionSelectorOptionsInterface::Roles::RoleOptionLabel).toString(), QString("Option1")); |
| 4454 | + QCOMPARE(opts->data(idx2, uss::OptionSelectorOptionsInterface::Roles::RoleOptionLabel).toString(), QString("Option2")); |
| 4455 | + |
| 4456 | + QSignalSpy dataChangedSignal(opts, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&))); |
| 4457 | + QSignalSpy stateChangeSignal(filtersModel.data(), SIGNAL(filterStateChanged())); |
| 4458 | + |
| 4459 | + unity::scopes::OptionSelectorFilter::SPtr f3 = unity::scopes::OptionSelectorFilter::create("f2", "Filter2", true); |
| 4460 | + auto f3o1 = f3->add_option("f2o1", "Option1"); |
| 4461 | + auto f3o2 = f3->add_option("f2o2", "UpdatedOption2"); |
| 4462 | + |
| 4463 | + QList<unity::scopes::FilterBase::SCPtr> backendFilters2; |
| 4464 | + backendFilters2.append(f1); |
| 4465 | + backendFilters2.append(f3); |
| 4466 | + |
| 4467 | + // sync model with new backend filters |
| 4468 | + filtersModel->update(backendFilters2); |
| 4469 | + |
| 4470 | + if (dataChangedSignal.empty()) { |
| 4471 | + QVERIFY(dataChangedSignal.wait()); |
| 4472 | + } |
| 4473 | + QCOMPARE(dataChangedSignal.count(), 1); |
| 4474 | + |
| 4475 | + QCOMPARE(opts->data(idx1, uss::OptionSelectorOptionsInterface::Roles::RoleOptionLabel).toString(), QString("Option1")); |
| 4476 | + QCOMPARE(opts->data(idx2, uss::OptionSelectorOptionsInterface::Roles::RoleOptionLabel).toString(), QString("UpdatedOption2")); |
| 4477 | + |
| 4478 | + QCOMPARE(stateChangeSignal.count(), 0); // no state change signal |
| 4479 | + |
| 4480 | + // verify arguments of dataChanged signal |
| 4481 | + { |
| 4482 | + auto args = dataChangedSignal.takeFirst(); |
| 4483 | + auto topLeft = args.at(0).value<QModelIndex>(); |
| 4484 | + auto roles = args.at(2).value<QVector<int>>(); |
| 4485 | + QCOMPARE(topLeft.row(), 1); |
| 4486 | + QCOMPARE(roles[0], static_cast<int>(uss::OptionSelectorOptionsInterface::Roles::RoleOptionLabel)); |
| 4487 | + } |
| 4488 | + } |
| 4489 | + } |
| 4490 | + |
| 4491 | + void testUICheckedStateChange() |
| 4492 | + { |
| 4493 | + auto idx1 = filtersModel->index(0, 0); |
| 4494 | + { |
| 4495 | + // get 1st option selector filter |
| 4496 | + auto opf = filtersModel->data(idx1, uss::FiltersInterface::Roles::RoleFilter).value<OptionSelectorFilter*>(); |
| 4497 | + QVERIFY(opf != nullptr); |
| 4498 | + auto opts = opf->options(); |
| 4499 | + QVERIFY(opts != nullptr); |
| 4500 | + QCOMPARE(opts->rowCount(), 2); |
| 4501 | + |
| 4502 | + QSignalSpy dataChangedSignal(opts, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&))); |
| 4503 | + QSignalSpy stateChangeSignal(filtersModel.data(), SIGNAL(filterStateChanged())); |
| 4504 | + |
| 4505 | + // enable second option (which disables 1st option) |
| 4506 | + opts->setChecked(1, true); |
| 4507 | + |
| 4508 | + if (stateChangeSignal.empty()) { |
| 4509 | + stateChangeSignal.wait(); |
| 4510 | + } |
| 4511 | + if (dataChangedSignal.empty()) { |
| 4512 | + dataChangedSignal.wait(); |
| 4513 | + } |
| 4514 | + QCOMPARE(stateChangeSignal.count(), 1); |
| 4515 | + QCOMPARE(dataChangedSignal.count(), 2); |
| 4516 | + |
| 4517 | + // verify arguments of dataChanged signal |
| 4518 | + { |
| 4519 | + auto args = dataChangedSignal.takeFirst(); |
| 4520 | + auto topLeft = args.at(0).value<QModelIndex>(); |
| 4521 | + auto roles = args.at(2).value<QVector<int>>(); |
| 4522 | + QCOMPARE(topLeft.row(), 0); |
| 4523 | + QCOMPARE(roles[0], static_cast<int>(uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked)); |
| 4524 | + } |
| 4525 | + |
| 4526 | + auto idx = opts->index(0, 0); |
| 4527 | + QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("f1o1")); |
| 4528 | + QVERIFY(!opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); // option 1 is now off |
| 4529 | + idx = opts->index(1, 0); |
| 4530 | + QCOMPARE(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionId).toString(), QString("f1o2")); |
| 4531 | + QVERIFY(opts->data(idx, uss::OptionSelectorOptionsInterface::Roles::RoleOptionChecked).toBool()); // option 2 is now on |
| 4532 | + } |
| 4533 | + |
| 4534 | + } |
| 4535 | + |
| 4536 | +private: |
| 4537 | + unity::scopes::FilterState filterState; |
| 4538 | + QScopedPointer<Filters> filtersModel; |
| 4539 | + unity::scopes::OptionSelectorFilter::SPtr f1, f2; |
| 4540 | + unity::scopes::FilterOption::SCPtr f1o1, f1o2, f2o1, f2o2; |
| 4541 | + QList<unity::scopes::FilterBase::SCPtr> backendFilters; |
| 4542 | +}; |
| 4543 | + |
| 4544 | +QTEST_GUILESS_MAIN(OptionSelectorFilterTest) |
| 4545 | +#include <optionselectorfiltertest.moc> |
