Merge lp:~stolowski/unity-scopes-api/inline-playback-doc into lp:unity-scopes-api

Proposed by Paweł Stołowski
Status: Superseded
Proposed branch: lp:~stolowski/unity-scopes-api/inline-playback-doc
Merge into: lp:unity-scopes-api
Diff against target: 7045 lines (+2644/-1317)
130 files modified
CMakeLists.txt (+1/-1)
CONFIGFILES (+0/-32)
HACKING (+4/-7)
STRUCTS (+15/-4)
debian/VERSION (+1/-1)
debian/changelog (+10/-0)
debian/control (+5/-115)
debian/control.in (+3/-2)
demo/client.cpp (+0/-1)
doc/tutorial.dox (+133/-0)
include/unity/scopes/FilterBase.h (+24/-0)
include/unity/scopes/FilterGroup.h (+83/-0)
include/unity/scopes/FilterOption.h (+6/-0)
include/unity/scopes/OptionSelectorFilter.h (+27/-1)
include/unity/scopes/RangeInputFilter.h (+120/-30)
include/unity/scopes/ValueSliderFilter.h (+35/-55)
include/unity/scopes/ValueSliderLabels.h (+117/-0)
include/unity/scopes/internal/ChildScopesRepository.h (+2/-2)
include/unity/scopes/internal/DfltConfig.h.in (+0/-4)
include/unity/scopes/internal/FilterBaseImpl.h (+9/-1)
include/unity/scopes/internal/FilterGroupImpl.h (+54/-0)
include/unity/scopes/internal/FilterOptionImpl.h (+3/-0)
include/unity/scopes/internal/Logger.h (+87/-69)
include/unity/scopes/internal/OptionSelectorFilterImpl.h (+1/-1)
include/unity/scopes/internal/RangeInputFilterImpl.h (+20/-9)
include/unity/scopes/internal/RatingFilterImpl.h (+4/-1)
include/unity/scopes/internal/RegistryObject.h (+3/-3)
include/unity/scopes/internal/RuntimeConfig.h (+0/-7)
include/unity/scopes/internal/RuntimeImpl.h (+1/-2)
include/unity/scopes/internal/ValueSliderFilterImpl.h (+6/-11)
include/unity/scopes/internal/ValueSliderLabelsImpl.h (+59/-0)
include/unity/scopes/internal/smartscopes/SmartScopesClient.h (+12/-7)
include/unity/scopes/internal/zmq_middleware/ObjectAdapter.h (+1/-2)
include/unity/scopes/internal/zmq_middleware/ZmqMiddleware.h (+1/-1)
scoperegistry/DirWatcher.cpp (+5/-5)
scoperegistry/DirWatcher.h (+2/-2)
scoperegistry/ScopesWatcher.cpp (+14/-15)
scoperegistry/ScopesWatcher.h (+2/-2)
src/scopes/CMakeLists.txt (+2/-0)
src/scopes/CategoryRenderer.cpp (+6/-2)
src/scopes/FilterBase.cpp (+15/-0)
src/scopes/FilterGroup.cpp (+56/-0)
src/scopes/FilterOption.cpp (+5/-0)
src/scopes/OptionSelectorFilter.cpp (+13/-1)
src/scopes/PreviewWidget.cpp (+3/-3)
src/scopes/RangeInputFilter.cpp (+93/-22)
src/scopes/ValueSliderFilter.cpp (+9/-22)
src/scopes/ValueSliderLabels.cpp (+89/-0)
src/scopes/internal/ActivationQueryObject.cpp (+2/-2)
src/scopes/internal/CMakeLists.txt (+2/-0)
src/scopes/internal/ChildScopesRepository.cpp (+13/-22)
src/scopes/internal/FilterBaseImpl.cpp (+59/-2)
src/scopes/internal/FilterGroupImpl.cpp (+97/-0)
src/scopes/internal/FilterOptionImpl.cpp (+12/-1)
src/scopes/internal/Logger.cpp (+146/-221)
src/scopes/internal/OptionSelectorFilterImpl.cpp (+29/-12)
src/scopes/internal/PreviewQueryObject.cpp (+2/-2)
src/scopes/internal/QueryCtrlImpl.cpp (+1/-1)
src/scopes/internal/QueryObject.cpp (+4/-4)
src/scopes/internal/RangeInputFilterImpl.cpp (+69/-27)
src/scopes/internal/RatingFilterImpl.cpp (+1/-1)
src/scopes/internal/RegistryObject.cpp (+31/-41)
src/scopes/internal/ReplyImpl.cpp (+3/-5)
src/scopes/internal/ReplyObject.cpp (+5/-5)
src/scopes/internal/ResultReplyObject.cpp (+9/-1)
src/scopes/internal/RuntimeConfig.cpp (+0/-59)
src/scopes/internal/RuntimeImpl.cpp (+15/-27)
src/scopes/internal/ScopeObject.cpp (+4/-4)
src/scopes/internal/SearchQueryBaseImpl.cpp (+1/-2)
src/scopes/internal/SearchReplyImpl.cpp (+31/-7)
src/scopes/internal/ValueSliderFilterImpl.cpp (+21/-44)
src/scopes/internal/ValueSliderLabelsImpl.cpp (+158/-0)
src/scopes/internal/smartscopes/SSQueryObject.cpp (+2/-2)
src/scopes/internal/smartscopes/SSRegistryObject.cpp (+11/-13)
src/scopes/internal/smartscopes/SSScopeObject.cpp (+2/-2)
src/scopes/internal/smartscopes/SmartScope.cpp (+14/-14)
src/scopes/internal/smartscopes/SmartScopesClient.cpp (+61/-65)
src/scopes/internal/zmq_middleware/ObjectAdapter.cpp (+12/-19)
src/scopes/internal/zmq_middleware/ZmqMiddleware.cpp (+9/-9)
src/scopes/internal/zmq_middleware/ZmqObject.cpp (+2/-2)
test/CMakeLists.txt (+2/-3)
test/abi-compliance/CMakeLists.txt (+10/-6)
test/abi-compliance/abi.xml.in (+0/-57)
test/abi-compliance/check-abi-compliance.sh.in (+61/-21)
test/abi-compliance/gen-abi-dump.sh.in (+2/-2)
test/abi-compliance/suppressions (+36/-0)
test/gtest/scopes/Activation/Runtime.ini.in (+0/-1)
test/gtest/scopes/ActivationResponse/Runtime.ini.in (+0/-1)
test/gtest/scopes/Aggregation/Runtime.ini.in (+0/-1)
test/gtest/scopes/Filters/Filters_test.cpp (+45/-1)
test/gtest/scopes/Filters/Runtime.ini.in (+0/-1)
test/gtest/scopes/Filters/TestScope.h (+2/-1)
test/gtest/scopes/IdleShutdown/Runtime.ini.in (+0/-1)
test/gtest/scopes/Invocation/Runtime.ini.in (+0/-1)
test/gtest/scopes/OptionSelectorFilter/OptionSelectorFilter_test.cpp (+57/-3)
test/gtest/scopes/RangeInputFilter/RangeInputFilter_test.cpp (+51/-30)
test/gtest/scopes/Registry/Runtime.ini.in (+0/-1)
test/gtest/scopes/ReplyReaper/Runtime.ini.in (+0/-1)
test/gtest/scopes/ResultCache/CMakeLists.txt (+1/-1)
test/gtest/scopes/ResultCache/CacheScope.cpp (+14/-2)
test/gtest/scopes/ResultCache/ResultCache_test.cpp (+51/-0)
test/gtest/scopes/ResultCache/Runtime.ini.in (+0/-1)
test/gtest/scopes/Runtime/Runtime.ini.in (+0/-1)
test/gtest/scopes/StripLocation/Runtime.ini.in (+0/-1)
test/gtest/scopes/ThrowingClient/Runtime.ini.in (+0/-1)
test/gtest/scopes/ThrowingScope/Runtime.ini.in (+0/-1)
test/gtest/scopes/ValueSliderFilter/ValueSliderFilter_test.cpp (+70/-32)
test/gtest/scopes/internal/CMakeLists.txt (+2/-1)
test/gtest/scopes/internal/Logger/CMakeLists.txt (+4/-0)
test/gtest/scopes/internal/Logger/Logger_test.cpp (+167/-0)
test/gtest/scopes/internal/ResultReplyObject/Runtime.ini.in (+0/-1)
test/gtest/scopes/internal/RuntimeConfig/BadLogDirSize.ini.in (+0/-7)
test/gtest/scopes/internal/RuntimeConfig/BadLogFileSize.ini.in (+0/-6)
test/gtest/scopes/internal/RuntimeConfig/CacheDir.ini.in (+0/-1)
test/gtest/scopes/internal/RuntimeConfig/Complete.ini.in (+0/-3)
test/gtest/scopes/internal/RuntimeConfig/ConfigDir.ini.in (+0/-1)
test/gtest/scopes/internal/RuntimeConfig/LogDir.ini.in (+0/-5)
test/gtest/scopes/internal/RuntimeConfig/RuntimeConfig_test.cpp (+0/-51)
test/gtest/scopes/internal/RuntimeImpl/Runtime.ini.in (+0/-1)
test/gtest/scopes/internal/ScopeMetadataImpl/Runtime.ini.in (+0/-1)
test/gtest/scopes/internal/smartscopes/SmartScopesClient/FakeSss.py (+10/-0)
test/gtest/scopes/internal/smartscopes/SmartScopesClient/SmartScopesClient_test.cpp (+61/-0)
test/gtest/scopes/internal/smartscopes/smartscopesproxy/Runtime.ini.in (+0/-1)
test/gtest/scopes/internal/zmq_middleware/ObjectAdapter/Runtime.ini.in (+0/-1)
test/gtest/scopes/internal/zmq_middleware/RegistryI/RegistryI_test.cpp (+2/-0)
test/gtest/scopes/internal/zmq_middleware/RegistryI/Runtime.ini.in (+0/-1)
test/gtest/scopes/internal/zmq_middleware/ZmqMiddleware/Runtime.ini.in (+0/-1)
test/gtest/scopes/stress/Runtime.ini.in (+0/-1)
test/gtest/scopes/testing/CMakeLists.txt (+5/-3)
unity-scopes.map (+2/-0)
To merge this branch: bzr merge lp:~stolowski/unity-scopes-api/inline-playback-doc
Reviewer Review Type Date Requested Status
Unity Team Pending
Review via email: mp+288122@code.launchpad.net

Commit message

Documentation for inline playback and concierge mode.

Description of the change

Documentation for inline playback and concierge mode.

To post a comment you must log in.
663. By Paweł Stołowski

Fix spelling

664. By Paweł Stołowski

Added CategoryRenderer doc

665. By Paweł Stołowski

Doc fixes

666. By Paweł Stołowski

-the

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 2015-10-19 04:22:03 +0000
3+++ CMakeLists.txt 2016-03-04 15:54:04 +0000
4@@ -60,7 +60,7 @@
5 endif()
6
7 include(FindPkgConfig)
8-find_package(Boost COMPONENTS system filesystem regex serialization thread log REQUIRED)
9+find_package(Boost COMPONENTS system filesystem regex serialization thread REQUIRED)
10 pkg_check_modules(UNITY_API libunity-api>=0.1.3 REQUIRED)
11 pkg_check_modules(PROCESS_CPP process-cpp>=1.0.1 REQUIRED)
12 pkg_check_modules(APPARMOR REQUIRED libapparmor REQUIRED)
13
14=== modified file 'CONFIGFILES'
15--- CONFIGFILES 2015-12-09 05:43:13 +0000
16+++ CONFIGFILES 2016-03-04 15:54:04 +0000
17@@ -114,38 +114,6 @@
18 The environment variable UNITY_SCOPES_CONFIG_DIR overrides this key (useful when running
19 automated tests that should not overwrite any of the real configuration files).
20
21-- LogDir
22-
23- The parent directory under which the run time writes the scope log files.
24- Setting this value explicitly to the empty string disables file logging and forces
25- all log entries to go to stderr.
26-
27- The default value is the empty string.
28-
29- If you set this value, you must set it to a directory that is writable to
30- confined scopes. We suggest $HOME/.cache/unity-scopes.
31-
32- Note that the actual logs are written into subdirectories of this
33- directory. Assuming LogDir is set to $HOME/.cache/unity-scopes,
34- the subdirectories are
35- $HOME/.cache/unity-scopes/leaf-net/<scope_id>/logs (for confined scopes) and
36- $HOME/.cache/unity-scopes/unconfined/<scope_id>/logs (for unconfined scopes).
37-
38- The environment variable UNITY_SCOPES_LOGDIR overrides this key.
39- Setting this variable explicitly to the empty string disables file logging and forces
40- all log entries to go to stderr.
41-
42-- Log.MaxFileSize
43-
44- The maximum size in bytes of an individual log file before it is rolled over.
45- The value must be at least 1024. The default value is 512 kB.
46-
47-- Log.MaxDirSize
48-
49- The maximum size in bytes of the sum of sizes of all log files in the log directory
50- before they are deleted. The value must be greater than Log.MaxFileSize.
51- The default value is 2 MB.
52-
53 - Log.TraceChannels
54
55 The names of channels for which to emit trace. This must be a semicolon-separated
56
57=== modified file 'HACKING'
58--- HACKING 2015-09-15 21:55:44 +0000
59+++ HACKING 2016-03-04 15:54:04 +0000
60@@ -293,13 +293,13 @@
61 ABI compliance test
62 -------------------
63
64-The tests include an ABI compliance test (for Wily and later). To run it:
65+The tests include an ABI compliance test (for xenial and later). To run it:
66
67 $ cd test/abi-compliance
68 $ make test
69
70 The test is also automatically run as part of the test suite.
71-It takes several minutes to run . If you don't want to wait during local builds,
72+It takes a while to run. If you don't want to wait during local builds,
73 set the cmake "slowtests" option to OFF to skip the check.
74
75 The baseline ABI files for the test are in test/abi-compliance/abi_dumps.
76@@ -313,11 +313,8 @@
77 Once all the packages are built, you can extract the ABI dump
78 files and add them to the corresponding directory in the source tree.
79
80-The abi-compliance-checker tool produces a report in
81-
82- test/abi-compliance/compat_reports/libunity-scopes.so/[version]_to_[version]/compat_report.html
83-
84-The report provides a nicely layed-out page with all the details.
85+The abi compliance test produces a report in
86+libunity-scopes_<current-version>_abi-report.txt if anything unusual is detected.
87
88 Autopkg test suite
89 ------------------
90
91=== modified file 'STRUCTS'
92--- STRUCTS 2015-07-14 15:11:48 +0000
93+++ STRUCTS 2016-03-04 15:54:04 +0000
94@@ -105,6 +105,11 @@
95 =====================================
96 filter_id : Variant (arbitrary, depends on filter type)
97
98+FilterGroup
99+===========
100+ 'id' : string
101+ 'label' : string
102+
103 FilterOption
104 ============
105 'id' : string
106@@ -115,6 +120,7 @@
107 'id' : string
108 'filter_type' : string
109 'display_hints': int, optional
110+ 'filter_group' : string, optional
111
112 OptionSelectorFilter (FilterBase)
113 =================================
114@@ -126,10 +132,15 @@
115
116 RangeInputFilter
117 ================
118- 'id' : string
119- 'start_label' : string
120- 'end_label' : string
121- 'unit_label' : string
122+ 'id' : string
123+ 'default_start_value' : variant (int, double, null)
124+ 'default_end_value' : variant (int, double, null)
125+ 'start_prefix_label' : string
126+ 'start_postfix_label' : string
127+ 'end_prefix_label' : string
128+ 'end_postfix_label' : string
129+ 'central_label' : string
130+ 'filter_group' : string, optional
131
132 Filters + FilterState
133 =====================
134
135=== modified file 'debian/VERSION'
136--- debian/VERSION 2016-02-09 10:26:20 +0000
137+++ debian/VERSION 2016-03-04 15:54:04 +0000
138@@ -1,1 +1,1 @@
139-1.0.3
140+1.0.4
141
142=== modified file 'debian/changelog'
143--- debian/changelog 2016-02-09 15:15:15 +0000
144+++ debian/changelog 2016-03-04 15:54:04 +0000
145@@ -1,3 +1,13 @@
146+unity-scopes-api (1.0.4-0ubuntu1) UNRELEASED; urgency=medium
147+
148+ [ Pawel Stolowski ]
149+ * New RangeInputFilter.
150+
151+ [ Michi Henning ]
152+ * Changed ABI compliance testing to use abigail.
153+
154+ -- Pawel Stolowski <pawel.stolowski@canonical.com> Mon, 11 Jan 2016 12:06:29 +0100
155+
156 unity-scopes-api (1.0.3+16.04.20160209-0ubuntu1) xenial; urgency=medium
157
158 [ Michi Henning ]
159
160=== modified file 'debian/control'
161--- debian/control 2015-12-18 09:21:53 +0000
162+++ debian/control 2016-03-04 15:54:04 +0000
163@@ -1,124 +1,14 @@
164 # This file is autogenerated. DO NOT EDIT!
165-#
166-# Modifications should be made to control.in instead.
167+#
168+# Modifications should be made to debian/control.in instead.
169 # This file is regenerated automatically in the clean target.
170 #
171 Source: unity-scopes-api
172-Priority: optional
173-Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
174-Build-Depends: abi-compliance-checker,
175- capnproto,
176- click-dev (>= 0.2.2),
177- cmake,
178- dbus-test-runner,
179+Maintainer: This not the real control file because it is generated during the build from control.in.
180+Build-Depends: click-dev (>= 0.2.2),
181 debhelper (>= 9),
182- devscripts,
183- doxygen,
184- exuberant-ctags,
185- google-mock,
186- graphviz,
187- libaccounts-glib-dev,
188- libapparmor-dev,
189- libboost-filesystem-dev,
190- libboost-log-dev,
191- libboost-regex-dev,
192- libboost-serialization-dev,
193- libcapnp-dev (>= 0.4.0),
194- libdbustest1-dev,
195- libjsoncpp-dev,
196- liblttng-ust-dev,
197- libnet-cpp-dev (>= 1.2.0),
198- libprocess-cpp-dev (>= 1.0.1),
199- libsignon-glib-dev,
200- libunity-api-dev (>= 7.80.7~),
201- libzmq3-dev,
202- libzmqpp-dev,
203 lsb-release,
204- lttng-tools,
205- pkg-config,
206- python3:any,
207- python-tornado,
208- valgrind,
209-Standards-Version: 3.9.6
210-XS-Testsuite: autopkgtest
211-Section: libs
212-Homepage: https://launchpad.net/unity-scopes-api
213-# if you don't have have commit access to this branch but would like to upload
214-# directly to Ubuntu, don't worry: your changes will be merged back into the
215-# upstream branch
216-Vcs-Bzr: lp:unity-scopes-api
217-Vcs-Browser: https://code.launchpad.net/unity-scopes-api
218
219 Package: libunity-scopes1.0
220 Architecture: any
221-Multi-Arch: same
222-Pre-Depends: ${misc:Pre-Depends},
223-Depends: ${misc:Depends},
224- ${shlibs:Depends},
225-Replaces: libunity-scopes0,
226- libunity-scopes3,
227- libunity-scopes1,
228- libunity-scopes2,
229-Conflicts: libunity-scopes0,
230- libunity-scopes3,
231- libunity-scopes1,
232- libunity-scopes2,
233-Description: API for Unity scopes integration
234- Library to integrate scopes with the Unity shell
235-
236-Package: libunity-scopes-dev
237-Section: libdevel
238-Architecture: any
239-Multi-Arch: same
240-Depends: libproperties-cpp-dev,
241- libunity-api-dev,
242- libunity-scopes1.0 (= ${binary:Version}),
243- ${misc:Depends},
244-Description: Header files for Unity scopes API
245- Library to integrate scopes with the Unity shell (dev files)
246-
247-Package: libunity-scopes-cli
248-Section: devel
249-Architecture: any
250-Multi-Arch: foreign
251-Depends: libunity-scopes1.0 (= ${binary:Version}),
252- ${misc:Depends},
253- ${shlibs:Depends},
254-Description: Client utility for Unity scopes API
255- Commandline client utility for querying Unity scopes, useful for testing.
256-
257-Package: libunity-scopes-doc
258-Section: doc
259-Architecture: all
260-Multi-Arch: foreign
261-Depends: ${misc:Depends},
262-Description: Documentation for Unity scopes API
263- Library to integrate scopes with the Unity shell (documentation)
264-
265-Package: libunity-scopes-qt0.2
266-Architecture: any
267-Multi-Arch: same
268-Pre-Depends: ${misc:Pre-Depends},
269-Depends: ${misc:Depends},
270- ${shlibs:Depends},
271-Description: Qt library for Unity scopes API
272- Library that integrates classes based on Qt for convenience
273-
274-Package: libunity-scopes-qt-dev
275-Section: libdevel
276-Architecture: any
277-Multi-Arch: same
278-Depends: libunity-scopes-dev (= ${binary:Version}),
279- libunity-scopes-qt0.2 (= ${binary:Version}),
280- libnet-cpp-dev (>=1.2.0),
281- ${misc:Depends},
282-Description: Header files for Qt library for Unity scopes API
283- Library that integrates classes based on Qt for convenience (dev files)
284-
285-Package: libunity-scopes-qt-doc
286-Section: doc
287-Architecture: all
288-Multi-Arch: foreign
289-Depends: ${misc:Depends},
290-Description: Documentation for Unity Qt library
291- Library that integrates classes based on Qt for convenience (documentation)
292+Description: This not the real control file because it is generated during the build from control.in.
293
294=== modified file 'debian/control.in'
295--- debian/control.in 2015-11-13 04:05:00 +0000
296+++ debian/control.in 2016-03-04 15:54:04 +0000
297@@ -1,7 +1,8 @@
298 Source: unity-scopes-api
299 Priority: optional
300 Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
301-Build-Depends: abi-compliance-checker,
302+Build-Depends: abigail-tools | libabigail-tools,
303+ binutils,
304 capnproto,
305 click-dev (>= 0.2.2),
306 cmake,
307@@ -15,9 +16,9 @@
308 libaccounts-glib-dev,
309 libapparmor-dev,
310 libboost-filesystem-dev,
311- libboost-log-dev,
312 libboost-regex-dev,
313 libboost-serialization-dev,
314+ libboost-thread-dev,
315 libcapnp-dev (>= 0.4.0),
316 libdbustest1-dev,
317 libjsoncpp-dev,
318
319=== modified file 'demo/client.cpp'
320--- demo/client.cpp 2015-02-09 02:23:22 +0000
321+++ demo/client.cpp 2016-03-04 15:54:04 +0000
322@@ -478,7 +478,6 @@
323 shared_ptr<Receiver> reply(new Receiver(result_index));
324
325 SearchMetadata metadata("C", "desktop");
326- metadata.set_cardinality(10);
327 auto ctrl = meta.proxy()->search(search_string, department_id, filter_state, metadata, reply); // May raise TimeoutException
328 cout << "client: created query" << endl;
329 reply->wait_until_finished();
330
331=== modified file 'doc/tutorial.dox'
332--- doc/tutorial.dox 2015-10-29 02:35:50 +0000
333+++ doc/tutorial.dox 2016-03-04 15:54:04 +0000
334@@ -410,6 +410,75 @@
335 (because `cancelled()` and `run()` are called by different threads and, therefore, can be dispatched out of order).
336
337
338+\paragraph filters Filters
339+
340+Scopes API offers support for filter widgets, which provide means for filtering search results based on user input other than search query string
341+alone. Filter widgets need to be defined by creating appropriate filters inside the overriden SearchQueryBase::run() method, and then pushed
342+to the UI. It is recommended to push filters early before search results are pushed for best user experience.
343+
344+Here is an example of how filters can be created:
345+
346+\code{.cpp}
347+void run(SearchReplyProxy const& reply)
348+{
349+ OptionSelectorFilter::UPtr filter1 = OptionSelectorFilter::create("brand", "Brand");
350+ filter1->add_option("audi", "Audi");
351+ filter1->add_option("bmw", "BMW");
352+
353+ RangeInputFilter::SPtr filter2 = RangeInputFilter::create("price", Variant(0.0f), Variant::null(), "Min", "", "", "Max", "");
354+ ValueSliderFilter::SPtr filter3 = ValueSliderFilter::create("horsepower", 1, 135, 50, ValueSliderLabels("Min", "Max"));
355+
356+ Filters filters;
357+ filters.push_back(filter1);
358+ filters.push_back(filter2);
359+ filters.push_back(filter3);
360+
361+ reply->push(filters, query().filter_state());
362+
363+ // push search results here
364+\endcode
365+
366+Scopes are free to change filters at any time - with every execution of search the scope can omit any of the previously visible filters or add new ones, if that
367+makes sense for particular use cases.
368+
369+Filters act only as UI widgets - it is the responsibility of the scope to check their state and actually apply them to search results. The current value of a filter
370+becomes just another parameter of the search query that needs to be taken into account in the implementation of search handling inside run().
371+
372+To examine current state of the filters, pass the instance of unity::scopes::FilterState received with search query to respective methods of
373+the filters. For example:
374+
375+\code{.cpp}
376+void run(SearchReplyProxy const& reply)
377+{
378+ // filter creation code omitted here
379+ auto state = query().filter_state();
380+ int search_start = 0;
381+ int search_end = 1000;
382+ if (rangefilter->has_start_value(state)) {
383+ search_start = rangefilter->start_value(state);
384+ }
385+ if (rangefilter->has_end_value(state)) {
386+ search_end = rangefilter->end_value(state);
387+ }
388+
389+ // apply search_start and search_end to search logic
390+\endcode
391+
392+The scope may nominate a single filter to act as "primary navigation". This is only possible if departments are not used at the same time (in which case departments
393+become a primary navigation tool). An attempt to nominate a filter to be a "primary navigation" while departments are present is ignored by the UI and the
394+filter acts as a regular filter. Also, only a single-selection OptionSelectorFilter can currently be promoted to be primary navigation. To do this, set the display
395+hints to FilterBase::DisplayHints::Primary:
396+
397+\code{.cpp}
398+OptionSelectorFilter::UPtr filter1 = OptionSelectorFilter::create("brand", "Brand");
399+filter1->set_display_hints(FilterBase::DisplayHints::Primary);
400+filter1->add_option("audi", "Audi");
401+\endcode
402+
403+When a filter becomes a primary navigation filter, it gets displayed in the search box drop-down, below recent searches, so it's readily available for quick access.
404+Also, currently selected option is displayed as a "brick" in the search box, hinting the user about the context of current search. All the other filters can be
405+revealed via the filters panel icon.
406+
407 \paragraph handlingpreview Handling previews
408
409 Your scope is responsible for handling preview requests for results it has returned; you implement this by overriding
410@@ -785,6 +854,70 @@
411 (See \link unity::scopes::utility::BufferedResultForwarder BufferedResultForwarder\endlink
412 for more details.)
413
414+\paragraph inlineplayback Inline music playback
415+
416+Results which represent music (songs, albums etc.) can contain an extra data about audio content and can then be played directly from the Dash.
417+Such results have a "play" button overlayed on them. To create results that support this functionality two conditions must be met:
418+<ul>
419+<li>Category renderer definition must contain the "quick-preview-type" key with the value of "audio" in the "template" section;
420+<li>Results in the respective category must contain a "quick-preview-data" attribute, each of them is a dictionary with the extra playback data described
421+below.
422+</ul>
423+
424+The data assigned to "quick-preview-data" attribute of a Result needs to contain the following keys:
425+<ul>
426+<li>uri - a playable uri of a media file (path of a local file, or http uri).
427+<li>duration - the duration of the media file, in seconds.
428+<li>playlist - an array of uris of additional songs, e.g. songs from same album; they will be played in the background when the main
429+song finishes. This list can contain the main song again.
430+</ul>
431+
432+Here is an example of a category renderer for inline playback, which uses component mapping to map quick-preview-data to audio-data attribute of a result:
433+\code{.cpp}
434+static const char CATEGORY_RENDERER[] = R"(
435+{
436+ "schema-version": 1,
437+ "template": {
438+ "category-layout": "grid",
439+ "card-size": "large",
440+ "card-layout" : "horizontal",
441+ "quick-preview-type" : "audio"
442+ },
443+ "components": {
444+ "title": "title",
445+ "art": {
446+ "field": "art"
447+ },
448+ "subtitle": "artist",
449+ "quick-preview-data": {
450+ "field": "audio-data"
451+ }
452+ }
453+}
454+)";
455+\endcode
456+
457+A sample code that creates a result card representing a song and all songs from same album in a background playlist may look this way:
458+\code{.cpp}
459+
460+CategorisedResult res(category);
461+res.set_uri(uri);
462+res.set_title(media.getTitle());
463+...
464+
465+VariantMap inline_playback_data;
466+inline_playback_data["uri"] = uri;
467+inline_playback_data["duration"] = song_duration_in_seconds;
468+VariantArray playlist;
469+for (const std::string& song: album_songs)
470+{
471+ playlist.push_back(Variant(song.getUri()));
472+}
473+inline_playback_data["playlist"] = playlist;
474+res["audio-data"] = inline_playback_data;
475+
476+\endcode
477+
478 \paragraph aggactiv Activation and preview
479
480 If an aggregator scope simply forwards the results it receives from other scopes (possibly changing their category),
481
482=== modified file 'include/unity/scopes/FilterBase.h'
483--- include/unity/scopes/FilterBase.h 2015-11-12 14:20:36 +0000
484+++ include/unity/scopes/FilterBase.h 2016-03-04 15:54:04 +0000
485@@ -21,6 +21,7 @@
486 #include <unity/util/NonCopyable.h>
487 #include <unity/scopes/Variant.h>
488 #include <unity/util/DefinesPtrs.h>
489+#include <unity/scopes/FilterGroup.h>
490 #include <memory>
491 #include <list>
492
493@@ -94,10 +95,33 @@
494
495 /// @cond
496 virtual ~FilterBase();
497+ /// @endcond
498+
499+ /**
500+ \brief Set an optional title of this filter.
501+ \param title The title.
502+ */
503+ void set_title(std::string const& title);
504+
505+ /**
506+ \brief Get the optional title of this filter.
507+ \return Filter title (can be empty).
508+ */
509+ std::string title() const;
510+
511+ /**
512+ \brief Get the filter group this filter belongs to.
513+
514+ \return The filter group (or null)
515+ */
516+ FilterGroup::SCPtr filter_group() const;
517
518 protected:
519+ /// @cond
520 FilterBase(internal::FilterBaseImpl *pimpl);
521 std::unique_ptr<internal::FilterBaseImpl> p;
522+
523+ friend class internal::FilterBaseImpl;
524 /// @endcond
525 };
526
527
528=== added file 'include/unity/scopes/FilterGroup.h'
529--- include/unity/scopes/FilterGroup.h 1970-01-01 00:00:00 +0000
530+++ include/unity/scopes/FilterGroup.h 2016-03-04 15:54:04 +0000
531@@ -0,0 +1,83 @@
532+/*
533+ * Copyright (C) 2016 Canonical Ltd
534+ *
535+ * This program is free software: you can redistribute it and/or modify
536+ * it under the terms of the GNU Lesser General Public License version 3 as
537+ * published by the Free Software Foundation.
538+ *
539+ * This program is distributed in the hope that it will be useful,
540+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
541+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
542+ * GNU Lesser General Public License for more details.
543+ *
544+ * You should have received a copy of the GNU Lesser General Public License
545+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
546+ *
547+ * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com>
548+ */
549+
550+#pragma once
551+
552+#include <unity/util/NonCopyable.h>
553+#include <unity/util/DefinesPtrs.h>
554+#include <string>
555+#include <memory>
556+
557+namespace unity
558+{
559+
560+namespace scopes
561+{
562+
563+namespace internal
564+{
565+ class FilterGroupImpl;
566+}
567+
568+/**
569+\brief Groups several filters into an expandable widget in the UI.
570+*/
571+class FilterGroup
572+{
573+public:
574+ /// @cond
575+ NONCOPYABLE(FilterGroup);
576+ UNITY_DEFINES_PTRS(FilterGroup);
577+
578+ virtual ~FilterGroup();
579+ /// @endcond
580+
581+ /**
582+ \brief Create a WidgetGroup.
583+
584+ \return An instance of WidgetGroup.
585+ */
586+ static FilterGroup::SCPtr create(std::string const& id, std::string const& label);
587+
588+ /**
589+ \brief Get the id of the widget group.
590+
591+ \return The identifier.
592+ */
593+ std::string id() const;
594+
595+ /**
596+ \brief Get the label of the widget group.
597+
598+ \return The label.
599+ */
600+ std::string label() const;
601+
602+private:
603+ /// @cond
604+ FilterGroup();
605+ FilterGroup(internal::FilterGroupImpl *pimpl);
606+ std::unique_ptr<internal::FilterGroupImpl> p;
607+
608+ friend class internal::FilterGroupImpl;
609+ /// @endcond
610+};
611+
612+} // namespace scopes
613+
614+} // namespace unity
615
616=== modified file 'include/unity/scopes/FilterOption.h'
617--- include/unity/scopes/FilterOption.h 2014-11-03 05:31:30 +0000
618+++ include/unity/scopes/FilterOption.h 2016-03-04 15:54:04 +0000
619@@ -62,6 +62,12 @@
620 ~FilterOption();
621 /// @endcond
622
623+ /**
624+ \brief Return the default value of this filter option.
625+ \return default value
626+ */
627+ bool default_value() const;
628+
629 private:
630 FilterOption(std::string const& id, std::string const& label);
631 std::unique_ptr<internal::FilterOptionImpl> p;
632
633=== modified file 'include/unity/scopes/OptionSelectorFilter.h'
634--- include/unity/scopes/OptionSelectorFilter.h 2015-11-12 14:20:36 +0000
635+++ include/unity/scopes/OptionSelectorFilter.h 2016-03-04 15:54:04 +0000
636@@ -21,6 +21,7 @@
637 #include <unity/scopes/FilterBase.h>
638 #include <unity/scopes/FilterOption.h>
639 #include <unity/scopes/Variant.h>
640+#include <unity/scopes/FilterGroup.h>
641 #include <string>
642 #include <list>
643 #include <set>
644@@ -74,7 +75,9 @@
645 bool multi_select() const;
646
647 /**
648- \brief Add a new option to this filter.
649+ \brief Add a new option to this filter. The option is 'off' by default.
650+
651+ \throws unity::InvalidArgumentException on invalid id or label
652 \return The new option instance.
653 */
654 FilterOption::SCPtr add_option(std::string const& id, std::string const& label);
655@@ -114,6 +117,29 @@
656 */
657 static void update_state(FilterState& filter_state, std::string const& filter_id, std::string const& option_id, bool value);
658
659+ /**
660+ \brief Add a new option to this filter and provide its default value.
661+
662+ \throws unity::LogicException if multiple options with value of 'true' are provided for a single-selection OptionSelectorFilter.
663+ \throws unity::InvalidArgumentException on invalid id or label
664+ \return The new option instance.
665+ */
666+ FilterOption::SCPtr add_option(std::string const& id, std::string const& label, bool value);
667+
668+ /**
669+ \brief Creates an OpionSelectorFilter inside a FilterGroup.
670+ \param id A unique identifier for the filter that can be used to identify it later among several filters.
671+ \param label A display label for the filter.
672+ \param group A filter group this filter should be added to.
673+ \param multi_select If true, the filter permits more than option to be selected; otherwise, only a single
674+ option can be selected.
675+ \throws unity::InvalidArgumentException on invalid null group.
676+
677+ \note The multi-selection cannot be combined with unity::scopes::FilterBase::DisplayHints::Primary flag set via
678+ unity::scopes::FilterBase::set_display_hints().
679+ */
680+ static OptionSelectorFilter::UPtr create(std::string const& id, std::string const& label, FilterGroup::SCPtr const& group, bool multi_select = false);
681+
682 private:
683 OptionSelectorFilter(internal::OptionSelectorFilterImpl*);
684 internal::OptionSelectorFilterImpl* fwd() const;
685
686=== modified file 'include/unity/scopes/RangeInputFilter.h'
687--- include/unity/scopes/RangeInputFilter.h 2014-11-03 05:31:30 +0000
688+++ include/unity/scopes/RangeInputFilter.h 2016-03-04 15:54:04 +0000
689@@ -1,5 +1,5 @@
690 /*
691- * Copyright (C) 2014 Canonical Ltd
692+ * Copyright (C) 2015 Canonical Ltd
693 *
694 * This program is free software: you can redistribute it and/or modify
695 * it under the terms of the GNU Lesser General Public License version 3 as
696@@ -20,6 +20,7 @@
697
698 #include <unity/scopes/FilterBase.h>
699 #include <unity/scopes/Variant.h>
700+#include <unity/scopes/FilterGroup.h>
701
702 namespace unity
703 {
704@@ -34,11 +35,13 @@
705 class RangeInputFilterImpl;
706 }
707
708-namespace experimental
709-{
710-
711 /**
712 \brief A range filter which allows a start and end value to be entered by user, and any of them is optional.
713+
714+RangeInputFilter is composed of two input boxes which accept numeric values. Any of them is optional. It can have
715+up to five labels: two labels for start value (prefix or postfix label, displayed left or right to the input box, respectively),
716+two labels for end value and a single label displayed in between both input boxes.
717+The filter may provide defaults for start and end values. Default values are used by the UI if user didn't enter values.
718 */
719 class UNITY_API RangeInputFilter : public FilterBase
720 {
721@@ -50,30 +53,119 @@
722 /**
723 \brief Creates a RangeInputFilter.
724 \param id A unique identifier for the filter that can be used to identify it later among several filters.
725- \param start_label A display label for the input box of start value (can be empty).
726- \param end_label A display label for the input box of end value (can be empty).
727- \param unit_label A display label for the unit of this range filter (e.g. currency name).
728- \return Instance of RangeInputFilter.
729- */
730- static RangeInputFilter::SPtr create(std::string const& id, std::string const& start_label, std::string const& end_label, std::string const& unit_label = "");
731-
732- /**
733- \brief Get the label of start value.
734- \return The label of start value.
735- */
736- std::string start_label() const;
737-
738- /**
739- \brief Get the label of end value.
740- \return The label of end value.
741- */
742- std::string end_label() const;
743-
744- /**
745- \brief Get the label of unit for this filter..
746- \return The label of unit.
747- */
748- std::string unit_label() const;
749+ \param start_prefix_label A display label for the input box of start value, displayed to the left (can be empty).
750+ \param start_postfix_label A display label for the input box of start value, displayed to the right (can be empty).
751+ \param central_label A display label displayed between the two input boxes (can be empty).
752+ \param end_prefix_label A display label for the input box of end value, displayed to the left (can be empty).
753+ \param end_postfix_label A display label for the input box of end value, displayed to the right (can be empty).
754+ \return Instance of RangeInputFilter.
755+ */
756+ static RangeInputFilter::SPtr create(std::string const& id,
757+ std::string const& start_prefix_label, std::string const& start_postfix_label,
758+ std::string const& central_label,
759+ std::string const& end_prefix_label, std::string const& end_postfix_label);
760+
761+ /**
762+ \brief Creates a RangeInputFilter with specific default values for start and end.
763+ \param id A unique identifier for the filter that can be used to identify it later among several filters.
764+ \param default_start_value A default start value (double, int or null).
765+ \param default_end_value A default end value (double, int or null).
766+ \param start_prefix_label A display label for the input box of start value, displayed to the left (can be empty).
767+ \param start_postfix_label A display label for the input box of start value, displayed to the right (can be empty).
768+ \param central_label A display label displayed between the two input boxes (can be empty).
769+ \param end_prefix_label A display label for the input box of end value, displayed to the left (can be empty).
770+ \param end_postfix_label A display label for the input box of end value, displayed to the right (can be empty).
771+ \return Instance of RangeInputFilter.
772+ */
773+ static RangeInputFilter::SPtr create(std::string const& id,
774+ Variant const& default_start_value,
775+ Variant const& default_end_value,
776+ std::string const& start_prefix_label, std::string const& start_postfix_label,
777+ std::string const& central_label,
778+ std::string const& end_prefix_label, std::string const& end_postfix_label);
779+
780+ /**
781+ \brief Creates a RangeInputFilter inside a FilterGroup.
782+ \param id A unique identifier for the filter that can be used to identify it later among several filters.
783+ \param start_prefix_label A display label for the input box of start value, displayed to the left (can be empty).
784+ \param start_postfix_label A display label for the input box of start value, displayed to the right (can be empty).
785+ \param central_label A display label displayed between the two input boxes (can be empty).
786+ \param end_prefix_label A display label for the input box of end value, displayed to the left (can be empty).
787+ \param end_postfix_label A display label for the input box of end value, displayed to the right (can be empty).
788+ \param group A filter group this filter should be added to.
789+ \return Instance of RangeInputFilter.
790+ */
791+ static RangeInputFilter::SPtr create(std::string const& id,
792+ std::string const& start_prefix_label, std::string const& start_postfix_label,
793+ std::string const& central_label,
794+ std::string const& end_prefix_label, std::string const& end_postfix_label, FilterGroup::SCPtr const& group);
795+
796+ /**
797+ \brief Creates a RangeInputFilter with specific default values for start and end, inside a FilterGroup.
798+ \param id A unique identifier for the filter that can be used to identify it later among several filters.
799+ \param start_prefix_label A display label for the input box of start value, displayed to the left (can be empty).
800+ \param start_postfix_label A display label for the input box of start value, displayed to the right (can be empty).
801+ \param central_label A display label displayed between the two input boxes (can be empty).
802+ \param end_prefix_label A display label for the input box of end value, displayed to the left (can be empty).
803+ \param end_postfix_label A display label for the input box of end value, displayed to the right (can be empty).
804+ \param group A filter group this filter should be added to.
805+ \return Instance of RangeInputFilter.
806+ */
807+ static RangeInputFilter::SPtr create(std::string const& id,
808+ Variant const& default_start_value,
809+ Variant const& default_end_value,
810+ std::string const& start_prefix_label, std::string const& start_postfix_label,
811+ std::string const& central_label,
812+ std::string const& end_prefix_label, std::string const& end_postfix_label,
813+ FilterGroup::SCPtr const& group);
814+
815+ /**
816+ \brief Get the prefix label of start value.
817+ \return The prefix label of start value.
818+ */
819+ std::string start_prefix_label() const;
820+
821+ /**
822+ \brief Get the postfix label of start value.
823+ \return The postfix label of start value.
824+ */
825+ std::string start_postfix_label() const;
826+
827+ /**
828+ \brief Get the prefix label of end value.
829+ \return The label of end value.
830+ */
831+ std::string end_prefix_label() const;
832+
833+ /**
834+ \brief Get the postfix label of end value.
835+ \return The label of end value.
836+ */
837+ std::string end_postfix_label() const;
838+
839+ /**
840+ \brief Get the central label for this filter.
841+ \return The central label.
842+ */
843+ std::string central_label() const;
844+
845+ /**
846+ \brief Get default start value if set (int, double or null).
847+
848+ The default value should be used unless a value is present in the FilterState -
849+ use unity::scopes::RangeInputFilter::has_start_value() and unity::scopes::RangeInputFilter::start_value()
850+ before resorting to the default value.
851+ */
852+ Variant default_start_value() const;
853+
854+ /**
855+ \brief Get default end value if set (int, double or null).
856+
857+ The default value should be used unless a value is present in the FilterState -
858+ use unity::scopes::RangeInputFilter::has_end_value() and unity::scopes::RangeInputFilter::end_value()
859+ before resorting to the default value.
860+ */
861+ Variant default_end_value() const;
862
863 /**
864 \brief Check if filter state holds a start value for this filter instance.
865@@ -144,8 +236,6 @@
866 friend class internal::RangeInputFilterImpl;
867 };
868
869-} // namespace experimental
870-
871 } // namespace scopes
872
873 } // namespace unity
874
875=== modified file 'include/unity/scopes/ValueSliderFilter.h'
876--- include/unity/scopes/ValueSliderFilter.h 2014-11-03 05:31:30 +0000
877+++ include/unity/scopes/ValueSliderFilter.h 2016-03-04 15:54:04 +0000
878@@ -19,6 +19,7 @@
879 #pragma once
880
881 #include <unity/scopes/FilterBase.h>
882+#include <unity/scopes/FilterGroup.h>
883
884 namespace unity
885 {
886@@ -33,16 +34,14 @@
887 class ValueSliderFilterImpl;
888 }
889
890-namespace experimental
891-{
892+class ValueSliderLabels;
893
894 /**
895 \brief A value slider filter that allows for selecting a value within given range.
896
897-The ValueSliderFilter displays a static label, such as "Maximum size" and a slider that
898-allows for selecting a value within range defined by minimum and maximum values. The currently
899-selected value gets displayed using a label template provided by scope, e.g. "Less than %1 MB",
900-resulting in labels such as "Less than 40.5 MB".
901+The ValueSliderFilter allows for selecting a value within range defined by minimum and maximum values.
902+Both minimum and maximum values can have labels and in addition, the scope may provide extra labels
903+to mark other values from that range - these label will serve as a guidance to the user.
904 */
905 class UNITY_API ValueSliderFilter : public FilterBase
906 {
907@@ -52,62 +51,52 @@
908 /// @endcond
909
910 /**
911- \brief The type of value slider.
912-
913- The type should be set according to the behaviour of the filter:
914- ValueSliderFilter::SliderType::LessThan should be used if values lesser than selected value are to be returned, otherwise
915- ValueSliderFilter::SliderType::MoreThan should be used.
916- Note: the selected type is a display hint for the Shell only. It's up to the scope to set it properly and actually follow
917- it on search.
918- */
919- enum SliderType
920- {
921- LessThan, /**< Scope will search for values lesser than selected value */
922- MoreThan /**< Scope will search for values greater than selected value */
923- };
924-
925- /**
926 \brief Create ValueSliderFilter.
927
928 Creates ValueSliderFilter of ValueSliderFilter::SliderType::LessThan type.
929
930 \param id A unique identifier for the filter that can be used to identify it later among several filters.
931- \param label The label for the filter
932- \param label_template The template for value label, e.g. "Less than %1"
933 \param min The minimum allowed value
934 \param max The maximum allowed value
935+ \param default_value The default value of this filter, from the min..max range.
936+ \param value_labels The labels for min and max values as well as optional extra labels.
937 \return Instance of ValueSliderFilter.
938- \throws unity::LogicException on invalid (min, max) range.
939+ \throws unity::LogicException on invalid (min, max) range or erroneous value_labels.
940 */
941- static ValueSliderFilter::UPtr create(std::string const& id, std::string const& label, std::string const& label_template, double min, double max);
942+ static ValueSliderFilter::UPtr create(std::string const& id, double min, double max, double default_value, ValueSliderLabels const& value_labels);
943
944 /**
945- \brief Change the type of this filter.
946-
947- \param tp The type of slider filter.
948- */
949- void set_slider_type(SliderType tp);
950+ \brief Create ValueSliderFilter inside a FilterGroup.
951+
952+ Creates ValueSliderFilter of ValueSliderFilter::SliderType::LessThan type.
953+
954+ \param id A unique identifier for the filter that can be used to identify it later among several filters.
955+ \param min The minimum allowed value
956+ \param max The maximum allowed value
957+ \param default_value The default value of this filter, from the min..max range.
958+ \param value_labels The labels for min and max values as well as optional extra labels.
959+ \param group A filter group this filter should be added to.
960+ \return Instance of ValueSliderFilter.
961+ \throws unity::LogicException on invalid (min, max) range or erroneous value_labels.
962+ */
963+ static ValueSliderFilter::UPtr create(std::string const& id, double min, double max, double default_value, ValueSliderLabels const& value_labels, FilterGroup::SCPtr const& group);
964
965 /**
966 \brief Change the default value of this filter.
967
968- The default value of this filter is by default the maximum value allowed. This value is used when calling unity::scopes::ValueSliderFilter::value_label()
969- and there is no state for this filter in unity::scopes::FilterState.
970+ The default value will be used by the shell if no value is present for this filter in the
971+ unity::scopes::FilterState (no value has been set by the user).
972
973 \param val The new default value.
974 */
975 void set_default_value(double val);
976
977 /**
978- \brief Get the type of this filter.
979-
980- \return The type of slider filter.
981- */
982- SliderType slider_type() const;
983-
984- /**
985 \brief Get the default value of this filter.
986
987+ The default value will be used by the shell if no value is present for this filter in the
988+ unity::scopes::FilterState (no value has been set by the user).
989+
990 \return The default value
991 */
992 double default_value() const;
993@@ -127,20 +116,6 @@
994 double max() const;
995
996 /**
997- \brief Get the label of this filter.
998-
999- \return The label
1000- */
1001- std::string label() const;
1002-
1003- /**
1004- \brief Get the value label template of this filter.
1005-
1006- \return The value label template.
1007- */
1008- std::string value_label_template() const;
1009-
1010- /**
1011 \brief Check if filter state object holds a value of this filter.
1012
1013 \return true if filter_state has a value of this filter.
1014@@ -156,6 +131,13 @@
1015 double value(FilterState const& filter_state) const;
1016
1017 /**
1018+ \brief Get value labeles for this slider filter.
1019+
1020+ \return the value labels.
1021+ */
1022+ ValueSliderLabels const& labels() const;
1023+
1024+ /**
1025 \brief Sets value of this filter instance in filter state object.
1026
1027 This is meant to be used to modify a FilterState received with a search request before sending it back to the client (UI shell).
1028@@ -178,8 +160,6 @@
1029 friend class internal::ValueSliderFilterImpl;
1030 };
1031
1032-} // namespace experimental
1033-
1034 } // namespace scopes
1035
1036 } // namespace unity
1037
1038=== added file 'include/unity/scopes/ValueSliderLabels.h'
1039--- include/unity/scopes/ValueSliderLabels.h 1970-01-01 00:00:00 +0000
1040+++ include/unity/scopes/ValueSliderLabels.h 2016-03-04 15:54:04 +0000
1041@@ -0,0 +1,117 @@
1042+/*
1043+ * Copyright (C) 2016 Canonical Ltd
1044+ *
1045+ * This program is free software: you can redistribute it and/or modify
1046+ * it under the terms of the GNU Lesser General Public License version 3 as
1047+ * published by the Free Software Foundation.
1048+ *
1049+ * This program is distributed in the hope that it will be useful,
1050+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1051+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1052+ * GNU Lesser General Public License for more details.
1053+ *
1054+ * You should have received a copy of the GNU Lesser General Public License
1055+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1056+ *
1057+ * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com>
1058+ */
1059+
1060+#pragma once
1061+
1062+#include <string>
1063+#include <list>
1064+#include <memory>
1065+#include <unity/SymbolExport.h>
1066+#include <unity/scopes/Variant.h>
1067+
1068+namespace unity
1069+{
1070+
1071+namespace scopes
1072+{
1073+
1074+namespace internal
1075+{
1076+class ValueSliderFilterImpl;
1077+class ValueSliderLabelsImpl;
1078+}
1079+
1080+/// @cond
1081+typedef std::pair<double, std::string> ValueLabelPair;
1082+typedef std::vector<ValueLabelPair> ValueLabelPairList;
1083+/// @endcond
1084+
1085+/**
1086+\brief Labels used by a ValueSliderFilter.
1087+
1088+The ValueSliderLabels objects holds labels for a ValueSliderFilter. At the very least labels for minimum and maximum
1089+values need to be provided. In addition, an arbitrary number of extra labels can be defined to mark values between minimum and maximum values.
1090+*/
1091+class UNITY_API ValueSliderLabels final
1092+{
1093+public:
1094+ /**@name Copy and assignment
1095+ Copy and assignment (move and non-move versions) have the usual value semantics.
1096+ */
1097+ //{@
1098+ ValueSliderLabels(ValueSliderLabels const& other);
1099+ ValueSliderLabels(ValueSliderLabels&&);
1100+ ValueSliderLabels& operator=(ValueSliderLabels const& other);
1101+ ValueSliderLabels& operator=(ValueSliderLabels&&);
1102+ ~ValueSliderLabels();
1103+ //@}
1104+
1105+ /**
1106+ \brief Create ValueSliderLabels object with labels for minimum and maximum values only.
1107+
1108+ \throws unity::InvalidArgumentException on invalid (empty or duplicated) labels.
1109+ */
1110+ ValueSliderLabels(std::string const& min_label, std::string const& max_label);
1111+
1112+ /**
1113+ \brief Create ValueSliderLabels object with labels for minimum and maximum, as well as extra labels.
1114+
1115+ Create ValueSliderLabels object with labels for minimum, maximum and values between minimum and maximum.
1116+ Note that these extra labels act only as a guidance for the user (i.e. they do not limit the available choices)
1117+ and also Unity shell is free to omit some or all of them depending on the available screen space.
1118+
1119+ \param min_label The label for minimum value of the associated ValueSliderFilter filter.
1120+ \param max_label The label for maximum value of the associated ValueSliderFilter filter.
1121+ \param extra_labels Additional labels for values between minimum and maximum values.
1122+
1123+ \throws unity::InvalidArgumentException on invalid labels (empty or duplicate labels, non-increasing values).
1124+ */
1125+ ValueSliderLabels(std::string const& min_label, std::string const& max_label, ValueLabelPairList const& extra_labels);
1126+
1127+ /**
1128+ \brief Get the label for the minimum value of the filter.
1129+ \return The label for minimum value
1130+ */
1131+ std::string min_label() const;
1132+
1133+ /**
1134+ \brief Get the label for the maximum value of the filter.
1135+ \return The label for maximum value
1136+ */
1137+ std::string max_label() const;
1138+
1139+ /**
1140+ \brief Get the labels for intermediate values of the filter.
1141+ */
1142+ ValueLabelPairList extra_labels() const;
1143+
1144+ /// @cond
1145+ VariantMap serialize() const;
1146+ /// @endcond
1147+
1148+private:
1149+ ValueSliderLabels(internal::ValueSliderLabelsImpl* pimpl);
1150+ ValueSliderLabels(VariantMap const& var);
1151+ std::unique_ptr<internal::ValueSliderLabelsImpl> p;
1152+ friend class internal::ValueSliderLabelsImpl;
1153+ friend class internal::ValueSliderFilterImpl;
1154+};
1155+
1156+} // namespace scopes
1157+
1158+} // namespace unity
1159
1160=== modified file 'include/unity/scopes/internal/ChildScopesRepository.h'
1161--- include/unity/scopes/internal/ChildScopesRepository.h 2015-04-01 10:15:25 +0000
1162+++ include/unity/scopes/internal/ChildScopesRepository.h 2016-03-04 15:54:04 +0000
1163@@ -43,7 +43,7 @@
1164 NONCOPYABLE(ChildScopesRepository);
1165
1166 ChildScopesRepository(std::string const& repo_file_path,
1167- boost::log::sources::severity_channel_logger_mt<>& logger);
1168+ unity::scopes::internal::Logger& logger);
1169
1170 ChildScopeList child_scopes(ChildScopeList const& child_scopes_defaulted);
1171 bool set_child_scopes(ChildScopeList const& child_scopes);
1172@@ -56,7 +56,7 @@
1173 ChildScopeEnabledMap json_to_list(std::string const& child_scopes_json);
1174
1175 std::string const repo_file_path_;
1176- boost::log::sources::severity_channel_logger_mt<>& logger_;
1177+ unity::scopes::internal::Logger& logger_;
1178
1179 std::mutex mutex_;
1180 ChildScopeEnabledMap cached_repo_;
1181
1182=== modified file 'include/unity/scopes/internal/DfltConfig.h.in'
1183--- include/unity/scopes/internal/DfltConfig.h.in 2015-12-09 05:43:13 +0000
1184+++ include/unity/scopes/internal/DfltConfig.h.in 2016-03-04 15:54:04 +0000
1185@@ -57,10 +57,6 @@
1186 static constexpr char const* DFLT_HOME_CACHE_SUBDIR = ".local/share/unity-scopes";
1187 static constexpr char const* DFLT_HOME_APP_SUBDIR = ".local/share";
1188 static constexpr char const* DFLT_HOME_CONFIG_SUBDIR = ".config/unity-scopes";
1189-static constexpr char const* DFLT_HOME_LOG_SUBDIR = "";
1190-
1191-static constexpr int DFLT_MAX_LOG_FILE_SIZE = 512 * 1024; // bytes, individual file size
1192-static constexpr int DFLT_MAX_LOG_DIR_SIZE = 2 * 1024 * 1024; // bytes, sum of file sizes
1193
1194 static constexpr bool DFLT_LOCATION_PERMITTED = true; // Whether a scope that wants location data, but does not
1195 // have a settings.ini file yet, actually gets the data.
1196
1197=== modified file 'include/unity/scopes/internal/FilterBaseImpl.h'
1198--- include/unity/scopes/internal/FilterBaseImpl.h 2015-11-12 14:20:36 +0000
1199+++ include/unity/scopes/internal/FilterBaseImpl.h 2016-03-04 15:54:04 +0000
1200@@ -20,7 +20,9 @@
1201
1202 #include <unity/scopes/Variant.h>
1203 #include <unity/scopes/FilterBase.h>
1204+#include <unity/scopes/FilterGroup.h>
1205 #include <string>
1206+#include <map>
1207
1208 namespace unity
1209 {
1210@@ -40,12 +42,16 @@
1211 virtual ~FilterBaseImpl();
1212 void set_display_hints(int hints);
1213 std::string id() const;
1214+ void set_title(std::string const& title);
1215+ std::string title() const;
1216 int display_hints() const;
1217+ void add_to_filter_group(FilterGroup::SCPtr const& group);
1218+ FilterGroup::SCPtr filter_group() const;
1219 VariantMap serialize() const;
1220 virtual std::string filter_type() const = 0;
1221 static FilterBase::SCPtr deserialize(VariantMap const& var);
1222 static VariantArray serialize_filters(Filters const& filters);
1223- static Filters deserialize_filters(VariantArray const& var);
1224+ static Filters deserialize_filters(VariantArray const& var, std::map<std::string, FilterGroup::SCPtr> const& groups);
1225 static void validate_filters(Filters const& filters);
1226 virtual void validate_display_hints() const = 0;
1227
1228@@ -56,7 +62,9 @@
1229
1230 private:
1231 std::string id_;
1232+ std::string title_;
1233 int display_hints_;
1234+ FilterGroup::SCPtr filter_group_;
1235 };
1236
1237 } // namespace internal
1238
1239=== added file 'include/unity/scopes/internal/FilterGroupImpl.h'
1240--- include/unity/scopes/internal/FilterGroupImpl.h 1970-01-01 00:00:00 +0000
1241+++ include/unity/scopes/internal/FilterGroupImpl.h 2016-03-04 15:54:04 +0000
1242@@ -0,0 +1,54 @@
1243+/*
1244+ * Copyright (C) 2016 Canonical Ltd
1245+ *
1246+ * This program is free software: you can redistribute it and/or modify
1247+ * it under the terms of the GNU Lesser General Public License version 3 as
1248+ * published by the Free Software Foundation.
1249+ *
1250+ * This program is distributed in the hope that it will be useful,
1251+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1252+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1253+ * GNU Lesser General Public License for more details.
1254+ *
1255+ * You should have received a copy of the GNU Lesser General Public License
1256+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1257+ *
1258+ * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com>
1259+ */
1260+
1261+#pragma once
1262+
1263+#include <string>
1264+#include <map>
1265+#include <unity/scopes/Variant.h>
1266+#include <unity/scopes/FilterBase.h>
1267+
1268+namespace unity
1269+{
1270+
1271+namespace scopes
1272+{
1273+class FilterState;
1274+
1275+namespace internal
1276+{
1277+
1278+class FilterGroupImpl
1279+{
1280+public:
1281+ FilterGroupImpl(std::string const& id, std::string const& label);
1282+ std::string id() const;
1283+ std::string label() const;
1284+ static VariantArray serialize_filter_groups(Filters const& filters);
1285+ static std::map<std::string, FilterGroup::SCPtr> deserialize_filter_groups(VariantArray const& var);
1286+
1287+private:
1288+ std::string id_;
1289+ std::string label_;
1290+};
1291+
1292+} // namespace internal
1293+
1294+} // namespace scopes
1295+
1296+} // namespace unity
1297
1298=== modified file 'include/unity/scopes/internal/FilterOptionImpl.h'
1299--- include/unity/scopes/internal/FilterOptionImpl.h 2014-11-03 05:31:30 +0000
1300+++ include/unity/scopes/internal/FilterOptionImpl.h 2016-03-04 15:54:04 +0000
1301@@ -35,10 +35,13 @@
1302 FilterOptionImpl(std::string const& id, std::string const& label);
1303 std::string id() const;
1304 std::string label() const;
1305+ void set_default_value(bool default_value);
1306+ bool default_value() const;
1307
1308 private:
1309 std::string id_;
1310 std::string label_;
1311+ bool default_value_;
1312 };
1313
1314 } // namespace internal
1315
1316=== modified file 'include/unity/scopes/internal/Logger.h'
1317--- include/unity/scopes/internal/Logger.h 2014-12-10 04:00:08 +0000
1318+++ include/unity/scopes/internal/Logger.h 2016-03-04 15:54:04 +0000
1319@@ -20,18 +20,11 @@
1320
1321 #include <unity/util/DefinesPtrs.h>
1322 #include <unity/util/NonCopyable.h>
1323-#include <unity/util/ResourcePtr.h>
1324-
1325-#define BOOST_LOG_DYN_LINK
1326-
1327-#include <boost/log/sinks.hpp>
1328-#include <boost/log/sources/global_logger_storage.hpp>
1329-#include <boost/log/sources/record_ostream.hpp>
1330-#include <boost/log/sources/severity_channel_logger.hpp>
1331-#include <boost/log/utility/value_ref.hpp>
1332-
1333+
1334+#include <array>
1335 #include <atomic>
1336-#include <unordered_map>
1337+#include <iostream>
1338+#include <sstream>
1339
1340 namespace unity
1341 {
1342@@ -42,18 +35,58 @@
1343 namespace internal
1344 {
1345
1346-namespace
1347+enum class LoggerSeverity { Info, Warning, Error, Fatal, Trace };
1348+
1349+enum class LoggerChannel { DefaultChannel, IPC, LastChannelEnum_ };
1350+
1351+class Logger;
1352+
1353+class LogStream : public std::ostringstream
1354 {
1355-
1356-#pragma GCC diagnostic push
1357-#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
1358-
1359-BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", int)
1360-BOOST_LOG_ATTRIBUTE_KEYWORD(channel, "Channel", std::string)
1361-
1362-#pragma GCC diagnostic pop
1363-
1364-}
1365+public:
1366+ NONCOPYABLE(LogStream);
1367+ UNITY_DEFINES_PTRS(LogStream);
1368+
1369+#if __GNUC__ == 4
1370+ // gcc 4.9 doesn't have a move constructor for ostringstream:
1371+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316
1372+ // We simulate the move with a copy and clear.
1373+ LogStream(LogStream&& other)
1374+ : id_(std::move(other.id_))
1375+ , outstream_(other.outstream_)
1376+ , severity_(other.severity_)
1377+ , channel_(other.channel_)
1378+ {
1379+ *this << other.str();
1380+ other.str("");
1381+ other.clear();
1382+ }
1383+#else
1384+ // We need an explicit move constructor because basic_ios does not have a move
1385+ // constructor. Instead, it has a protected move() method that ostringstream calls
1386+ // as part if its move constructor.
1387+ LogStream(LogStream&& other)
1388+ : std::ostringstream(std::move(other))
1389+ , id_(std::move(other.id_))
1390+ , outstream_(other.outstream_)
1391+ , severity_(other.severity_)
1392+ , channel_(other.channel_)
1393+ {
1394+ }
1395+#endif
1396+
1397+ LogStream& operator=(LogStream&&) = delete; // Move assignment is impossible due to reference member.
1398+
1399+ LogStream();
1400+ LogStream(std::ostream& outstream, std::string const& id, LoggerSeverity s, LoggerChannel c);
1401+ ~LogStream();
1402+
1403+private:
1404+ std::string const id_;
1405+ std::ostream& outstream_;
1406+ LoggerSeverity severity_;
1407+ LoggerChannel channel_;
1408+};
1409
1410 class Logger
1411 {
1412@@ -61,57 +94,42 @@
1413 NONCOPYABLE(Logger);
1414 UNITY_DEFINES_PTRS(Logger);
1415
1416- // Instantiate a logger that logs to std::clog.
1417- Logger(std::string const& id);
1418- ~Logger();
1419-
1420- enum Channel
1421+ // We need an explicit move constructor because atomics are not movable.
1422+ Logger(Logger&& other)
1423+ : id_(move(other.id_))
1424+ , outstream_(other.outstream_)
1425 {
1426- IPC,
1427- LastChannelEnum_
1428- };
1429-
1430- // Returns default logger (no channel)
1431- operator boost::log::sources::severity_channel_logger_mt<>&();
1432-
1433- // Returns logger for specified channel.
1434- boost::log::sources::severity_channel_logger_mt<>& operator()(Channel c);
1435-
1436- void set_log_file(std::string const& path, int rotation_size, int dir_size);
1437-
1438- enum Severity { Info, Warning, Error, Fatal, Trace };
1439- Severity set_severity_threshold(Severity s);
1440-
1441- bool set_channel(Channel c, bool enable);
1442+ severity_threshold_.exchange(other.severity_threshold_);
1443+ for (unsigned i = 0; i < other.enabled_.size(); ++i)
1444+ {
1445+ enabled_[i].exchange(other.enabled_[i]);
1446+ }
1447+ }
1448+
1449+ Logger& operator=(Logger&&) = delete; // Move assignment is impossible due to reference member.
1450+
1451+ // Instantiate a logger that logs to the given stream.
1452+ Logger(std::string const& id, std::ostream& outstream = std::clog);
1453+
1454+ // Returns default writer for severity Error on the default channel.
1455+ LogStream operator()();
1456+
1457+ // Returns writer for specified severity.
1458+ LogStream operator()(LoggerSeverity s);
1459+
1460+ // Returns writer for specified channel.
1461+ LogStream operator()(LoggerChannel c);
1462+
1463+ LoggerSeverity set_severity_threshold(LoggerSeverity s);
1464+
1465+ bool set_channel(LoggerChannel c, bool enable);
1466 bool set_channel(std::string channel_name, bool enable);
1467- void enable_channels(std::vector<std::string> const& names);
1468
1469 private:
1470- bool filter(boost::log::value_ref<int, tag::severity> const& level,
1471- boost::log::value_ref<std::string, tag::channel> const& channel);
1472-
1473- void formatter(boost::log::record_view const& rec,
1474- boost::log::formatting_ostream& strm);
1475-
1476- std::string scope_id_; // immutable
1477-
1478- boost::log::sources::severity_channel_logger_mt<> logger_; // Default logger, no channel, immutable
1479-
1480- std::atomic<Severity> severity_;
1481-
1482- typedef boost::log::sinks::asynchronous_sink<boost::log::sinks::text_ostream_backend> ClogSinkT;
1483- typedef boost::shared_ptr<ClogSinkT> ClogSinkPtr;
1484- ClogSinkPtr clog_sink_;
1485-
1486- typedef boost::log::sinks::asynchronous_sink<boost::log::sinks::text_file_backend> FileSinkT;
1487- typedef boost::shared_ptr<FileSinkT> FileSinkPtr;
1488- FileSinkPtr file_sink_;
1489-
1490- typedef std::pair<boost::log::sources::severity_channel_logger_mt<>, std::atomic_bool> ChannelData;
1491- typedef std::unordered_map<std::string, ChannelData> ChannelMap;
1492- ChannelMap channel_loggers_; // immutable
1493-
1494- std::mutex mutex_; // Protects clog_sink_ and file_sink_
1495+ std::string const id_;
1496+ std::ostream& outstream_;
1497+ std::atomic<LoggerSeverity> severity_threshold_;
1498+ std::array<std::atomic_bool, int(LoggerChannel::LastChannelEnum_)> enabled_;
1499 };
1500
1501 } // namespace internal
1502
1503=== modified file 'include/unity/scopes/internal/OptionSelectorFilterImpl.h'
1504--- include/unity/scopes/internal/OptionSelectorFilterImpl.h 2015-11-12 14:20:36 +0000
1505+++ include/unity/scopes/internal/OptionSelectorFilterImpl.h 2016-03-04 15:54:04 +0000
1506@@ -42,7 +42,7 @@
1507 OptionSelectorFilterImpl(VariantMap const& var);
1508 std::string label() const;
1509 bool multi_select() const;
1510- virtual FilterOption::SCPtr add_option(std::string const& id, std::string const& label);
1511+ virtual FilterOption::SCPtr add_option(std::string const& id, std::string const& label, bool default_value = false);
1512 std::list<FilterOption::SCPtr> options() const;
1513 int num_of_options() const;
1514 std::set<FilterOption::SCPtr> active_options(FilterState const& filter_state) const;
1515
1516=== modified file 'include/unity/scopes/internal/RangeInputFilterImpl.h'
1517--- include/unity/scopes/internal/RangeInputFilterImpl.h 2015-11-12 14:20:36 +0000
1518+++ include/unity/scopes/internal/RangeInputFilterImpl.h 2016-03-04 15:54:04 +0000
1519@@ -30,18 +30,25 @@
1520 namespace internal
1521 {
1522
1523-using namespace experimental;
1524-
1525 class RangeInputFilterImpl : public FilterBaseImpl
1526 {
1527 public:
1528- RangeInputFilterImpl(std::string const& id, std::string const& start_label, std::string const& end_label, std::string const& unit_label);
1529+ RangeInputFilterImpl(std::string const& id,
1530+ Variant const& default_start_value, Variant const& default_end_value,
1531+ std::string const& start_prefix_label, std::string const& start_postfix_label,
1532+ std::string const& central_label,
1533+ std::string const& end_prefix_label, std::string const& end_postfix_label);
1534+
1535 RangeInputFilterImpl(VariantMap const& var);
1536
1537- std::string start_label() const;
1538- std::string end_label() const;
1539- std::string unit_label() const;
1540+ std::string start_prefix_label() const;
1541+ std::string start_postfix_label() const;
1542+ std::string end_prefix_label() const;
1543+ std::string end_postfix_label() const;
1544+ std::string central_label() const;
1545
1546+ Variant default_start_value() const;
1547+ Variant default_end_value() const;
1548 bool has_start_value(FilterState const& filter_state) const;
1549 bool has_end_value(FilterState const& filter_state) const;
1550 double start_value(FilterState const& filter_state) const;
1551@@ -64,9 +71,13 @@
1552 double get_value(FilterState const& filter_state, unsigned int index) const;
1553 static void check_type(Variant const& val, std::string const& filter_id, std::string const& varname);
1554
1555- std::string start_label_;
1556- std::string end_label_;
1557- std::string unit_label_;
1558+ Variant default_start_value_;
1559+ Variant default_end_value_;
1560+ std::string start_prefix_label_;
1561+ std::string start_postfix_label_;
1562+ std::string end_prefix_label_;
1563+ std::string end_postfix_label_;
1564+ std::string central_label_;
1565 };
1566
1567 } // namespace internal
1568
1569=== modified file 'include/unity/scopes/internal/RatingFilterImpl.h'
1570--- include/unity/scopes/internal/RatingFilterImpl.h 2014-11-03 05:31:30 +0000
1571+++ include/unity/scopes/internal/RatingFilterImpl.h 2016-03-04 15:54:04 +0000
1572@@ -31,6 +31,8 @@
1573 {
1574
1575 using namespace experimental;
1576+// FIXME: reconsider using FilterOption and RadioButtonsFilterImpl as a base when moving this filter out from experimental namespace,
1577+// the default values of individual FilterOption don't make much sense with RatingFilter.
1578
1579 class RatingFilterImpl : public RadioButtonsFilterImpl
1580 {
1581@@ -38,7 +40,8 @@
1582 RatingFilterImpl(std::string const& id, std::string const& label);
1583 RatingFilterImpl(std::string const& id, std::string const& label, int top_rating);
1584 RatingFilterImpl(VariantMap const& var);
1585- FilterOption::SCPtr add_option(std::string const& id, std::string const& label) override;
1586+
1587+ FilterOption::SCPtr add_option(std::string const& id, std::string const& label, bool default_value = false) override;
1588 void set_on_icon(std::string const& on_icon);
1589 void set_off_icon(std::string const& off_icon);
1590 std::string on_icon() const;
1591
1592=== modified file 'include/unity/scopes/internal/RegistryObject.h'
1593--- include/unity/scopes/internal/RegistryObject.h 2015-12-08 01:02:15 +0000
1594+++ include/unity/scopes/internal/RegistryObject.h 2016-03-04 15:54:04 +0000
1595@@ -100,7 +100,7 @@
1596
1597 ScopeProcess(ScopeExecData exec_data,
1598 std::weak_ptr<MWPublisher> const& publisher,
1599- boost::log::sources::severity_channel_logger_mt<>& logger);
1600+ unity::scopes::internal::Logger& logger);
1601 ~ScopeProcess();
1602
1603 ProcessState state() const;
1604@@ -131,12 +131,12 @@
1605 core::posix::ChildProcess process_ = core::posix::ChildProcess::invalid();
1606 std::weak_ptr<MWPublisher> reg_publisher_; // weak_ptr, so processes don't hold publisher alive
1607 bool manually_started_;
1608- boost::log::sources::severity_channel_logger_mt<>& logger_;
1609+ unity::scopes::internal::Logger& logger_;
1610 };
1611
1612 private:
1613 std::unique_ptr<unity::scopes::internal::Logger> test_logger_;
1614- boost::log::sources::severity_channel_logger_mt<>& logger_;
1615+ unity::scopes::internal::Logger& logger_;
1616
1617 core::posix::ChildProcess::DeathObserver& death_observer_;
1618 core::ScopedConnection death_observer_connection_;
1619
1620=== modified file 'include/unity/scopes/internal/RuntimeConfig.h'
1621--- include/unity/scopes/internal/RuntimeConfig.h 2014-12-10 03:18:53 +0000
1622+++ include/unity/scopes/internal/RuntimeConfig.h 2016-03-04 15:54:04 +0000
1623@@ -47,15 +47,11 @@
1624 std::string cache_directory() const;
1625 std::string app_directory() const;
1626 std::string config_directory() const;
1627- std::string log_directory() const;
1628- int max_log_file_size() const;
1629- int max_log_dir_size() const;
1630 std::vector<std::string> trace_channels() const;
1631
1632 static std::string default_cache_directory();
1633 static std::string default_app_directory();
1634 static std::string default_config_directory();
1635- static std::string default_log_directory();
1636
1637 private:
1638 std::string registry_identity_;
1639@@ -69,9 +65,6 @@
1640 std::string cache_directory_;
1641 std::string app_directory_;
1642 std::string config_directory_;
1643- std::string log_directory_;
1644- int max_log_file_size_;
1645- int max_log_dir_size_;
1646 std::vector<std::string> trace_channels_;
1647 };
1648
1649
1650=== modified file 'include/unity/scopes/internal/RuntimeImpl.h'
1651--- include/unity/scopes/internal/RuntimeImpl.h 2015-03-02 03:59:01 +0000
1652+++ include/unity/scopes/internal/RuntimeImpl.h 2016-03-04 15:54:04 +0000
1653@@ -53,8 +53,7 @@
1654 Reaper::SPtr reply_reaper() const;
1655 ThreadPool::SPtr async_pool() const;
1656 ThreadSafeQueue<std::future<void>>::SPtr future_queue() const;
1657- boost::log::sources::severity_channel_logger_mt<>& logger() const;
1658- boost::log::sources::severity_channel_logger_mt<>& logger(Logger::Channel channel) const;
1659+ unity::scopes::internal::Logger& logger() const;
1660 void run_scope(ScopeBase* scope_base,
1661 std::string const& scope_ini_file,
1662 std::promise<void> ready_promise = std::promise<void>());
1663
1664=== modified file 'include/unity/scopes/internal/ValueSliderFilterImpl.h'
1665--- include/unity/scopes/internal/ValueSliderFilterImpl.h 2015-11-12 14:20:36 +0000
1666+++ include/unity/scopes/internal/ValueSliderFilterImpl.h 2016-03-04 15:54:04 +0000
1667@@ -20,6 +20,8 @@
1668
1669 #include <unity/scopes/internal/FilterBaseImpl.h>
1670 #include <unity/scopes/ValueSliderFilter.h>
1671+#include <unity/scopes/ValueSliderLabels.h>
1672+#include <unity/scopes/internal/ValueSliderLabelsImpl.h>
1673
1674 namespace unity
1675 {
1676@@ -32,24 +34,19 @@
1677 namespace internal
1678 {
1679
1680-using namespace experimental;
1681-
1682 class ValueSliderFilterImpl : public FilterBaseImpl
1683 {
1684 public:
1685- ValueSliderFilterImpl(std::string const& id, std::string const& label, std::string const& label_template, double min, double max);
1686+ ValueSliderFilterImpl(std::string const& id, double min, double max, double default_value, ValueSliderLabels const& labels);
1687 ValueSliderFilterImpl(VariantMap const& var);
1688- void set_slider_type(ValueSliderFilter::SliderType tp);
1689- ValueSliderFilter::SliderType slider_type() const;
1690 void set_default_value(double val);
1691- std::string label() const;
1692 double min() const;
1693 double max() const;
1694 double default_value() const;
1695- std::string value_label_template() const;
1696 bool has_value(FilterState const& filter_state) const;
1697 double value(FilterState const& filter_state) const;
1698 void update_state(FilterState& filter_state, double value) const;
1699+ ValueSliderLabels const& labels() const;
1700 static ValueSliderFilter::SPtr create(VariantMap const& var);
1701 static void update_state(FilterState& filter_state, std::string const& filter_id, double value);
1702 void validate_display_hints() const override;
1703@@ -61,12 +58,10 @@
1704 void check_range(double val) const;
1705
1706 private:
1707- std::string label_;
1708- std::string label_template_;
1709- ValueSliderFilter::SliderType slider_type_;
1710- double default_val_;
1711 double min_;
1712 double max_;
1713+ double default_val_;
1714+ std::unique_ptr<ValueSliderLabels> labels_;
1715 };
1716
1717 } // namespace internal
1718
1719=== added file 'include/unity/scopes/internal/ValueSliderLabelsImpl.h'
1720--- include/unity/scopes/internal/ValueSliderLabelsImpl.h 1970-01-01 00:00:00 +0000
1721+++ include/unity/scopes/internal/ValueSliderLabelsImpl.h 2016-03-04 15:54:04 +0000
1722@@ -0,0 +1,59 @@
1723+/*
1724+ * Copyright (C) 2015 Canonical Ltd
1725+ *
1726+ * This program is free software: you can redistribute it and/or modify
1727+ * it under the terms of the GNU Lesser General Public License version 3 as
1728+ * published by the Free Software Foundation.
1729+ *
1730+ * This program is distributed in the hope that it will be useful,
1731+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1732+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1733+ * GNU Lesser General Public License for more details.
1734+ *
1735+ * You should have received a copy of the GNU Lesser General Public License
1736+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1737+ *
1738+ * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com>
1739+ */
1740+
1741+#pragma once
1742+
1743+#include <unity/scopes/ValueSliderLabels.h>
1744+#include <unity/scopes/Variant.h>
1745+
1746+namespace unity
1747+{
1748+
1749+namespace scopes
1750+{
1751+
1752+namespace internal
1753+{
1754+
1755+class ValueSliderLabelsImpl
1756+{
1757+public:
1758+ ValueSliderLabelsImpl(std::string const& min_label, std::string const& max_label);
1759+ ValueSliderLabelsImpl(std::string const& min_label, std::string const& max_label, std::vector<std::pair<double, std::string>> const& extra_labels);
1760+ ValueSliderLabelsImpl(VariantMap const& var);
1761+ ValueSliderLabelsImpl(ValueSliderLabelsImpl const&) = default;
1762+
1763+ std::string min_label() const;
1764+ std::string max_label() const;
1765+ std::vector<std::pair<double, std::string>> extra_labels() const;
1766+ VariantMap serialize() const;
1767+ void deserialize(VariantMap const& var);
1768+
1769+ void validate(double min, double max) const;
1770+
1771+private:
1772+ std::string min_label_;
1773+ std::string max_label_;
1774+ std::vector<std::pair<double, std::string>> extra_labels_;
1775+};
1776+
1777+}
1778+
1779+}
1780+
1781+}
1782
1783=== modified file 'include/unity/scopes/internal/smartscopes/SmartScopesClient.h'
1784--- include/unity/scopes/internal/smartscopes/SmartScopesClient.h 2015-12-08 01:02:15 +0000
1785+++ include/unity/scopes/internal/smartscopes/SmartScopesClient.h 2016-03-04 15:54:04 +0000
1786@@ -20,6 +20,7 @@
1787
1788 #include <unity/scopes/FilterBase.h>
1789 #include <unity/scopes/FilterState.h>
1790+#include <unity/scopes/FilterGroup.h>
1791 #include <unity/scopes/internal/JsonNodeInterface.h>
1792 #include <unity/scopes/internal/Logger.h>
1793 #include <unity/scopes/internal/smartscopes/HttpClientInterface.h>
1794@@ -27,12 +28,13 @@
1795
1796 #include <unity/util/NonCopyable.h>
1797
1798-#include <string>
1799-#include <vector>
1800 #include <map>
1801 #include <memory>
1802 #include <mutex>
1803+#include <set>
1804+#include <string>
1805 #include <tuple>
1806+#include <vector>
1807
1808 namespace unity
1809 {
1810@@ -152,6 +154,8 @@
1811 std::function<void(std::shared_ptr<DepartmentInfo> const&)> departments_handler;
1812 std::function<void(Filters const&)> filters_handler;
1813 std::function<void(FilterState const&)> filter_state_handler;
1814+
1815+ std::map<std::string, FilterGroup::SCPtr> filter_groups;
1816 };
1817
1818 struct PreviewReplyHandler
1819@@ -179,7 +183,7 @@
1820
1821 bool get_remote_scopes(std::vector<RemoteScope>& scopes, std::string const& locale = "", bool caching_enabled = true);
1822
1823- SearchHandle::UPtr search(SearchReplyHandler const& handler,
1824+ SearchHandle::UPtr search(SearchReplyHandler& handler,
1825 std::string const& base_url,
1826 std::string const& query,
1827 std::string const& department_id,
1828@@ -204,7 +208,7 @@
1829 std::string const& country = "",
1830 std::string const& user_agent_hdr = "");
1831
1832- boost::log::sources::severity_channel_logger_mt<>& logger() const;
1833+ unity::scopes::internal::Logger& logger() const;
1834
1835 private:
1836 friend class SearchHandle;
1837@@ -213,11 +217,12 @@
1838 void wait_for_search(unsigned int search_id);
1839 void wait_for_preview(unsigned int preview_id);
1840 std::shared_ptr<DepartmentInfo> parse_departments(JsonNodeInterface::SPtr node);
1841- Filters parse_filters(JsonNodeInterface::SPtr node);
1842+ std::map<std::string, FilterGroup::SCPtr> parse_filter_groups(JsonNodeInterface::SPtr node);
1843+ Filters parse_filters(JsonNodeInterface::SPtr node, std::map<std::string, FilterGroup::SCPtr> const& filter_groups);
1844 FilterState parse_filter_state(JsonNodeInterface::SPtr node);
1845
1846 std::string handle_chunk(const std::string& chunk, std::function<void(const std::string&)> line_handler);
1847- void handle_line(std::string const& json, SearchReplyHandler const& handler);
1848+ void handle_line(std::string const& json, SearchReplyHandler& handler);
1849 void handle_line(std::string const& json, PreviewReplyHandler const& handler);
1850
1851 std::vector<std::string> extract_json_stream(std::string const& json_stream);
1852@@ -232,7 +237,7 @@
1853 HttpClientInterface::SPtr http_client_;
1854 JsonNodeInterface::SPtr json_node_;
1855 std::unique_ptr<unity::scopes::internal::Logger> test_logger_;
1856- boost::log::sources::severity_channel_logger_mt<>& logger_;
1857+ unity::scopes::internal::Logger& logger_;
1858 std::string url_;
1859
1860 std::map<unsigned int, HttpResponseHandle::SPtr> query_results_;
1861
1862=== modified file 'include/unity/scopes/internal/zmq_middleware/ObjectAdapter.h'
1863--- include/unity/scopes/internal/zmq_middleware/ObjectAdapter.h 2015-12-08 01:02:15 +0000
1864+++ include/unity/scopes/internal/zmq_middleware/ObjectAdapter.h 2016-03-04 15:54:04 +0000
1865@@ -109,8 +109,7 @@
1866
1867 void store_exception(scopes::MiddlewareException& ex);
1868
1869- boost::log::sources::severity_channel_logger_mt<>& logger() const;
1870- boost::log::sources::severity_channel_logger_mt<>& ipc_logger() const;
1871+ unity::scopes::internal::Logger& logger() const;
1872
1873 void trace_dispatch(Current const& c);
1874 void trace_response();
1875
1876=== modified file 'include/unity/scopes/internal/zmq_middleware/ZmqMiddleware.h'
1877--- include/unity/scopes/internal/zmq_middleware/ZmqMiddleware.h 2015-12-08 01:02:15 +0000
1878+++ include/unity/scopes/internal/zmq_middleware/ZmqMiddleware.h 2016-03-04 15:54:04 +0000
1879@@ -135,7 +135,7 @@
1880 mutable std::mutex state_mutex_; // Protects state_
1881 std::atomic_bool shutdown_flag_;
1882 std::unique_ptr<unity::scopes::internal::Logger> test_logger_;
1883- boost::log::sources::severity_channel_logger_mt<>& logger_;
1884+ unity::scopes::internal::Logger& logger_;
1885
1886 int64_t twoway_timeout_; // Default timeout for twoway invocations
1887 int64_t locate_timeout_; // Timeout for registry locate()
1888
1889=== modified file 'scoperegistry/DirWatcher.cpp'
1890--- scoperegistry/DirWatcher.cpp 2015-01-07 02:24:43 +0000
1891+++ scoperegistry/DirWatcher.cpp 2016-03-04 15:54:04 +0000
1892@@ -32,7 +32,7 @@
1893 namespace scoperegistry
1894 {
1895
1896-DirWatcher::DirWatcher(boost::log::sources::severity_channel_logger_mt<>& logger)
1897+DirWatcher::DirWatcher(Logger& logger)
1898 : fd_(inotify_init())
1899 , thread_state_(Running)
1900 , thread_exception_(nullptr)
1901@@ -137,11 +137,11 @@
1902 }
1903 catch (std::exception const& e)
1904 {
1905- BOOST_LOG(logger_) << "~DirWatcher(): " << e.what();
1906+ logger_() << "~DirWatcher(): " << e.what();
1907 }
1908 catch (...)
1909 {
1910- BOOST_LOG(logger_) << "~DirWatcher(): watch_thread was aborted due to an unknown exception";
1911+ logger_() << "~DirWatcher(): watch_thread was aborted due to an unknown exception";
1912 }
1913 }
1914 else
1915@@ -283,14 +283,14 @@
1916 }
1917 catch (std::exception const& e)
1918 {
1919- BOOST_LOG(logger_) << "DirWatcher::watch_thread(): " << e.what();
1920+ logger_() << "DirWatcher::watch_thread(): " << e.what();
1921 std::lock_guard<std::mutex> lock(mutex_);
1922 thread_state_ = Failed;
1923 thread_exception_ = std::current_exception();
1924 }
1925 catch (...)
1926 {
1927- BOOST_LOG(logger_) << "DirWatcher::watch_thread(): Thread aborted: unknown exception";
1928+ logger_() << "DirWatcher::watch_thread(): Thread aborted: unknown exception";
1929 std::lock_guard<std::mutex> lock(mutex_);
1930 thread_state_ = Failed;
1931 thread_exception_ = std::current_exception();
1932
1933=== modified file 'scoperegistry/DirWatcher.h'
1934--- scoperegistry/DirWatcher.h 2014-11-24 05:06:00 +0000
1935+++ scoperegistry/DirWatcher.h 2016-03-04 15:54:04 +0000
1936@@ -48,7 +48,7 @@
1937 Directory
1938 };
1939
1940- DirWatcher(boost::log::sources::severity_channel_logger_mt<>& logger);
1941+ DirWatcher(unity::scopes::internal::Logger& logger);
1942 virtual ~DirWatcher();
1943
1944 void add_watch(std::string const& path);
1945@@ -73,7 +73,7 @@
1946 std::mutex mutex_;
1947 ThreadState thread_state_;
1948 std::exception_ptr thread_exception_;
1949- boost::log::sources::severity_channel_logger_mt<>& logger_;
1950+ unity::scopes::internal::Logger& logger_;
1951
1952 void watch_thread();
1953 virtual void watch_event(EventType, FileType, std::string const&) = 0;
1954
1955=== modified file 'scoperegistry/ScopesWatcher.cpp'
1956--- scoperegistry/ScopesWatcher.cpp 2015-01-20 06:18:36 +0000
1957+++ scoperegistry/ScopesWatcher.cpp 2016-03-04 15:54:04 +0000
1958@@ -35,7 +35,7 @@
1959
1960 ScopesWatcher::ScopesWatcher(RegistryObject::SPtr registry,
1961 std::function<void(std::pair<std::string, std::string> const&)> ini_added_callback,
1962- boost::log::sources::severity_channel_logger_mt<>& logger)
1963+ Logger& logger)
1964 : DirWatcher(logger)
1965 , registry_(registry)
1966 , ini_added_callback_(ini_added_callback)
1967@@ -60,7 +60,7 @@
1968 catch (unity::LogicException const&) {} // Ignore already exists exception
1969 catch (unity::SyscallException const& e)
1970 {
1971- BOOST_LOG(logger_) << "ScopesWatcher::add_install_dir(): parent dir watch: " << e.what();
1972+ logger_() << "ScopesWatcher::add_install_dir(): parent dir watch: " << e.what();
1973 }
1974
1975 // Create a new entry for this install dir into idir_to_sdirs_map_
1976@@ -101,11 +101,11 @@
1977 }
1978 catch (unity::ResourceException const& e)
1979 {
1980- BOOST_LOG(logger_) << "ScopesWatcher::add_install_dir(): install dir watch: " << e.what();
1981+ logger_() << "ScopesWatcher::add_install_dir(): install dir watch: " << e.what();
1982 }
1983 catch (unity::SyscallException const& e)
1984 {
1985- BOOST_LOG(logger_) << "ScopesWatcher::add_install_dir(): install dir watch: " << e.what();
1986+ logger_() << "ScopesWatcher::add_install_dir(): install dir watch: " << e.what();
1987 }
1988 }
1989
1990@@ -196,13 +196,13 @@
1991
1992 // New config found, execute callback
1993 ini_added_callback_(config);
1994- BOOST_LOG_SEV(logger_, Logger::Info)
1995- << "ScopesWatcher: scope: \"" << config.first << "\" installed to: \"" << dir << "\"";
1996+ logger_(LoggerSeverity::Info) << "ScopesWatcher: scope: \"" << config.first
1997+ << "\" installed to: \"" << dir << "\"";
1998 }
1999 }
2000 catch (std::exception const& e)
2001 {
2002- BOOST_LOG(logger_) << "scoperegistry: add_scope_dir(): " << e.what();
2003+ logger_() << "scoperegistry: add_scope_dir(): " << e.what();
2004 }
2005 }
2006
2007@@ -227,8 +227,8 @@
2008 filesystem::path p(ini_path);
2009 std::string scope_id = p.stem().native();
2010 registry_->remove_local_scope(scope_id);
2011- BOOST_LOG_SEV(logger_, Logger::Info)
2012- << "ScopesWatcher: scope: \"" << scope_id << "\" uninstalled from: \"" << dir << "\"";
2013+ logger_(LoggerSeverity::Info) << "ScopesWatcher: scope: \"" << scope_id
2014+ << "\" uninstalled from: \"" << dir << "\"";
2015 }
2016
2017 // Remove the watch for this directory
2018@@ -273,8 +273,8 @@
2019 {
2020 sdir_to_ini_map_[parent_path] = path;
2021 ini_added_callback_(std::make_pair(scope_id, path));
2022- BOOST_LOG_SEV(logger_, Logger::Info)
2023- << "scopeswatcher: scope: \"" << scope_id << "\" .ini installed: \"" << path << "\"";
2024+ logger_(LoggerSeverity::Info) << "scopeswatcher: scope: \"" << scope_id
2025+ << "\" .ini installed: \"" << path << "\"";
2026 }
2027 }
2028 // a .ini has been removed
2029@@ -282,9 +282,8 @@
2030 {
2031 sdir_to_ini_map_.erase(parent_path);
2032 registry_->remove_local_scope(scope_id);
2033- BOOST_LOG_SEV(logger_, Logger::Info)
2034- << "scopeswatcher: scope: \"" << scope_id << "\" .ini uninstalled: \""
2035- << path << "\"";
2036+ logger_(LoggerSeverity::Info) << "scopeswatcher: scope: \"" << scope_id
2037+ << "\" .ini uninstalled: \"" << path << "\"";
2038 }
2039 }
2040 else
2041@@ -317,7 +316,7 @@
2042 {
2043 bool is_inside_install_dir;
2044 {
2045- std::lock_guard<std::mutex> lock(mutex);
2046+ std::lock_guard<std::mutex> lock(mutex_);
2047 is_inside_install_dir = idir_to_sdirs_map_.find(parent_dir(path)) != idir_to_sdirs_map_.end();
2048 }
2049
2050
2051=== modified file 'scoperegistry/ScopesWatcher.h'
2052--- scoperegistry/ScopesWatcher.h 2014-11-28 06:41:23 +0000
2053+++ scoperegistry/ScopesWatcher.h 2016-03-04 15:54:04 +0000
2054@@ -34,7 +34,7 @@
2055 public:
2056 ScopesWatcher(unity::scopes::internal::RegistryObject::SPtr registry,
2057 std::function<void(std::pair<std::string, std::string> const&)> ini_added_callback,
2058- boost::log::sources::severity_channel_logger_mt<>& logger);
2059+ unity::scopes::internal::Logger& logger);
2060
2061 ~ScopesWatcher();
2062
2063@@ -43,7 +43,7 @@
2064 private:
2065 unity::scopes::internal::RegistryObject::SPtr const registry_;
2066 std::function<void(std::pair<std::string, std::string> const&)> const ini_added_callback_;
2067- boost::log::sources::severity_channel_logger_mt<>& logger_;
2068+ unity::scopes::internal::Logger& logger_;
2069 std::map<std::string, std::string> sdir_to_ini_map_;
2070 std::map<std::string, std::set<std::string>> idir_to_sdirs_map_;
2071 std::mutex mutex_;
2072
2073=== modified file 'src/scopes/CMakeLists.txt'
2074--- src/scopes/CMakeLists.txt 2015-04-09 15:59:17 +0000
2075+++ src/scopes/CMakeLists.txt 2016-03-04 15:54:04 +0000
2076@@ -22,6 +22,7 @@
2077 ${CMAKE_CURRENT_SOURCE_DIR}/Department.cpp
2078 ${CMAKE_CURRENT_SOURCE_DIR}/DateTimePickerFilter.cpp
2079 ${CMAKE_CURRENT_SOURCE_DIR}/FilterBase.cpp
2080+ ${CMAKE_CURRENT_SOURCE_DIR}/FilterGroup.cpp
2081 ${CMAKE_CURRENT_SOURCE_DIR}/FilterOption.cpp
2082 ${CMAKE_CURRENT_SOURCE_DIR}/FilterState.cpp
2083 ${CMAKE_CURRENT_SOURCE_DIR}/Link.cpp
2084@@ -55,6 +56,7 @@
2085 ${CMAKE_CURRENT_SOURCE_DIR}/SearchReply.cpp
2086 ${CMAKE_CURRENT_SOURCE_DIR}/SwitchFilter.cpp
2087 ${CMAKE_CURRENT_SOURCE_DIR}/ValueSliderFilter.cpp
2088+ ${CMAKE_CURRENT_SOURCE_DIR}/ValueSliderLabels.cpp
2089 ${CMAKE_CURRENT_SOURCE_DIR}/VariantBuilder.cpp
2090 ${CMAKE_CURRENT_SOURCE_DIR}/Variant.cpp
2091 ${CMAKE_CURRENT_SOURCE_DIR}/Version.cpp
2092
2093=== modified file 'src/scopes/CategoryRenderer.cpp'
2094--- src/scopes/CategoryRenderer.cpp 2015-01-07 22:36:31 +0000
2095+++ src/scopes/CategoryRenderer.cpp 2016-03-04 15:54:04 +0000
2096@@ -49,8 +49,12 @@
2097
2098 As specified by the \c "category-layout" key of the \c "template" dictionary, Unity will render results associated with this category in a grid layout. The \c "components" dictionary specifies which result fields are used by Unity. In case of this definition, each tile of the grid will map the "title" field from the result (set also by the call to unity::scopes::Result::set_title()) as title for the grid tile, and "art" field from the result (see unity::scopes::Result::set_art()) as the icon for the grid tile.
2099
2100-To sum up, the \c "template" dictionary contains information to determine the correct renderer and its parameters, and the \c "components" dictionary contains mapping specifying which fields of the results are used by the renderer, where keys of the dictionary are understood by Unity and values specify either field name of the results directly (<tt>{"title": "album_name"}</tt> would mean that Unity will use <tt>result["album_name"]</tt> as a title for the grid tile), or the value can specify extra hints for the renderer as well as the result field name and a fallback image
2101-(<tt>{"art": {"field": "icon", "aspect-ratio": 1.3, "fallback": "file:///path_to_fallback_image}}</tt>).
2102+To sum up, the \c "template" dictionary contains information to determine the correct renderer and its parameters, and the \c "components" dictionary contains a mapping that specifies which fields of the results are used by the renderer.
2103+The keys of the dictionary are understood by Unity and the values specify a field name of the results. For example, <tt>{"title": "album_name"}</tt> means that Unity will use <tt>result["album_name"]</tt> as a title for the grid tile.r
2104+
2105+A value also can specify extra hints for the renderer, such as the result field name and a fallback image. For example,
2106+<tt>{"art": {"field": "icon", "aspect-ratio": 1.3, "fallback": "file:///path_to_fallback_image}}</tt>.
2107+The fallback image is shown by Unity if no image URL is provided by the result, but the card requires an image. The fallback image is also shown if the result provides an empty URL for an image, the image does not load due to an error, or if loading results in an empty image. If a result does not specify a fallback image and the actual image is empty or cannot be loaded, Unity substitutes a generic fallback image.
2108
2109 \section jsonschema1 JSON structure (v1)
2110
2111
2112=== modified file 'src/scopes/FilterBase.cpp'
2113--- src/scopes/FilterBase.cpp 2015-11-12 14:20:36 +0000
2114+++ src/scopes/FilterBase.cpp 2016-03-04 15:54:04 +0000
2115@@ -54,6 +54,16 @@
2116 return p->id();
2117 }
2118
2119+void FilterBase::set_title(std::string const& title)
2120+{
2121+ p->set_title(title);
2122+}
2123+
2124+std::string FilterBase::title() const
2125+{
2126+ return p->title();
2127+}
2128+
2129 int FilterBase::display_hints() const
2130 {
2131 return p->display_hints();
2132@@ -64,6 +74,11 @@
2133 return p->filter_type();
2134 }
2135
2136+FilterGroup::SCPtr FilterBase::filter_group() const
2137+{
2138+ return p->filter_group();
2139+}
2140+
2141 } // namespace scopes
2142
2143 } // namespace unity
2144
2145=== added file 'src/scopes/FilterGroup.cpp'
2146--- src/scopes/FilterGroup.cpp 1970-01-01 00:00:00 +0000
2147+++ src/scopes/FilterGroup.cpp 2016-03-04 15:54:04 +0000
2148@@ -0,0 +1,56 @@
2149+/*
2150+ * Copyright (C) 2016 Canonical Ltd
2151+ *
2152+ * This program is free software: you can redistribute it and/or modify
2153+ * it under the terms of the GNU Lesser General Public License version 3 as
2154+ * published by the Free Software Foundation.
2155+ *
2156+ * This program is distributed in the hope that it will be useful,
2157+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2158+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2159+ * GNU Lesser General Public License for more details.
2160+ *
2161+ * You should have received a copy of the GNU Lesser General Public License
2162+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2163+ *
2164+ * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com>
2165+ */
2166+
2167+#include <unity/scopes/FilterGroup.h>
2168+#include <unity/scopes/internal/FilterGroupImpl.h>
2169+
2170+namespace unity
2171+{
2172+
2173+namespace scopes
2174+{
2175+
2176+/// @cond
2177+FilterGroup::FilterGroup(internal::FilterGroupImpl *pimpl)
2178+ : p(pimpl)
2179+{
2180+}
2181+
2182+FilterGroup::FilterGroup() = default;
2183+FilterGroup::~FilterGroup() = default;
2184+
2185+/// @endcond
2186+
2187+FilterGroup::SCPtr FilterGroup::create(std::string const& id, std::string const& label)
2188+{
2189+ return std::shared_ptr<FilterGroup>(new FilterGroup(new internal::FilterGroupImpl(id, label)));
2190+}
2191+
2192+std::string FilterGroup::label() const
2193+{
2194+ return p->label();
2195+}
2196+
2197+std::string FilterGroup::id() const
2198+{
2199+ return p->id();
2200+}
2201+
2202+} // namespace scopes
2203+
2204+} // namespace unity
2205
2206=== modified file 'src/scopes/FilterOption.cpp'
2207--- src/scopes/FilterOption.cpp 2014-02-25 14:59:28 +0000
2208+++ src/scopes/FilterOption.cpp 2016-03-04 15:54:04 +0000
2209@@ -44,6 +44,11 @@
2210 return p->label();
2211 }
2212
2213+bool FilterOption::default_value() const
2214+{
2215+ return p->default_value();
2216+}
2217+
2218 } // namespace scopes
2219
2220 } // namespace unity
2221
2222=== modified file 'src/scopes/OptionSelectorFilter.cpp'
2223--- src/scopes/OptionSelectorFilter.cpp 2014-05-19 09:54:37 +0000
2224+++ src/scopes/OptionSelectorFilter.cpp 2016-03-04 15:54:04 +0000
2225@@ -35,6 +35,13 @@
2226 return std::unique_ptr<OptionSelectorFilter>(new OptionSelectorFilter(new internal::OptionSelectorFilterImpl(id, label, multi_select)));
2227 }
2228
2229+OptionSelectorFilter::UPtr OptionSelectorFilter::create(std::string const& id, std::string const& label, FilterGroup::SCPtr const& group, bool multi_select)
2230+{
2231+ auto filter = std::unique_ptr<OptionSelectorFilter>(new OptionSelectorFilter(new internal::OptionSelectorFilterImpl(id, label, multi_select)));
2232+ filter->p->add_to_filter_group(group);
2233+ return filter;
2234+}
2235+
2236 std::string OptionSelectorFilter::label() const
2237 {
2238 return fwd()->label();
2239@@ -47,7 +54,12 @@
2240
2241 FilterOption::SCPtr OptionSelectorFilter::add_option(std::string const& id, std::string const& label)
2242 {
2243- return fwd()->add_option(id, label);
2244+ return fwd()->add_option(id, label, false);
2245+}
2246+
2247+FilterOption::SCPtr OptionSelectorFilter::add_option(std::string const& id, std::string const& label, bool value)
2248+{
2249+ return fwd()->add_option(id, label, value);
2250 }
2251
2252 std::list<FilterOption::SCPtr> OptionSelectorFilter::options() const
2253
2254=== modified file 'src/scopes/PreviewWidget.cpp'
2255--- src/scopes/PreviewWidget.cpp 2015-12-10 16:26:30 +0000
2256+++ src/scopes/PreviewWidget.cpp 2016-03-04 15:54:04 +0000
2257@@ -158,7 +158,7 @@
2258
2259 \arg \c source A URI pointing to the image
2260 \arg \c zoomable A boolean specifying whether the image is zoomable (default: \c false)
2261-\arg \c fallback A fallback image to be used if the image URI cannot be retrieved (default: none)
2262+\arg \c fallback A fallback image to be used if the image URI is empty or cannot be retrieved (default: none)
2263 \arg \c share-data An optional dictionary for making this image shareable with Content Hub. See \link contentsharing content sharing\endlink below.
2264
2265 \code{.cpp}
2266@@ -178,7 +178,7 @@
2267 List of attributes:
2268
2269 \arg \c sources An array of image URIs
2270-\arg \c fallback A fallback image to be used if an image URI cannot be resolved (default: none)
2271+\arg \c fallback A fallback image to be used if an image URI is empty or cannot be retrieved (default: none)
2272
2273 \code{.cpp}
2274 {
2275@@ -203,7 +203,7 @@
2276 \arg \c title A string specifying the title
2277 \arg \c subtitle A string specifying the subtitle
2278 \arg \c mascot A URI specifying the mascot
2279-\arg \c fallback A fallback image to be used if the mascot URI cannot be retrieved (default: none)
2280+\arg \c fallback A fallback image to be used if the mascot URI is empty or cannot be retrieved (default: none)
2281 \arg \c emblem A URI specifying the emblem
2282
2283 \code{.cpp}
2284
2285=== modified file 'src/scopes/RangeInputFilter.cpp'
2286--- src/scopes/RangeInputFilter.cpp 2014-06-17 10:30:03 +0000
2287+++ src/scopes/RangeInputFilter.cpp 2016-03-04 15:54:04 +0000
2288@@ -26,32 +26,105 @@
2289 namespace scopes
2290 {
2291
2292-namespace experimental
2293-{
2294-
2295-RangeInputFilter::SPtr RangeInputFilter::create(std::string const& id, std::string const& start_label, std::string const& end_label, std::string const& unit_label)
2296-{
2297- return std::shared_ptr<RangeInputFilter>(new RangeInputFilter(new internal::RangeInputFilterImpl(id, start_label, end_label, unit_label)));
2298-}
2299+RangeInputFilter::SPtr RangeInputFilter::create(std::string const& id,
2300+ std::string const& start_prefix_label, std::string const& start_postfix_label,
2301+ std::string const& central_label,
2302+ std::string const& end_prefix_label, std::string const& end_postfix_label)
2303+{
2304+ return std::shared_ptr<RangeInputFilter>(new RangeInputFilter(new internal::RangeInputFilterImpl(id,
2305+ Variant::null(), Variant::null(),
2306+ start_prefix_label, start_postfix_label,
2307+ central_label,
2308+ end_prefix_label, end_postfix_label)));
2309+}
2310+
2311+RangeInputFilter::SPtr RangeInputFilter::create(std::string const& id,
2312+ Variant const& default_start_value,
2313+ Variant const& default_end_value,
2314+ std::string const& start_prefix_label, std::string const& start_postfix_label,
2315+ std::string const& central_label,
2316+ std::string const& end_prefix_label, std::string const& end_postfix_label)
2317+{
2318+ return std::shared_ptr<RangeInputFilter>(new RangeInputFilter(new internal::RangeInputFilterImpl(id,
2319+ default_start_value, default_end_value,
2320+ start_prefix_label, start_postfix_label,
2321+ central_label,
2322+ end_prefix_label, end_postfix_label)));
2323+}
2324+
2325+RangeInputFilter::SPtr RangeInputFilter::create(std::string const& id,
2326+ std::string const& start_prefix_label, std::string const& start_postfix_label,
2327+ std::string const& central_label,
2328+ std::string const& end_prefix_label, std::string const& end_postfix_label,
2329+ FilterGroup::SCPtr const& group
2330+ )
2331+{
2332+ auto filter = std::shared_ptr<RangeInputFilter>(new RangeInputFilter(new internal::RangeInputFilterImpl(id,
2333+ Variant::null(), Variant::null(),
2334+ start_prefix_label, start_postfix_label,
2335+ central_label,
2336+ end_prefix_label, end_postfix_label)));
2337+ filter->p->add_to_filter_group(group);
2338+ return filter;
2339+}
2340+
2341+RangeInputFilter::SPtr RangeInputFilter::create(std::string const& id,
2342+ Variant const& default_start_value,
2343+ Variant const& default_end_value,
2344+ std::string const& start_prefix_label, std::string const& start_postfix_label,
2345+ std::string const& central_label,
2346+ std::string const& end_prefix_label, std::string const& end_postfix_label,
2347+ FilterGroup::SCPtr const& group
2348+ )
2349+{
2350+ auto filter = std::shared_ptr<RangeInputFilter>(new RangeInputFilter(new internal::RangeInputFilterImpl(id,
2351+ default_start_value, default_end_value,
2352+ start_prefix_label, start_postfix_label,
2353+ central_label,
2354+ end_prefix_label, end_postfix_label)));
2355+ filter->p->add_to_filter_group(group);
2356+ return filter;
2357+}
2358+
2359
2360 RangeInputFilter::RangeInputFilter(internal::RangeInputFilterImpl* impl)
2361 : FilterBase(impl)
2362 {
2363 }
2364
2365-std::string RangeInputFilter::start_label() const
2366-{
2367- return fwd()->start_label();
2368-}
2369-
2370-std::string RangeInputFilter::end_label() const
2371-{
2372- return fwd()->end_label();
2373-}
2374-
2375-std::string RangeInputFilter::unit_label() const
2376-{
2377- return fwd()->unit_label();
2378+std::string RangeInputFilter::start_prefix_label() const
2379+{
2380+ return fwd()->start_prefix_label();
2381+}
2382+
2383+std::string RangeInputFilter::start_postfix_label() const
2384+{
2385+ return fwd()->start_postfix_label();
2386+}
2387+
2388+std::string RangeInputFilter::end_prefix_label() const
2389+{
2390+ return fwd()->end_prefix_label();
2391+}
2392+
2393+std::string RangeInputFilter::end_postfix_label() const
2394+{
2395+ return fwd()->end_postfix_label();
2396+}
2397+
2398+std::string RangeInputFilter::central_label() const
2399+{
2400+ return fwd()->central_label();
2401+}
2402+
2403+Variant RangeInputFilter::default_start_value() const
2404+{
2405+ return fwd()->default_start_value();
2406+}
2407+
2408+Variant RangeInputFilter::default_end_value() const
2409+{
2410+ return fwd()->default_end_value();
2411 }
2412
2413 bool RangeInputFilter::has_start_value(FilterState const& filter_state) const
2414@@ -89,8 +162,6 @@
2415 return dynamic_cast<internal::RangeInputFilterImpl*>(p.get());
2416 }
2417
2418-} // namespace experimental
2419-
2420 } // namespace scopes
2421
2422 } // namespace unity
2423
2424=== modified file 'src/scopes/ValueSliderFilter.cpp'
2425--- src/scopes/ValueSliderFilter.cpp 2014-06-17 10:30:03 +0000
2426+++ src/scopes/ValueSliderFilter.cpp 2016-03-04 15:54:04 +0000
2427@@ -25,22 +25,21 @@
2428 namespace scopes
2429 {
2430
2431-namespace experimental
2432-{
2433-
2434 ValueSliderFilter::ValueSliderFilter(internal::ValueSliderFilterImpl *impl)
2435 : FilterBase(impl)
2436 {
2437 }
2438
2439-ValueSliderFilter::UPtr ValueSliderFilter::create(std::string const& id, std::string const& label, std::string const& label_template, double min, double max)
2440+ValueSliderFilter::UPtr ValueSliderFilter::create(std::string const& id, double min, double max, double default_value, ValueSliderLabels const& labels)
2441 {
2442- return std::unique_ptr<ValueSliderFilter>(new ValueSliderFilter(new internal::ValueSliderFilterImpl(id, label, label_template, min, max)));
2443+ return std::unique_ptr<ValueSliderFilter>(new ValueSliderFilter(new internal::ValueSliderFilterImpl(id, min, max, default_value, labels)));
2444 }
2445
2446-void ValueSliderFilter::set_slider_type(SliderType tp)
2447+ValueSliderFilter::UPtr ValueSliderFilter::create(std::string const& id, double min, double max, double default_value, ValueSliderLabels const& labels, FilterGroup::SCPtr const& group)
2448 {
2449- fwd()->set_slider_type(tp);
2450+ auto filter = std::unique_ptr<ValueSliderFilter>(new ValueSliderFilter(new internal::ValueSliderFilterImpl(id, min, max, default_value, labels)));
2451+ filter->p->add_to_filter_group(group);
2452+ return filter;
2453 }
2454
2455 void ValueSliderFilter::set_default_value(double val)
2456@@ -48,11 +47,6 @@
2457 fwd()->set_default_value(val);
2458 }
2459
2460-ValueSliderFilter::SliderType ValueSliderFilter::slider_type() const
2461-{
2462- return fwd()->slider_type();
2463-}
2464-
2465 double ValueSliderFilter::default_value() const
2466 {
2467 return fwd()->default_value();
2468@@ -68,14 +62,9 @@
2469 return fwd()->max();
2470 }
2471
2472-std::string ValueSliderFilter::label() const
2473-{
2474- return fwd()->label();
2475-}
2476-
2477-std::string ValueSliderFilter::value_label_template() const
2478-{
2479- return fwd()->value_label_template();
2480+ValueSliderLabels const& ValueSliderFilter::labels() const
2481+{
2482+ return fwd()->labels();
2483 }
2484
2485 bool ValueSliderFilter::has_value(FilterState const& filter_state) const
2486@@ -103,8 +92,6 @@
2487 return dynamic_cast<internal::ValueSliderFilterImpl*>(p.get());
2488 }
2489
2490-} // namespace experimental
2491-
2492 } // namespace scopes
2493
2494 } // namespace unity
2495
2496=== added file 'src/scopes/ValueSliderLabels.cpp'
2497--- src/scopes/ValueSliderLabels.cpp 1970-01-01 00:00:00 +0000
2498+++ src/scopes/ValueSliderLabels.cpp 2016-03-04 15:54:04 +0000
2499@@ -0,0 +1,89 @@
2500+/*
2501+ * Copyright (C) 2015 Canonical Ltd
2502+ *
2503+ * This program is free software: you can redistribute it and/or modify
2504+ * it under the terms of the GNU Lesser General Public License version 3 as
2505+ * published by the Free Software Foundation.
2506+ *
2507+ * This program is distributed in the hope that it will be useful,
2508+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2509+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2510+ * GNU Lesser General Public License for more details.
2511+ *
2512+ * You should have received a copy of the GNU Lesser General Public License
2513+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2514+ *
2515+ * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com>
2516+*/
2517+
2518+#include <unity/scopes/ValueSliderLabels.h>
2519+#include <unity/scopes/internal/ValueSliderLabelsImpl.h>
2520+
2521+namespace unity
2522+{
2523+
2524+namespace scopes
2525+{
2526+
2527+ValueSliderLabels::ValueSliderLabels(internal::ValueSliderLabelsImpl* pimpl)
2528+ : p(pimpl)
2529+{
2530+}
2531+
2532+ValueSliderLabels::ValueSliderLabels(std::string const& min_label, std::string const& max_label)
2533+ : p(new internal::ValueSliderLabelsImpl(min_label, max_label))
2534+{
2535+}
2536+
2537+ValueSliderLabels::ValueSliderLabels(std::string const& min_label, std::string const& max_label, ValueLabelPairList const& extra_labels)
2538+ : p(new internal::ValueSliderLabelsImpl(min_label, max_label, extra_labels))
2539+{
2540+}
2541+
2542+ValueSliderLabels::ValueSliderLabels(VariantMap const& var)
2543+ : p(new internal::ValueSliderLabelsImpl(var))
2544+{
2545+}
2546+
2547+ValueSliderLabels::ValueSliderLabels(ValueSliderLabels const& other)
2548+ : p(new internal::ValueSliderLabelsImpl(*(other.p)))
2549+{
2550+}
2551+
2552+ValueSliderLabels& ValueSliderLabels::operator=(ValueSliderLabels const& other)
2553+{
2554+ if (this != &other)
2555+ {
2556+ p.reset(new internal::ValueSliderLabelsImpl(*(other.p)));
2557+ }
2558+ return *this;
2559+}
2560+
2561+ValueSliderLabels::ValueSliderLabels(ValueSliderLabels&&) = default;
2562+ValueSliderLabels& ValueSliderLabels::operator=(ValueSliderLabels&&) = default;
2563+
2564+ValueSliderLabels::~ValueSliderLabels() = default;
2565+
2566+std::string ValueSliderLabels::min_label() const
2567+{
2568+ return p->min_label();
2569+}
2570+
2571+std::string ValueSliderLabels::max_label() const
2572+{
2573+ return p->max_label();
2574+}
2575+
2576+ValueLabelPairList ValueSliderLabels::extra_labels() const
2577+{
2578+ return p->extra_labels();
2579+}
2580+
2581+VariantMap ValueSliderLabels::serialize() const
2582+{
2583+ return p->serialize();
2584+}
2585+
2586+}
2587+
2588+}
2589
2590=== modified file 'src/scopes/internal/ActivationQueryObject.cpp'
2591--- src/scopes/internal/ActivationQueryObject.cpp 2015-01-21 23:35:22 +0000
2592+++ src/scopes/internal/ActivationQueryObject.cpp 2016-03-04 15:54:04 +0000
2593@@ -71,13 +71,13 @@
2594 }
2595 catch (std::exception const& e)
2596 {
2597- BOOST_LOG(info.mw->runtime()->logger()) << "ActivationQueryBase::activate(): " << e.what();
2598+ info.mw->runtime()->logger()() << "ActivationQueryBase::activate(): " << e.what();
2599 reply_->finished(CompletionDetails(CompletionDetails::Error,
2600 string("ActivationQueryBase::activate(): ") + e.what()));
2601 }
2602 catch (...)
2603 {
2604- BOOST_LOG(info.mw->runtime()->logger()) << "ActivationQueryBase::activate(): unknown exception";
2605+ info.mw->runtime()->logger()() << "ActivationQueryBase::activate(): unknown exception";
2606 reply_->finished(CompletionDetails(CompletionDetails::Error,
2607 "ActivationQueryBase::activate(): unknown exception"));
2608 }
2609
2610=== modified file 'src/scopes/internal/CMakeLists.txt'
2611--- src/scopes/internal/CMakeLists.txt 2015-03-27 17:18:09 +0000
2612+++ src/scopes/internal/CMakeLists.txt 2016-03-04 15:54:04 +0000
2613@@ -25,6 +25,7 @@
2614 ${CMAKE_CURRENT_SOURCE_DIR}/DynamicLoader.cpp
2615 ${CMAKE_CURRENT_SOURCE_DIR}/Executor.cpp
2616 ${CMAKE_CURRENT_SOURCE_DIR}/FilterBaseImpl.cpp
2617+ ${CMAKE_CURRENT_SOURCE_DIR}/FilterGroupImpl.cpp
2618 ${CMAKE_CURRENT_SOURCE_DIR}/FilterOptionImpl.cpp
2619 ${CMAKE_CURRENT_SOURCE_DIR}/FilterStateImpl.cpp
2620 ${CMAKE_CURRENT_SOURCE_DIR}/IniSettingsSchema.cpp
2621@@ -89,6 +90,7 @@
2622 ${CMAKE_CURRENT_SOURCE_DIR}/UniqueID.cpp
2623 ${CMAKE_CURRENT_SOURCE_DIR}/Utils.cpp
2624 ${CMAKE_CURRENT_SOURCE_DIR}/ValueSliderFilterImpl.cpp
2625+ ${CMAKE_CURRENT_SOURCE_DIR}/ValueSliderLabelsImpl.cpp
2626 ${CMAKE_CURRENT_SOURCE_DIR}/VariantBuilderImpl.cpp
2627 )
2628 set(UNITY_SCOPES_LIB_SRC ${UNITY_SCOPES_LIB_SRC} ${SRC} PARENT_SCOPE)
2629
2630=== modified file 'src/scopes/internal/ChildScopesRepository.cpp'
2631--- src/scopes/internal/ChildScopesRepository.cpp 2015-04-01 11:28:32 +0000
2632+++ src/scopes/internal/ChildScopesRepository.cpp 2016-03-04 15:54:04 +0000
2633@@ -19,6 +19,7 @@
2634 #include <unity/scopes/internal/ChildScopesRepository.h>
2635 #include <unity/scopes/internal/JsonCppNode.h>
2636
2637+#include <cassert>
2638 #include <fstream>
2639 #include <set>
2640 #include <sstream>
2641@@ -26,8 +27,7 @@
2642 using namespace unity::scopes;
2643 using namespace unity::scopes::internal;
2644
2645-ChildScopesRepository::ChildScopesRepository(std::string const& repo_file_path,
2646- boost::log::sources::severity_channel_logger_mt<>& logger)
2647+ChildScopesRepository::ChildScopesRepository(std::string const& repo_file_path, Logger& logger)
2648 : repo_file_path_(repo_file_path)
2649 , logger_(logger)
2650 , have_latest_cache_(false)
2651@@ -79,9 +79,7 @@
2652 std::ofstream repo_file(repo_file_path_);
2653 if (repo_file.fail())
2654 {
2655- BOOST_LOG_SEV(logger_, Logger::Error) << "ChildScopesRepository::write_repo(): "
2656- << "Failed to open file: \"" << repo_file_path_
2657- << "\"";
2658+ logger_() << "ChildScopesRepository::write_repo(): Failed to open file: \"" << repo_file_path_ << "\"";
2659 return false;
2660 }
2661
2662@@ -104,9 +102,8 @@
2663 std::ifstream repo_file(repo_file_path_);
2664 if (repo_file.fail())
2665 {
2666- BOOST_LOG_SEV(logger_, Logger::Info) << "ChildScopesRepository::read_repo(): "
2667- << "Failed to open file: \"" << repo_file_path_
2668- << "\"";
2669+ logger_(LoggerSeverity::Info) << "ChildScopesRepository::read_repo(): "
2670+ << "Failed to open file: \"" << repo_file_path_ << "\"";
2671 return ChildScopeEnabledMap();
2672 }
2673
2674@@ -143,16 +140,13 @@
2675 }
2676 catch (std::exception const& e)
2677 {
2678- BOOST_LOG_SEV(logger_, Logger::Error) << "ChildScopesRepository::json_to_list(): "
2679- << "Exception thrown while reading json string: "
2680- << e.what();
2681+ logger_() << "ChildScopesRepository::json_to_list(): Exception thrown while reading json string: " << e.what();
2682 return ChildScopeEnabledMap();
2683 }
2684 if (json_node.type() != JsonCppNode::Array)
2685 {
2686- BOOST_LOG_SEV(logger_, Logger::Error) << "ChildScopesRepository::json_to_list(): "
2687- << "Root node of json string is not an array:"
2688- << std::endl << child_scopes_json;
2689+ logger_() << "ChildScopesRepository::json_to_list(): Root node of json string is not an array:"
2690+ << std::endl << child_scopes_json;
2691 return ChildScopeEnabledMap();
2692 }
2693
2694@@ -164,10 +158,8 @@
2695 if (!child_node->has_node("id") ||
2696 !child_node->has_node("enabled"))
2697 {
2698- BOOST_LOG_SEV(logger_, Logger::Error) << "ChildScopesRepository::json_to_list(): "
2699- << "Child node is missing a required field. "
2700- << "Skipping child node:" << std::endl
2701- << child_node->to_json_string();
2702+ logger_() << "ChildScopesRepository::json_to_list(): Child node is missing a required field. "
2703+ << "Skipping child node:" << std::endl << child_node->to_json_string();
2704 continue;
2705 }
2706 auto id_node = child_node->get_node("id");
2707@@ -176,10 +168,9 @@
2708 if (id_node->type() != JsonCppNode::String ||
2709 enabled_node->type() != JsonCppNode::Bool)
2710 {
2711- BOOST_LOG_SEV(logger_, Logger::Error) << "ChildScopesRepository::json_to_list(): "
2712- << "Child node contains an invalid value type. "
2713- << "Skipping child node:" << std::endl
2714- << child_node->to_json_string();
2715+ logger_() << "ChildScopesRepository::json_to_list(): "
2716+ << "Child node contains an invalid value type. Skipping child node:"
2717+ << std::endl << child_node->to_json_string();
2718 continue;
2719 }
2720
2721
2722=== modified file 'src/scopes/internal/FilterBaseImpl.cpp'
2723--- src/scopes/internal/FilterBaseImpl.cpp 2015-03-30 15:59:08 +0000
2724+++ src/scopes/internal/FilterBaseImpl.cpp 2016-03-04 15:54:04 +0000
2725@@ -54,6 +54,12 @@
2726 {
2727 auto it = find_or_throw("FilterBase()", var, "id");
2728 id_ = it->second.get_string();
2729+ it = var.find("title");
2730+ if (it != var.end())
2731+ {
2732+ title_ = it->second.get_string();
2733+ }
2734+
2735 it = var.find("display_hints");
2736 if (it != var.end())
2737 {
2738@@ -75,6 +81,23 @@
2739
2740 FilterBaseImpl::~FilterBaseImpl() = default;
2741
2742+void FilterBaseImpl::add_to_filter_group(FilterGroup::SCPtr const& group)
2743+{
2744+ // Filter can only belong to one group. The API guarantees this by only allowing group to be passed at Filter's construction time,
2745+ // so this assert should never be reached.
2746+ assert(filter_group_ == nullptr);
2747+ if (!group)
2748+ {
2749+ throw unity::InvalidArgumentException("FilterBaseImpl::add_to_filter_group(): invalid null group");
2750+ }
2751+ filter_group_ = group;
2752+}
2753+
2754+FilterGroup::SCPtr FilterBaseImpl::filter_group() const
2755+{
2756+ return filter_group_;
2757+}
2758+
2759 void FilterBaseImpl::set_display_hints(int hints)
2760 {
2761 // note: make sure all_flags is updated whenever new values are added to the DisplayHints enum
2762@@ -98,15 +121,33 @@
2763 return display_hints_;
2764 }
2765
2766+void FilterBaseImpl::set_title(std::string const& title)
2767+{
2768+ title_ = title;
2769+}
2770+
2771+std::string FilterBaseImpl::title() const
2772+{
2773+ return title_;
2774+}
2775+
2776 VariantMap FilterBaseImpl::serialize() const
2777 {
2778 VariantMap vm;
2779 vm["id"] = id_;
2780+ if (title_.size() > 0)
2781+ {
2782+ vm["title"] = title_;
2783+ }
2784 if (display_hints_ != FilterBase::DisplayHints::Default)
2785 {
2786 vm["display_hints"] = static_cast<int>(display_hints_);
2787 }
2788 vm["filter_type"] = filter_type();
2789+ if (filter_group_)
2790+ {
2791+ vm["filter_group"] = filter_group_->id();
2792+ }
2793 serialize(vm);
2794 return vm;
2795 }
2796@@ -170,12 +211,28 @@
2797 return var;
2798 }
2799
2800-Filters FilterBaseImpl::deserialize_filters(VariantArray const& var)
2801+Filters FilterBaseImpl::deserialize_filters(VariantArray const& var, std::map<std::string, FilterGroup::SCPtr> const& groups)
2802 {
2803 Filters filters;
2804 for (auto const& f: var)
2805 {
2806- filters.push_back(FilterBaseImpl::deserialize(f.get_dict()));
2807+ auto const data = f.get_dict();
2808+ auto filter = FilterBaseImpl::deserialize(data);
2809+ auto grit = data.find("filter_group");
2810+ if (grit != data.end())
2811+ {
2812+ auto const group_id = grit->second.get_string();
2813+ auto it = groups.find(group_id);
2814+ if (it != groups.end())
2815+ {
2816+ filter->p->add_to_filter_group(it->second);
2817+ }
2818+ else
2819+ {
2820+ throw unity::LogicException("FilterBaseImpl::deserialize_filters(): Invalid group '" + group_id + "' for filter '" + filter->id() + "'");
2821+ }
2822+ }
2823+ filters.push_back(filter);
2824 }
2825 return filters;
2826 }
2827
2828=== added file 'src/scopes/internal/FilterGroupImpl.cpp'
2829--- src/scopes/internal/FilterGroupImpl.cpp 1970-01-01 00:00:00 +0000
2830+++ src/scopes/internal/FilterGroupImpl.cpp 2016-03-04 15:54:04 +0000
2831@@ -0,0 +1,97 @@
2832+/*
2833+ * Copyright (C) 2016 Canonical Ltd
2834+ *
2835+ * This program is free software: you can redistribute it and/or modify
2836+ * it under the terms of the GNU Lesser General Public License version 3 as
2837+ * published by the Free Software Foundation.
2838+ *
2839+ * This program is distributed in the hope that it will be useful,
2840+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2841+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2842+ * GNU Lesser General Public License for more details.
2843+ *
2844+ * You should have received a copy of the GNU Lesser General Public License
2845+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2846+ *
2847+ * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com>
2848+*/
2849+
2850+#include <unity/scopes/internal/FilterGroupImpl.h>
2851+#include <unity/UnityExceptions.h>
2852+#include <unity/scopes/FilterState.h>
2853+#include <unity/scopes/internal/Utils.h>
2854+
2855+namespace unity
2856+{
2857+
2858+namespace scopes
2859+{
2860+
2861+namespace internal
2862+{
2863+
2864+FilterGroupImpl::FilterGroupImpl(std::string const& id, std::string const& label)
2865+ : id_(id),
2866+ label_(label)
2867+{
2868+}
2869+
2870+std::string FilterGroupImpl::id() const
2871+{
2872+ return id_;
2873+}
2874+
2875+std::string FilterGroupImpl::label() const
2876+{
2877+ return label_;
2878+}
2879+
2880+VariantArray FilterGroupImpl::serialize_filter_groups(Filters const& filters)
2881+{
2882+ std::map<std::string, FilterGroup::SCPtr> group_lookup;
2883+ VariantArray va;
2884+ for (auto const& filter: filters)
2885+ {
2886+ auto grp = filter->filter_group();
2887+ if (grp)
2888+ {
2889+ auto it = group_lookup.find(grp->id());
2890+ if (it == group_lookup.end())
2891+ {
2892+ group_lookup[grp->id()] = grp;
2893+ VariantMap grpvar;
2894+ grpvar["id"] = grp->id();
2895+ grpvar["label"] = grp->label();
2896+ va.push_back(Variant(grpvar));
2897+ }
2898+ else
2899+ {
2900+ if (it->second != grp)
2901+ {
2902+ throw unity::LogicException("FilterGroupImpl::serialize_filter_groups(): duplicate FilterGroup definitions for group id '" + grp->id() + "'");
2903+ }
2904+ }
2905+ }
2906+ }
2907+ return va;
2908+}
2909+
2910+std::map<std::string, FilterGroup::SCPtr> FilterGroupImpl::deserialize_filter_groups(VariantArray const& var)
2911+{
2912+ std::map<std::string, FilterGroup::SCPtr> groups;
2913+ for (auto it = var.begin(); it != var.end(); it++)
2914+ {
2915+ auto const grvar = it->get_dict();
2916+ auto const id = find_or_throw("FilterGroup::deserialize_filter_groups", grvar, "id")->second.get_string();
2917+ auto const label = find_or_throw("FilterGroup::deserialize_filter_groups", grvar, "label")->second.get_string();
2918+ auto group = FilterGroup::create(id, label);
2919+ groups[id] = group;
2920+ }
2921+ return groups;
2922+}
2923+
2924+} // namespace internal
2925+
2926+} // namespace scopes
2927+
2928+} // namespace unity
2929
2930=== modified file 'src/scopes/internal/FilterOptionImpl.cpp'
2931--- src/scopes/internal/FilterOptionImpl.cpp 2014-05-15 03:23:43 +0000
2932+++ src/scopes/internal/FilterOptionImpl.cpp 2016-03-04 15:54:04 +0000
2933@@ -31,7 +31,8 @@
2934
2935 FilterOptionImpl::FilterOptionImpl(std::string const& id, std::string const& label)
2936 : id_(id),
2937- label_(label)
2938+ label_(label),
2939+ default_value_(false)
2940 {
2941 if (id_.empty())
2942 {
2943@@ -53,6 +54,16 @@
2944 return label_;
2945 }
2946
2947+void FilterOptionImpl::set_default_value(bool default_value)
2948+{
2949+ default_value_ = default_value;
2950+}
2951+
2952+bool FilterOptionImpl::default_value() const
2953+{
2954+ return default_value_;
2955+}
2956+
2957 } // namespace internal
2958
2959 } // namespace scopes
2960
2961=== modified file 'src/scopes/internal/Logger.cpp'
2962--- src/scopes/internal/Logger.cpp 2015-03-02 13:18:28 +0000
2963+++ src/scopes/internal/Logger.cpp 2016-03-04 15:54:04 +0000
2964@@ -18,33 +18,14 @@
2965
2966 #include <unity/scopes/internal/Logger.h>
2967
2968-#include <boost/log/attributes.hpp>
2969-#include <boost/log/core.hpp>
2970-#include <boost/log/expressions.hpp>
2971-#include <boost/log/sources/record_ostream.hpp>
2972-#include <boost/log/support/date_time.hpp>
2973-#include <boost/log/trivial.hpp>
2974-#include <boost/phoenix/bind.hpp>
2975-
2976-#if (BOOST_VERSION / 100000 == 1) && (((BOOST_VERSION / 100) % 1000) < 56)
2977-#include <boost/utility/empty_deleter.hpp>
2978-typedef boost::empty_deleter NullDeleter;
2979-#else
2980-#include <boost/core/null_deleter.hpp>
2981-typedef boost::null_deleter NullDeleter;
2982-#endif
2983-
2984 #include <unity/UnityExceptions.h>
2985
2986+#include <cassert>
2987+#include <chrono>
2988+#include <iomanip>
2989+
2990 using namespace std;
2991
2992-namespace logging = boost::log;
2993-namespace sinks = boost::log::sinks;
2994-namespace src = boost::log::sources;
2995-namespace attrs = boost::log::attributes;
2996-namespace expr = boost::log::expressions;
2997-namespace keywords = boost::log::keywords;
2998-
2999 namespace unity
3000 {
3001
3002@@ -57,214 +38,158 @@
3003 namespace
3004 {
3005
3006-static array<string, Logger::LastChannelEnum_> const channel_names = {{"IPC"}};
3007+static array<string, 5> const severities = {{"INFO", "WARNING", "ERROR", "FATAL", "TRACE"}};
3008
3009-string const& to_severity(int s)
3010+static array<pair<string, LoggerChannel>, int(LoggerChannel::LastChannelEnum_)> const channel_names =
3011 {
3012- static array<string, 5> const severities = {{"INFO", "WARNING", "ERROR", "FATAL", "TRACE"}};
3013- static string const unknown = "UNKNOWN";
3014+ pair<string, LoggerChannel>{"", LoggerChannel::DefaultChannel},
3015+ pair<string, LoggerChannel>{"IPC", LoggerChannel::IPC}
3016+};
3017
3018- if (s < 0 || s >= static_cast<int>(severities.size()))
3019- {
3020- return unknown;
3021- }
3022- return severities[s];
3023-}
3024-}
3025+} // namespace
3026
3027 // Instantiate a logger for the scope/client with the given ID.
3028
3029-Logger::Logger(string const& scope_id)
3030- : scope_id_(scope_id)
3031- , logger_(keywords::severity = Logger::Error)
3032- , severity_(Logger::Info)
3033-{
3034- namespace ph = std::placeholders;
3035-
3036- assert(!scope_id_.empty());
3037-
3038- logger_.add_attribute("TimeStamp", attrs::local_clock());
3039-
3040- // Create a channel logger for each channel.
3041- for (auto&& name : channel_names)
3042- {
3043- auto clogger = boost::log::sources::severity_channel_logger_mt<>(keywords::severity = Logger::Trace,
3044- keywords::channel = name);
3045- clogger.add_attribute("TimeStamp", attrs::local_clock());
3046- channel_loggers_[name] = make_pair(clogger, false);
3047- }
3048-
3049- // Set up sink that logs to std::clog.
3050- clog_sink_ = boost::make_shared<ClogSinkT>();
3051- clog_sink_->set_formatter(bind(&Logger::formatter, this, ph::_1, ph::_2));
3052- boost::shared_ptr<std::ostream> console_stream(&std::clog, NullDeleter());
3053- clog_sink_->locked_backend()->add_stream(console_stream);
3054- clog_sink_->locked_backend()->auto_flush(true);
3055- logging::core::get()->add_sink(clog_sink_);
3056-
3057- set_severity_threshold(severity_);
3058-}
3059-
3060-Logger::~Logger()
3061-{
3062- lock_guard<mutex> lock(mutex_);
3063-
3064- if (clog_sink_)
3065- {
3066- logging::core::get()->remove_sink(clog_sink_);
3067- clog_sink_->stop();
3068- clog_sink_->flush();
3069- }
3070- else
3071- {
3072- logging::core::get()->remove_sink(file_sink_);
3073- file_sink_->stop();
3074- file_sink_->flush();
3075- }
3076-}
3077-
3078-Logger::operator boost::log::sources::severity_channel_logger_mt<>&()
3079-{
3080- return logger_; // No lock needed, immutable
3081-}
3082-
3083-src::severity_channel_logger_mt<>& Logger::operator()(Channel c)
3084-{
3085- // No lock needed: channel_loggers_ is immutable, and the boolean is atomic.
3086- return channel_loggers_[channel_names[c]].first;
3087-}
3088-
3089-bool Logger::set_channel(Channel c, bool enable)
3090-{
3091- auto it = channel_loggers_.find(channel_names[c]);
3092- assert(it != channel_loggers_.end());
3093- bool was_enabled = it->second.second.exchange(enable);
3094- return was_enabled;
3095+Logger::Logger(string const& id, ostream& outstream)
3096+ : id_(id)
3097+ , outstream_(outstream)
3098+ , severity_threshold_(LoggerSeverity::Info) // By default, log all severities
3099+{
3100+ // Channels are disabled by default.
3101+ for (auto& e : enabled_)
3102+ {
3103+ e = false;
3104+ }
3105+ // Except for the default channel.
3106+ enabled_[0] = true;
3107+}
3108+
3109+// Default writes to the default channel at severity Error.
3110+
3111+LogStream Logger::operator()()
3112+{
3113+ if (LoggerSeverity::Error >= severity_threshold_)
3114+ {
3115+ return LogStream(outstream_, id_, LoggerSeverity::Error, LoggerChannel::DefaultChannel);
3116+ }
3117+ return LogStream(); // Null writer
3118+}
3119+
3120+LogStream Logger::operator()(LoggerSeverity s)
3121+{
3122+ if (s >= severity_threshold_)
3123+ {
3124+ return LogStream(outstream_, id_, s, LoggerChannel::DefaultChannel);
3125+ }
3126+ return LogStream(); // Null writer
3127+}
3128+
3129+LogStream Logger::operator()(LoggerChannel c)
3130+{
3131+ if (enabled_[int(c)])
3132+ {
3133+ return LogStream(outstream_, id_, LoggerSeverity::Trace, c);
3134+ }
3135+ return LogStream(); // Null writer
3136+}
3137+
3138+bool Logger::set_channel(LoggerChannel c, bool enable)
3139+{
3140+ return enabled_[int(c)].exchange(enable);
3141 }
3142
3143 bool Logger::set_channel(string channel_name, bool enable)
3144 {
3145- auto it = channel_loggers_.find(channel_name);
3146- if (it == channel_loggers_.end())
3147- {
3148- throw InvalidArgumentException("Logger::set_channel(): invalid channel name: " + channel_name);
3149- }
3150- bool was_enabled = it->second.second.exchange(enable);
3151- return was_enabled;
3152-}
3153-
3154-void Logger::enable_channels(vector<string> const& names)
3155-{
3156- exception_ptr ep;
3157- for (auto&& name : names)
3158- {
3159- try
3160- {
3161- set_channel(name, true);
3162- }
3163- catch (InvalidArgumentException& e)
3164- {
3165- ep = ep ? make_exception_ptr(current_exception()) : e.remember(ep);
3166- }
3167- }
3168- if (ep)
3169- {
3170- rethrow_exception(ep);
3171- }
3172-}
3173-
3174-void Logger::set_log_file(string const& path, int rotation_size, int dir_size)
3175-{
3176- namespace ph = std::placeholders;
3177-
3178- FileSinkPtr s =
3179- boost::make_shared<FileSinkT>(keywords::file_name = path + "-%N.log", keywords::rotation_size = rotation_size);
3180-
3181- string parent = boost::filesystem::path(path).parent_path().native();
3182- s->locked_backend()->set_file_collector(sinks::file::make_collector(
3183- keywords::target = parent, keywords::max_size = dir_size, keywords::min_free_space = 1024 * 1024 * 5));
3184- try
3185- {
3186- s->locked_backend()->scan_for_files();
3187- }
3188- catch (std::exception const& e)
3189- {
3190- BOOST_LOG_SEV(logger_, Warning) << "RuntimeImpl::Logger(): log rotation failed (path = " << parent
3191- << "): " << e.what();
3192- return;
3193- }
3194- catch (...)
3195- {
3196- BOOST_LOG_SEV(logger_, Warning) << "RuntimeImpl::Logger(): log rotation failed (path = " << parent
3197- << "): unknown exception";
3198- return;
3199- }
3200-
3201- {
3202- lock_guard<mutex> lock(mutex_);
3203-
3204- if (clog_sink_)
3205- {
3206- logging::core::get()->remove_sink(clog_sink_);
3207- clog_sink_ = nullptr;
3208- }
3209- else
3210- {
3211- logging::core::get()->remove_sink(file_sink_);
3212- }
3213-
3214- file_sink_ = s;
3215- file_sink_->locked_backend()->auto_flush(true);
3216- file_sink_->set_formatter(bind(&Logger::formatter, this, ph::_1, ph::_2));
3217- logging::core::get()->add_sink(file_sink_);
3218- }
3219- set_severity_threshold(severity_);
3220-}
3221-
3222-Logger::Severity Logger::set_severity_threshold(Logger::Severity s)
3223-{
3224- auto old_s = severity_.exchange(s);
3225-
3226- lock_guard<mutex> lock(mutex_);
3227-
3228- auto filter = boost::phoenix::bind(&Logger::filter, this, severity.or_none(), channel.or_none());
3229- if (clog_sink_)
3230- {
3231- clog_sink_->set_filter(filter);
3232- }
3233- else
3234- {
3235- file_sink_->set_filter(filter);
3236- }
3237-
3238- return old_s;
3239-}
3240-
3241-bool Logger::filter(logging::value_ref<int, tag::severity> const& level,
3242- logging::value_ref<string, tag::channel> const& channel)
3243-{
3244- if (level.get() < static_cast<int>(severity_)) // atomic
3245- {
3246- return false;
3247- }
3248- if (channel.get().empty())
3249- {
3250- return true;
3251- }
3252- // No lock needed: channel_loggers_ is immutable, and the boolean is atomic.
3253- auto it = channel_loggers_.find(channel.get());
3254- assert(it != channel_loggers_.end());
3255- return it->second.second;
3256-}
3257-
3258-void Logger::formatter(logging::record_view const& rec, logging::formatting_ostream& strm)
3259-{
3260- string channel = expr::attr<string>("Channel")(rec).get();
3261-
3262- string prefix = channel.empty() ? to_severity(expr::attr<int>("Severity")(rec).get()) : channel;
3263-
3264- strm << "[" << expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d %H:%M:%S.%f")(rec) << "] "
3265- << prefix << ": " << scope_id_ << ": " << rec[expr::smessage];
3266+ for (auto const& p : channel_names)
3267+ {
3268+ if (!p.first.empty() && channel_name == p.first)
3269+ {
3270+ return set_channel(p.second, enable);
3271+ }
3272+ }
3273+ throw InvalidArgumentException("Logger::set_channel(): invalid channel name: \"" + channel_name + "\"");
3274+}
3275+
3276+LoggerSeverity Logger::set_severity_threshold(LoggerSeverity s)
3277+{
3278+ return severity_threshold_.exchange(s);
3279+}
3280+
3281+namespace
3282+{
3283+
3284+// Null streambuf implementation that always reports success.
3285+// This allows the operator<<() functions to inject into a stream without
3286+// having to check in each function whether we actually want to log something.
3287+
3288+template <class cT, class traits = std::char_traits<cT>>
3289+class NullBuf : public std::basic_streambuf<cT, traits>
3290+{
3291+ typename traits::int_type overflow(typename traits::int_type c)
3292+ {
3293+ return traits::not_eof(c); // Indicate success
3294+ }
3295+};
3296+
3297+static string const null_id;
3298+static NullBuf<char> null_buf;
3299+static ostream null_stream(&null_buf);
3300+
3301+} // namespace
3302+
3303+LogStream::LogStream() // Doesn't log anything
3304+ : id_(null_id)
3305+ , outstream_(null_stream)
3306+ , severity_(static_cast<LoggerSeverity>(0))
3307+ , channel_(static_cast<LoggerChannel>(0))
3308+{
3309+}
3310+
3311+LogStream::LogStream(ostream& outstream, string const& id, LoggerSeverity s, LoggerChannel c)
3312+ : id_(id)
3313+ , outstream_(outstream)
3314+ , severity_(s)
3315+ , channel_(c)
3316+{
3317+}
3318+
3319+namespace
3320+{
3321+
3322+string get_time()
3323+{
3324+ auto now = chrono::system_clock::now();
3325+ auto curr_t = chrono::system_clock::to_time_t(now);
3326+ auto millisecs = chrono::duration_cast<chrono::milliseconds>(now.time_since_epoch()).count() % 1000;
3327+
3328+ struct tm result;
3329+ localtime_r(&curr_t, &result);
3330+
3331+ // Should use std::put_time(&result, "%F %T') here, but gcc 4.9 doesn't provide it.
3332+ char buf[]{"yyyy-mm-dd hh:mm:ss"};
3333+ strftime(buf, sizeof(buf), "%F %T", &result);
3334+ stringstream s;
3335+ s << buf << "." << setw(3) << setfill('0') << millisecs;
3336+ return s.str();
3337+}
3338+
3339+} // namespace
3340+
3341+LogStream::~LogStream()
3342+{
3343+ string msg = str();
3344+ if (msg.empty())
3345+ {
3346+ return;
3347+ }
3348+ // Something was logged. Accumulate all the details in an output string.
3349+ string prefix = channel_ != LoggerChannel::DefaultChannel
3350+ ? channel_names[int(channel_)].first
3351+ : severities[int(severity_)];
3352+ string output = "[" + get_time() + "] " + prefix + ": " + id_ + ": " + msg + "\n";
3353+
3354+ // Write contents with a single insertion to avoid interleaving of messages from different threads.
3355+ outstream_ << output;
3356 }
3357
3358 } // namespace internal
3359
3360=== modified file 'src/scopes/internal/OptionSelectorFilterImpl.cpp'
3361--- src/scopes/internal/OptionSelectorFilterImpl.cpp 2015-11-12 14:20:36 +0000
3362+++ src/scopes/internal/OptionSelectorFilterImpl.cpp 2016-03-04 15:54:04 +0000
3363@@ -17,6 +17,7 @@
3364 */
3365
3366 #include <unity/scopes/internal/OptionSelectorFilterImpl.h>
3367+#include <unity/scopes/internal/FilterOptionImpl.h>
3368 #include <unity/scopes/FilterState.h>
3369 #include <unity/scopes/ScopeExceptions.h>
3370 #include <unity/UnityExceptions.h>
3371@@ -75,6 +76,10 @@
3372 VariantMap vm;
3373 vm["id"] = opt->id();
3374 vm["label"] = opt->label();
3375+ if (opt->default_value())
3376+ {
3377+ vm["default"] = Variant(true);
3378+ }
3379 ops.push_back(Variant(vm));
3380 }
3381 var["label"] = label_;
3382@@ -111,7 +116,14 @@
3383 auto opt_id = it->second.get_string();
3384 it = optvar.find("label");
3385 throw_on_missing(it, optvar.end(), "option label");
3386- add_option(opt_id, it->second.get_string());
3387+ auto const label = it->second.get_string();
3388+ bool default_val = false;
3389+ it = optvar.find("default");
3390+ if (it != optvar.end() && it->second.get_bool())
3391+ {
3392+ default_val = true;
3393+ }
3394+ add_option(opt_id, label, default_val);
3395 }
3396 }
3397
3398@@ -120,18 +132,23 @@
3399 return "option_selector";
3400 }
3401
3402-FilterOption::SCPtr OptionSelectorFilterImpl::add_option(std::string const& id, std::string const& label)
3403+FilterOption::SCPtr OptionSelectorFilterImpl::add_option(std::string const& id, std::string const& label, bool default_value)
3404 {
3405- try
3406- {
3407- auto opt = std::shared_ptr<FilterOption>(new FilterOption(id, label));
3408- options_.push_back(opt);
3409- return opt;
3410- }
3411- catch (...)
3412- {
3413- throw ResourceException("OptionSelectorFilter(): cannot create FilterOption");
3414- }
3415+ auto opt = std::shared_ptr<FilterOption>(new FilterOption(id, label));
3416+ // if it's not a multi-selection filter, then there can only be a single option selected by default
3417+ if (default_value && !multi_select_)
3418+ {
3419+ for (auto const& o: options_)
3420+ {
3421+ if (o->default_value())
3422+ {
3423+ throw unity::LogicException("OptionSelectorFilter::add_option(): only one option with default value 'true' allowed for a single-selection OptionSelectorFilter");
3424+ }
3425+ }
3426+ }
3427+ opt->p->set_default_value(default_value);
3428+ options_.push_back(opt);
3429+ return opt;
3430 }
3431
3432 int OptionSelectorFilterImpl::num_of_options() const
3433
3434=== modified file 'src/scopes/internal/PreviewQueryObject.cpp'
3435--- src/scopes/internal/PreviewQueryObject.cpp 2015-01-20 02:14:29 +0000
3436+++ src/scopes/internal/PreviewQueryObject.cpp 2016-03-04 15:54:04 +0000
3437@@ -94,7 +94,7 @@
3438 lock_guard<mutex> lock(mutex_);
3439 pushable_ = false;
3440 }
3441- BOOST_LOG(info.mw->runtime()->logger()) << "PreviewQueryBase::run(): " << e.what();
3442+ info.mw->runtime()->logger()() << "PreviewQueryBase::run(): " << e.what();
3443 reply_->finished(CompletionDetails(CompletionDetails::Error, string("PreviewQueryBase::run(): ") + e.what()));
3444 }
3445 catch (...)
3446@@ -103,7 +103,7 @@
3447 lock_guard<mutex> lock(mutex_);
3448 pushable_ = false;
3449 }
3450- BOOST_LOG(info.mw->runtime()->logger()) << "PreviewQueryBase::run(): unknown exception";
3451+ info.mw->runtime()->logger()() << "PreviewQueryBase::run(): unknown exception";
3452 reply_->finished(CompletionDetails(CompletionDetails::Error, "PreviewQueryBase::run(): unknown exception"));
3453 }
3454 }
3455
3456=== modified file 'src/scopes/internal/QueryCtrlImpl.cpp'
3457--- src/scopes/internal/QueryCtrlImpl.cpp 2015-01-26 08:20:45 +0000
3458+++ src/scopes/internal/QueryCtrlImpl.cpp 2016-03-04 15:54:04 +0000
3459@@ -78,7 +78,7 @@
3460 }
3461 catch (std::exception const& e)
3462 {
3463- BOOST_LOG(reply_proxy_->mw_base()->runtime()->logger()) << e.what();
3464+ reply_proxy_->mw_base()->runtime()->logger()() << e.what();
3465 }
3466 }
3467
3468
3469=== modified file 'src/scopes/internal/QueryObject.cpp'
3470--- src/scopes/internal/QueryObject.cpp 2015-04-10 10:00:19 +0000
3471+++ src/scopes/internal/QueryObject.cpp 2016-03-04 15:54:04 +0000
3472@@ -128,7 +128,7 @@
3473 lock_guard<mutex> lock(mutex_);
3474 pushable_ = false;
3475 }
3476- BOOST_LOG(info.mw->runtime()->logger()) << "QueryBase::run(): " << e.what();
3477+ info.mw->runtime()->logger()() << "QueryBase::run(): " << e.what();
3478 reply_->finished(CompletionDetails(CompletionDetails::Error, string("QueryBase::run(): ") + e.what()));
3479 }
3480 catch (...)
3481@@ -137,7 +137,7 @@
3482 lock_guard<mutex> lock(mutex_);
3483 pushable_ = false;
3484 }
3485- BOOST_LOG(info.mw->runtime()->logger()) << "QueryBase::run(): unknown exception";
3486+ info.mw->runtime()->logger()() << "QueryBase::run(): unknown exception";
3487 reply_->finished(CompletionDetails(CompletionDetails::Error, "QueryBase::run(): unknown exception"));
3488 }
3489 }
3490@@ -171,7 +171,7 @@
3491 }
3492 catch (std::exception const& e)
3493 {
3494- BOOST_LOG(info.mw->runtime()->logger()) << "QueryBase::cancelled(): " << e.what();
3495+ info.mw->runtime()->logger()() << "QueryBase::cancelled(): " << e.what();
3496 // Deliberately no error completion here. On the client side, we short-cut the cancelled()
3497 // callback locally, which unregisters the servant for the cancel message and assumes that
3498 // cancellation will work, passing a Cancelled status, even if cancellation throws in the scope.
3499@@ -182,7 +182,7 @@
3500 }
3501 catch (...)
3502 {
3503- BOOST_LOG(info.mw->runtime()->logger()) << "QueryBase::cancelled(): unknown exception";
3504+ info.mw->runtime()->logger()() << "QueryBase::cancelled(): unknown exception";
3505 // Same caveat as for std::exception here.
3506 reply_->finished(CompletionDetails(CompletionDetails::Cancelled, ""));
3507 }
3508
3509=== modified file 'src/scopes/internal/RangeInputFilterImpl.cpp'
3510--- src/scopes/internal/RangeInputFilterImpl.cpp 2015-11-12 14:20:36 +0000
3511+++ src/scopes/internal/RangeInputFilterImpl.cpp 2016-03-04 15:54:04 +0000
3512@@ -1,5 +1,5 @@
3513 /*
3514- * Copyright (C) 2014 Canonical Ltd
3515+ * Copyright (C) 2015 Canonical Ltd
3516 *
3517 * This program is free software: you can redistribute it and/or modify
3518 * it under the terms of the GNU Lesser General Public License version 3 as
3519@@ -31,11 +31,19 @@
3520 namespace internal
3521 {
3522
3523-RangeInputFilterImpl::RangeInputFilterImpl(std::string const& id, std::string const& start_label, std::string const& end_label, std::string const& unit_label)
3524+RangeInputFilterImpl::RangeInputFilterImpl(std::string const& id,
3525+ Variant const& default_start_value, Variant const& default_end_value,
3526+ std::string const& start_prefix_label, std::string const& start_postfix_label,
3527+ std::string const& central_label,
3528+ std::string const& end_prefix_label, std::string const& end_postfix_label)
3529 : FilterBaseImpl(id),
3530- start_label_(start_label),
3531- end_label_(end_label),
3532- unit_label_(unit_label)
3533+ default_start_value_(default_start_value),
3534+ default_end_value_(default_end_value),
3535+ start_prefix_label_(start_prefix_label),
3536+ start_postfix_label_(start_postfix_label),
3537+ end_prefix_label_(end_prefix_label),
3538+ end_postfix_label_(end_postfix_label),
3539+ central_label_(central_label)
3540 {
3541 }
3542
3543@@ -52,19 +60,39 @@
3544 return filter;
3545 }
3546
3547-std::string RangeInputFilterImpl::start_label() const
3548-{
3549- return start_label_;
3550-}
3551-
3552-std::string RangeInputFilterImpl::end_label() const
3553-{
3554- return end_label_;
3555-}
3556-
3557-std::string RangeInputFilterImpl::unit_label() const
3558-{
3559- return unit_label_;
3560+std::string RangeInputFilterImpl::start_prefix_label() const
3561+{
3562+ return start_prefix_label_;
3563+}
3564+
3565+std::string RangeInputFilterImpl::start_postfix_label() const
3566+{
3567+ return start_postfix_label_;
3568+}
3569+
3570+std::string RangeInputFilterImpl::end_prefix_label() const
3571+{
3572+ return end_prefix_label_;
3573+}
3574+
3575+std::string RangeInputFilterImpl::end_postfix_label() const
3576+{
3577+ return end_postfix_label_;
3578+}
3579+
3580+std::string RangeInputFilterImpl::central_label() const
3581+{
3582+ return central_label_;
3583+}
3584+
3585+Variant RangeInputFilterImpl::default_start_value() const
3586+{
3587+ return default_start_value_;
3588+}
3589+
3590+Variant RangeInputFilterImpl::default_end_value() const
3591+{
3592+ return default_end_value_;
3593 }
3594
3595 bool RangeInputFilterImpl::has_value(FilterState const& filter_state, unsigned int index) const
3596@@ -131,7 +159,9 @@
3597 void RangeInputFilterImpl::check_type(Variant const& val, std::string const& filter_id, std::string const& varname)
3598 {
3599 if (val.which() == Variant::Type::Int || val.which() == Variant::Type::Double || val.is_null())
3600+ {
3601 return;
3602+ }
3603 std::stringstream err;
3604 err << "RangeInputFilterImpl::check_type(): Invalid variant type for " << varname << ", filter '" << filter_id << "'";
3605 throw unity::InvalidArgumentException(err.str());
3606@@ -178,19 +208,31 @@
3607
3608 void RangeInputFilterImpl::serialize(VariantMap& var) const
3609 {
3610- var["start_label"] = start_label_;
3611- var["end_label"] = end_label_;
3612- var["unit_label"] = unit_label_;
3613+ var["default_start_value"] = default_start_value_;
3614+ var["default_end_value"] = default_end_value_;
3615+ var["start_prefix_label"] = start_prefix_label_;
3616+ var["start_postfix_label"] = start_postfix_label_;
3617+ var["end_prefix_label"] = end_prefix_label_;
3618+ var["end_postfix_label"] = end_postfix_label_;
3619+ var["central_label"] = central_label_;
3620 }
3621
3622 void RangeInputFilterImpl::deserialize(VariantMap const& var)
3623 {
3624- auto it = find_or_throw("RangeInputFilterImpl::deserialize()", var, "start_label");
3625- start_label_ = it->second.get_string();
3626- it = find_or_throw("RangeInputFilterImpl::deserialize()", var, "end_label");
3627- end_label_ = it->second.get_string();
3628- it = find_or_throw("RangeInputFilterImpl::deserialize()", var, "unit_label");
3629- unit_label_ = it->second.get_string();
3630+ auto it = find_or_throw("RangeInputFilterImpl::deserialize()", var, "start_prefix_label");
3631+ start_prefix_label_ = it->second.get_string();
3632+ it = find_or_throw("RangeInputFilterImpl::deserialize()", var, "start_postfix_label");
3633+ start_postfix_label_ = it->second.get_string();
3634+ it = find_or_throw("RangeInputFilterImpl::deserialize()", var, "end_prefix_label");
3635+ end_prefix_label_ = it->second.get_string();
3636+ it = find_or_throw("RangeInputFilterImpl::deserialize()", var, "end_postfix_label");
3637+ end_postfix_label_ = it->second.get_string();
3638+ it = find_or_throw("RangeInputFilterImpl::deserialize()", var, "central_label");
3639+ central_label_ = it->second.get_string();
3640+ it = find_or_throw("RangeInputFilterImpl::deserialize()", var, "default_start_value");
3641+ default_start_value_ = it->second;
3642+ it = find_or_throw("RangeInputFilterImpl::deserialize()", var, "default_end_value");
3643+ default_end_value_ = it->second;
3644 }
3645
3646 void RangeInputFilterImpl::validate_display_hints() const
3647
3648=== modified file 'src/scopes/internal/RatingFilterImpl.cpp'
3649--- src/scopes/internal/RatingFilterImpl.cpp 2014-05-15 14:51:39 +0000
3650+++ src/scopes/internal/RatingFilterImpl.cpp 2016-03-04 15:54:04 +0000
3651@@ -58,7 +58,7 @@
3652 {
3653 }
3654
3655-FilterOption::SCPtr RatingFilterImpl::add_option(std::string const& id, std::string const& label)
3656+FilterOption::SCPtr RatingFilterImpl::add_option(std::string const& id, std::string const& label, bool /* default_value */)
3657 {
3658 if (num_of_options() < max_rating)
3659 {
3660
3661=== modified file 'src/scopes/internal/RegistryObject.cpp'
3662--- src/scopes/internal/RegistryObject.cpp 2015-12-08 01:02:15 +0000
3663+++ src/scopes/internal/RegistryObject.cpp 2016-03-04 15:54:04 +0000
3664@@ -91,7 +91,7 @@
3665 }
3666 catch (std::exception const& e)
3667 {
3668- BOOST_LOG(logger_) << "RegistryObject(): failed to create registry publisher: " << e.what();
3669+ logger_() << "RegistryObject(): failed to create registry publisher: " << e.what();
3670 }
3671 }
3672 }
3673@@ -120,7 +120,7 @@
3674 }
3675 catch(std::exception const& e)
3676 {
3677- BOOST_LOG(logger_) << "RegistryObject::~RegistryObject(): " << e.what();
3678+ logger_() << "RegistryObject::~RegistryObject(): " << e.what();
3679 }
3680 }
3681 }
3682@@ -154,7 +154,7 @@
3683 }
3684 catch (std::exception const& e)
3685 {
3686- BOOST_LOG(logger_) << "cannot get metadata from remote registry: " << e.what();
3687+ logger_() << "cannot get metadata from remote registry: " << e.what();
3688 }
3689 }
3690
3691@@ -182,7 +182,7 @@
3692 }
3693 catch (std::exception const& e)
3694 {
3695- BOOST_LOG(logger_) << "cannot get scopes list from remote registry: " << e.what();
3696+ logger_() << "cannot get scopes list from remote registry: " << e.what();
3697 }
3698 }
3699
3700@@ -377,8 +377,7 @@
3701 it->second->update_state(ScopeProcess::ProcessState::Stopping);
3702 break;
3703 default:
3704- BOOST_LOG(logger_)
3705- << "RegistryObject::on_state_received(): unknown state received from scope: " << scope_id;
3706+ logger_() << "RegistryObject::on_state_received(): unknown state received from scope: " << scope_id;
3707 }
3708 }
3709 // simply ignore states from scopes the registry does not know about
3710@@ -463,7 +462,7 @@
3711
3712 RegistryObject::ScopeProcess::ScopeProcess(ScopeExecData exec_data,
3713 std::weak_ptr<MWPublisher> const& publisher,
3714- boost::log::sources::severity_channel_logger_mt<>& logger)
3715+ unity::scopes::internal::Logger& logger)
3716 : exec_data_(exec_data)
3717 , reg_publisher_(publisher)
3718 , manually_started_(false)
3719@@ -479,7 +478,7 @@
3720 }
3721 catch(std::exception const& e)
3722 {
3723- BOOST_LOG(logger_) << "RegistryObject::ScopeProcess::~ScopeProcess(): " << e.what();
3724+ logger_() << "RegistryObject::ScopeProcess::~ScopeProcess(): " << e.what();
3725 }
3726 }
3727
3728@@ -518,16 +517,15 @@
3729 {
3730 if (!wait_for_state(lock, ScopeProcess::Stopped))
3731 {
3732- BOOST_LOG(logger_)
3733- << "RegistryObject::ScopeProcess::exec(): Force killing process. Scope: \""
3734- << exec_data_.scope_id << "\" did not stop after " << exec_data_.timeout_ms << " ms.";
3735+ logger_() << "RegistryObject::ScopeProcess::exec(): Force killing process. Scope: \""
3736+ << exec_data_.scope_id << "\" did not stop after " << exec_data_.timeout_ms << " ms.";
3737 try
3738 {
3739 kill(lock);
3740 }
3741 catch(std::exception const& e)
3742 {
3743- BOOST_LOG(logger_) << "RegistryObject::ScopeProcess::exec(): kill() failed: " << e.what();
3744+ logger_() << "RegistryObject::ScopeProcess::exec(): kill() failed: " << e.what();
3745 }
3746 }
3747 }
3748@@ -599,15 +597,15 @@
3749 }
3750 catch(std::exception const& e)
3751 {
3752- BOOST_LOG(logger_) << "RegistryObject::ScopeProcess::exec(): kill() failed: " << e.what();
3753+ logger_() << "RegistryObject::ScopeProcess::exec(): kill() failed: " << e.what();
3754 }
3755 throw unity::ResourceException("RegistryObject::ScopeProcess::exec(): exec aborted. Scope: \""
3756 + exec_data_.scope_id + "\" took longer than "
3757 + std::to_string(exec_data_.timeout_ms) + " ms to start.");
3758 }
3759
3760- BOOST_LOG_SEV(logger_, Logger::Info)
3761- << "RegistryObject::ScopeProcess::exec(): Process for scope: \"" << exec_data_.scope_id << "\" started";
3762+ logger_(LoggerSeverity::Info) << "RegistryObject::ScopeProcess::exec(): Process for scope: \""
3763+ << exec_data_.scope_id << "\" started";
3764
3765 // 4. add the scope process to the death observer
3766 death_observer.add(process_);
3767@@ -626,9 +624,8 @@
3768 // check if this is the process reported to have died
3769 if (pid == process_.pid())
3770 {
3771- BOOST_LOG_SEV(logger_, Logger::Info)
3772- << "RegistryObject::ScopeProcess::on_process_death(): Process for scope: \"" << exec_data_.scope_id
3773- << "\" exited";
3774+ logger_(LoggerSeverity::Info) << "RegistryObject::ScopeProcess::on_process_death(): Process for scope: \""
3775+ << exec_data_.scope_id << "\" exited";
3776 clear_handle_unlocked();
3777 return true;
3778 }
3779@@ -659,9 +656,8 @@
3780
3781 if (state_ != Starting)
3782 {
3783- BOOST_LOG_SEV(logger_, Logger::Info)
3784- << "RegistryObject::ScopeProcess: Process for scope: \"" << exec_data_.scope_id
3785- << "\" started manually";
3786+ logger_(LoggerSeverity::Info) << "RegistryObject::ScopeProcess: Process for scope: \""
3787+ << exec_data_.scope_id << "\" started manually";
3788
3789 manually_started_ = true;
3790 }
3791@@ -676,9 +672,8 @@
3792
3793 if (state_ != Stopping)
3794 {
3795- BOOST_LOG(logger_)
3796- << "RegistryObject::ScopeProcess: Scope: \"" << exec_data_.scope_id
3797- << "\" closed unexpectedly. Either the process crashed or was killed forcefully.";
3798+ logger_() << "RegistryObject::ScopeProcess: Scope: \"" << exec_data_.scope_id
3799+ << "\" closed unexpectedly. Either the process crashed or was killed forcefully.";
3800 }
3801 }
3802 else if (new_state == Stopping && manually_started_)
3803@@ -689,9 +684,8 @@
3804 reg_publisher->send_message("stopped", exec_data_.scope_id);
3805 }
3806
3807- BOOST_LOG(logger_)
3808- << "RegistryObject::ScopeProcess: Manually started process for scope: \""
3809- << exec_data_.scope_id << "\" exited";
3810+ logger_() << "RegistryObject::ScopeProcess: Manually started process for scope: \""
3811+ << exec_data_.scope_id << "\" exited";
3812
3813 new_state = Stopped;
3814 manually_started_ = false;
3815@@ -731,10 +725,9 @@
3816 {
3817 std::error_code ec;
3818
3819- BOOST_LOG(logger_)
3820- << "RegistryObject::ScopeProcess::kill(): Scope: \"" << exec_data_.scope_id
3821- << "\" took longer than " << exec_data_.timeout_ms << " ms to exit gracefully. "
3822- << "Killing the process instead.";
3823+ logger_() << "RegistryObject::ScopeProcess::kill(): Scope: \"" << exec_data_.scope_id
3824+ << "\" took longer than " << exec_data_.timeout_ms << " ms to exit gracefully. "
3825+ << "Killing the process instead.";
3826
3827 // scope is taking too long to close, send kill signal
3828 process_.send_signal(core::posix::Signal::sig_kill, ec);
3829@@ -745,8 +738,7 @@
3830 }
3831 catch (std::exception const&)
3832 {
3833- BOOST_LOG(logger_)
3834- << "RegistryObject::ScopeProcess::kill(): Failed to kill scope: \"" << exec_data_.scope_id << "\"";
3835+ logger_() << "RegistryObject::ScopeProcess::kill(): Failed to kill scope: \"" << exec_data_.scope_id << "\"";
3836
3837 // clear the process handle
3838 // even on error, the previous handle will be unrecoverable at this point
3839@@ -821,10 +813,9 @@
3840 started_message += " string:" + exec_data_.scope_id + " uint64:" + std::to_string(process_.pid());
3841 if (safe_system_call(started_message) != 0)
3842 {
3843- BOOST_LOG(logger_)
3844- << "RegistryObject::ScopeProcess::publish_state_change(): "
3845- "Failed to execute SDK DBus ScopeLoaded callback "
3846- "(Scope ID: " << exec_data_.scope_id << ")";
3847+ logger_() << "RegistryObject::ScopeProcess::publish_state_change(): "
3848+ "Failed to execute SDK DBus ScopeLoaded callback "
3849+ "(Scope ID: " << exec_data_.scope_id << ")";
3850 }
3851 }
3852 }
3853@@ -842,10 +833,9 @@
3854 stopped_message += " string:" + exec_data_.scope_id;
3855 if (safe_system_call(stopped_message) != 0)
3856 {
3857- BOOST_LOG(logger_)
3858- << "RegistryObject::ScopeProcess::publish_state_change(): "
3859- "Failed to execute SDK DBus ScopeStopped callback "
3860- "(Scope ID: " << exec_data_.scope_id << ")";
3861+ logger_() << "RegistryObject::ScopeProcess::publish_state_change(): "
3862+ "Failed to execute SDK DBus ScopeStopped callback "
3863+ "(Scope ID: " << exec_data_.scope_id << ")";
3864 }
3865 }
3866 }
3867
3868=== modified file 'src/scopes/internal/ReplyImpl.cpp'
3869--- src/scopes/internal/ReplyImpl.cpp 2015-11-25 08:55:19 +0000
3870+++ src/scopes/internal/ReplyImpl.cpp 2016-03-04 15:54:04 +0000
3871@@ -121,7 +121,7 @@
3872 {
3873 error_message = "unknown exception";
3874 }
3875- BOOST_LOG(mw_proxy_->mw_base()->runtime()->logger()) << "ReplyImpl::error(): " << error_message;
3876+ mw_proxy_->mw_base()->runtime()->logger()() << "ReplyImpl::error(): " << error_message;
3877
3878 try
3879 {
3880@@ -129,8 +129,7 @@
3881 }
3882 catch (std::exception const&)
3883 {
3884- BOOST_LOG(mw_proxy_->mw_base()->runtime()->logger())
3885- << "ReplyImpl::error(): exception from finished(): " << error_message;
3886+ mw_proxy_->mw_base()->runtime()->logger()() << "ReplyImpl::error(): exception from finished(): " << error_message;
3887 }
3888 }
3889
3890@@ -147,8 +146,7 @@
3891 }
3892 catch (std::exception const& e)
3893 {
3894- BOOST_LOG(mw_proxy_->mw_base()->runtime()->logger())
3895- << "ReplyImpl::error(): exception from info(): " << e.what();
3896+ mw_proxy_->mw_base()->runtime()->logger()() << "ReplyImpl::error(): exception from info(): " << e.what();
3897 }
3898 }
3899
3900
3901=== modified file 'src/scopes/internal/ReplyObject.cpp'
3902--- src/scopes/internal/ReplyObject.cpp 2015-06-09 07:27:24 +0000
3903+++ src/scopes/internal/ReplyObject.cpp 2016-03-04 15:54:04 +0000
3904@@ -135,7 +135,7 @@
3905 // Safe to call finished now if something went wrong or cardinality was exceeded.
3906 if (!error.empty())
3907 {
3908- BOOST_LOG(runtime_->logger()) << "ReplyObject::push(): " << error;
3909+ runtime_->logger()() << "ReplyObject::push(): " << error;
3910 finished(CompletionDetails(CompletionDetails::Error, error));
3911 }
3912 else if (stop)
3913@@ -183,11 +183,11 @@
3914 }
3915 catch (std::exception const& e)
3916 {
3917- BOOST_LOG(runtime_->logger()) << "ReplyObject::finished(): " << e.what();
3918+ runtime_->logger()() << "ReplyObject::finished(): " << e.what();
3919 }
3920 catch (...)
3921 {
3922- BOOST_LOG(runtime_->logger()) << "ReplyObject::finished(): unknown exception";
3923+ runtime_->logger()() << "ReplyObject::finished(): unknown exception";
3924 }
3925
3926 // Disconnect self from middleware, if this hasn't happened yet.
3927@@ -219,11 +219,11 @@
3928 }
3929 catch (std::exception const& e)
3930 {
3931- BOOST_LOG(runtime_->logger()) << "ReplyObject::info(): " << e.what();
3932+ runtime_->logger()() << "ReplyObject::info(): " << e.what();
3933 }
3934 catch (...)
3935 {
3936- BOOST_LOG(runtime_->logger()) << "ReplyObject::info(): unknown exception";
3937+ runtime_->logger()() << "ReplyObject::info(): unknown exception";
3938 }
3939 }
3940
3941
3942=== modified file 'src/scopes/internal/ResultReplyObject.cpp'
3943--- src/scopes/internal/ResultReplyObject.cpp 2015-06-09 07:27:24 +0000
3944+++ src/scopes/internal/ResultReplyObject.cpp 2016-03-04 15:54:04 +0000
3945@@ -24,6 +24,7 @@
3946 #include <unity/scopes/internal/CategorisedResultImpl.h>
3947 #include <unity/scopes/internal/DepartmentImpl.h>
3948 #include <unity/scopes/FilterBase.h>
3949+#include <unity/scopes/internal/FilterGroupImpl.h>
3950 #include <unity/scopes/internal/FilterBaseImpl.h>
3951 #include <unity/scopes/internal/FilterStateImpl.h>
3952 #include <unity/UnityExceptions.h>
3953@@ -65,7 +66,14 @@
3954 auto it = data.find("filters");
3955 if (it != data.end())
3956 {
3957- Filters const filters = FilterBaseImpl::deserialize_filters(it->second.get_array());
3958+ auto itgr = data.find("filter_groups");
3959+ std::map<std::string, FilterGroup::SCPtr> groups;
3960+ if (itgr != data.end())
3961+ {
3962+ groups = FilterGroupImpl::deserialize_filter_groups(itgr->second.get_array());
3963+ }
3964+
3965+ Filters const filters = FilterBaseImpl::deserialize_filters(it->second.get_array(), groups);
3966 it = data.find("filter_state");
3967 if (it != data.end())
3968 {
3969
3970=== modified file 'src/scopes/internal/RuntimeConfig.cpp'
3971--- src/scopes/internal/RuntimeConfig.cpp 2015-12-16 06:55:08 +0000
3972+++ src/scopes/internal/RuntimeConfig.cpp 2016-03-04 15:54:04 +0000
3973@@ -53,9 +53,6 @@
3974 const string cache_dir_key = "CacheDir";
3975 const string app_dir_key = "AppDir";
3976 const string config_dir_key = "ConfigDir";
3977-const string log_dir_key = "LogDir";
3978-const string max_log_file_size_key = "Log.MaxFileSize";
3979-const string max_log_dir_size_key = "Log.MaxDirSize";
3980 const string trace_channels_key = "Log.TraceChannels";
3981
3982 } // namespace
3983@@ -73,8 +70,6 @@
3984 default_middleware_configfile_ = DFLT_ZMQ_MIDDLEWARE_INI;
3985 reap_expiry_ = DFLT_REAP_EXPIRY;
3986 reap_interval_ = DFLT_REAP_INTERVAL;
3987- max_log_file_size_ = DFLT_MAX_LOG_FILE_SIZE;
3988- max_log_dir_size_ = DFLT_MAX_LOG_DIR_SIZE;
3989 cache_directory_ = default_cache_directory();
3990 app_directory_ = default_app_directory();
3991 config_directory_ = default_config_directory();
3992@@ -142,29 +137,6 @@
3993 }
3994 }
3995
3996- log_directory_ = get_optional_string(runtime_config_group, log_dir_key);
3997-
3998- // Check if we have an override for the log directory.
3999- char const* logdir = getenv("UNITY_SCOPES_LOGDIR");
4000- if (logdir)
4001- {
4002- log_directory_ = logdir;
4003- }
4004-
4005- max_log_file_size_ = get_optional_int(runtime_config_group, max_log_file_size_key, DFLT_MAX_LOG_FILE_SIZE);
4006- if (max_log_file_size_ < 1024)
4007- {
4008- throw_ex("Illegal value (" + to_string(max_log_file_size_) + ") for " + max_log_file_size_key
4009- + ": value must be > 1024");
4010- }
4011-
4012- max_log_dir_size_ = get_optional_int(runtime_config_group, max_log_dir_size_key, DFLT_MAX_LOG_DIR_SIZE);
4013- if (max_log_dir_size_ <= max_log_file_size_)
4014- {
4015- throw_ex("Illegal value (" + to_string(max_log_dir_size_) + ") for " + max_log_dir_size_key
4016- + ": value must be > " + max_log_file_size_key + " (" + to_string(max_log_file_size_) + ")");
4017- }
4018-
4019 try
4020 {
4021 trace_channels_ = parser()->get_string_array(runtime_config_group, trace_channels_key);
4022@@ -198,9 +170,6 @@
4023 cache_dir_key,
4024 app_dir_key,
4025 config_dir_key,
4026- log_dir_key,
4027- max_log_file_size_key,
4028- max_log_dir_size_key,
4029 trace_channels_key
4030 }
4031 }
4032@@ -267,21 +236,6 @@
4033 return config_directory_;
4034 }
4035
4036-string RuntimeConfig::log_directory() const
4037-{
4038- return log_directory_;
4039-}
4040-
4041-int RuntimeConfig::max_log_file_size() const
4042-{
4043- return max_log_file_size_;
4044-}
4045-
4046-int RuntimeConfig::max_log_dir_size() const
4047-{
4048- return max_log_dir_size_;
4049-}
4050-
4051 vector<string> RuntimeConfig::trace_channels() const
4052 {
4053 return trace_channels_;
4054@@ -317,19 +271,6 @@
4055 return string(home) + "/" + DFLT_HOME_CONFIG_SUBDIR;
4056 }
4057
4058-string RuntimeConfig::default_log_directory()
4059-{
4060- char const* home = getenv("HOME");
4061- if (!home || *home == '\0')
4062- {
4063- throw ResourceException("RuntimeConfig::default_log_directory(): $HOME not set");
4064- }
4065- string dir = string(home) + "/" + DFLT_HOME_LOG_SUBDIR;
4066- make_directories(dir, 0700);
4067-
4068- return dir;
4069-}
4070-
4071 } // namespace internal
4072
4073 } // namespace scopes
4074
4075=== modified file 'src/scopes/internal/RuntimeImpl.cpp'
4076--- src/scopes/internal/RuntimeImpl.cpp 2015-12-18 09:21:53 +0000
4077+++ src/scopes/internal/RuntimeImpl.cpp 2016-03-04 15:54:04 +0000
4078@@ -81,23 +81,16 @@
4079 RuntimeConfig config(configfile);
4080
4081 // Configure trace channels.
4082- try
4083- {
4084- logger_->enable_channels(config.trace_channels());
4085- }
4086- catch (...)
4087- {
4088- throw InvalidArgumentException("Runtime(): invalid trace channel name(s)");
4089- }
4090-
4091- // Now that we have the config, change the logger to log to a file.
4092- // If log_dir is set to the empty string, continue logging to std::clog.
4093- log_dir_ = config.log_directory();
4094- if (!log_dir_.empty())
4095- {
4096- logger_->set_log_file(find_log_dir(log_file_basename) + "/" + log_file_basename,
4097- config.max_log_file_size(),
4098- config.max_log_dir_size());
4099+ for (auto const& c : config.trace_channels())
4100+ {
4101+ try
4102+ {
4103+ logger_->set_channel(c, true);
4104+ }
4105+ catch (...)
4106+ {
4107+ throw InvalidArgumentException("Runtime(): invalid trace channel name");
4108+ }
4109 }
4110
4111 string default_middleware = config.default_middleware();
4112@@ -119,7 +112,7 @@
4113
4114 if (registry_configfile_.empty() || registry_identity_.empty())
4115 {
4116- BOOST_LOG_SEV(logger(), Logger::Warning) << "no registry configured";
4117+ logger()(LoggerSeverity::Warning) << "no registry configured";
4118 registry_identity_ = "";
4119 }
4120 else
4121@@ -140,7 +133,7 @@
4122 string msg = "Cannot instantiate run time for " + (scope_id.empty() ? "client" : scope_id) +
4123 ", config file: " + configfile;
4124 ConfigException ex(msg);
4125- BOOST_LOG(logger()) << ex.what();
4126+ logger()() << ex.what();
4127 throw ex;
4128 }
4129 }
4130@@ -153,11 +146,11 @@
4131 }
4132 catch (std::exception const& e) // LCOV_EXCL_LINE
4133 {
4134- BOOST_LOG(logger()) << "~RuntimeImpl(): " << e.what();
4135+ logger()() << "~RuntimeImpl(): " << e.what();
4136 }
4137 catch (...) // LCOV_EXCL_LINE
4138 {
4139- BOOST_LOG(logger()) << "~RuntimeImpl(): unknown exception";
4140+ logger()() << "~RuntimeImpl(): unknown exception";
4141 }
4142 }
4143
4144@@ -311,16 +304,11 @@
4145 return future_queue_; // Immutable
4146 }
4147
4148-boost::log::sources::severity_channel_logger_mt<>& RuntimeImpl::logger() const
4149+internal::Logger& RuntimeImpl::logger() const
4150 {
4151 return *logger_;
4152 }
4153
4154-boost::log::sources::severity_channel_logger_mt<>& RuntimeImpl::logger(Logger::Channel channel) const
4155-{
4156- return (*logger_)(channel);
4157-}
4158-
4159 namespace
4160 {
4161
4162
4163=== modified file 'src/scopes/internal/ScopeObject.cpp'
4164--- src/scopes/internal/ScopeObject.cpp 2015-06-01 13:33:27 +0000
4165+++ src/scopes/internal/ScopeObject.cpp 2016-03-04 15:54:04 +0000
4166@@ -84,7 +84,7 @@
4167 if (!query_base)
4168 {
4169 string msg = "Scope \"" + mw_base->runtime()->scope_id() + "\" returned nullptr from " + method + "()";
4170- BOOST_LOG(mw_base->runtime()->logger()) << msg;
4171+ mw_base->runtime()->logger()() << msg;
4172 throw ResourceException(msg);
4173 }
4174 query_base->p->set_settings_db(scope_base_->p->settings_db());
4175@@ -92,7 +92,7 @@
4176 catch (...)
4177 {
4178 string msg = "Scope \"" + mw_base->runtime()->scope_id() + "\" threw an exception from " + method + "()";
4179- BOOST_LOG(mw_base->runtime()->logger()) << msg;
4180+ mw_base->runtime()->logger()() << msg;
4181 throw ResourceException(msg);
4182 }
4183
4184@@ -130,7 +130,7 @@
4185 catch (...)
4186 {
4187 }
4188- BOOST_LOG(mw_base->runtime()->logger()) << "ScopeObject::query(): " << e.what();
4189+ mw_base->runtime()->logger()() << "ScopeObject::query(): " << e.what();
4190 throw;
4191 }
4192 catch (...)
4193@@ -142,7 +142,7 @@
4194 catch (...)
4195 {
4196 }
4197- BOOST_LOG(mw_base->runtime()->logger()) << "ScopeObject::query(): unknown exception";
4198+ mw_base->runtime()->logger()() << "ScopeObject::query(): unknown exception";
4199 throw;
4200 }
4201 return ctrl_proxy;
4202
4203=== modified file 'src/scopes/internal/SearchQueryBaseImpl.cpp'
4204--- src/scopes/internal/SearchQueryBaseImpl.cpp 2015-05-29 15:06:06 +0000
4205+++ src/scopes/internal/SearchQueryBaseImpl.cpp 2016-03-04 15:54:04 +0000
4206@@ -210,8 +210,7 @@
4207 // scope_impl can be nullptr if we use a mock scope: TypedScopeFixture<testing::Scope>
4208 if (scope_impl)
4209 {
4210- auto logger = scope_impl->runtime()->logger();
4211- BOOST_LOG_SEV(logger, Logger::Warning)
4212+ scope_impl->runtime()->logger()(LoggerSeverity::Warning)
4213 << "query loop for query \"" << canned_query_.query_string()
4214 << "\", client: " << get<0>(tuple)
4215 << ", aggregator: " << get<1>(tuple)
4216
4217=== modified file 'src/scopes/internal/SearchReplyImpl.cpp'
4218--- src/scopes/internal/SearchReplyImpl.cpp 2015-11-25 08:55:19 +0000
4219+++ src/scopes/internal/SearchReplyImpl.cpp 2016-03-04 15:54:04 +0000
4220@@ -24,14 +24,19 @@
4221 #include <unity/scopes/internal/DepartmentImpl.h>
4222 #include <unity/scopes/internal/FilterBaseImpl.h>
4223 #include <unity/scopes/internal/FilterStateImpl.h>
4224+#include <unity/scopes/internal/FilterGroupImpl.h>
4225 #include <unity/scopes/internal/MWReply.h>
4226 #include <unity/scopes/internal/QueryObjectBase.h>
4227 #include <unity/scopes/internal/RuntimeImpl.h>
4228 #include <unity/scopes/ScopeExceptions.h>
4229 #include <unity/UnityExceptions.h>
4230 #include <unity/util/FileIO.h>
4231+#include <unity/util/ResourcePtr.h>
4232+
4233+#include <cassert>
4234
4235 #include <stdlib.h>
4236+#include <unistd.h>
4237
4238 using namespace std;
4239
4240@@ -185,6 +190,11 @@
4241 }
4242
4243 VariantMap var;
4244+ auto filter_groups = internal::FilterGroupImpl::serialize_filter_groups(filters);
4245+ if (filter_groups.size())
4246+ {
4247+ var["filter_groups"] = filter_groups;
4248+ }
4249 var["filters"] = internal::FilterBaseImpl::serialize_filters(filters);
4250 var["filter_state"] = filter_state.serialize();
4251 return ReplyImpl::push(var);
4252@@ -260,8 +270,17 @@
4253 VariantMap vm;
4254 vm["departments"] = move(departments);
4255 vm["categories"] = move(categories);
4256+
4257+ // serialize filter groups if present
4258+ auto filter_groups = internal::FilterGroupImpl::serialize_filter_groups(cached_filters_);
4259+ if (filter_groups.size())
4260+ {
4261+ vm["filter_groups"] = move(filter_groups);
4262+ }
4263+
4264 vm["filters"] = move(filters);
4265 vm["filter_state"] = move(filter_state);
4266+
4267 vm["results"] = move(results);
4268 string const json = Variant(move(vm)).serialize_json();
4269
4270@@ -285,15 +304,13 @@
4271 catch (std::exception const& e)
4272 {
4273 ::unlink(tmp_path.c_str());
4274- BOOST_LOG(mw_proxy_->mw_base()->runtime()->logger())
4275- << "SearchReply::write_cached_results(): " << e.what();
4276+ mw_proxy_->mw_base()->runtime()->logger()() << "SearchReply::write_cached_results(): " << e.what();
4277 }
4278 // LCOV_EXCL_START
4279 catch (...)
4280 {
4281 ::unlink(tmp_path.c_str());
4282- BOOST_LOG(mw_proxy_->mw_base()->runtime()->logger())
4283- << "SearchReply::write_cached_results(): unknown exception";
4284+ mw_proxy_->mw_base()->runtime()->logger()() << "SearchReply::write_cached_results(): unknown exception";
4285 }
4286 // LCOV_EXCL_STOP
4287 }
4288@@ -383,7 +400,14 @@
4289 register_category(cp);
4290 }
4291
4292- auto filters = FilterBaseImpl::deserialize_filters(move(filter_array));
4293+ std::map<std::string, FilterGroup::SCPtr> groups;
4294+ it = vm.find("filter_groups");
4295+ if (it != vm.end())
4296+ {
4297+ groups = FilterGroupImpl::deserialize_filter_groups(it->second.get_array());
4298+ }
4299+
4300+ auto filters = FilterBaseImpl::deserialize_filters(move(filter_array), groups);
4301 auto filter_state = FilterStateImpl::deserialize(move(filter_state_dict));
4302 push(filters, filter_state);
4303
4304@@ -396,13 +420,13 @@
4305 }
4306 catch (std::exception const& e)
4307 {
4308- BOOST_LOG(mw_proxy_->mw_base()->runtime()->logger())
4309+ mw_proxy_->mw_base()->runtime()->logger()()
4310 << "SearchReply::push_surfacing_results_from_cache() (file = " + cache_path + "): " << e.what();
4311 }
4312 // LCOV_EXCL_START
4313 catch (...)
4314 {
4315- BOOST_LOG(mw_proxy_->mw_base()->runtime()->logger())
4316+ mw_proxy_->mw_base()->runtime()->logger()()
4317 << "SearchReply::push_surfacing_results_from_cache() (file = " + cache_path + "): unknown exception";
4318 }
4319 // LCOV_EXCL_STOP
4320
4321=== modified file 'src/scopes/internal/ValueSliderFilterImpl.cpp'
4322--- src/scopes/internal/ValueSliderFilterImpl.cpp 2015-11-12 14:20:36 +0000
4323+++ src/scopes/internal/ValueSliderFilterImpl.cpp 2016-03-04 15:54:04 +0000
4324@@ -32,26 +32,21 @@
4325 namespace internal
4326 {
4327
4328-ValueSliderFilterImpl::ValueSliderFilterImpl(std::string const& id, std::string const& label, std::string const& label_template, double min, double max)
4329+ValueSliderFilterImpl::ValueSliderFilterImpl(std::string const& id, double min, double max, double default_value, ValueSliderLabels const& labels)
4330 : FilterBaseImpl(id),
4331- label_(label),
4332- label_template_(label_template),
4333- slider_type_(ValueSliderFilter::SliderType::LessThan),
4334 min_(min),
4335- max_(max)
4336+ max_(max),
4337+ default_val_(default_value),
4338+ labels_(new ValueSliderLabels(labels))
4339 {
4340- if (label.empty())
4341- {
4342- throw InvalidArgumentException("ValueSliderFilterImpl(): Invalid empty label string");
4343- }
4344-
4345- if (min < 0 || min >= max)
4346+ if (default_value < min || default_value > max)
4347 {
4348 std::stringstream err;
4349- err << "ValueSliderFilterImpl::ValueSliderFilterImpl(): invalid min or max value for filter '" << id << "', min is " << min << ", max is " << max;
4350- throw LogicException(err.str());
4351+ err << "ValueSliderFilterImpl::ValueSliderFilterImpl(): invalid default value for filter '" << id << "', " << default_value << " not in " << min << "-"
4352+ << max << " range";
4353+ throw InvalidArgumentException(err.str());
4354 }
4355- default_val_ = max;
4356+ labels_->p->validate(min_, max_);
4357 }
4358
4359 ValueSliderFilterImpl::ValueSliderFilterImpl(VariantMap const& var)
4360@@ -73,16 +68,6 @@
4361 default_val_ = val;
4362 }
4363
4364-void ValueSliderFilterImpl::set_slider_type(ValueSliderFilter::SliderType tp)
4365-{
4366- slider_type_ = tp;
4367-}
4368-
4369-ValueSliderFilter::SliderType ValueSliderFilterImpl::slider_type() const
4370-{
4371- return slider_type_;
4372-}
4373-
4374 double ValueSliderFilterImpl::default_value() const
4375 {
4376 return default_val_;
4377@@ -98,14 +83,11 @@
4378 return max_;
4379 }
4380
4381-std::string ValueSliderFilterImpl::label() const
4382-{
4383- return label_;
4384-}
4385-
4386-std::string ValueSliderFilterImpl::value_label_template() const
4387-{
4388- return label_template_;
4389+ValueSliderLabels const& ValueSliderFilterImpl::labels() const
4390+{
4391+ // labels_ pointer is guaranteed to be initialized either by the regular ctor or when deserialized from a variant
4392+ assert(labels_);
4393+ return *labels_;
4394 }
4395
4396 bool ValueSliderFilterImpl::has_value(FilterState const& filter_state) const
4397@@ -119,7 +101,7 @@
4398 {
4399 try
4400 {
4401- double val = FilterBaseImpl::get(filter_state, id()).get_double(); // this can throw if of different type
4402+ auto val = FilterBaseImpl::get(filter_state, id()).get_double(); // this can throw if of different type
4403 check_range(val);
4404 return val;
4405 }
4406@@ -154,28 +136,23 @@
4407
4408 void ValueSliderFilterImpl::serialize(VariantMap& var) const
4409 {
4410- var["label"] = label_;
4411- var["label_template"] = label_template_;
4412 var["min"] = Variant(min_);
4413 var["max"] = Variant(max_);
4414 var["default"] = Variant(default_val_);
4415- var["slider_type"] = static_cast<int>(slider_type_);
4416+ var["labels"] = Variant(labels_->serialize());
4417 }
4418
4419 void ValueSliderFilterImpl::deserialize(VariantMap const& var)
4420 {
4421- auto it = find_or_throw("ValueSliderFilterImpl::deserialize()", var, "label");
4422- label_ = it->second.get_string();
4423- it = find_or_throw("ValueSliderFilterImpl::deserialize()", var, "label_template");
4424- label_template_ = it->second.get_string();
4425- it = find_or_throw("ValueSliderFilterImpl::deserialize()", var, "min");
4426+ auto it = find_or_throw("ValueSliderFilterImpl::deserialize()", var, "min");
4427 min_ = it->second.get_double();
4428 it = find_or_throw("ValueSliderFilterImpl::deserialize()", var, "max");
4429 max_ = it->second.get_double();
4430 it = find_or_throw("ValueSliderFilterImpl::deserialize()", var, "default");
4431 default_val_ = it->second.get_double();
4432- it = find_or_throw("ValueSliderFilterImpl::deserialize()", var, "slider_type");
4433- slider_type_ = static_cast<ValueSliderFilter::SliderType>(it->second.get_int());
4434+ it = find_or_throw("ValueSliderFilterImpl::deserialize()", var, "labels");
4435+ labels_.reset(new ValueSliderLabels(it->second.get_dict()));
4436+ labels_->p->validate(min_, max_);
4437 }
4438
4439 std::string ValueSliderFilterImpl::filter_type() const
4440@@ -189,7 +166,7 @@
4441 {
4442 std::stringstream err;
4443 err << "ValueSliderFilterImpl::check_range(): value " << val << " outside of allowed range (" << min_ << ", " << max_ << ")";
4444- throw LogicException(err.str());
4445+ throw InvalidArgumentException(err.str());
4446 }
4447 }
4448
4449
4450=== added file 'src/scopes/internal/ValueSliderLabelsImpl.cpp'
4451--- src/scopes/internal/ValueSliderLabelsImpl.cpp 1970-01-01 00:00:00 +0000
4452+++ src/scopes/internal/ValueSliderLabelsImpl.cpp 2016-03-04 15:54:04 +0000
4453@@ -0,0 +1,158 @@
4454+/*
4455+ * Copyright (C) 2015 Canonical Ltd
4456+ *
4457+ * This program is free software: you can redistribute it and/or modify
4458+ * it under the terms of the GNU Lesser General Public License version 3 as
4459+ * published by the Free Software Foundation.
4460+ *
4461+ * This program is distributed in the hope that it will be useful,
4462+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4463+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4464+ * GNU Lesser General Public License for more details.
4465+ *
4466+ * You should have received a copy of the GNU Lesser General Public License
4467+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4468+ *
4469+ * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com>
4470+ */
4471+
4472+#include <unity/scopes/internal/ValueSliderLabelsImpl.h>
4473+#include <unity/scopes/internal/Utils.h>
4474+#include <unity/UnityExceptions.h>
4475+#include <unordered_set>
4476+
4477+namespace unity
4478+{
4479+
4480+namespace scopes
4481+{
4482+
4483+namespace internal
4484+{
4485+
4486+ValueSliderLabelsImpl::ValueSliderLabelsImpl(std::string const& min_label, std::string const& max_label)
4487+ : min_label_(min_label),
4488+ max_label_(max_label)
4489+{
4490+}
4491+
4492+ValueSliderLabelsImpl::ValueSliderLabelsImpl(std::string const& min_label, std::string const& max_label, std::vector<std::pair<double, std::string>> const& extra_labels)
4493+ : min_label_(min_label),
4494+ max_label_(max_label),
4495+ extra_labels_(extra_labels)
4496+{
4497+}
4498+
4499+ValueSliderLabelsImpl::ValueSliderLabelsImpl(VariantMap const& var)
4500+{
4501+ deserialize(var);
4502+}
4503+
4504+std::string ValueSliderLabelsImpl::min_label() const
4505+{
4506+ return min_label_;
4507+}
4508+
4509+std::string ValueSliderLabelsImpl::max_label() const
4510+{
4511+ return max_label_;
4512+}
4513+
4514+std::vector<std::pair<double, std::string>> ValueSliderLabelsImpl::extra_labels() const
4515+{
4516+ return extra_labels_;
4517+}
4518+
4519+void ValueSliderLabelsImpl::validate(double min, double max) const
4520+{
4521+ if (min >= max)
4522+ {
4523+ std::stringstream err;
4524+ err << "ValueSliderLabelsImpl::validate(): invalid range " << min << ", " << max;
4525+ throw InvalidArgumentException(err.str());
4526+ }
4527+
4528+ double last_value = min;
4529+ std::unordered_set<std::string> label_lut;
4530+
4531+ // check that values of extra labels grow, i.e. v1 < v2 < v3 ... and lables are unique and not empty
4532+ for (auto const &p: extra_labels_)
4533+ {
4534+ if (p.first <= last_value)
4535+ {
4536+ std::stringstream err;
4537+ err << "ValueSliderLabelsImpl::validate(): value " << p.first << " for extra label '" << p.second << "' must be greater than previous value";
4538+ throw InvalidArgumentException(err.str());
4539+ }
4540+ if (p.second == "")
4541+ {
4542+ std::stringstream err;
4543+ err << "ValueSliderLabelsImpl::validate(): extra label for value " << p.first << " cannot be empty";
4544+ throw InvalidArgumentException(err.str());
4545+ }
4546+ if (p.second == min_label_ || p.second == max_label_)
4547+ {
4548+ std::stringstream err;
4549+ err << "ValueSliderLabelsImpl::validate(): extra label for value " << p.first << " must not be equal to min or max labels";
4550+ throw InvalidArgumentException(err.str());
4551+ }
4552+ if (label_lut.find(p.second) != label_lut.end())
4553+ {
4554+ std::stringstream err;
4555+ err << "ValueSliderLabelsImpl::validate(): multiple definitions of label '" << p.second << "'";
4556+ throw InvalidArgumentException(err.str());
4557+ }
4558+ label_lut.insert(p.second);
4559+ last_value = p.first;
4560+ }
4561+
4562+ if (max <= last_value)
4563+ {
4564+ std::stringstream err;
4565+ err << "ValueSliderLabelsImpl::validate(): the value of last extra label must not be greater than the maximum value " << max;
4566+ throw InvalidArgumentException(err.str());
4567+ }
4568+}
4569+
4570+VariantMap ValueSliderLabelsImpl::serialize() const
4571+{
4572+ VariantMap vm;
4573+ VariantArray va;
4574+ for (auto const& p: extra_labels_)
4575+ {
4576+ va.push_back(Variant(p.first));
4577+ va.push_back(Variant(p.second));
4578+ }
4579+ vm["extra_labels"] = Variant(va);
4580+ vm["min_label"] = Variant(min_label_);
4581+ vm["max_label"] = Variant(max_label_);
4582+ return vm;
4583+}
4584+
4585+void ValueSliderLabelsImpl::deserialize(VariantMap const& var)
4586+{
4587+ auto it = find_or_throw("ValueSliderLabels::deserialize()", var, "min_label");
4588+ min_label_ = it->second.get_string();
4589+ it = find_or_throw("ValueSliderLabels::deserialize()", var, "max_label");
4590+ max_label_ = it->second.get_string();
4591+ it = var.find("extra_labels");
4592+ if (it != var.end())
4593+ {
4594+ auto const va = it->second.get_array();
4595+ for (auto it = va.begin(); it != va.end();)
4596+ {
4597+ auto const value = (it++)->get_double();
4598+ if (it == va.end())
4599+ {
4600+ throw unity::InvalidArgumentException("ValueSliderLabels::deserialize(): invalid value-label array");
4601+ }
4602+ std::string const label = (it++)->get_string();
4603+ extra_labels_.push_back(std::make_pair<>(value, label));
4604+ }
4605+ }
4606+}
4607+}
4608+
4609+}
4610+
4611+}
4612
4613=== modified file 'src/scopes/internal/smartscopes/SSQueryObject.cpp'
4614--- src/scopes/internal/smartscopes/SSQueryObject.cpp 2015-01-09 07:10:07 +0000
4615+++ src/scopes/internal/smartscopes/SSQueryObject.cpp 2016-03-04 15:54:04 +0000
4616@@ -95,7 +95,7 @@
4617 std::lock_guard<std::mutex> lock(queries_mutex_);
4618
4619 query_it->second->q_pushable = false;
4620- BOOST_LOG(info.mw->runtime()->logger()) << "SSQueryObject::run(): " << e.what();
4621+ info.mw->runtime()->logger()() << "SSQueryObject::run(): " << e.what();
4622 reply->finished(CompletionDetails(CompletionDetails::Error, e.what())); // Oneway, can't block
4623 }
4624 catch (...)
4625@@ -103,7 +103,7 @@
4626 std::lock_guard<std::mutex> lock(queries_mutex_);
4627
4628 query_it->second->q_pushable = false;
4629- BOOST_LOG(info.mw->runtime()->logger()) << "SSQueryObject::run(): unknown exception";
4630+ info.mw->runtime()->logger()() << "SSQueryObject::run(): unknown exception";
4631 reply->finished(CompletionDetails(CompletionDetails::Error, "unknown exception")); // Oneway, can't block
4632 }
4633
4634
4635=== modified file 'src/scopes/internal/smartscopes/SSRegistryObject.cpp'
4636--- src/scopes/internal/smartscopes/SSRegistryObject.cpp 2015-11-26 05:48:01 +0000
4637+++ src/scopes/internal/smartscopes/SSRegistryObject.cpp 2016-03-04 15:54:04 +0000
4638@@ -82,7 +82,7 @@
4639 catch (std::exception const& e)
4640 {
4641
4642- BOOST_LOG(middleware_->runtime()->logger()) << "SSRegistryObject: get_remote_scopes() failed: " << e.what();
4643+ middleware_->runtime()->logger()() << "SSRegistryObject: get_remote_scopes() failed: " << e.what();
4644 }
4645
4646 refresh_thread_ = std::thread(&SSRegistryObject::refresh_thread, this);
4647@@ -95,8 +95,8 @@
4648 }
4649 catch (std::exception const& e)
4650 {
4651- BOOST_LOG(middleware_->runtime()->logger())
4652- << "SSRegistryObject(): failed to create registry publisher: " << e.what();
4653+ middleware_->runtime()->logger()() << "SSRegistryObject(): failed to create registry publisher: "
4654+ << e.what();
4655 }
4656 }
4657 }
4658@@ -209,8 +209,7 @@
4659 }
4660 catch (std::exception const& e)
4661 {
4662- BOOST_LOG(middleware_->runtime()->logger())
4663- << "SSRegistryObject: get_remote_scopes() failed: " << e.what();
4664+ middleware_->runtime()->logger()() << "SSRegistryObject: get_remote_scopes() failed: " << e.what();
4665 }
4666 }
4667 }
4668@@ -283,9 +282,9 @@
4669 }
4670 catch (ResourceException const& e)
4671 {
4672- BOOST_LOG(middleware_->runtime()->logger())
4673- << "SSRegistryObject: ignoring invalid settings JSON for scope \"" << scope.id << "\": "
4674- << e.what();
4675+ middleware_->runtime()->logger()()
4676+ << "SSRegistryObject: ignoring invalid settings JSON for scope \""
4677+ << scope.id << "\": " << e.what();
4678 }
4679 }
4680 else if (needs_location_data)
4681@@ -330,9 +329,8 @@
4682 }
4683 catch (ResourceException const& e)
4684 {
4685- BOOST_LOG(middleware_->runtime()->logger())
4686- << "SSRegistryObject: ignoring invalid settings JSON for scope \"" << scope.id << "\": "
4687- << e.what();
4688+ middleware_->runtime()->logger()() << "SSRegistryObject: ignoring invalid settings JSON for scope \""
4689+ << scope.id << "\": " << e.what();
4690 }
4691 }
4692
4693@@ -356,8 +354,8 @@
4694 }
4695 catch (std::exception const& e)
4696 {
4697- BOOST_LOG(middleware_->runtime()->logger())
4698- << "SSRegistryObject: skipping scope \"" << scope.id << "\": " << e.what();
4699+ middleware_->runtime()->logger()() << "SSRegistryObject: skipping scope \""
4700+ << scope.id << "\": " << e.what();
4701 }
4702 }
4703
4704
4705=== modified file 'src/scopes/internal/smartscopes/SSScopeObject.cpp'
4706--- src/scopes/internal/smartscopes/SSScopeObject.cpp 2015-05-29 12:02:54 +0000
4707+++ src/scopes/internal/smartscopes/SSScopeObject.cpp 2016-03-04 15:54:04 +0000
4708@@ -187,7 +187,7 @@
4709 catch (...)
4710 {
4711 }
4712- BOOST_LOG(info.mw->runtime()->logger()) << "SSScopeObject::query(): " << e.what();
4713+ info.mw->runtime()->logger()() << "SSScopeObject::query(): " << e.what();
4714 throw;
4715 }
4716 catch (...)
4717@@ -199,7 +199,7 @@
4718 catch (...)
4719 {
4720 }
4721- BOOST_LOG(info.mw->runtime()->logger()) << "SSScopeObject::query(): unknown exception";
4722+ info.mw->runtime()->logger()() << "SSScopeObject::query(): unknown exception";
4723 throw;
4724 }
4725
4726
4727=== modified file 'src/scopes/internal/smartscopes/SmartScope.cpp'
4728--- src/scopes/internal/smartscopes/SmartScope.cpp 2015-11-25 08:55:19 +0000
4729+++ src/scopes/internal/smartscopes/SmartScope.cpp 2016-03-04 15:54:04 +0000
4730@@ -94,7 +94,7 @@
4731 }
4732 catch (std::exception const& e)
4733 {
4734- BOOST_LOG(ss_client_->logger())
4735+ ss_client_->logger()()
4736 << "SmartScope::run(): Failed to register filters for scope '" << filters_data.scope_id
4737 << "': " << e.what();
4738 }
4739@@ -106,7 +106,7 @@
4740 }
4741 catch (std::exception const& e)
4742 {
4743- BOOST_LOG(ss_client_->logger())
4744+ ss_client_->logger()()
4745 << "SmartScope::run(): Failed to set filter state for scope '" << filters_data.scope_id
4746 << "': " << e.what();
4747 }
4748@@ -119,7 +119,7 @@
4749 }
4750 catch (std::exception const&)
4751 {
4752- BOOST_LOG(this->ss_client_->logger())
4753+ this->ss_client_->logger()()
4754 << "SmartScope: failed to register category: \"" << category->id
4755 << "\" for scope \"" << scope_id_ << "\" and query: \"" << query_.query_string() << "\"";
4756 }
4757@@ -142,7 +142,7 @@
4758 }
4759 else
4760 {
4761- BOOST_LOG(this->ss_client_->logger())
4762+ this->ss_client_->logger()()
4763 << "SmartScope: result for query: \"" << scope_id_ << "\": \"" << query_.query_string()
4764 << "\" returned an invalid cat_id. Skipping result.";
4765 }
4766@@ -155,7 +155,7 @@
4767 }
4768 catch (std::exception const& e)
4769 {
4770- BOOST_LOG(this->ss_client_->logger())
4771+ this->ss_client_->logger()()
4772 << "SmartScope::run(): Failed to register departments for scope '" << scope_id_ << "': " << e.what();
4773 }
4774 };
4775@@ -173,7 +173,7 @@
4776 else
4777 {
4778 session_id = "session_id_missing";
4779- BOOST_LOG_SEV(this->ss_client_->logger(), Logger::Info)
4780+ this->ss_client_->logger()(LoggerSeverity::Info)
4781 << "SmartScope: missing or invalid session id for \"" << scope_id_ << "\": \""
4782 << query_.query_string() << "\"";
4783 }
4784@@ -183,7 +183,7 @@
4785 }
4786 else
4787 {
4788- BOOST_LOG_SEV(this->ss_client_->logger(), Logger::Info)
4789+ this->ss_client_->logger()(LoggerSeverity::Info)
4790 << "SmartScope: missing or invalid query id for \"" << scope_id_ << "\": \""
4791 << query_.query_string() << "\"";
4792 }
4793@@ -209,7 +209,7 @@
4794 settings(), query_.filter_state().serialize(), hints_.locale(), loc, agent, hints_.cardinality());
4795 search_handle_->wait();
4796
4797- BOOST_LOG_SEV(this->ss_client_->logger(), Logger::Info)
4798+ this->ss_client_->logger()(LoggerSeverity::Info)
4799 << "SmartScope: query for \"" << scope_id_ << "\": \"" << query_.query_string() << "\" complete";
4800 }
4801
4802@@ -286,7 +286,7 @@
4803 else
4804 {
4805 session_id = "session_id_missing";
4806- BOOST_LOG_SEV(this->ss_client_->logger(), Logger::Info)
4807+ this->ss_client_->logger()(LoggerSeverity::Info)
4808 << "SmartScope: missing or invalid session id for \"" << scope_id_ << "\" preview: \""
4809 << result().uri() << "\"";
4810 }
4811@@ -301,7 +301,7 @@
4812
4813 preview_handle_->wait();
4814
4815- BOOST_LOG_SEV(this->ss_client_->logger(), Logger::Info)
4816+ this->ss_client_->logger()(LoggerSeverity::Info)
4817 << "SmartScope: preview for \"" << scope_id_ << "\": \"" << result().uri() << "\" complete";
4818 }
4819
4820@@ -335,7 +335,7 @@
4821 SearchQueryBase::UPtr SmartScope::search(std::string const& scope_id, CannedQuery const& q, SearchMetadata const& hints)
4822 {
4823 SearchQueryBase::UPtr query(new SmartQuery(scope_id, reg_, q, hints));
4824- BOOST_LOG_SEV(ss_client_->logger(), Logger::Info)
4825+ ss_client_->logger()(LoggerSeverity::Info)
4826 << "SmartScope: created query for \"" << scope_id << "\": \"" << q.query_string() << "\"";
4827 return query;
4828 }
4829@@ -343,7 +343,7 @@
4830 QueryBase::UPtr SmartScope::preview(std::string const& scope_id, Result const& result, ActionMetadata const& hints)
4831 {
4832 QueryBase::UPtr preview(new SmartPreview(scope_id, reg_, result, hints));
4833- BOOST_LOG_SEV(ss_client_->logger(), Logger::Info)
4834+ ss_client_->logger()(LoggerSeverity::Info)
4835 << "SmartScope: created preview for \"" << scope_id << "\": \"" << result.uri() << "\"";
4836 return preview;
4837 }
4838@@ -357,7 +357,7 @@
4839 ActivationQueryBase::UPtr SmartScope::perform_action(std::string const& scope_id, Result const& result, ActionMetadata const& metadata, std::string const& widget_id, std::string const& action_id)
4840 {
4841 ActivationQueryBase::UPtr activation(new SmartActivation(result, metadata, widget_id, action_id));
4842- BOOST_LOG_SEV(ss_client_->logger(), Logger::Info)
4843+ ss_client_->logger()(LoggerSeverity::Info)
4844 << "SmartScope: created activation for \"" << scope_id << "\": \"" << result.uri() << "\"";
4845 return activation;
4846 }
4847@@ -366,7 +366,7 @@
4848 {
4849 // NOTE: there is no endpoint for it really, SmartActivation is a no-op (not-handled)
4850 ActivationQueryBase::UPtr activation(new SmartActivation(result, metadata, "", action_id));
4851- BOOST_LOG_SEV(ss_client_->logger(), Logger::Info)
4852+ ss_client_->logger()(LoggerSeverity::Info)
4853 << "SmartScope: created result action activation for \"" << scope_id << "\": \"" << result.uri() << "\", action_id=" << action_id;
4854 return activation;
4855 }
4856
4857=== modified file 'src/scopes/internal/smartscopes/SmartScopesClient.cpp'
4858--- src/scopes/internal/smartscopes/SmartScopesClient.cpp 2015-12-08 01:02:15 +0000
4859+++ src/scopes/internal/smartscopes/SmartScopesClient.cpp 2016-03-04 15:54:04 +0000
4860@@ -19,6 +19,7 @@
4861
4862 #include <unity/scopes/internal/FilterBaseImpl.h>
4863 #include <unity/scopes/internal/FilterStateImpl.h>
4864+#include <unity/scopes/internal/FilterGroupImpl.h>
4865 #include <unity/scopes/internal/RuntimeImpl.h>
4866 #include <unity/scopes/internal/smartscopes/SmartScopesClient.h>
4867 #include <unity/scopes/internal/Utils.h>
4868@@ -179,7 +180,7 @@
4869 remote_scopes_uri << "locale=" << locale;
4870 }
4871
4872- BOOST_LOG_SEV(logger_, Logger::Info)
4873+ logger_(LoggerSeverity::Info)
4874 << "SmartScopesClient.get_remote_scopes(): GET " << remote_scopes_uri.str();
4875
4876 HttpHeaders headers;
4877@@ -190,12 +191,13 @@
4878 {
4879 std::string const user_agent_hdr = "partner=" + http_client_->to_percent_encoding(partner_id);
4880 headers.push_back(std::make_pair("User-Agent", user_agent_hdr));
4881- BOOST_LOG_SEV(logger_, Logger::Info) << "User agent: " << user_agent_hdr;
4882+ logger_(LoggerSeverity::Info) << "User agent: " << user_agent_hdr;
4883 }
4884 }
4885 catch (std::exception const& e)
4886 {
4887- BOOST_LOG_SEV(logger_, Logger::Error) << "SmartScopesClient.get_remote_scopes(): failed to read " << partner_file_ << ": " << e.what();
4888+ logger_() << "SmartScopesClient.get_remote_scopes(): failed to read "
4889+ << partner_file_ << ": " << e.what();
4890 }
4891
4892 std::mutex reponse_mutex;
4893@@ -207,18 +209,16 @@
4894
4895 response->get();
4896
4897- BOOST_LOG_SEV(logger_, Logger::Info)
4898- << "SmartScopesClient.get_remote_scopes(): Remote scopes:\n" << response_str;
4899+ logger_(LoggerSeverity::Info) << "SmartScopesClient.get_remote_scopes(): Remote scopes:\n" << response_str;
4900 }
4901 catch (std::exception const& e)
4902 {
4903- BOOST_LOG(logger_)
4904- << "SmartScopesClient.get_remote_scopes(): Failed to retrieve remote scopes from uri: "
4905- << url_ << c_remote_scopes_resource << ": " << e.what();
4906+ logger_() << "SmartScopesClient.get_remote_scopes(): Failed to retrieve remote scopes from uri: "
4907+ << url_ << c_remote_scopes_resource << ": " << e.what();
4908
4909 if (caching_enabled)
4910 {
4911- BOOST_LOG(logger_) << "SmartScopesClient.get_remote_scopes(): Using remote scopes from cache";
4912+ logger_() << "SmartScopesClient.get_remote_scopes(): Using remote scopes from cache";
4913
4914 response_str = read_cache();
4915 if (response_str.empty())
4916@@ -245,8 +245,8 @@
4917 }
4918 catch (std::exception const& e)
4919 {
4920- BOOST_LOG(logger_) << "SmartScopesClient.get_remote_scopes() Failed to parse json response from uri: "
4921- << url_ << c_remote_scopes_resource << ": " << e.what();
4922+ logger_() << "SmartScopesClient.get_remote_scopes() Failed to parse json response from uri: "
4923+ << url_ << c_remote_scopes_resource << ": " << e.what();
4924 throw;
4925 }
4926
4927@@ -261,7 +261,7 @@
4928
4929 if (!child_node->has_node("id"))
4930 {
4931- BOOST_LOG(logger_) << "SmartScopesClient.get_remote_scopes(): Skipping scope with no id";
4932+ logger_() << "SmartScopesClient.get_remote_scopes(): Skipping scope with no id";
4933 continue;
4934 }
4935
4936@@ -273,15 +273,14 @@
4937 {
4938 if (!child_node->has_node(field))
4939 {
4940- BOOST_LOG(logger_)
4941- << "SmartScopesClient.get_remote_scopes(): Scope: \"" << scope.id
4942- << "\" has no \"" << field << "\" field";
4943+ logger_() << "SmartScopesClient.get_remote_scopes(): Scope: \"" << scope.id
4944+ << "\" has no \"" << field << "\" field";
4945 err = true;
4946 }
4947 }
4948 if (err)
4949 {
4950- BOOST_LOG(logger_) << "SmartScopesClient.get_remote_scopes(): Skipping scope: \"" << scope.id << "\"";
4951+ logger_() << "SmartScopesClient.get_remote_scopes(): Skipping scope: \"" << scope.id << "\"";
4952 continue;
4953 }
4954
4955@@ -320,9 +319,8 @@
4956 scope.version = child_node->has_node("version") ? child_node->get_node("version")->as_int() : 0;
4957 if (scope.version < 0)
4958 {
4959- BOOST_LOG(logger_)
4960- << "SmartScopesClient.get_remote_scopes(): Scope: \"" << scope.id
4961- << "\" returned a negative \"version\" value, skipping scope";
4962+ logger_() << "SmartScopesClient.get_remote_scopes(): Scope: \"" << scope.id
4963+ << "\" returned a negative \"version\" value, skipping scope";
4964 continue;
4965 }
4966
4967@@ -340,17 +338,15 @@
4968 }
4969 catch (unity::LogicException const&)
4970 {
4971- BOOST_LOG(logger_)
4972- << "SmartScopesClient.get_remote_scopes(): Scope: \"" << scope.id
4973- << "\" returned a non-string keyword";
4974+ logger_() << "SmartScopesClient.get_remote_scopes(): Scope: \"" << scope.id
4975+ << "\" returned a non-string keyword";
4976 }
4977 }
4978 }
4979 else
4980 {
4981- BOOST_LOG(logger_)
4982- << "SmartScopesClient.get_remote_scopes(): Scope: \"" << scope.id
4983- << "\" returned an invalid value type for \"keywords\"";
4984+ logger_() << "SmartScopesClient.get_remote_scopes(): Scope: \"" << scope.id
4985+ << "\" returned an invalid value type for \"keywords\"";
4986 }
4987 }
4988
4989@@ -358,17 +354,15 @@
4990 }
4991 catch (std::exception const& e)
4992 {
4993- BOOST_LOG(logger_)
4994- << "SmartScopesClient.get_remote_scopes(): Skipping scope: \""
4995- << scope.id << "\" due to a json parsing failure: " << e.what();
4996+ logger_() << "SmartScopesClient.get_remote_scopes(): Skipping scope: \""
4997+ << scope.id << "\" due to a json parsing failure: " << e.what();
4998 }
4999 }
5000
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: