Merge lp:unity-scopes-api/staging into lp:unity-scopes-api

Proposed by Michal Hruby
Status: Merged
Merged at revision: 205
Proposed branch: lp:unity-scopes-api/staging
Merge into: lp:unity-scopes-api
Diff against target: 3746 lines (+2416/-313)
73 files modified
CMakeLists.txt (+1/-1)
CONFIGFILES (+1/-1)
RELEASE_NOTES.md (+6/-0)
debian/changelog (+9/-0)
debian/libunity-scopes1.symbols (+38/-4)
demo/client.cpp (+5/-4)
demo/scopes/scope-A/scope-A.cpp (+1/-1)
doc/tutorial.dox (+44/-19)
include/unity/scopes/OptionSelectorFilter.h (+8/-1)
include/unity/scopes/RadioButtonsFilter.h (+124/-0)
include/unity/scopes/RangeInputFilter.h (+1/-1)
include/unity/scopes/RatingFilter.h (+180/-0)
include/unity/scopes/internal/FilterBaseImpl.h (+1/-0)
include/unity/scopes/internal/MWPublisher.h (+55/-0)
include/unity/scopes/internal/MWSubscriber.h (+57/-0)
include/unity/scopes/internal/MiddlewareBase.h (+5/-0)
include/unity/scopes/internal/OptionSelectorFilterImpl.h (+3/-1)
include/unity/scopes/internal/RadioButtonsFilterImpl.h (+50/-0)
include/unity/scopes/internal/RatingFilterImpl.h (+64/-0)
include/unity/scopes/internal/smartscopes/SmartScopesClient.h (+1/-0)
include/unity/scopes/internal/zmq_middleware/ObjectAdapter.h (+0/-2)
include/unity/scopes/internal/zmq_middleware/Util.h (+4/-0)
include/unity/scopes/internal/zmq_middleware/ZmqMiddleware.h (+4/-1)
include/unity/scopes/internal/zmq_middleware/ZmqPublisher.h (+83/-0)
include/unity/scopes/internal/zmq_middleware/ZmqSubscriber.h (+86/-0)
scoperegistry/CMakeLists.txt (+0/-1)
scoperegistry/FindFiles.cpp (+17/-6)
scoperegistry/FindFiles.h (+7/-3)
scoperegistry/ScopeSet.cpp (+0/-124)
scoperegistry/ScopeSet.h (+0/-56)
scoperegistry/scoperegistry.cpp (+3/-4)
scoperunner/scoperunner.cpp (+31/-1)
src/scopes/CMakeLists.txt (+2/-0)
src/scopes/OptionSelectorFilter.cpp (+7/-2)
src/scopes/RadioButtonsFilter.cpp (+80/-0)
src/scopes/RatingFilter.cpp (+105/-0)
src/scopes/internal/CMakeLists.txt (+4/-0)
src/scopes/internal/FilterBaseImpl.cpp (+60/-0)
src/scopes/internal/MWPublisher.cpp (+42/-0)
src/scopes/internal/MWSubscriber.cpp (+42/-0)
src/scopes/internal/OptionSelectorFilterImpl.cpp (+32/-0)
src/scopes/internal/RadioButtonsFilterImpl.cpp (+81/-0)
src/scopes/internal/RatingFilterImpl.cpp (+109/-0)
src/scopes/internal/SearchReplyImpl.cpp (+11/-1)
src/scopes/internal/smartscopes/SSRegistryObject.cpp (+5/-0)
src/scopes/internal/smartscopes/SmartScopesClient.cpp (+5/-0)
src/scopes/internal/zmq_middleware/CMakeLists.txt (+2/-0)
src/scopes/internal/zmq_middleware/ObjectAdapter.cpp (+0/-41)
src/scopes/internal/zmq_middleware/Util.cpp (+42/-0)
src/scopes/internal/zmq_middleware/ZmqMiddleware.cpp (+17/-4)
src/scopes/internal/zmq_middleware/ZmqPublisher.cpp (+157/-0)
src/scopes/internal/zmq_middleware/ZmqSubscriber.cpp (+185/-0)
test/gtest/scopes/CMakeLists.txt (+2/-0)
test/gtest/scopes/Filters/Filters_test.cpp (+72/-0)
test/gtest/scopes/Filters/TestScope.h (+1/-1)
test/gtest/scopes/IdleShutdown/IdleShutdown_test.cpp (+12/-6)
test/gtest/scopes/IdleShutdown/SlowSearchScope.cpp (+1/-1)
test/gtest/scopes/IdleShutdown/Zmq.ini.in (+5/-1)
test/gtest/scopes/OptionSelectorFilter/OptionSelectorFilter_test.cpp (+3/-0)
test/gtest/scopes/RadioButtonsFilter/CMakeLists.txt (+4/-0)
test/gtest/scopes/RadioButtonsFilter/RadioButtonsFilter_test.cpp (+71/-0)
test/gtest/scopes/RatingFilter/CMakeLists.txt (+4/-0)
test/gtest/scopes/RatingFilter/RatingFilter_test.cpp (+111/-0)
test/gtest/scopes/Registry/Registry_test.cpp (+0/-19)
test/gtest/scopes/Registry/Zmq.ini.in (+1/-0)
test/gtest/scopes/internal/smartscopes/SmartScopesClient/FakeSss.py (+1/-1)
test/gtest/scopes/internal/smartscopes/SmartScopesClient/SmartScopesClient_test.cpp (+2/-0)
test/gtest/scopes/internal/zmq_middleware/CMakeLists.txt (+1/-0)
test/gtest/scopes/internal/zmq_middleware/ObjectAdapter/ObjectAdapter_test.cpp (+2/-4)
test/gtest/scopes/internal/zmq_middleware/PubSub/CMakeLists.txt (+6/-0)
test/gtest/scopes/internal/zmq_middleware/PubSub/PubSub_test.cpp (+237/-0)
test/gtest/scopes/internal/zmq_middleware/PubSub/Zmq.ini.in (+2/-0)
test/gtest/scopes/internal/zmq_middleware/RegistryI/RegistryI_test.cpp (+1/-1)
To merge this branch: bzr merge lp:unity-scopes-api/staging
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Unity Team Pending
Review via email: mp+220461@code.launchpad.net

Commit message

Sync with devel.

Description of the change

Sync with devel.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:unity-scopes-api/staging updated
205. By Tarmac

Sync with devel.

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 2014-05-15 08:17:57 +0000
3+++ CMakeLists.txt 2014-05-21 14:02:43 +0000
4@@ -179,7 +179,7 @@
5 # API version
6 set(UNITY_SCOPES_MAJOR 0)
7 set(UNITY_SCOPES_MINOR 4)
8-set(UNITY_SCOPES_MICRO 6)
9+set(UNITY_SCOPES_MICRO 7)
10
11 # Version for testing, with all symbols visible
12 set(UNITY_SCOPES_TEST_LIB ${UNITY_SCOPES_LIB}-test)
13
14=== modified file 'CONFIGFILES'
15--- CONFIGFILES 2014-05-15 07:33:37 +0000
16+++ CONFIGFILES 2014-05-21 14:02:43 +0000
17@@ -279,7 +279,7 @@
18
19 If set, the results for this scope will be set to expire, and be refreshed. Valid values are:
20
21- - none
22+ - None
23
24 - Small - in the order of a minute
25
26
27=== modified file 'RELEASE_NOTES.md'
28--- RELEASE_NOTES.md 2014-05-15 10:34:30 +0000
29+++ RELEASE_NOTES.md 2014-05-21 14:02:43 +0000
30@@ -1,6 +1,12 @@
31 Release notes
32 =============
33
34+Changes in version 0.4.7
35+========================
36+ - Implemented RatingFilter and RadioButtonsFilter.
37+ - changed create() methods of OptionSelectorFilter and RangeInputFilter to return unique_ptr (UPtr)
38+ instead of shared pointers.
39+
40 Changes in version 0.4.6
41 ========================
42 - Added method to get and set display hints for filters (at this moment the only display hint
43
44=== modified file 'debian/changelog'
45--- debian/changelog 2014-05-19 10:10:28 +0000
46+++ debian/changelog 2014-05-21 14:02:43 +0000
47@@ -1,3 +1,12 @@
48+unity-scopes-api (0.4.7-0ubuntu1) UNRELEASED; urgency=medium
49+
50+ [ Pawel Stolowski ]
51+ * Implemented RatingFilter and RadioButtonFilter.
52+ * Fixed lp:1319712: Appearance attributes not supported for remote scopes.
53+ * Changed create() methods of OptionSelectorFilter and RangeInputFilter to return unique ptr.
54+
55+ -- Pawel Stolowski <pawel.stolowski@ubuntu.com> Fri, 16 May 2014 17:48:23 +0200
56+
57 unity-scopes-api (0.4.6+14.10.20140519-0ubuntu1) utopic; urgency=medium
58
59 [ Pete Woods ]
60
61=== modified file 'debian/libunity-scopes1.symbols'
62--- debian/libunity-scopes1.symbols 2014-05-19 10:10:27 +0000
63+++ debian/libunity-scopes1.symbols 2014-05-21 14:02:43 +0000
64@@ -82,6 +82,14 @@
65 (c++)"unity::scopes::ListenerBase::~ListenerBase()@Base" 0.4.0+14.04.20140312.1
66 (c++)"unity::scopes::PreviewReply::PreviewReply()@Base" 0.4.0+14.04.20140312.1
67 (c++)"unity::scopes::PreviewReply::~PreviewReply()@Base" 0.4.0+14.04.20140312.1
68+ (c++)"unity::scopes::RatingFilter::add_option(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0replaceme
69+ (c++)"unity::scopes::RatingFilter::set_on_icon(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0replaceme
70+ (c++)"unity::scopes::RatingFilter::set_off_icon(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0replaceme
71+ (c++)"unity::scopes::RatingFilter::update_state(unity::scopes::FilterState&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)@Base" 0replaceme
72+ (c++)"unity::scopes::RatingFilter::create(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0replaceme
73+ (c++)"unity::scopes::RatingFilter::create(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int)@Base" 0replaceme
74+ (c++)"unity::scopes::RatingFilter::RatingFilter(unity::scopes::internal::RatingFilterImpl*)@Base" 0replaceme
75+ (c++)"unity::scopes::RatingFilter::~RatingFilter()@Base" 0replaceme
76 (c++)"unity::scopes::PreviewWidget::add_attribute_value(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unity::scopes::Variant const&)@Base" 0.4.0+14.04.20140312.1
77 (c++)"unity::scopes::PreviewWidget::add_attribute_mapping(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.4.0+14.04.20140312.1
78 (c++)"unity::scopes::PreviewWidget::PreviewWidget(unity::scopes::PreviewWidget&&)@Base" 0.4.0+14.04.20140312.1
79@@ -216,6 +224,11 @@
80 (c++)"unity::scopes::ActivationResponse::~ActivationResponse()@Base" 0.4.0+14.04.20140312.1
81 (c++)"unity::scopes::ActivationResponse::operator=(unity::scopes::ActivationResponse&&)@Base" 0.4.0+14.04.20140312.1
82 (c++)"unity::scopes::ActivationResponse::operator=(unity::scopes::ActivationResponse const&)@Base" 0.4.0+14.04.20140312.1
83+ (c++)"unity::scopes::RadioButtonsFilter::add_option(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0replaceme
84+ (c++)"unity::scopes::RadioButtonsFilter::update_state(unity::scopes::FilterState&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)@Base" 0replaceme
85+ (c++)"unity::scopes::RadioButtonsFilter::create(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0replaceme
86+ (c++)"unity::scopes::RadioButtonsFilter::RadioButtonsFilter(unity::scopes::internal::RadioButtonsFilterImpl*)@Base" 0replaceme
87+ (c++)"unity::scopes::RadioButtonsFilter::~RadioButtonsFilter()@Base" 0replaceme
88 (c++)"unity::scopes::SearchListenerBase::push(unity::scopes::Annotation)@Base" 0.4.0+14.04.20140312.1
89 (c++)"unity::scopes::SearchListenerBase::push(std::list<unity::scopes::Department, std::allocator<unity::scopes::Department> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.4.0+14.04.20140312.1
90 (c++)"unity::scopes::SearchListenerBase::push(std::list<std::shared_ptr<unity::scopes::FilterBase const>, std::allocator<std::shared_ptr<unity::scopes::FilterBase const> > > const&, unity::scopes::FilterState const&)@Base" 0.4.0+14.04.20140312.1
91@@ -447,13 +460,12 @@
92 (c++)"unity::scopes::internal::ScopeMetadataImpl::set_search_hint(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.4.0+14.04.20140312.1
93 (c++)"unity::scopes::internal::ScopeMetadataImpl::set_display_name(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.4.0+14.04.20140312.1
94 (c++)"unity::scopes::internal::ScopeMetadataImpl::set_scope_directory(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.4.2+14.04.20140404.2
95+ (c++)"unity::scopes::internal::ScopeMetadataImpl::set_results_ttl_type(unity::scopes::ScopeMetadata::ResultsTtlType)@Base" 0.4.6+14.10.20140519
96 (c++)"unity::scopes::internal::ScopeMetadataImpl::set_appearance_attributes(std::map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, unity::scopes::Variant, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, unity::scopes::Variant> > > const&)@Base" 0.4.2+14.04.20140404.2
97 (c++)"unity::scopes::internal::ScopeMetadataImpl::create(std::unique_ptr<unity::scopes::internal::ScopeMetadataImpl, std::default_delete<unity::scopes::internal::ScopeMetadataImpl> >)@Base" 0.4.0+14.04.20140312.1
98 (c++)"unity::scopes::internal::ScopeMetadataImpl::set_art(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.4.0+14.04.20140312.1
99 (c++)"unity::scopes::internal::ScopeMetadataImpl::set_icon(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.4.0+14.04.20140312.1
100 (c++)"unity::scopes::internal::ScopeMetadataImpl::set_proxy(std::shared_ptr<unity::scopes::Scope> const&)@Base" 0.4.0+14.04.20140312.1
101- (c++)"unity::scopes::internal::ScopeMetadataImpl::set_results_ttl_type(unity::scopes::ScopeMetadata::ResultsTtlType)@Base" 0.4.6+14.10.20140519
102- (c++)"unity::scopes::internal::ScopeMetadataImpl::results_ttl_type() const@Base" 0.4.6+14.10.20140519
103 (c++)"unity::scopes::internal::ScopeMetadataImpl::ScopeMetadataImpl(unity::scopes::internal::MiddlewareBase*)@Base" 0.4.0+14.04.20140312.1
104 (c++)"unity::scopes::internal::ScopeMetadataImpl::ScopeMetadataImpl(unity::scopes::internal::ScopeMetadataImpl const&)@Base" 0.4.0+14.04.20140312.1
105 (c++)"unity::scopes::internal::ScopeMetadataImpl::ScopeMetadataImpl(std::map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, unity::scopes::Variant, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, unity::scopes::Variant> > > const&, unity::scopes::internal::MiddlewareBase*)@Base" 0.4.0+14.04.20140312.1
106@@ -522,6 +534,14 @@
107 (c++)"unity::scopes::ColumnLayout::serialize() const@Base" 0.4.0+14.04.20140312.1
108 (c++)"unity::scopes::FilterOption::id() const@Base" 0.4.0+14.04.20140312.1
109 (c++)"unity::scopes::FilterOption::label() const@Base" 0.4.0+14.04.20140312.1
110+ (c++)"unity::scopes::RatingFilter::update_state(unity::scopes::FilterState&, std::shared_ptr<unity::scopes::FilterOption const>, bool) const@Base" 0replaceme
111+ (c++)"unity::scopes::RatingFilter::active_rating(unity::scopes::FilterState const&) const@Base" 0replaceme
112+ (c++)"unity::scopes::RatingFilter::has_active_rating(unity::scopes::FilterState const&) const@Base" 0replaceme
113+ (c++)"unity::scopes::RatingFilter::fwd() const@Base" 0replaceme
114+ (c++)"unity::scopes::RatingFilter::label() const@Base" 0replaceme
115+ (c++)"unity::scopes::RatingFilter::on_icon() const@Base" 0replaceme
116+ (c++)"unity::scopes::RatingFilter::options() const@Base" 0replaceme
117+ (c++)"unity::scopes::RatingFilter::off_icon() const@Base" 0replaceme
118 (c++)"unity::scopes::PreviewWidget::widget_type() const@Base" 0.4.0+14.04.20140312.1
119 (c++)"unity::scopes::PreviewWidget::attribute_values() const@Base" 0.4.0+14.04.20140312.1
120 (c++)"unity::scopes::PreviewWidget::attribute_mappings() const@Base" 0.4.0+14.04.20140312.1
121@@ -532,6 +552,7 @@
122 (c++)"unity::scopes::ScopeMetadata::search_hint() const@Base" 0.4.0+14.04.20140312.1
123 (c++)"unity::scopes::ScopeMetadata::display_name() const@Base" 0.4.0+14.04.20140312.1
124 (c++)"unity::scopes::ScopeMetadata::scope_directory() const@Base" 0.4.2+14.04.20140404.2
125+ (c++)"unity::scopes::ScopeMetadata::results_ttl_type() const@Base" 0.4.6+14.10.20140519
126 (c++)"unity::scopes::ScopeMetadata::appearance_attributes() const@Base" 0.4.2+14.04.20140404.2
127 (c++)"unity::scopes::ScopeMetadata::art() const@Base" 0.4.0+14.04.20140312.1
128 (c++)"unity::scopes::ScopeMetadata::icon() const@Base" 0.4.0+14.04.20140312.1
129@@ -541,7 +562,6 @@
130 (c++)"unity::scopes::ScopeMetadata::scope_id() const@Base" 0.4.0+14.04.20140312.1
131 (c++)"unity::scopes::ScopeMetadata::invisible() const@Base" 0.4.0+14.04.20140312.1
132 (c++)"unity::scopes::ScopeMetadata::serialize() const@Base" 0.4.0+14.04.20140312.1
133- (c++)"unity::scopes::ScopeMetadata::results_ttl_type() const@Base" 0.4.6+14.10.20140519
134 (c++)"unity::scopes::ActionMetadata::scope_data() const@Base" 0.4.0+14.04.20140312.1
135 (c++)"unity::scopes::ActionMetadata::form_factor() const@Base" 0.4.0+14.04.20140312.1
136 (c++)"unity::scopes::ActionMetadata::locale() const@Base" 0.4.0+14.04.20140312.1
137@@ -573,10 +593,17 @@
138 (c++)"unity::scopes::ActivationResponse::query() const@Base" 0.4.0+14.04.20140312.1
139 (c++)"unity::scopes::ActivationResponse::status() const@Base" 0.4.0+14.04.20140312.1
140 (c++)"unity::scopes::ActivationResponse::serialize() const@Base" 0.4.0+14.04.20140312.1
141+ (c++)"unity::scopes::RadioButtonsFilter::update_state(unity::scopes::FilterState&, std::shared_ptr<unity::scopes::FilterOption const>, bool) const@Base" 0replaceme
142+ (c++)"unity::scopes::RadioButtonsFilter::active_option(unity::scopes::FilterState const&) const@Base" 0replaceme
143+ (c++)"unity::scopes::RadioButtonsFilter::has_active_option(unity::scopes::FilterState const&) const@Base" 0replaceme
144+ (c++)"unity::scopes::RadioButtonsFilter::fwd() const@Base" 0replaceme
145+ (c++)"unity::scopes::RadioButtonsFilter::label() const@Base" 0replaceme
146+ (c++)"unity::scopes::RadioButtonsFilter::options() const@Base" 0replaceme
147 (c++)"unity::scopes::MiddlewareException::self() const@Base" 0.4.0+14.04.20140312.1
148 (c++)"unity::scopes::OptionSelectorFilter::multi_select() const@Base" 0.4.0+14.04.20140312.1
149 (c++)"unity::scopes::OptionSelectorFilter::update_state(unity::scopes::FilterState&, std::shared_ptr<unity::scopes::FilterOption const>, bool) const@Base" 0.4.0+14.04.20140312.1
150 (c++)"unity::scopes::OptionSelectorFilter::active_options(unity::scopes::FilterState const&) const@Base" 0.4.0+14.04.20140312.1
151+ (c++)"unity::scopes::OptionSelectorFilter::has_active_option(unity::scopes::FilterState const&) const@Base" 0replaceme
152 (c++)"unity::scopes::OptionSelectorFilter::fwd() const@Base" 0.4.0+14.04.20140312.1
153 (c++)"unity::scopes::OptionSelectorFilter::label() const@Base" 0.4.0+14.04.20140312.1
154 (c++)"unity::scopes::OptionSelectorFilter::options() const@Base" 0.4.0+14.04.20140312.1
155@@ -644,13 +671,13 @@
156 (c++)"unity::scopes::internal::ScopeConfig::idle_timeout() const@Base" 0.4.5+14.10.20140513
157 (c++)"unity::scopes::internal::ScopeConfig::overrideable() const@Base" 0.4.0+14.04.20140312.1
158 (c++)"unity::scopes::internal::ScopeConfig::scope_runner() const@Base" 0.4.2+14.04.20140404.2
159+ (c++)"unity::scopes::internal::ScopeConfig::results_ttl_type() const@Base" 0.4.6+14.10.20140519
160 (c++)"unity::scopes::internal::ScopeConfig::appearance_attributes() const@Base" 0.4.2+14.04.20140404.2
161 (c++)"unity::scopes::internal::ScopeConfig::art() const@Base" 0.4.0+14.04.20140312.1
162 (c++)"unity::scopes::internal::ScopeConfig::icon() const@Base" 0.4.0+14.04.20140312.1
163 (c++)"unity::scopes::internal::ScopeConfig::author() const@Base" 0.4.0+14.04.20140312.1
164 (c++)"unity::scopes::internal::ScopeConfig::hot_key() const@Base" 0.4.0+14.04.20140312.1
165 (c++)"unity::scopes::internal::ScopeConfig::invisible() const@Base" 0.4.0+14.04.20140312.1
166- (c++)"unity::scopes::internal::ScopeConfig::results_ttl_type() const@Base" 0.4.6+14.10.20140519
167 (c++)"unity::scopes::internal::ScopeLoader::scope_base() const@Base" 0.4.0+14.04.20140312.1
168 (c++)"unity::scopes::internal::ScopeLoader::libpath() const@Base" 0.4.0+14.04.20140312.1
169 (c++)"unity::scopes::internal::ScopeLoader::scope_id() const@Base" 0.4.2+14.04.20140404.2
170@@ -693,6 +720,7 @@
171 (c++)"unity::scopes::internal::ScopeMetadataImpl::search_hint() const@Base" 0.4.0+14.04.20140312.1
172 (c++)"unity::scopes::internal::ScopeMetadataImpl::display_name() const@Base" 0.4.0+14.04.20140312.1
173 (c++)"unity::scopes::internal::ScopeMetadataImpl::scope_directory() const@Base" 0.4.2+14.04.20140404.2
174+ (c++)"unity::scopes::internal::ScopeMetadataImpl::results_ttl_type() const@Base" 0.4.6+14.10.20140519
175 (c++)"unity::scopes::internal::ScopeMetadataImpl::appearance_attributes() const@Base" 0.4.2+14.04.20140404.2
176 (c++)"unity::scopes::internal::ScopeMetadataImpl::art() const@Base" 0.4.0+14.04.20140312.1
177 (c++)"unity::scopes::internal::ScopeMetadataImpl::icon() const@Base" 0.4.0+14.04.20140312.1
178@@ -710,6 +738,7 @@
179 (c++)"typeinfo for unity::scopes::SearchReply@Base" 0.4.0+14.04.20140312.1
180 (c++)"typeinfo for unity::scopes::ListenerBase@Base" 0.4.0+14.04.20140312.1
181 (c++)"typeinfo for unity::scopes::PreviewReply@Base" 0.4.0+14.04.20140312.1
182+ (c++)"typeinfo for unity::scopes::RatingFilter@Base" 0replaceme
183 (c++)"typeinfo for unity::scopes::PreviewWidget@Base" 0.4.0+14.04.20140312.1
184 (c++)"typeinfo for unity::scopes::VariantBuilder@Base" 0.4.0+14.04.20140312.1
185 (c++)"typeinfo for unity::scopes::ConfigException@Base" 0.4.0+14.04.20140312.1
186@@ -720,6 +749,7 @@
187 (c++)"typeinfo for unity::scopes::TimeoutException@Base" 0.4.0+14.04.20140312.1
188 (c++)"typeinfo for unity::scopes::CategorisedResult@Base" 0.4.0+14.04.20140312.1
189 (c++)"typeinfo for unity::scopes::NotFoundException@Base" 0.4.0+14.04.20140312.1
190+ (c++)"typeinfo for unity::scopes::RadioButtonsFilter@Base" 0replaceme
191 (c++)"typeinfo for unity::scopes::SearchListenerBase@Base" 0.4.0+14.04.20140312.1
192 (c++)"typeinfo for unity::scopes::ActivationQueryBase@Base" 0.4.0+14.04.20140312.1
193 (c++)"typeinfo for unity::scopes::MiddlewareException@Base" 0.4.0+14.04.20140312.1
194@@ -748,6 +778,7 @@
195 (c++)"typeinfo name for unity::scopes::SearchReply@Base" 0.4.0+14.04.20140312.1
196 (c++)"typeinfo name for unity::scopes::ListenerBase@Base" 0.4.0+14.04.20140312.1
197 (c++)"typeinfo name for unity::scopes::PreviewReply@Base" 0.4.0+14.04.20140312.1
198+ (c++)"typeinfo name for unity::scopes::RatingFilter@Base" 0replaceme
199 (c++)"typeinfo name for unity::scopes::PreviewWidget@Base" 0.4.0+14.04.20140312.1
200 (c++)"typeinfo name for unity::scopes::VariantBuilder@Base" 0.4.0+14.04.20140312.1
201 (c++)"typeinfo name for unity::scopes::ConfigException@Base" 0.4.0+14.04.20140312.1
202@@ -758,6 +789,7 @@
203 (c++)"typeinfo name for unity::scopes::TimeoutException@Base" 0.4.0+14.04.20140312.1
204 (c++)"typeinfo name for unity::scopes::CategorisedResult@Base" 0.4.0+14.04.20140312.1
205 (c++)"typeinfo name for unity::scopes::NotFoundException@Base" 0.4.0+14.04.20140312.1
206+ (c++)"typeinfo name for unity::scopes::RadioButtonsFilter@Base" 0replaceme
207 (c++)"typeinfo name for unity::scopes::SearchListenerBase@Base" 0.4.0+14.04.20140312.1
208 (c++)"typeinfo name for unity::scopes::ActivationQueryBase@Base" 0.4.0+14.04.20140312.1
209 (c++)"typeinfo name for unity::scopes::MiddlewareException@Base" 0.4.0+14.04.20140312.1
210@@ -797,6 +829,7 @@
211 (c++)"vtable for unity::scopes::SearchReply@Base" 0.4.0+14.04.20140312.1
212 (c++)"vtable for unity::scopes::ListenerBase@Base" 0.4.0+14.04.20140312.1
213 (c++)"vtable for unity::scopes::PreviewReply@Base" 0.4.0+14.04.20140312.1
214+ (c++)"vtable for unity::scopes::RatingFilter@Base" 0replaceme
215 (c++)"vtable for unity::scopes::PreviewWidget@Base" 0.4.0+14.04.20140312.1
216 (c++)"vtable for unity::scopes::VariantBuilder@Base" 0.4.0+14.04.20140312.1
217 (c++)"vtable for unity::scopes::ConfigException@Base" 0.4.0+14.04.20140312.1
218@@ -807,6 +840,7 @@
219 (c++)"vtable for unity::scopes::TimeoutException@Base" 0.4.0+14.04.20140312.1
220 (c++)"vtable for unity::scopes::CategorisedResult@Base" 0.4.0+14.04.20140312.1
221 (c++)"vtable for unity::scopes::NotFoundException@Base" 0.4.0+14.04.20140312.1
222+ (c++)"vtable for unity::scopes::RadioButtonsFilter@Base" 0replaceme
223 (c++)"vtable for unity::scopes::SearchListenerBase@Base" 0.4.0+14.04.20140312.1
224 (c++)"vtable for unity::scopes::ActivationQueryBase@Base" 0.4.0+14.04.20140312.1
225 (c++)"vtable for unity::scopes::MiddlewareException@Base" 0.4.0+14.04.20140312.1
226
227=== modified file 'demo/client.cpp'
228--- demo/client.cpp 2014-04-29 13:51:44 +0000
229+++ demo/client.cpp 2014-05-21 14:02:43 +0000
230@@ -422,10 +422,11 @@
231 }
232
233 auto meta = r->get_metadata(scope_id);
234- cout << "Scope metadata: " << endl;
235- cout << "\tscope_id: " << meta.scope_id() << endl;
236- cout << "\tdisplay_name: " << meta.display_name() << endl;
237- cout << "\tdescription: " << meta.description() << endl;
238+ cout << "Scope metadata: " << endl;
239+ cout << "\tscope_id: " << meta.scope_id() << endl;
240+ cout << "\tdisplay_name: " << meta.display_name() << endl;
241+ cout << "\tdescription: " << meta.description() << endl;
242+ cout << "\tappearance attr: " << to_string(Variant(meta.appearance_attributes())) << endl;
243 string tmp;
244 try
245 {
246
247=== modified file 'demo/scopes/scope-A/scope-A.cpp'
248--- demo/scopes/scope-A/scope-A.cpp 2014-04-29 11:20:57 +0000
249+++ demo/scopes/scope-A/scope-A.cpp 2014-05-21 14:02:43 +0000
250@@ -59,7 +59,7 @@
251 reply->register_departments(departments);
252
253 Filters filters;
254- auto filter = OptionSelectorFilter::create("f1", "Options");
255+ OptionSelectorFilter::SPtr filter = OptionSelectorFilter::create("f1", "Options");
256 filter->add_option("1", "Option 1");
257 filter->add_option("2", "Option 2");
258 filters.push_back(filter);
259
260=== modified file 'doc/tutorial.dox'
261--- doc/tutorial.dox 2014-05-08 10:47:45 +0000
262+++ doc/tutorial.dox 2014-05-21 14:02:43 +0000
263@@ -188,7 +188,7 @@
264 and \link unity::scopes::SearchReply::push push\endlink.
265
266 The \link unity::scopes::SearchReply::register_category register_category\endlink method is a factory method for creating new categories (see
267-\link unity::scopes::Category\endlink). Categories can be created at any point during query processing inside run method, but it's recommended to create
268+\link unity::scopes::Category\endlink). Categories can be created at any point during query processing inside run method, but we recommend to create
269 them as soon as possible (ideally as soon as they are known to the scope).
270
271 When creating a category, one of its parameters is a \link unity::scopes::CategoryRenderer \endlink instance,
272@@ -552,29 +552,39 @@
273 restart scope-registry
274 \endverbatim
275
276-The scope will be installed under one of the "scopes directories"
277+Scopes are installed under one of the "scopes directories"
278 scanned by the scope registry. Currently these default to:
279
280 <ul>
281 <li>/usr/lib/${arch}/unity-scopes</li>
282 <li>/custom/lib/${arch}/unity-scopes</li>
283-<!-- <li>??? Click packages?</li> -->
284+<li>$HOME/.local/share/unity-scopes</li>
285 </ul>
286
287-Individual scopes are installed into a subdirectory matching the
288-scope's name. At a minimum, the directory structure should contain
289-the following:
290+The `/usr/lib` directory is for scopes that are pre-installed by Canonical.
291+The `/custom/lib` directory is for scopes that pre-installed by OEMs.
292+The `$HOME/.local` directory is for scopes that are installed from click packages.
293+
294+Individual scopes are installed into subdirectories of these
295+installation directories. The name of the subdirectory containing
296+a scope's `.ini` and `.so` files can be anything but, to avoid name clashes,
297+we strongly suggest something that is unique, such as `com.canonical.scopes.scopename`.
298+At a minimum, the directory structure must contain the following:
299
300 -+- ${scopesdir}
301- `-+- scopename
302+ `-+- subdirectory
303 |--- scopename.ini
304- `--- libscopename.so
305+ `--- <library>.so
306
307-That is, a scope metadata file and a shared library containing the
308-scope code. The scope author is free to ship additional data in this
309+That is, each subdirectory must contain a scope `.ini` file and a shared library containing the
310+scope code. The scope author is free to ship additional data in this
311 directory (e.g. icons and screenshots).
312
313-The scope metadata file uses the standard ini file format, with the
314+The name of the scope's `.ini` file _must_ be a unique ID for the scope. We _strongly_
315+suggest to use a unique identifier, such as `com.canonical.scopes.scopename`, to avoid
316+clashes with scopes created by other developers.
317+
318+The scope `.ini` file uses the standard `.ini` file format, with the
319 following keys:
320
321 [ScopeConfig]
322@@ -585,8 +595,22 @@
323 Art = path to screenshot of the scope
324 SearchHint = hint text displayed to user when viewing scope
325 HotKey =
326-
327-In addition to allowing the registry to make the scope available, this information controls how the scope appears in the "Scopes" scope.
328+ ResultsTtlType = None, Small, Medium, or Large
329+
330+ [Appearance]
331+ TODO: document valid attributes
332+
333+The `ScopeConfig` group is mandatory and must contain settings for at least `DisplayName`, `Description`, and Author.
334+`DisplayName` and `Description` can (and should) be localized. For example:
335+
336+`Description[de] = Fu&szlig;ballergebnisse`
337+
338+In addition to allowing the registry to make the scope available, this information controls how the scope appears
339+in the "Scopes" scope.
340+
341+The name of of the scope's `.so` file can be `libscopename.so`, `scopename.so`, or simply `scope.so`. For example,
342+for a scope named `Fred`, the names `libFred.so`, `Fred.so`, and `scope.so` are acceptable. (No other library
343+names are valid.)
344
345 \subsection scopetool Previewing scope
346
347@@ -599,16 +623,17 @@
348 sudo apt-get install unity-scope-tool
349 \endverbatim
350
351-After installation, you can run the scope-tool with a parameter specifying
352-path to your scope configuration file (for example `unity-scope-tool ~/dev/myscope/build/myscope.ini`). If a binary for your scope can be found in the same
353-directory (ie there's `~/dev/myscope/build/libmyscope.so`), the scope-tool will
354+After installation, you can run the scope-tool with a parameter specifying the
355+path to your scope configuration file (for example `unity-scope-tool ~/dev/myscope/build/myscope.ini`).
356+If a binary for your scope can be found in the same
357+directory, the scope-tool will
358 display surfacing and search results provided by your scope, and allow you to
359 perform searches, invoke previews and actions within previews.
360
361-Note that the scope-tool is using the same rendering mechanism as Unity
362-itself, and therefore what you see in the scope-tool is what you get in Unity.
363+Note that the scope-tool uses the same rendering mechanism as Unity
364+itself and, therefore, what you see in the scope-tool is what you get in Unity.
365 It can also be used to fine-tune the category definitions, as it allows you
366-to manipulate the definitions on the fly, and once you're happy with the result
367+to manipulate the definitions on the fly. Once you are happy with the result
368 you can just copy the JSON definition back into your scope
369 (see unity::scopes::CategoryRenderer::CategoryRenderer()).
370
371
372=== modified file 'include/unity/scopes/OptionSelectorFilter.h'
373--- include/unity/scopes/OptionSelectorFilter.h 2014-05-08 16:10:18 +0000
374+++ include/unity/scopes/OptionSelectorFilter.h 2014-05-21 14:02:43 +0000
375@@ -57,7 +57,7 @@
376 \param multi_select If true, the filter permits more than option to be selected; otherwise, only a single
377 option can be selected.
378 */
379- static OptionSelectorFilter::SPtr create(std::string const& id, std::string const& label, bool multi_select = false);
380+ static OptionSelectorFilter::UPtr create(std::string const& id, std::string const& label, bool multi_select = false);
381
382 /**
383 \brief Get the label of this filter.
384@@ -84,6 +84,13 @@
385 std::list<FilterOption::SCPtr> options() const;
386
387 /**
388+ \brief Check if an option is active for this filter.
389+ \param filter_state The state of filters
390+ \return true if an option is active
391+ */
392+ bool has_active_option(FilterState const& filter_state) const;
393+
394+ /**
395 \brief Get active options from an instance of FilterState for this filter.
396 \return The set of selected filter options.
397 */
398
399=== added file 'include/unity/scopes/RadioButtonsFilter.h'
400--- include/unity/scopes/RadioButtonsFilter.h 1970-01-01 00:00:00 +0000
401+++ include/unity/scopes/RadioButtonsFilter.h 2014-05-21 14:02:43 +0000
402@@ -0,0 +1,124 @@
403+/*
404+ * Copyright (C) 2014 Canonical Ltd
405+ *
406+ * This program is free software: you can redistribute it and/or modify
407+ * it under the terms of the GNU Lesser General Public License version 3 as
408+ * published by the Free Software Foundation.
409+ *
410+ * This program is distributed in the hope that it will be useful,
411+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
412+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
413+ * GNU Lesser General Public License for more details.
414+ *
415+ * You should have received a copy of the GNU Lesser General Public License
416+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
417+ *
418+ * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com>
419+ */
420+
421+#ifndef UNITY_SCOPES_RADIOBUTTONSFILTER_H
422+#define UNITY_SCOPES_RADIOBUTTONSFILTER_H
423+
424+#include <unity/scopes/FilterBase.h>
425+#include <unity/scopes/FilterOption.h>
426+
427+namespace unity
428+{
429+
430+namespace scopes
431+{
432+
433+class FilterState;
434+
435+namespace internal
436+{
437+
438+class RadioButtonsFilterImpl;
439+
440+}
441+
442+/**
443+\brief A filter that displays mutually exclusive list of options.
444+
445+Displays filter with a set of options and allows only one option to be selected at a time.
446+*/
447+class UNITY_API RadioButtonsFilter : public FilterBase
448+{
449+public:
450+/// @cond
451+ UNITY_DEFINES_PTRS(RadioButtonsFilter);
452+/// @endcond
453+
454+ /**
455+ \brief Creates RadioButtonsFilter filter.
456+
457+ Creates an empty RadioButtonsFilter filter. Use unity::scopes::RadioButtonsFilter::add_option() to add options to it.
458+ \param id A unique identifier for the filter that can be used to identify it later among several filters.
459+ \param label A display label for this filter
460+ \return Instance of RadioButtonsFilter
461+ */
462+ static RadioButtonsFilter::UPtr create(std::string const& id, std::string const& label);
463+
464+ /**
465+ \brief Adds a new option to the filter.
466+
467+ \param id A unique identifier of the option.
468+ \param label A display label for the option
469+ \return Instance of FilterOption
470+ */
471+ FilterOption::SCPtr add_option(std::string const& id, std::string const& label);
472+
473+ /**
474+ \brief Get the label of this filter.
475+ \return The filter label.
476+ */
477+ std::string label() const;
478+
479+ /**
480+ \brief Get active option from an instance of FilterState for this filter.
481+ \return The active option or nullptr if no option is active.
482+ */
483+ FilterOption::SCPtr active_option(FilterState const& filter_state) const;
484+
485+ /**
486+ \brief Check if active options.
487+ \param filter_state The state of filters
488+ \return true if there is at least one option active
489+ */
490+ bool has_active_option(FilterState const& filter_state) const;
491+
492+
493+ /**
494+ \brief Get all options of this filter, in the order they were added.
495+ \return The list of options.
496+ */
497+ std::list<FilterOption::SCPtr> options() const;
498+
499+ /**
500+ \brief Marks given FilterOption of this filter instance as active (or not active) in a FilterState object.
501+
502+ Records the given FilterOption as "selected" in the FilterState. This is meant to be used to modify a
503+ FilterState received with a search request before sending it back to the client (UI shell).
504+ Only one option can be active at a time - marking an option active automatically deactivates any other option.
505+ */
506+ void update_state(FilterState& filter_state, FilterOption::SCPtr option, bool active) const;
507+
508+ /**
509+ \brief Marks an option of a filter active/inactive in a FilterState object, without having an instance of OptionSelectorFilter.
510+
511+ Updates an instance of FilterState, without the need for an OptionSelectorFilter instance. This is meant
512+ to be used when creating a canned Query that references another scope.
513+ */
514+ static void update_state(FilterState& filter_state, std::string const& filter_id, std::string const& option_id, bool value);
515+
516+private:
517+ RadioButtonsFilter(internal::RadioButtonsFilterImpl*);
518+ internal::RadioButtonsFilterImpl* fwd() const;
519+ friend class internal::RadioButtonsFilterImpl;
520+};
521+
522+} // namespace scopes
523+
524+} // namespace unity
525+
526+#endif
527
528=== modified file 'include/unity/scopes/RangeInputFilter.h'
529--- include/unity/scopes/RangeInputFilter.h 2014-05-09 11:26:27 +0000
530+++ include/unity/scopes/RangeInputFilter.h 2014-05-21 14:02:43 +0000
531@@ -124,10 +124,10 @@
532 \brief Store start and end value in the filter state, without having an instance of RangeInputFilter.
533
534 Updates filter_state with start and end values without an instance of RangeInputFilter. This is meant
535+ for the explanation of this method.
536 to be used when creating a CannedQuery that points to a foreign scope.
537
538 See the documentation of unity::scopes::update_state(FilterState const& filter_state, Variant const& start_value, Variant const& end_value)
539- for the explanation of this method.
540
541 \param filter_state FilterState instance to update
542 \param filter_id Unique identifier of filter
543
544=== added file 'include/unity/scopes/RatingFilter.h'
545--- include/unity/scopes/RatingFilter.h 1970-01-01 00:00:00 +0000
546+++ include/unity/scopes/RatingFilter.h 2014-05-21 14:02:43 +0000
547@@ -0,0 +1,180 @@
548+/*
549+ * Copyright (C) 2014 Canonical Ltd
550+ *
551+ * This program is free software: you can redistribute it and/or modify
552+ * it under the terms of the GNU Lesser General Public License version 3 as
553+ * published by the Free Software Foundation.
554+ *
555+ * This program is distributed in the hope that it will be useful,
556+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
557+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
558+ * GNU Lesser General Public License for more details.
559+ *
560+ * You should have received a copy of the GNU Lesser General Public License
561+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
562+ *
563+ * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com>
564+ */
565+
566+#ifndef UNITY_SCOPES_RATINGFILTER_H
567+#define UNITY_SCOPES_RATINGFILTER_H
568+
569+#include <unity/scopes/FilterBase.h>
570+#include <unity/scopes/FilterOption.h>
571+
572+namespace unity
573+{
574+
575+namespace scopes
576+{
577+
578+class FilterState;
579+
580+namespace internal
581+{
582+
583+class RatingFilterImpl;
584+
585+}
586+
587+/**
588+\brief A filter that allows for rating-based selection.
589+
590+Displays filter with a set of options, where every option has a label and icon.
591+Only one option can be active at a time. The active option uses the icon in "on" state
592+(see unity::scopes::RatingFilter::set_on_icon() ). All other icons are "off" (see unity::scopes::RatingFilter::set_off_icon() ).
593+By default, "on" and "off" icons are bright and dim star respectively.
594+
595+This filter is best suited for rating-based filtering.
596+*/
597+class UNITY_API RatingFilter : public FilterBase
598+{
599+public:
600+/// @cond
601+ UNITY_DEFINES_PTRS(RatingFilter);
602+/// @endcond
603+
604+ /**
605+ \brief Creates RatingFilter widget.
606+
607+ Creates an empty RatingFilter widget. Use unity::scopes::RatingFilter::add_option() to add rating options to it.
608+ \param id A unique identifier for the filter that can be used to identify it later among several filters.
609+ \param label A display label for this filter
610+ \return Instance of RatingFilter
611+ */
612+ static RatingFilter::UPtr create(std::string const& id, std::string const& label);
613+
614+ /**
615+ \brief Creates RatingFilter widget.
616+
617+ Creates a RatingFilter widget and populates it with some standard rating options.
618+ This is a convienience factory method, that fills RatingFilter in with options for ratings
619+ from 1 up to top_rating. Options are created with identifiers "1", "2" and so on, and labels
620+ "1+", "2+" etc., except for that last label, which is just the number (no plus sign). The maximum top_rating
621+ allowed is 10.
622+
623+ \param id A unique identifier for the filter that can be used to identify it later among several filters.
624+ \param label A display label for this filter
625+ \param top_rating The maximum rating allowed.
626+ \return Instance of RatingFilter
627+ */
628+ static RatingFilter::UPtr create(std::string const& id, std::string const& label, int top_rating);
629+
630+ /**
631+ \brief Adds a new option to the filter.
632+
633+ \param id A unique identifier of the option.
634+ \param label A display label for the option
635+ \return Instance of FilterOption
636+ */
637+ FilterOption::SCPtr add_option(std::string const& id, std::string const& label);
638+
639+ /**
640+ \brief Set a custom icon for the "on" state.
641+
642+ If not set, a star icon will be used by default.
643+
644+ \param on_icon icon uri
645+ */
646+ void set_on_icon(std::string const& on_icon);
647+
648+ /**
649+ \brief Set a custom icon for the "off" state.
650+
651+ If not set, a dim star icon will be used by default.
652+
653+ \param off_icon icon uri
654+ */
655+ void set_off_icon(std::string const& off_icon);
656+
657+ /**
658+ \brief Get the label of this filter.
659+ \return The filter label.
660+ */
661+ std::string label() const;
662+
663+ /**
664+ \brief Get custom icon for the "on" state.
665+
666+ If empty, then the default icon will be used.
667+
668+ \return icon uri or empty string
669+ */
670+ std::string on_icon() const;
671+
672+ /**
673+ \brief Get custom icon for the "off" state.
674+
675+ If empty, then the default icon will be used.
676+
677+ \return icon uri or empty string
678+ */
679+ std::string off_icon() const;
680+
681+ /**
682+ \brief Get all options of this filter, in the order they were added.
683+ \return The list of options.
684+ */
685+ std::list<FilterOption::SCPtr> options() const;
686+
687+ /**
688+ \brief Check if a rating option is active.
689+ \param filter_state The state of filters
690+ \return true if a rating option is active.
691+ */
692+ bool has_active_rating(FilterState const& filter_state) const;
693+
694+ /**
695+ \brief Get active option from an instance of FilterState for this filter.
696+ \return The active option or nullptr if no option is active.
697+ */
698+ FilterOption::SCPtr active_rating(FilterState const& filter_state) const;
699+
700+ /**
701+ \brief Marks given FilterOption of this filter instance as active (or not active) in a FilterState object.
702+
703+ Records the given FilterOption as "selected" in the FilterState. This is meant to be used to modify a
704+ FilterState received with a search request before sending it back to the client (UI shell).
705+ Only one option can be active at a time - marking an option active automatically deactivates any other option.
706+ */
707+ void update_state(FilterState& filter_state, FilterOption::SCPtr option, bool active) const;
708+
709+ /**
710+ \brief Marks an option of a filter active/inactive in a FilterState object, without having an instance of OptionSelectorFilter.
711+
712+ Updates an instance of FilterState, without the need for an OptionSelectorFilter instance. This is meant
713+ to be used when creating a canned Query that references another scope.
714+ */
715+ static void update_state(FilterState& filter_state, std::string const& filter_id, std::string const& option_id, bool value);
716+
717+private:
718+ RatingFilter(internal::RatingFilterImpl*);
719+ internal::RatingFilterImpl* fwd() const;
720+ friend class internal::RatingFilterImpl;
721+};
722+
723+} // namespace scopes
724+
725+} // namespace unity
726+
727+#endif
728
729=== modified file 'include/unity/scopes/internal/FilterBaseImpl.h'
730--- include/unity/scopes/internal/FilterBaseImpl.h 2014-05-02 10:19:46 +0000
731+++ include/unity/scopes/internal/FilterBaseImpl.h 2014-05-21 14:02:43 +0000
732@@ -47,6 +47,7 @@
733 static FilterBase::SCPtr deserialize(VariantMap const& var);
734 static VariantArray serialize_filters(Filters const& filters);
735 static Filters deserialize_filters(VariantArray const& var);
736+ static void validate_filters(Filters const& filters);
737
738 protected:
739 virtual void serialize(VariantMap& var) const = 0;
740
741=== added file 'include/unity/scopes/internal/MWPublisher.h'
742--- include/unity/scopes/internal/MWPublisher.h 1970-01-01 00:00:00 +0000
743+++ include/unity/scopes/internal/MWPublisher.h 2014-05-21 14:02:43 +0000
744@@ -0,0 +1,55 @@
745+/*
746+ * Copyright (C) 2014 Canonical Ltd
747+ *
748+ * This program is free software: you can redistribute it and/or modify
749+ * it under the terms of the GNU Lesser General Public License version 3 as
750+ * published by the Free Software Foundation.
751+ *
752+ * This program is distributed in the hope that it will be useful,
753+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
754+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
755+ * GNU Lesser General Public License for more details.
756+ *
757+ * You should have received a copy of the GNU Lesser General Public License
758+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
759+ *
760+ * Authored by: Marcus Tomlinson <marcus.tomlinson@canonical.com>
761+ */
762+
763+#ifndef UNITY_SCOPES_INTERNAL_MWPUBLISHER_H
764+#define UNITY_SCOPES_INTERNAL_MWPUBLISHER_H
765+
766+#include <unity/util/DefinesPtrs.h>
767+#include <unity/util/NonCopyable.h>
768+
769+namespace unity
770+{
771+
772+namespace scopes
773+{
774+
775+namespace internal
776+{
777+
778+class MWPublisher
779+{
780+public:
781+ NONCOPYABLE(MWPublisher);
782+ UNITY_DEFINES_PTRS(MWPublisher);
783+
784+ virtual ~MWPublisher();
785+
786+ virtual std::string endpoint() const = 0;
787+ virtual void send_message(std::string const& message, std::string const& topic = "") = 0;
788+
789+protected:
790+ MWPublisher();
791+};
792+
793+} // namespace internal
794+
795+} // namespace scopes
796+
797+} // namespace unity
798+
799+#endif // UNITY_SCOPES_INTERNAL_MWPUBLISHER_H
800
801=== added file 'include/unity/scopes/internal/MWSubscriber.h'
802--- include/unity/scopes/internal/MWSubscriber.h 1970-01-01 00:00:00 +0000
803+++ include/unity/scopes/internal/MWSubscriber.h 2014-05-21 14:02:43 +0000
804@@ -0,0 +1,57 @@
805+/*
806+ * Copyright (C) 2014 Canonical Ltd
807+ *
808+ * This program is free software: you can redistribute it and/or modify
809+ * it under the terms of the GNU Lesser General Public License version 3 as
810+ * published by the Free Software Foundation.
811+ *
812+ * This program is distributed in the hope that it will be useful,
813+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
814+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
815+ * GNU Lesser General Public License for more details.
816+ *
817+ * You should have received a copy of the GNU Lesser General Public License
818+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
819+ *
820+ * Authored by: Marcus Tomlinson <marcus.tomlinson@canonical.com>
821+ */
822+
823+#ifndef UNITY_SCOPES_INTERNAL_MWSUBSCRIBER_H
824+#define UNITY_SCOPES_INTERNAL_MWSUBSCRIBER_H
825+
826+#include <unity/util/DefinesPtrs.h>
827+#include <unity/util/NonCopyable.h>
828+
829+namespace unity
830+{
831+
832+namespace scopes
833+{
834+
835+namespace internal
836+{
837+
838+typedef std::function<void(std::string const& message)> SubscriberCallback;
839+
840+class MWSubscriber
841+{
842+public:
843+ NONCOPYABLE(MWSubscriber);
844+ UNITY_DEFINES_PTRS(MWSubscriber);
845+
846+ virtual ~MWSubscriber();
847+
848+ virtual std::string endpoint() const = 0;
849+ virtual void set_message_callback(SubscriberCallback callback) = 0;
850+
851+protected:
852+ MWSubscriber();
853+};
854+
855+} // namespace internal
856+
857+} // namespace scopes
858+
859+} // namespace unity
860+
861+#endif // UNITY_SCOPES_INTERNAL_MWSUBSCRIBER_H
862
863=== modified file 'include/unity/scopes/internal/MiddlewareBase.h'
864--- include/unity/scopes/internal/MiddlewareBase.h 2014-05-08 12:55:26 +0000
865+++ include/unity/scopes/internal/MiddlewareBase.h 2014-05-21 14:02:43 +0000
866@@ -20,11 +20,13 @@
867 #define UNITY_SCOPES_INTERNAL_MIDDLEWAREBASE_H
868
869 #include <unity/scopes/internal/MWObjectProxyFwd.h>
870+#include <unity/scopes/internal/MWPublisher.h>
871 #include <unity/scopes/internal/MWQueryCtrlProxyFwd.h>
872 #include <unity/scopes/internal/MWQueryProxyFwd.h>
873 #include <unity/scopes/internal/MWRegistryProxyFwd.h>
874 #include <unity/scopes/internal/MWScopeProxyFwd.h>
875 #include <unity/scopes/internal/MWStateReceiverProxyFwd.h>
876+#include <unity/scopes/internal/MWSubscriber.h>
877 #include <unity/scopes/internal/QueryObjectBase.h>
878 #include <unity/scopes/internal/QueryCtrlObjectBase.h>
879 #include <unity/scopes/internal/RegistryObjectBase.h>
880@@ -84,6 +86,9 @@
881 virtual void add_dflt_scope_object(ScopeObjectBase::SPtr const& scope) = 0;
882 virtual MWStateReceiverProxy add_state_receiver_object(std::string const& identity, StateReceiverObject::SPtr const& state_receiver) = 0;
883
884+ virtual MWPublisher::UPtr create_publisher(std::string const& publisher_id) = 0;
885+ virtual MWSubscriber::UPtr create_subscriber(std::string const& publisher_id, std::string const& topic = "") = 0;
886+
887 virtual std::string get_scope_endpoint() = 0;
888 virtual std::string get_query_endpoint() = 0;
889 virtual std::string get_query_ctrl_endpoint() = 0;
890
891=== modified file 'include/unity/scopes/internal/OptionSelectorFilterImpl.h'
892--- include/unity/scopes/internal/OptionSelectorFilterImpl.h 2014-05-08 16:10:18 +0000
893+++ include/unity/scopes/internal/OptionSelectorFilterImpl.h 2014-05-21 14:02:43 +0000
894@@ -43,9 +43,11 @@
895 OptionSelectorFilterImpl(VariantMap const& var);
896 std::string label() const;
897 bool multi_select() const;
898- FilterOption::SCPtr add_option(std::string const& id, std::string const& label);
899+ virtual FilterOption::SCPtr add_option(std::string const& id, std::string const& label);
900 std::list<FilterOption::SCPtr> options() const;
901+ int num_of_options() const;
902 std::set<FilterOption::SCPtr> active_options(FilterState const& filter_state) const;
903+ bool has_active_option(FilterState const& filter_state) const;
904 void update_state(FilterState& filter_state, FilterOption::SCPtr option, bool active) const;
905 static void update_state(FilterState& filter_state, std::string const& filter_id, std::string const& option_id, bool value);
906 static OptionSelectorFilter::SPtr create(VariantMap const& var);
907
908=== added file 'include/unity/scopes/internal/RadioButtonsFilterImpl.h'
909--- include/unity/scopes/internal/RadioButtonsFilterImpl.h 1970-01-01 00:00:00 +0000
910+++ include/unity/scopes/internal/RadioButtonsFilterImpl.h 2014-05-21 14:02:43 +0000
911@@ -0,0 +1,50 @@
912+/*
913+ * Copyright (C) 2014 Canonical Ltd
914+ *
915+ * This program is free software: you can redistribute it and/or modify
916+ * it under the terms of the GNU Lesser General Public License version 3 as
917+ * published by the Free Software Foundation.
918+ *
919+ * This program is distributed in the hope that it will be useful,
920+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
921+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
922+ * GNU Lesser General Public License for more details.
923+ *
924+ * You should have received a copy of the GNU Lesser General Public License
925+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
926+ *
927+ * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com>
928+ */
929+
930+#ifndef UNITY_INTERNAL_RADIOBUTTONSFILTERIMPL_H
931+#define UNITY_INTERNAL_RADIOBUTTONSFILTERIMPL_H
932+
933+#include <unity/scopes/internal/OptionSelectorFilterImpl.h>
934+#include <unity/scopes/RadioButtonsFilter.h>
935+
936+namespace unity
937+{
938+
939+namespace scopes
940+{
941+
942+namespace internal
943+{
944+
945+class RadioButtonsFilterImpl : public OptionSelectorFilterImpl
946+{
947+public:
948+ RadioButtonsFilterImpl(std::string const& id, std::string const& label);
949+ RadioButtonsFilterImpl(VariantMap const& var);
950+ FilterOption::SCPtr active_option(FilterState const& filter_state) const;
951+ std::string filter_type() const override;
952+ static RadioButtonsFilter::SPtr create(VariantMap const& var);
953+};
954+
955+} // namespace internal
956+
957+} // namespace scopes
958+
959+} // namespace unity
960+
961+#endif
962
963=== added file 'include/unity/scopes/internal/RatingFilterImpl.h'
964--- include/unity/scopes/internal/RatingFilterImpl.h 1970-01-01 00:00:00 +0000
965+++ include/unity/scopes/internal/RatingFilterImpl.h 2014-05-21 14:02:43 +0000
966@@ -0,0 +1,64 @@
967+/*
968+ * Copyright (C) 2014 Canonical Ltd
969+ *
970+ * This program is free software: you can redistribute it and/or modify
971+ * it under the terms of the GNU Lesser General Public License version 3 as
972+ * published by the Free Software Foundation.
973+ *
974+ * This program is distributed in the hope that it will be useful,
975+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
976+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
977+ * GNU Lesser General Public License for more details.
978+ *
979+ * You should have received a copy of the GNU Lesser General Public License
980+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
981+ *
982+ * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com>
983+ */
984+
985+#ifndef UNITY_INTERNAL_RATINGFILTERIMPL_H
986+#define UNITY_INTERNAL_RATINGFILTERIMPL_H
987+
988+#include <unity/scopes/internal/RadioButtonsFilterImpl.h>
989+#include <unity/scopes/RatingFilter.h>
990+
991+namespace unity
992+{
993+
994+namespace scopes
995+{
996+
997+namespace internal
998+{
999+
1000+class RatingFilterImpl : public RadioButtonsFilterImpl
1001+{
1002+public:
1003+ RatingFilterImpl(std::string const& id, std::string const& label);
1004+ RatingFilterImpl(std::string const& id, std::string const& label, int top_rating);
1005+ RatingFilterImpl(VariantMap const& var);
1006+ FilterOption::SCPtr add_option(std::string const& id, std::string const& label) override;
1007+ void set_on_icon(std::string const& on_icon);
1008+ void set_off_icon(std::string const& off_icon);
1009+ std::string on_icon() const;
1010+ std::string off_icon() const;
1011+ FilterOption::SCPtr active_rating(FilterState const& filter_state) const;
1012+
1013+ static RatingFilter::SPtr create(VariantMap const& var);
1014+
1015+ std::string filter_type() const override;
1016+
1017+ static const int max_rating = 10;
1018+
1019+private:
1020+ std::string on_icon_;
1021+ std::string off_icon_;
1022+};
1023+
1024+} // namespace internal
1025+
1026+} // namespace scopes
1027+
1028+} // namespace unity
1029+
1030+#endif
1031
1032=== modified file 'include/unity/scopes/internal/smartscopes/SmartScopesClient.h'
1033--- include/unity/scopes/internal/smartscopes/SmartScopesClient.h 2014-03-24 10:15:20 +0000
1034+++ include/unity/scopes/internal/smartscopes/SmartScopesClient.h 2014-05-21 14:02:43 +0000
1035@@ -54,6 +54,7 @@
1036 std::string base_url;
1037 std::shared_ptr<std::string> icon; // optional
1038 std::shared_ptr<std::string> art; // optional
1039+ std::shared_ptr<VariantMap> appearance; // optional
1040 bool invisible = false;
1041 };
1042
1043
1044=== modified file 'include/unity/scopes/internal/zmq_middleware/ObjectAdapter.h'
1045--- include/unity/scopes/internal/zmq_middleware/ObjectAdapter.h 2014-05-08 13:27:38 +0000
1046+++ include/unity/scopes/internal/zmq_middleware/ObjectAdapter.h 2014-05-21 14:02:43 +0000
1047@@ -98,8 +98,6 @@
1048 // zmqpp::socket subscribe_to_ctrl_socket();
1049 // void stop_workers() noexcept;
1050
1051- void safe_bind(zmqpp::socket& s, std::string const& endpoint);
1052-
1053 std::shared_ptr<ServantBase> find_servant(std::string const& id, std::string const& category);
1054
1055 // Thread start functions
1056
1057=== modified file 'include/unity/scopes/internal/zmq_middleware/Util.h'
1058--- include/unity/scopes/internal/zmq_middleware/Util.h 2014-01-28 06:34:03 +0000
1059+++ include/unity/scopes/internal/zmq_middleware/Util.h 2014-05-21 14:02:43 +0000
1060@@ -19,6 +19,8 @@
1061 #ifndef UNITY_SCOPES_INTERNAL_ZMQMIDDLEWARE_UTIL_H
1062 #define UNITY_SCOPES_INTERNAL_ZMQMIDDLEWARE_UTIL_H
1063
1064+#include <zmqpp/socket.hpp>
1065+
1066 #include <string>
1067
1068 namespace unity
1069@@ -35,6 +37,8 @@
1070
1071 void throw_if_bad_endpoint(std::string const& endpoint);
1072
1073+void safe_bind(zmqpp::socket& s, std::string const& endpoint);
1074+
1075 } // namespace zmq_middleware
1076
1077 } // namespace internal
1078
1079=== modified file 'include/unity/scopes/internal/zmq_middleware/ZmqMiddleware.h'
1080--- include/unity/scopes/internal/zmq_middleware/ZmqMiddleware.h 2014-05-15 00:34:39 +0000
1081+++ include/unity/scopes/internal/zmq_middleware/ZmqMiddleware.h 2014-05-21 14:02:43 +0000
1082@@ -78,10 +78,13 @@
1083 virtual void add_dflt_query_object(QueryObjectBase::SPtr const& query) override;
1084 virtual MWRegistryProxy add_registry_object(std::string const& identity, RegistryObjectBase::SPtr const& registry) override;
1085 virtual MWReplyProxy add_reply_object(ReplyObjectBase::SPtr const& reply) override;
1086- virtual MWScopeProxy add_scope_object(std::string const& identity, ScopeObjectBase::SPtr const& scope, int64_t idle_timeout = 0) override;
1087+ virtual MWScopeProxy add_scope_object(std::string const& identity, ScopeObjectBase::SPtr const& scope, int64_t idle_timeout) override;
1088 virtual void add_dflt_scope_object(ScopeObjectBase::SPtr const& scope) override;
1089 virtual MWStateReceiverProxy add_state_receiver_object(std::string const& identity, StateReceiverObject::SPtr const& state_receiver) override;
1090
1091+ virtual MWPublisher::UPtr create_publisher(std::string const& publisher_id) override;
1092+ virtual MWSubscriber::UPtr create_subscriber(std::string const& publisher_id, std::string const& topic) override;
1093+
1094 virtual std::string get_scope_endpoint() override;
1095 virtual std::string get_query_endpoint() override;
1096 virtual std::string get_query_ctrl_endpoint() override;
1097
1098=== added file 'include/unity/scopes/internal/zmq_middleware/ZmqPublisher.h'
1099--- include/unity/scopes/internal/zmq_middleware/ZmqPublisher.h 1970-01-01 00:00:00 +0000
1100+++ include/unity/scopes/internal/zmq_middleware/ZmqPublisher.h 2014-05-21 14:02:43 +0000
1101@@ -0,0 +1,83 @@
1102+/*
1103+ * Copyright (C) 2014 Canonical Ltd
1104+ *
1105+ * This program is free software: you can redistribute it and/or modify
1106+ * it under the terms of the GNU Lesser General Public License version 3 as
1107+ * published by the Free Software Foundation.
1108+ *
1109+ * This program is distributed in the hope that it will be useful,
1110+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1111+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1112+ * GNU Lesser General Public License for more details.
1113+ *
1114+ * You should have received a copy of the GNU Lesser General Public License
1115+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1116+ *
1117+ * Authored by: Marcus Tomlinson <marcus.tomlinson@canonical.com>
1118+ */
1119+
1120+#ifndef UNITY_SCOPES_INTERNAL_ZMQMIDDLEWARE_ZMQPUBLISHER_H
1121+#define UNITY_SCOPES_INTERNAL_ZMQMIDDLEWARE_ZMQPUBLISHER_H
1122+
1123+#include <unity/scopes/internal/MWPublisher.h>
1124+
1125+#include <zmqpp/context.hpp>
1126+#include <zmqpp/socket.hpp>
1127+
1128+#include <condition_variable>
1129+#include <queue>
1130+#include <thread>
1131+
1132+namespace unity
1133+{
1134+
1135+namespace scopes
1136+{
1137+
1138+namespace internal
1139+{
1140+
1141+namespace zmq_middleware
1142+{
1143+
1144+class ZmqPublisher : public virtual MWPublisher
1145+{
1146+public:
1147+ ZmqPublisher(zmqpp::context* context, std::string const& publisher_id,
1148+ std::string const& endpoint_dir);
1149+ virtual ~ZmqPublisher();
1150+
1151+ std::string endpoint() const override;
1152+ void send_message(std::string const& message, std::string const& topic) override;
1153+
1154+private:
1155+ enum ThreadState
1156+ {
1157+ NotRunning,
1158+ Running,
1159+ Stopping,
1160+ Failed
1161+ };
1162+
1163+ zmqpp::context* const context_;
1164+ std::string const endpoint_;
1165+ std::queue<std::string> message_queue_;
1166+
1167+ std::thread thread_;
1168+ std::mutex mutex_;
1169+ std::condition_variable cond_;
1170+ ThreadState thread_state_;
1171+ std::exception_ptr thread_exception_;
1172+
1173+ void publisher_thread();
1174+};
1175+
1176+} // namespace zmq_middleware
1177+
1178+} // namespace internal
1179+
1180+} // namespace scopes
1181+
1182+} // namespace unity
1183+
1184+#endif // UNITY_SCOPES_INTERNAL_ZMQMIDDLEWARE_ZMQPUBLISHER_H
1185
1186=== added file 'include/unity/scopes/internal/zmq_middleware/ZmqSubscriber.h'
1187--- include/unity/scopes/internal/zmq_middleware/ZmqSubscriber.h 1970-01-01 00:00:00 +0000
1188+++ include/unity/scopes/internal/zmq_middleware/ZmqSubscriber.h 2014-05-21 14:02:43 +0000
1189@@ -0,0 +1,86 @@
1190+/*
1191+ * Copyright (C) 2014 Canonical Ltd
1192+ *
1193+ * This program is free software: you can redistribute it and/or modify
1194+ * it under the terms of the GNU Lesser General Public License version 3 as
1195+ * published by the Free Software Foundation.
1196+ *
1197+ * This program is distributed in the hope that it will be useful,
1198+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1199+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1200+ * GNU Lesser General Public License for more details.
1201+ *
1202+ * You should have received a copy of the GNU Lesser General Public License
1203+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1204+ *
1205+ * Authored by: Marcus Tomlinson <marcus.tomlinson@canonical.com>
1206+ */
1207+
1208+#ifndef UNITY_SCOPES_INTERNAL_ZMQMIDDLEWARE_ZMQSUBSCRIBER_H
1209+#define UNITY_SCOPES_INTERNAL_ZMQMIDDLEWARE_ZMQSUBSCRIBER_H
1210+
1211+#include <unity/scopes/internal/MWSubscriber.h>
1212+
1213+#include <zmqpp/context.hpp>
1214+
1215+#include <condition_variable>
1216+#include <thread>
1217+
1218+namespace unity
1219+{
1220+
1221+namespace scopes
1222+{
1223+
1224+namespace internal
1225+{
1226+
1227+namespace zmq_middleware
1228+{
1229+
1230+class StopPublisher;
1231+
1232+class ZmqSubscriber : public virtual MWSubscriber
1233+{
1234+public:
1235+ ZmqSubscriber(zmqpp::context* context, std::string const& publisher_id,
1236+ std::string const& endpoint_dir, std::string const& topic);
1237+ virtual ~ZmqSubscriber();
1238+
1239+ std::string endpoint() const override;
1240+ void set_message_callback(SubscriberCallback callback) override;
1241+
1242+private:
1243+ enum ThreadState
1244+ {
1245+ NotRunning,
1246+ Running,
1247+ Stopping,
1248+ Failed
1249+ };
1250+
1251+ zmqpp::context* const context_;
1252+ std::string const endpoint_;
1253+ std::string const topic_;
1254+
1255+ std::thread thread_;
1256+ std::unique_ptr<StopPublisher> thread_stopper_;
1257+ std::mutex mutex_;
1258+ std::condition_variable cond_;
1259+ ThreadState thread_state_;
1260+ std::exception_ptr thread_exception_;
1261+
1262+ SubscriberCallback callback_;
1263+
1264+ void subscriber_thread();
1265+};
1266+
1267+} // namespace zmq_middleware
1268+
1269+} // namespace internal
1270+
1271+} // namespace scopes
1272+
1273+} // namespace unity
1274+
1275+#endif // UNITY_SCOPES_INTERNAL_ZMQMIDDLEWARE_ZMQSUBSCRIBER_H
1276
1277=== modified file 'scoperegistry/CMakeLists.txt'
1278--- scoperegistry/CMakeLists.txt 2014-05-06 09:00:45 +0000
1279+++ scoperegistry/CMakeLists.txt 2014-05-21 14:02:43 +0000
1280@@ -1,7 +1,6 @@
1281 set(SRC
1282 FindFiles.cpp
1283 scoperegistry.cpp
1284- ScopeSet.cpp
1285 )
1286
1287 include_directories(${CMAKE_CURRENT_SOURCE_DIR})
1288
1289=== modified file 'scoperegistry/FindFiles.cpp'
1290--- scoperegistry/FindFiles.cpp 2014-04-04 13:22:38 +0000
1291+++ scoperegistry/FindFiles.cpp 2014-05-21 14:02:43 +0000
1292@@ -21,12 +21,14 @@
1293 #include <unity/UnityExceptions.h>
1294 #include <unity/util/ResourcePtr.h>
1295
1296+#include <boost/filesystem/path.hpp>
1297+
1298+#include <map>
1299+
1300 #include <dirent.h>
1301 #include <string.h>
1302 #include <sys/stat.h>
1303
1304-#include <boost/filesystem/path.hpp>
1305-
1306 using namespace std;
1307 using namespace unity;
1308 using namespace boost;
1309@@ -86,10 +88,14 @@
1310 // Return all files of the form dir/*/<scomescope>.ini that are regular files or
1311 // symbolic links and have the specified suffix.
1312 // The empty suffix is legal and causes all regular files and symlinks to be returned.
1313+// Print error message for any scopes with an id that was seen previously.
1314
1315-vector<string> find_scope_config_files(string const& install_dir, string const& suffix)
1316+vector<string> find_scope_config_files(string const& install_dir,
1317+ string const& suffix,
1318+ function<void(string const&)> error)
1319 {
1320 vector<string> files;
1321+ map<string, string> scopes_seen;
1322
1323 auto subdirs = find_entries(install_dir, Directory);
1324 for (auto subdir : subdirs)
1325@@ -97,13 +103,18 @@
1326 auto candidates = find_entries(subdir, File);
1327 for (auto c : candidates)
1328 {
1329- // TODO Check for multiple ini files
1330-
1331 filesystem::path path(c);
1332 if (path.extension() != suffix) {
1333 continue;
1334 }
1335-
1336+ auto stem = path.stem().native();
1337+ auto const it = scopes_seen.find(stem);
1338+ if (it != scopes_seen.end())
1339+ {
1340+ error("ignoring second instance of non-unique scope: " + path.native() + "\n"
1341+ "previous instance: " + it->second);
1342+ }
1343+ scopes_seen[stem] = path.native();
1344 files.emplace_back(c);
1345 }
1346 }
1347
1348=== modified file 'scoperegistry/FindFiles.h'
1349--- scoperegistry/FindFiles.h 2013-11-21 21:44:00 +0000
1350+++ scoperegistry/FindFiles.h 2014-05-21 14:02:43 +0000
1351@@ -19,8 +19,9 @@
1352 #ifndef SCOPEREGISTRY_FINDFILES_H
1353 #define SCOPEREGISTRY_FINDFILES_H
1354
1355+#include <functional>
1356+#include <string>
1357 #include <vector>
1358-#include <string>
1359
1360 namespace scoperegistry
1361 {
1362@@ -34,11 +35,14 @@
1363 // we get those two .ini files, but no .ini files in canonical or underneath
1364 // further-nested directories.
1365
1366-std::vector<std::string> find_scope_config_files(std::string const& install_dir, std::string const& suffix);
1367+std::vector<std::string> find_scope_config_files(std::string const& install_dir,
1368+ std::string const& suffix,
1369+ std::function<void(std::string const&)> error);
1370
1371 // Return a vector of file names in dir with the given suffix.
1372
1373-std::vector<std::string> find_files(std::string const& dir, std::string const& suffix);
1374+std::vector<std::string> find_files(std::string const& dir,
1375+ std::string const& suffix);
1376
1377 } // namespace scoperegistry
1378
1379
1380=== removed file 'scoperegistry/ScopeSet.cpp'
1381--- scoperegistry/ScopeSet.cpp 2014-04-03 12:57:25 +0000
1382+++ scoperegistry/ScopeSet.cpp 1970-01-01 00:00:00 +0000
1383@@ -1,124 +0,0 @@
1384-/*
1385- * Copyright (C) 2013 Canonical Ltd
1386- *
1387- * This program is free software: you can redistribute it and/or modify
1388- * it under the terms of the Lesser GNU General Public License version 3 as
1389- * published by the Free Software Foundation.
1390- *
1391- * This program is distributed in the hope that it will be useful,
1392- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1393- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1394- * GNU Lesser General Public License for more details.
1395- *
1396- * You should have received a copy of the GNU Lesser General Public License
1397- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1398- *
1399- * Authored by: Jussi Pakkanen <jussi.pakkanen@canonical.com>
1400- */
1401-
1402-#include"FindFiles.h"
1403-#include"ScopeSet.h"
1404-#include <unity/scopes/ScopeMetadata.h>
1405-#include <unity/scopes/internal/RegistryConfig.h>
1406-#include <unity/scopes/internal/ScopeConfig.h>
1407-#include <unity/scopes/ScopeExceptions.h>
1408-#include<memory>
1409-#include<map>
1410-#include<set>
1411-#include<cstring>
1412-
1413-using namespace std;
1414-using namespace unity::scopes;
1415-using namespace unity::scopes::internal;
1416-
1417-namespace scoperegistry
1418-{
1419-
1420-static string strip_suffix(string const& s, string const& suffix)
1421-{
1422- auto s_len = s.length();
1423- auto suffix_len = suffix.length();
1424- if (s_len >= suffix_len)
1425- {
1426- if (s.compare(s_len - suffix_len, suffix_len, suffix) == 0)
1427- {
1428- return string(s, 0, s_len - suffix_len);
1429- }
1430- }
1431- return s;
1432-}
1433-
1434-struct ScopeSetPrivate
1435-{
1436- std::set<string> overridable_scopes;
1437- std::map<string, unique_ptr<ScopeConfig>> scopes;
1438-};
1439-
1440-ScopeSet::ScopeSet(const RegistryConfig& c) : p(new ScopeSetPrivate())
1441-{
1442- string canonical_dir = c.scope_installdir();
1443- string oem_dir = c.oem_installdir();
1444- auto canonical_files = find_scope_config_files(canonical_dir, ".ini");
1445- auto oem_files = find_scope_config_files(oem_dir, ".ini");
1446- for (const auto &path : canonical_files)
1447- {
1448- unique_ptr<ScopeConfig> sc(new ScopeConfig(path));
1449- // basename() modifies its argument
1450- string file_name = basename(const_cast<char*>(string(path).c_str()));
1451- string scope_id = strip_suffix(file_name, ".ini");
1452- if (sc->overrideable())
1453- {
1454- p->overridable_scopes.insert(path);
1455- }
1456- p->scopes[scope_id] = move(sc);
1457- }
1458- for (const auto &path : oem_files)
1459- {
1460- unique_ptr<ScopeConfig> sc(new ScopeConfig(path));
1461- string file_name = basename(const_cast<char*>(string(path).c_str()));
1462- string scope_id = strip_suffix(file_name, ".ini");
1463- if (p->scopes.find(scope_id) != p->scopes.end())
1464- {
1465- if (p->overridable_scopes.find(scope_id) != p->overridable_scopes.end())
1466- {
1467- p->scopes[scope_id] = move(sc);
1468- }
1469- else
1470- {
1471- // print error about trying to override a non-overridable scope.
1472- }
1473- }
1474- else
1475- {
1476- p->scopes[scope_id] = move(sc);
1477- }
1478- }
1479- // Add click scope parsing here.
1480-}
1481-
1482-ScopeSet::~ScopeSet()
1483-{
1484- delete p;
1485-}
1486-
1487-std::vector<std::string> ScopeSet::list() const
1488-{
1489- vector<string> list;
1490- for (auto &i : p->scopes)
1491- {
1492- list.push_back(i.first);
1493- }
1494- return list;
1495-}
1496-
1497-const unity::scopes::internal::ScopeConfig&
1498-ScopeSet::get(const std::string& name)
1499-{
1500- if (p->scopes.find(name) == p->scopes.end())
1501- {
1502- throw NotFoundException("Scope does not exist", name);
1503- }
1504- return *p->scopes[name].get();
1505-}
1506-
1507-}
1508
1509=== removed file 'scoperegistry/ScopeSet.h'
1510--- scoperegistry/ScopeSet.h 2014-01-14 13:36:43 +0000
1511+++ scoperegistry/ScopeSet.h 1970-01-01 00:00:00 +0000
1512@@ -1,56 +0,0 @@
1513-/*
1514- * Copyright (C) 2013 Canonical Ltd
1515- *
1516- * This program is free software: you can redistribute it and/or modify
1517- * it under the terms of the Lesser GNU General Public License version 3 as
1518- * published by the Free Software Foundation.
1519- *
1520- * This program is distributed in the hope that it will be useful,
1521- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1522- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1523- * GNU Lesser General Public License for more details.
1524- *
1525- * You should have received a copy of the GNU Lesser General Public License
1526- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1527- *
1528- * Authored by: Jussi Pakkanen <jussi.pakkanen@canonical.com>
1529- */
1530-
1531-#ifndef SCOPEREGISTRY_SCOPESET_H_
1532-#define SCOPEREGISTRY_SCOPESET_H_
1533-
1534-#include<vector>
1535-#include<string>
1536-#include<unity/scopes/internal/RegistryConfig.h>
1537-#include<unity/scopes/internal/ScopeConfig.h>
1538-
1539-
1540-namespace scoperegistry
1541-{
1542-
1543-struct ScopeSetPrivate;
1544-
1545-
1546-class ScopeSet final
1547-{
1548-
1549-public:
1550-
1551- ScopeSet(const ::unity::scopes::internal::RegistryConfig& c);
1552- ~ScopeSet();
1553-
1554- ScopeSet(const ScopeSet&) = delete;
1555- ScopeSet& operator=(const ScopeSet&) = delete;
1556-
1557- std::vector<std::string> list() const;
1558- const unity::scopes::internal::ScopeConfig& get(const std::string& name);
1559-
1560-private:
1561- ScopeSetPrivate* p;
1562-
1563-};
1564-
1565-
1566-}
1567-
1568-#endif
1569
1570=== modified file 'scoperegistry/scoperegistry.cpp'
1571--- scoperegistry/scoperegistry.cpp 2014-05-14 17:26:34 +0000
1572+++ scoperegistry/scoperegistry.cpp 2014-05-21 14:02:43 +0000
1573@@ -136,7 +136,7 @@
1574 map<string, string> fixed_scopes; // Scopes that the OEM cannot override
1575 map<string, string> overrideable_scopes; // Scopes that the OEM can override
1576
1577- auto config_files = find_scope_config_files(scope_installdir, ".ini");
1578+ auto config_files = find_scope_config_files(scope_installdir, ".ini", error);
1579 for (auto&& path : config_files)
1580 {
1581 filesystem::path p(path);
1582@@ -163,7 +163,7 @@
1583 {
1584 try
1585 {
1586- auto oem_paths = find_scope_config_files(oem_installdir, ".ini");
1587+ auto oem_paths = find_scope_config_files(oem_installdir, ".ini", error);
1588 for (auto&& path : oem_paths)
1589 {
1590 filesystem::path p(path);
1591@@ -199,7 +199,7 @@
1592 {
1593 try
1594 {
1595- auto click_paths = find_scope_config_files(click_installdir, ".ini");
1596+ auto click_paths = find_scope_config_files(click_installdir, ".ini", error);
1597 for (auto&& path : click_paths)
1598 {
1599 filesystem::path p(path);
1600@@ -424,7 +424,6 @@
1601
1602 add_local_scopes(registry, local_scopes, middleware, scoperunner_path, config_file, false, process_timeout);
1603 add_local_scopes(registry, click_scopes, middleware, scoperunner_path, config_file, true, process_timeout);
1604- local_scopes.insert(click_scopes.begin(), click_scopes.end());
1605 if (ss_reg_id.empty())
1606 {
1607 error("no remote registry configured, only local scopes will be available");
1608
1609=== modified file 'scoperunner/scoperunner.cpp'
1610--- scoperunner/scoperunner.cpp 2014-05-09 04:04:06 +0000
1611+++ scoperunner/scoperunner.cpp 2014-05-21 14:02:43 +0000
1612@@ -93,7 +93,37 @@
1613 auto rt = RuntimeImpl::create(scope_id, runtime_config);
1614 auto mw = rt->factory()->create(scope_id, reg_conf.mw_kind(), reg_conf.mw_configfile());
1615
1616- ScopeLoader::SPtr loader = ScopeLoader::load(scope_id, lib_dir + "lib" + scope_id + ".so", rt->registry());
1617+ // For a scope_id "Fred", we look for the library as "libFred.so", "Fred.so", and "scope.so".
1618+ vector<string> libs;
1619+ libs.push_back(lib_dir + "lib" + scope_id + ".so");
1620+ libs.push_back(lib_dir + scope_id + ".so");
1621+ libs.push_back(lib_dir + "scope.so");
1622+ string failed_libs;
1623+ ScopeLoader::SPtr loader;
1624+ exception_ptr ep;
1625+ for (auto const& lib : libs)
1626+ {
1627+ try
1628+ {
1629+ loader = ScopeLoader::load(scope_id, lib, rt->registry());
1630+ }
1631+ catch (unity::ResourceException& e)
1632+ {
1633+ failed_libs += "\n " + lib;
1634+ ep = e.remember(ep);
1635+ }
1636+ if (loader)
1637+ {
1638+ break;
1639+ }
1640+ }
1641+ if (!loader)
1642+ {
1643+ unity::ResourceException e("Cannot load scope " + scope_id + "; tried in the following locations:"
1644+ + failed_libs);
1645+ e.remember(ep);
1646+ throw e;
1647+ }
1648 loader->start();
1649
1650 // Give a thread to the scope to do with as it likes. If the scope doesn't want to use it and
1651
1652=== modified file 'src/scopes/CMakeLists.txt'
1653--- src/scopes/CMakeLists.txt 2014-05-08 14:49:31 +0000
1654+++ src/scopes/CMakeLists.txt 2014-05-21 14:02:43 +0000
1655@@ -29,6 +29,8 @@
1656 ${CMAKE_CURRENT_SOURCE_DIR}/PreviewWidget.cpp
1657 ${CMAKE_CURRENT_SOURCE_DIR}/QueryBase.cpp
1658 ${CMAKE_CURRENT_SOURCE_DIR}/QueryCtrl.cpp
1659+ ${CMAKE_CURRENT_SOURCE_DIR}/RadioButtonsFilter.cpp
1660+ ${CMAKE_CURRENT_SOURCE_DIR}/RatingFilter.cpp
1661 ${CMAKE_CURRENT_SOURCE_DIR}/Registry.cpp
1662 ${CMAKE_CURRENT_SOURCE_DIR}/Reply.cpp
1663 ${CMAKE_CURRENT_SOURCE_DIR}/Result.cpp
1664
1665=== modified file 'src/scopes/OptionSelectorFilter.cpp'
1666--- src/scopes/OptionSelectorFilter.cpp 2014-05-08 16:10:18 +0000
1667+++ src/scopes/OptionSelectorFilter.cpp 2014-05-21 14:02:43 +0000
1668@@ -30,9 +30,9 @@
1669 {
1670 }
1671
1672-OptionSelectorFilter::SPtr OptionSelectorFilter::create(std::string const& id, std::string const& label, bool multi_select)
1673+OptionSelectorFilter::UPtr OptionSelectorFilter::create(std::string const& id, std::string const& label, bool multi_select)
1674 {
1675- return std::shared_ptr<OptionSelectorFilter>(new OptionSelectorFilter(new internal::OptionSelectorFilterImpl(id, label, multi_select)));
1676+ return std::unique_ptr<OptionSelectorFilter>(new OptionSelectorFilter(new internal::OptionSelectorFilterImpl(id, label, multi_select)));
1677 }
1678
1679 std::string OptionSelectorFilter::label() const
1680@@ -55,6 +55,11 @@
1681 return fwd()->options();
1682 }
1683
1684+bool OptionSelectorFilter::has_active_option(FilterState const& filter_state) const
1685+{
1686+ return fwd()->has_active_option(filter_state);
1687+}
1688+
1689 std::set<FilterOption::SCPtr> OptionSelectorFilter::active_options(FilterState const& filter_state) const
1690 {
1691 return fwd()->active_options(filter_state);
1692
1693=== added file 'src/scopes/RadioButtonsFilter.cpp'
1694--- src/scopes/RadioButtonsFilter.cpp 1970-01-01 00:00:00 +0000
1695+++ src/scopes/RadioButtonsFilter.cpp 2014-05-21 14:02:43 +0000
1696@@ -0,0 +1,80 @@
1697+/*
1698+ * Copyright (C) 2014 Canonical Ltd
1699+ *
1700+ * This program is free software: you can redistribute it and/or modify
1701+ * it under the terms of the GNU Lesser General Public License version 3 as
1702+ * published by the Free Software Foundation.
1703+ *
1704+ * This program is distributed in the hope that it will be useful,
1705+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1706+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1707+ * GNU Lesser General Public License for more details.
1708+ *
1709+ * You should have received a copy of the GNU Lesser General Public License
1710+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1711+ *
1712+ * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com>
1713+*/
1714+
1715+#include <unity/scopes/RadioButtonsFilter.h>
1716+#include <unity/scopes/internal/RadioButtonsFilterImpl.h>
1717+
1718+namespace unity
1719+{
1720+
1721+namespace scopes
1722+{
1723+
1724+RadioButtonsFilter::RadioButtonsFilter(internal::RadioButtonsFilterImpl *impl)
1725+ : FilterBase(impl)
1726+{
1727+}
1728+
1729+FilterOption::SCPtr RadioButtonsFilter::add_option(std::string const& id, std::string const& label)
1730+{
1731+ return fwd()->add_option(id, label);
1732+}
1733+
1734+std::string RadioButtonsFilter::label() const
1735+{
1736+ return fwd()->label();
1737+}
1738+
1739+FilterOption::SCPtr RadioButtonsFilter::active_option(FilterState const& filter_state) const
1740+{
1741+ return fwd()->active_option(filter_state);
1742+}
1743+
1744+bool RadioButtonsFilter::has_active_option(FilterState const& filter_state) const
1745+{
1746+ return fwd()->has_active_option(filter_state);
1747+}
1748+
1749+std::list<FilterOption::SCPtr> RadioButtonsFilter::options() const
1750+{
1751+ return fwd()->options();
1752+}
1753+
1754+void RadioButtonsFilter::update_state(FilterState& filter_state, FilterOption::SCPtr option, bool active) const
1755+{
1756+ fwd()->update_state(filter_state, option, active);
1757+}
1758+
1759+void RadioButtonsFilter::update_state(FilterState& filter_state, std::string const& filter_id, std::string const& option_id, bool value)
1760+{
1761+ internal::RadioButtonsFilterImpl::update_state(filter_state, filter_id, option_id, value);
1762+}
1763+
1764+RadioButtonsFilter::UPtr RadioButtonsFilter::create(std::string const& id, std::string const& label)
1765+{
1766+ return std::unique_ptr<RadioButtonsFilter>(new RadioButtonsFilter(new internal::RadioButtonsFilterImpl(id, label)));
1767+}
1768+
1769+internal::RadioButtonsFilterImpl* RadioButtonsFilter::fwd() const
1770+{
1771+ return dynamic_cast<internal::RadioButtonsFilterImpl*>(p.get());
1772+}
1773+
1774+} // namespace scopes
1775+
1776+} // namespace unity
1777
1778=== added file 'src/scopes/RatingFilter.cpp'
1779--- src/scopes/RatingFilter.cpp 1970-01-01 00:00:00 +0000
1780+++ src/scopes/RatingFilter.cpp 2014-05-21 14:02:43 +0000
1781@@ -0,0 +1,105 @@
1782+/*
1783+ * Copyright (C) 2014 Canonical Ltd
1784+ *
1785+ * This program is free software: you can redistribute it and/or modify
1786+ * it under the terms of the GNU Lesser General Public License version 3 as
1787+ * published by the Free Software Foundation.
1788+ *
1789+ * This program is distributed in the hope that it will be useful,
1790+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1791+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1792+ * GNU Lesser General Public License for more details.
1793+ *
1794+ * You should have received a copy of the GNU Lesser General Public License
1795+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1796+ *
1797+ * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com>
1798+*/
1799+
1800+#include <unity/scopes/RatingFilter.h>
1801+#include <unity/scopes/internal/RatingFilterImpl.h>
1802+
1803+namespace unity
1804+{
1805+
1806+namespace scopes
1807+{
1808+
1809+RatingFilter::RatingFilter(internal::RatingFilterImpl *impl)
1810+ : FilterBase(impl)
1811+{
1812+}
1813+
1814+RatingFilter::UPtr RatingFilter::create(std::string const& id, std::string const& label, int top_rating)
1815+{
1816+ return std::unique_ptr<RatingFilter>(new RatingFilter(new internal::RatingFilterImpl(id, label, top_rating)));
1817+}
1818+
1819+RatingFilter::UPtr RatingFilter::create(std::string const& id, std::string const& label)
1820+{
1821+ return std::unique_ptr<RatingFilter>(new RatingFilter(new internal::RatingFilterImpl(id, label)));
1822+}
1823+
1824+FilterOption::SCPtr RatingFilter::add_option(std::string const& id, std::string const& label)
1825+{
1826+ return fwd()->add_option(id, label);
1827+}
1828+
1829+void RatingFilter::set_on_icon(std::string const& on_icon)
1830+{
1831+ fwd()->set_on_icon(on_icon);
1832+}
1833+
1834+void RatingFilter::set_off_icon(std::string const& off_icon)
1835+{
1836+ fwd()->set_off_icon(off_icon);
1837+}
1838+
1839+std::string RatingFilter::label() const
1840+{
1841+ return fwd()->label();
1842+}
1843+
1844+std::list<FilterOption::SCPtr> RatingFilter::options() const
1845+{
1846+ return fwd()->options();
1847+}
1848+
1849+std::string RatingFilter::on_icon() const
1850+{
1851+ return fwd()->on_icon();
1852+}
1853+
1854+std::string RatingFilter::off_icon() const
1855+{
1856+ return fwd()->off_icon();
1857+}
1858+
1859+FilterOption::SCPtr RatingFilter::active_rating(FilterState const& filter_state) const
1860+{
1861+ return fwd()->active_option(filter_state);
1862+}
1863+
1864+bool RatingFilter::has_active_rating(FilterState const& filter_state) const
1865+{
1866+ return fwd()->has_active_option(filter_state);
1867+}
1868+
1869+void RatingFilter::update_state(FilterState& filter_state, FilterOption::SCPtr option, bool active) const
1870+{
1871+ fwd()->update_state(filter_state, option, active);
1872+}
1873+
1874+void RatingFilter::update_state(FilterState& filter_state, std::string const& filter_id, std::string const& option_id, bool value)
1875+{
1876+ internal::RatingFilterImpl::update_state(filter_state, filter_id, option_id, value);
1877+}
1878+
1879+internal::RatingFilterImpl* RatingFilter::fwd() const
1880+{
1881+ return dynamic_cast<internal::RatingFilterImpl*>(p.get());
1882+}
1883+
1884+} // namespace scopes
1885+
1886+} // namespace unity
1887
1888=== modified file 'src/scopes/internal/CMakeLists.txt'
1889--- src/scopes/internal/CMakeLists.txt 2014-05-08 14:49:31 +0000
1890+++ src/scopes/internal/CMakeLists.txt 2014-05-21 14:02:43 +0000
1891@@ -29,12 +29,14 @@
1892 ${CMAKE_CURRENT_SOURCE_DIR}/MiddlewareBase.cpp
1893 ${CMAKE_CURRENT_SOURCE_DIR}/MiddlewareFactory.cpp
1894 ${CMAKE_CURRENT_SOURCE_DIR}/MWObject.cpp
1895+ ${CMAKE_CURRENT_SOURCE_DIR}/MWPublisher.cpp
1896 ${CMAKE_CURRENT_SOURCE_DIR}/MWQuery.cpp
1897 ${CMAKE_CURRENT_SOURCE_DIR}/MWQueryCtrl.cpp
1898 ${CMAKE_CURRENT_SOURCE_DIR}/MWRegistry.cpp
1899 ${CMAKE_CURRENT_SOURCE_DIR}/MWReply.cpp
1900 ${CMAKE_CURRENT_SOURCE_DIR}/MWScope.cpp
1901 ${CMAKE_CURRENT_SOURCE_DIR}/MWStateReceiver.cpp
1902+ ${CMAKE_CURRENT_SOURCE_DIR}/MWSubscriber.cpp
1903 ${CMAKE_CURRENT_SOURCE_DIR}/ObjectImpl.cpp
1904 ${CMAKE_CURRENT_SOURCE_DIR}/OptionSelectorFilterImpl.cpp
1905 ${CMAKE_CURRENT_SOURCE_DIR}/PreviewQueryObject.cpp
1906@@ -46,6 +48,8 @@
1907 ${CMAKE_CURRENT_SOURCE_DIR}/QueryCtrlObject.cpp
1908 ${CMAKE_CURRENT_SOURCE_DIR}/QueryMetadataImpl.cpp
1909 ${CMAKE_CURRENT_SOURCE_DIR}/QueryObject.cpp
1910+ ${CMAKE_CURRENT_SOURCE_DIR}/RadioButtonsFilterImpl.cpp
1911+ ${CMAKE_CURRENT_SOURCE_DIR}/RatingFilterImpl.cpp
1912 ${CMAKE_CURRENT_SOURCE_DIR}/RangeInputFilterImpl.cpp
1913 ${CMAKE_CURRENT_SOURCE_DIR}/Reaper.cpp
1914 ${CMAKE_CURRENT_SOURCE_DIR}/RegistryConfig.cpp
1915
1916=== modified file 'src/scopes/internal/FilterBaseImpl.cpp'
1917--- src/scopes/internal/FilterBaseImpl.cpp 2014-05-15 22:32:00 +0000
1918+++ src/scopes/internal/FilterBaseImpl.cpp 2014-05-21 14:02:43 +0000
1919@@ -22,6 +22,8 @@
1920 #include <unity/scopes/internal/Utils.h>
1921 #include <unity/scopes/internal/OptionSelectorFilterImpl.h>
1922 #include <unity/scopes/internal/RangeInputFilterImpl.h>
1923+#include <unity/scopes/internal/RadioButtonsFilterImpl.h>
1924+#include <unity/scopes/internal/RatingFilterImpl.h>
1925 #include <unity/UnityExceptions.h>
1926 #include <sstream>
1927
1928@@ -117,6 +119,14 @@
1929 {
1930 return RangeInputFilterImpl::create(var);
1931 }
1932+ if (ftype == "radio_buttons")
1933+ {
1934+ return RadioButtonsFilterImpl::create(var);
1935+ }
1936+ if (ftype == "rating")
1937+ {
1938+ return RatingFilterImpl::create(var);
1939+ }
1940 throw unity::LogicException("Unknown filter type: " + ftype);
1941 }
1942 throw unity::LogicException("FilterBase: Missing 'filter_type'");
1943@@ -142,6 +152,56 @@
1944 return filters;
1945 }
1946
1947+void FilterBaseImpl::validate_filters(Filters const& filters)
1948+{
1949+ for (auto const& f: filters)
1950+ {
1951+ if (f == nullptr)
1952+ {
1953+ throw unity::LogicException("FilterBaseImpl::validate_filters(): invalid null filter pointer");
1954+ }
1955+ {
1956+ OptionSelectorFilter::SCPtr optsel = std::dynamic_pointer_cast<OptionSelectorFilter const>(f);
1957+ if (optsel)
1958+ {
1959+ if (optsel->options().size() == 0)
1960+ {
1961+ std::stringstream err;
1962+ err << "FilterBaseImpl::validate_filters(): invalid empty OptionSelectorFilter '" << f->id() << "'";
1963+ throw unity::LogicException(err.str());
1964+ }
1965+ continue;
1966+ }
1967+ }
1968+ {
1969+ RatingFilter::SCPtr rating = std::dynamic_pointer_cast<RatingFilter const>(f);
1970+ if (rating)
1971+ {
1972+ if (rating->options().size() == 0)
1973+ {
1974+ std::stringstream err;
1975+ err << "FilterBaseImpl::validate_filters(): invalid empty RatingFilter '" << f->id() << "'";
1976+ throw unity::LogicException(err.str());
1977+ }
1978+ continue;
1979+ }
1980+ }
1981+ {
1982+ RadioButtonsFilter::SCPtr radiobtn = std::dynamic_pointer_cast<RadioButtonsFilter const>(f);
1983+ if (radiobtn)
1984+ {
1985+ if (radiobtn->options().size() == 0)
1986+ {
1987+ std::stringstream err;
1988+ err << "FilterBaseImpl::validate_filters(): invalid empty RadioButtonsFilter '" << f->id() << "'";
1989+ throw unity::LogicException(err.str());
1990+ }
1991+ continue;
1992+ }
1993+ }
1994+ }
1995+}
1996+
1997 } // namespace internal
1998
1999 } // namespace scopes
2000
2001=== added file 'src/scopes/internal/MWPublisher.cpp'
2002--- src/scopes/internal/MWPublisher.cpp 1970-01-01 00:00:00 +0000
2003+++ src/scopes/internal/MWPublisher.cpp 2014-05-21 14:02:43 +0000
2004@@ -0,0 +1,42 @@
2005+/*
2006+ * Copyright (C) 2014 Canonical Ltd
2007+ *
2008+ * This program is free software: you can redistribute it and/or modify
2009+ * it under the terms of the GNU Lesser General Public License version 3 as
2010+ * published by the Free Software Foundation.
2011+ *
2012+ * This program is distributed in the hope that it will be useful,
2013+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2014+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2015+ * GNU Lesser General Public License for more details.
2016+ *
2017+ * You should have received a copy of the GNU Lesser General Public License
2018+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2019+ *
2020+ * Authored by: Marcus Tomlinson <marcus.tomlinson@canonical.com>
2021+ */
2022+
2023+#include <unity/scopes/internal/MWPublisher.h>
2024+
2025+namespace unity
2026+{
2027+
2028+namespace scopes
2029+{
2030+
2031+namespace internal
2032+{
2033+
2034+MWPublisher::MWPublisher()
2035+{
2036+}
2037+
2038+MWPublisher::~MWPublisher()
2039+{
2040+}
2041+
2042+} // namespace internal
2043+
2044+} // namespace scopes
2045+
2046+} // namespace unity
2047
2048=== added file 'src/scopes/internal/MWSubscriber.cpp'
2049--- src/scopes/internal/MWSubscriber.cpp 1970-01-01 00:00:00 +0000
2050+++ src/scopes/internal/MWSubscriber.cpp 2014-05-21 14:02:43 +0000
2051@@ -0,0 +1,42 @@
2052+/*
2053+ * Copyright (C) 2014 Canonical Ltd
2054+ *
2055+ * This program is free software: you can redistribute it and/or modify
2056+ * it under the terms of the GNU Lesser General Public License version 3 as
2057+ * published by the Free Software Foundation.
2058+ *
2059+ * This program is distributed in the hope that it will be useful,
2060+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2061+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2062+ * GNU Lesser General Public License for more details.
2063+ *
2064+ * You should have received a copy of the GNU Lesser General Public License
2065+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2066+ *
2067+ * Authored by: Marcus Tomlinson <marcus.tomlinson@canonical.com>
2068+ */
2069+
2070+#include <unity/scopes/internal/MWSubscriber.h>
2071+
2072+namespace unity
2073+{
2074+
2075+namespace scopes
2076+{
2077+
2078+namespace internal
2079+{
2080+
2081+MWSubscriber::MWSubscriber()
2082+{
2083+}
2084+
2085+MWSubscriber::~MWSubscriber()
2086+{
2087+}
2088+
2089+} // namespace internal
2090+
2091+} // namespace scopes
2092+
2093+} // namespace unity
2094
2095=== modified file 'src/scopes/internal/OptionSelectorFilterImpl.cpp'
2096--- src/scopes/internal/OptionSelectorFilterImpl.cpp 2014-05-15 03:23:43 +0000
2097+++ src/scopes/internal/OptionSelectorFilterImpl.cpp 2014-05-21 14:02:43 +0000
2098@@ -131,6 +131,11 @@
2099 }
2100 }
2101
2102+int OptionSelectorFilterImpl::num_of_options() const
2103+{
2104+ return options_.size();
2105+}
2106+
2107 std::list<FilterOption::SCPtr> OptionSelectorFilterImpl::options() const
2108 {
2109 return options_;
2110@@ -170,6 +175,33 @@
2111 return opts;
2112 }
2113
2114+bool OptionSelectorFilterImpl::has_active_option(FilterState const& filter_state) const
2115+{
2116+ if (filter_state.has_filter(id()))
2117+ {
2118+ try
2119+ {
2120+ auto const var = FilterBaseImpl::get(filter_state, id()).get_array(); // this can throw if of different type
2121+
2122+ for (auto const& idvar: var)
2123+ {
2124+ auto const opt_id = idvar.get_string();
2125+ for (auto const& opt: options_)
2126+ {
2127+ if (opt_id == opt->id())
2128+ {
2129+ return true;
2130+ }
2131+ }
2132+ }
2133+ }
2134+ catch (...)
2135+ {
2136+ }
2137+ }
2138+ return false;
2139+}
2140+
2141 void OptionSelectorFilterImpl::update_state(FilterState& filter_state, FilterOption::SCPtr option, bool active) const
2142 {
2143 auto const oid(option->id());
2144
2145=== added file 'src/scopes/internal/RadioButtonsFilterImpl.cpp'
2146--- src/scopes/internal/RadioButtonsFilterImpl.cpp 1970-01-01 00:00:00 +0000
2147+++ src/scopes/internal/RadioButtonsFilterImpl.cpp 2014-05-21 14:02:43 +0000
2148@@ -0,0 +1,81 @@
2149+/*
2150+ * Copyright (C) 2014 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/internal/RadioButtonsFilterImpl.h>
2168+#include <unity/scopes/FilterState.h>
2169+#include <sstream>
2170+#include <unity/UnityExceptions.h>
2171+
2172+namespace unity
2173+{
2174+
2175+namespace scopes
2176+{
2177+
2178+namespace internal
2179+{
2180+
2181+RadioButtonsFilterImpl::RadioButtonsFilterImpl(std::string const& id, std::string const& label)
2182+ : OptionSelectorFilterImpl(id, label, false)
2183+{
2184+}
2185+
2186+RadioButtonsFilterImpl::RadioButtonsFilterImpl(VariantMap const& var)
2187+ : OptionSelectorFilterImpl(var)
2188+{
2189+ if (multi_select()) // this should never happen unless a client bypasses the api
2190+ {
2191+ std::stringstream err;
2192+ err << "RadioButtonsFilterImpl(): invalid filter data, multi selection is not available with RadioButtonsFilter, filter id '" << id() << "'";
2193+ throw unity::LogicException(err.str());
2194+ }
2195+}
2196+
2197+FilterOption::SCPtr RadioButtonsFilterImpl::active_option(FilterState const& filter_state) const
2198+{
2199+ auto const active = active_options(filter_state);
2200+ if (active.size() > 1) // this should never happen unless a client bypasses the api
2201+ {
2202+ std::stringstream err;
2203+ err << "RadioButtonsFilterImpl::active_option(): internal error, more than one button active, filter id '" << id() << "'";
2204+ throw unity::LogicException(err.str());
2205+ }
2206+
2207+ if (active.size() == 1)
2208+ {
2209+ return *active.begin();
2210+ }
2211+
2212+ return nullptr;
2213+}
2214+
2215+std::string RadioButtonsFilterImpl::filter_type() const
2216+{
2217+ return "radio_buttons";
2218+}
2219+
2220+RadioButtonsFilter::SPtr RadioButtonsFilterImpl::create(VariantMap const& var)
2221+{
2222+ return std::shared_ptr<RadioButtonsFilter>(new RadioButtonsFilter(new RadioButtonsFilterImpl(var)));
2223+}
2224+
2225+} // namespace internal
2226+
2227+} // namespace scopes
2228+
2229+} // namespace unity
2230
2231=== added file 'src/scopes/internal/RatingFilterImpl.cpp'
2232--- src/scopes/internal/RatingFilterImpl.cpp 1970-01-01 00:00:00 +0000
2233+++ src/scopes/internal/RatingFilterImpl.cpp 2014-05-21 14:02:43 +0000
2234@@ -0,0 +1,109 @@
2235+/*
2236+ * Copyright (C) 2014 Canonical Ltd
2237+ *
2238+ * This program is free software: you can redistribute it and/or modify
2239+ * it under the terms of the GNU Lesser General Public License version 3 as
2240+ * published by the Free Software Foundation.
2241+ *
2242+ * This program is distributed in the hope that it will be useful,
2243+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2244+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2245+ * GNU Lesser General Public License for more details.
2246+ *
2247+ * You should have received a copy of the GNU Lesser General Public License
2248+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2249+ *
2250+ * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com>
2251+*/
2252+
2253+#include <unity/scopes/RatingFilter.h>
2254+#include <unity/scopes/internal/RatingFilterImpl.h>
2255+#include <unity/UnityExceptions.h>
2256+#include <sstream>
2257+
2258+namespace unity
2259+{
2260+
2261+namespace scopes
2262+{
2263+
2264+namespace internal
2265+{
2266+
2267+RatingFilterImpl::RatingFilterImpl(std::string const& id, std::string const& label)
2268+ : RadioButtonsFilterImpl(id, label)
2269+{
2270+}
2271+
2272+RatingFilterImpl::RatingFilterImpl(std::string const& id, std::string const& label, int top_rating)
2273+ : RadioButtonsFilterImpl(id, label)
2274+{
2275+ if (top_rating < 2 || top_rating > max_rating)
2276+ {
2277+ std::stringstream err;
2278+ err << "RatingFilterImpl(): top_rating " << top_rating << " outside of allowed range for filter '" << id << "'";
2279+ throw unity::LogicException(err.str());
2280+ }
2281+
2282+ // create rating options from 1..top_rating range, e.g. "1+", "2+", ..., "5".
2283+ for (int i = 1; i <= top_rating; i++)
2284+ {
2285+ auto const num = std::to_string(i);
2286+ RadioButtonsFilterImpl::add_option(num, i < top_rating ? num + "+" : num);
2287+ }
2288+}
2289+
2290+RatingFilterImpl::RatingFilterImpl(VariantMap const& var)
2291+ : RadioButtonsFilterImpl(var)
2292+{
2293+}
2294+
2295+FilterOption::SCPtr RatingFilterImpl::add_option(std::string const& id, std::string const& label)
2296+{
2297+ if (num_of_options() < max_rating)
2298+ {
2299+ return RadioButtonsFilterImpl::add_option(id, label);
2300+ }
2301+ else
2302+ {
2303+ std::stringstream err;
2304+ err << "RatingFilterImpl::add_option(): maximum number of rating options reached for filter '" << id << "'";
2305+ throw unity::LogicException(err.str());
2306+ }
2307+}
2308+
2309+void RatingFilterImpl::set_on_icon(std::string const& on_icon)
2310+{
2311+ on_icon_ = on_icon;
2312+}
2313+
2314+void RatingFilterImpl::set_off_icon(std::string const& off_icon)
2315+{
2316+ off_icon_ = off_icon;
2317+}
2318+
2319+std::string RatingFilterImpl::on_icon() const
2320+{
2321+ return on_icon_;
2322+}
2323+
2324+std::string RatingFilterImpl::off_icon() const
2325+{
2326+ return off_icon_;
2327+}
2328+
2329+RatingFilter::SPtr RatingFilterImpl::create(VariantMap const& var)
2330+{
2331+ return std::shared_ptr<RatingFilter>(new RatingFilter(new RatingFilterImpl(var)));
2332+}
2333+
2334+std::string RatingFilterImpl::filter_type() const
2335+{
2336+ return "rating";
2337+}
2338+
2339+} // namespace internal
2340+
2341+} // namespace scopes
2342+
2343+} // namespace unity
2344
2345=== modified file 'src/scopes/internal/SearchReplyImpl.cpp'
2346--- src/scopes/internal/SearchReplyImpl.cpp 2014-04-29 11:20:57 +0000
2347+++ src/scopes/internal/SearchReplyImpl.cpp 2014-05-21 14:02:43 +0000
2348@@ -62,7 +62,7 @@
2349 }
2350 catch (unity::LogicException const &e)
2351 {
2352- throw unity::LogicException("Reply::register_departments(): Failed to validate departments");
2353+ throw unity::LogicException("SearchReplyImpl::register_departments(): Failed to validate departments");
2354 }
2355
2356 ReplyImpl::push(internal::DepartmentImpl::serialize_departments(departments, current_department_id)); // ignore return value?
2357@@ -129,6 +129,16 @@
2358
2359 bool SearchReplyImpl::push(unity::scopes::Filters const& filters, unity::scopes::FilterState const& filter_state)
2360 {
2361+ // basic consistency check
2362+ try
2363+ {
2364+ internal::FilterBaseImpl::validate_filters(filters);
2365+ }
2366+ catch (unity::LogicException const &e)
2367+ {
2368+ throw unity::LogicException("SearchReplyImpl::push(): Failed to validate filters");
2369+ }
2370+
2371 VariantMap var;
2372 var["filters"] = internal::FilterBaseImpl::serialize_filters(filters);
2373 var["filter_state"] = filter_state.serialize();
2374
2375=== modified file 'src/scopes/internal/smartscopes/SSRegistryObject.cpp'
2376--- src/scopes/internal/smartscopes/SSRegistryObject.cpp 2014-05-09 08:20:57 +0000
2377+++ src/scopes/internal/smartscopes/SSRegistryObject.cpp 2014-05-21 14:02:43 +0000
2378@@ -232,6 +232,11 @@
2379 metadata->set_art(*scope.art);
2380 }
2381
2382+ if (scope.appearance)
2383+ {
2384+ metadata->set_appearance_attributes(*scope.appearance);
2385+ }
2386+
2387 metadata->set_invisible(scope.invisible);
2388
2389 ScopeProxy proxy = ScopeImpl::create(middleware_->create_scope_proxy(scope.id, ss_scope_endpoint_),
2390
2391=== modified file 'src/scopes/internal/smartscopes/SmartScopesClient.cpp'
2392--- src/scopes/internal/smartscopes/SmartScopesClient.cpp 2014-05-09 09:56:09 +0000
2393+++ src/scopes/internal/smartscopes/SmartScopesClient.cpp 2014-05-21 14:02:43 +0000
2394@@ -259,6 +259,11 @@
2395 scope.art.reset(new std::string(child_node->get_node("art")->as_string()));
2396 }
2397
2398+ if (child_node->has_node("appearance"))
2399+ {
2400+ scope.appearance.reset(new VariantMap(child_node->get_node("appearance")->to_variant().get_dict()));
2401+ }
2402+
2403 scope.invisible = child_node->has_node("invisible") ? child_node->get_node("invisible")->as_bool() : false;
2404
2405 remote_scopes.push_back(scope);
2406
2407=== modified file 'src/scopes/internal/zmq_middleware/CMakeLists.txt'
2408--- src/scopes/internal/zmq_middleware/CMakeLists.txt 2014-04-15 00:30:07 +0000
2409+++ src/scopes/internal/zmq_middleware/CMakeLists.txt 2014-05-21 14:02:43 +0000
2410@@ -21,6 +21,7 @@
2411 ${CMAKE_CURRENT_SOURCE_DIR}/ZmqMiddleware.cpp
2412 ${CMAKE_CURRENT_SOURCE_DIR}/ZmqException.cpp
2413 ${CMAKE_CURRENT_SOURCE_DIR}/ZmqObject.cpp
2414+ ${CMAKE_CURRENT_SOURCE_DIR}/ZmqPublisher.cpp
2415 ${CMAKE_CURRENT_SOURCE_DIR}/ZmqQuery.cpp
2416 ${CMAKE_CURRENT_SOURCE_DIR}/ZmqQueryCtrl.cpp
2417 ${CMAKE_CURRENT_SOURCE_DIR}/ZmqReceiver.cpp
2418@@ -29,5 +30,6 @@
2419 ${CMAKE_CURRENT_SOURCE_DIR}/ZmqScope.cpp
2420 ${CMAKE_CURRENT_SOURCE_DIR}/ZmqSender.cpp
2421 ${CMAKE_CURRENT_SOURCE_DIR}/ZmqStateReceiver.cpp
2422+ ${CMAKE_CURRENT_SOURCE_DIR}/ZmqSubscriber.cpp
2423 )
2424 set(UNITY_SCOPES_LIB_SRC ${UNITY_SCOPES_LIB_SRC} ${SRC} PARENT_SCOPE)
2425
2426=== modified file 'src/scopes/internal/zmq_middleware/ObjectAdapter.cpp'
2427--- src/scopes/internal/zmq_middleware/ObjectAdapter.cpp 2014-05-14 04:50:14 +0000
2428+++ src/scopes/internal/zmq_middleware/ObjectAdapter.cpp 2014-05-21 14:02:43 +0000
2429@@ -494,47 +494,6 @@
2430 }
2431 }
2432
2433-// For the ipc transport, zmq permits more than one server to bind to the same endpoint.
2434-// If a server binds to an endpoint while another server is using that endpoint, the
2435-// second server silently "steals" the endpoint from the previous server, so all
2436-// connects after that point go to the new server, while connects that happened earlier
2437-// go to the old server. This is meant as a fail-over feature, and cannot be disabled.
2438-//
2439-// We don't want this and need an error if two servers try to use the same endpoint.
2440-// Hacky solution: we check whether it's possible to successfully connect to the
2441-// endpoint. If so, a server is still running there, and we throw. This has a
2442-// small race because a second server may connect after the check, but before
2443-// the bind. But, in practice, that's good enough for our purposes.
2444-
2445-void ObjectAdapter::safe_bind(zmqpp::socket& s, string const& endpoint)
2446-{
2447- const std::string transport_prefix = "ipc://";
2448- if (endpoint.substr(0, transport_prefix.size()) == transport_prefix)
2449- {
2450- string path = endpoint.substr(transport_prefix.size());
2451- struct sockaddr_un addr;
2452- memset(&addr, 0, sizeof(addr));
2453- addr.sun_family = AF_UNIX;
2454- strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path) - 1);
2455- int fd = ::socket(AF_UNIX, SOCK_STREAM, 0);
2456- if (fd == -1)
2457- {
2458- // LCOV_EXCL_START
2459- throw MiddlewareException("ObjectAdapter: broker thread failure (adapter: " + name_ + "): " +
2460- "cannot create socket: " + strerror(errno));
2461- // LCOV_EXCL_STOP
2462- }
2463- util::ResourcePtr<int, decltype(&::close)> close_guard(fd, ::close);
2464- if (::connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0)
2465- {
2466- // Connect succeeded, so another server is using the socket already.
2467- throw MiddlewareException("ObjectAdapter: broker thread failure (adapter: " + name_ + "): " +
2468- "address in use: " + endpoint);
2469- }
2470- }
2471- s.bind(endpoint);
2472-}
2473-
2474 shared_ptr<ServantBase> ObjectAdapter::find_servant(string const& id, string const& category)
2475 {
2476 shared_ptr<ServantBase> servant = find(id);
2477
2478=== modified file 'src/scopes/internal/zmq_middleware/Util.cpp'
2479--- src/scopes/internal/zmq_middleware/Util.cpp 2014-01-28 06:34:03 +0000
2480+++ src/scopes/internal/zmq_middleware/Util.cpp 2014-05-21 14:02:43 +0000
2481@@ -19,7 +19,10 @@
2482 #include <unity/scopes/internal/zmq_middleware/Util.h>
2483
2484 #include <unity/scopes/ScopeExceptions.h>
2485+#include <unity/util/ResourcePtr.h>
2486
2487+#include <unistd.h>
2488+#include <sys/socket.h>
2489 #include <sys/un.h>
2490
2491 using namespace std;
2492@@ -55,6 +58,45 @@
2493 }
2494 }
2495
2496+// For the ipc transport, zmq permits more than one server to bind to the same endpoint.
2497+// If a server binds to an endpoint while another server is using that endpoint, the
2498+// second server silently "steals" the endpoint from the previous server, so all
2499+// connects after that point go to the new server, while connects that happened earlier
2500+// go to the old server. This is meant as a fail-over feature, and cannot be disabled.
2501+//
2502+// We don't want this and need an error if two servers try to use the same endpoint.
2503+// Hacky solution: we check whether it's possible to successfully connect to the
2504+// endpoint. If so, a server is still running there, and we throw. This has a
2505+// small race because a second server may connect after the check, but before
2506+// the bind. But, in practice, that's good enough for our purposes.
2507+
2508+void safe_bind(zmqpp::socket& s, string const& endpoint)
2509+{
2510+ const std::string transport_prefix = "ipc://";
2511+ if (endpoint.substr(0, transport_prefix.size()) == transport_prefix)
2512+ {
2513+ string path = endpoint.substr(transport_prefix.size());
2514+ struct sockaddr_un addr;
2515+ memset(&addr, 0, sizeof(addr));
2516+ addr.sun_family = AF_UNIX;
2517+ strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path) - 1);
2518+ int fd = ::socket(AF_UNIX, SOCK_STREAM, 0);
2519+ if (fd == -1)
2520+ {
2521+ // LCOV_EXCL_START
2522+ throw MiddlewareException("safe_bind(): cannot create socket: " + std::string(strerror(errno)));
2523+ // LCOV_EXCL_STOP
2524+ }
2525+ util::ResourcePtr<int, decltype(&::close)> close_guard(fd, ::close);
2526+ if (::connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0)
2527+ {
2528+ // Connect succeeded, so another server is using the socket already.
2529+ throw MiddlewareException("safe_bind(): address in use: " + endpoint);
2530+ }
2531+ }
2532+ s.bind(endpoint);
2533+}
2534+
2535 } // namespace zmq_middleware
2536
2537 } // namespace internal
2538
2539=== modified file 'src/scopes/internal/zmq_middleware/ZmqMiddleware.cpp'
2540--- src/scopes/internal/zmq_middleware/ZmqMiddleware.cpp 2014-05-15 08:12:19 +0000
2541+++ src/scopes/internal/zmq_middleware/ZmqMiddleware.cpp 2014-05-21 14:02:43 +0000
2542@@ -29,12 +29,14 @@
2543 #include <unity/scopes/internal/zmq_middleware/ReplyI.h>
2544 #include <unity/scopes/internal/zmq_middleware/ScopeI.h>
2545 #include <unity/scopes/internal/zmq_middleware/StateReceiverI.h>
2546+#include <unity/scopes/internal/zmq_middleware/ZmqPublisher.h>
2547 #include <unity/scopes/internal/zmq_middleware/ZmqQuery.h>
2548 #include <unity/scopes/internal/zmq_middleware/ZmqQueryCtrl.h>
2549 #include <unity/scopes/internal/zmq_middleware/ZmqRegistry.h>
2550 #include <unity/scopes/internal/zmq_middleware/ZmqReply.h>
2551 #include <unity/scopes/internal/zmq_middleware/ZmqScope.h>
2552 #include <unity/scopes/internal/zmq_middleware/ZmqStateReceiver.h>
2553+#include <unity/scopes/internal/zmq_middleware/ZmqSubscriber.h>
2554 #include <unity/scopes/internal/zmq_middleware/RethrowException.h>
2555 #include <unity/scopes/ScopeExceptions.h>
2556 #include <unity/UnityExceptions.h>
2557@@ -59,10 +61,11 @@
2558 namespace
2559 {
2560
2561-char const* query_suffix = "-q"; // Appended to server_name_ to create query adapter name
2562-char const* ctrl_suffix = "-c"; // Appended to server_name_ to create control adapter name
2563-char const* reply_suffix = "-r"; // Appended to server_name_ to create reply adapter name
2564-char const* state_suffix = "-s"; // Appended to server_name_ to create state adapter name
2565+char const* query_suffix = "-q"; // Appended to server_name_ to create query adapter name
2566+char const* ctrl_suffix = "-c"; // Appended to server_name_ to create control adapter name
2567+char const* reply_suffix = "-r"; // Appended to server_name_ to create reply adapter name
2568+char const* state_suffix = "-s"; // Appended to server_name_ to create state adapter name
2569+char const* publisher_suffix = "-p"; // Appended to publisher_id to create a publisher endpoint
2570
2571 char const* query_category = "Query"; // query adapter category name
2572 char const* ctrl_category = "QueryCtrl"; // control adapter category name
2573@@ -657,6 +660,16 @@
2574 return proxy;
2575 }
2576
2577+MWPublisher::UPtr ZmqMiddleware::create_publisher(std::string const& publisher_id)
2578+{
2579+ return MWPublisher::UPtr(new ZmqPublisher(&context_, publisher_id + publisher_suffix, config_.public_dir()));
2580+}
2581+
2582+MWSubscriber::UPtr ZmqMiddleware::create_subscriber(std::string const& publisher_id, std::string const& topic)
2583+{
2584+ return MWSubscriber::UPtr(new ZmqSubscriber(&context_, publisher_id + publisher_suffix, config_.public_dir(), topic));
2585+}
2586+
2587 std::string ZmqMiddleware::get_scope_endpoint()
2588 {
2589 return "ipc://" + config_.private_dir() + "/" + server_name_;
2590
2591=== added file 'src/scopes/internal/zmq_middleware/ZmqPublisher.cpp'
2592--- src/scopes/internal/zmq_middleware/ZmqPublisher.cpp 1970-01-01 00:00:00 +0000
2593+++ src/scopes/internal/zmq_middleware/ZmqPublisher.cpp 2014-05-21 14:02:43 +0000
2594@@ -0,0 +1,157 @@
2595+/*
2596+ * Copyright (C) 2014 Canonical Ltd
2597+ *
2598+ * This program is free software: you can redistribute it and/or modify
2599+ * it under the terms of the GNU Lesser General Public License version 3 as
2600+ * published by the Free Software Foundation.
2601+ *
2602+ * This program is distributed in the hope that it will be useful,
2603+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2604+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2605+ * GNU Lesser General Public License for more details.
2606+ *
2607+ * You should have received a copy of the GNU Lesser General Public License
2608+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2609+ *
2610+ * Authored by: Marcus Tomlinson <marcus.tomlinson@canonical.com>
2611+ */
2612+
2613+#include <unity/scopes/internal/zmq_middleware/ZmqPublisher.h>
2614+
2615+#include <unity/scopes/internal/zmq_middleware/Util.h>
2616+#include <unity/scopes/ScopeExceptions.h>
2617+#include <unity/util/ResourcePtr.h>
2618+
2619+#include <unistd.h>
2620+#include <sys/socket.h>
2621+#include <sys/un.h>
2622+
2623+namespace unity
2624+{
2625+
2626+namespace scopes
2627+{
2628+
2629+namespace internal
2630+{
2631+
2632+namespace zmq_middleware
2633+{
2634+
2635+ZmqPublisher::ZmqPublisher(zmqpp::context* context, std::string const& publisher_id,
2636+ std::string const& endpoint_dir)
2637+ : context_(context)
2638+ , endpoint_("ipc://" + endpoint_dir + "/" + publisher_id)
2639+ , thread_state_(NotRunning)
2640+ , thread_exception_(nullptr)
2641+{
2642+ // Validate publisher_id
2643+ if (publisher_id.find('/') != std::string::npos)
2644+ {
2645+ throw MiddlewareException("ZmqPublisher(): A publisher cannot contain a '/' in its id");
2646+ }
2647+
2648+ // Start the publisher thread
2649+ thread_ = std::thread(&ZmqPublisher::publisher_thread, this);
2650+
2651+ std::unique_lock<std::mutex> lock(mutex_);
2652+ cond_.wait(lock, [this] { return thread_state_ == Running || thread_state_ == Failed; });
2653+
2654+ if (thread_state_ == Failed)
2655+ {
2656+ if (thread_.joinable())
2657+ {
2658+ thread_.join();
2659+ }
2660+ try
2661+ {
2662+ std::rethrow_exception(thread_exception_);
2663+ }
2664+ catch (...)
2665+ {
2666+ throw MiddlewareException("ZmqPublisher(): publisher thread failed to start (endpoint: " +
2667+ endpoint_ + ")");
2668+ }
2669+ }
2670+}
2671+
2672+ZmqPublisher::~ZmqPublisher()
2673+{
2674+ {
2675+ std::lock_guard<std::mutex> lock(mutex_);
2676+ thread_state_ = Stopping;
2677+ cond_.notify_all();
2678+ }
2679+
2680+ if (thread_.joinable())
2681+ {
2682+ thread_.join();
2683+ }
2684+}
2685+
2686+std::string ZmqPublisher::endpoint() const
2687+{
2688+ return endpoint_;
2689+}
2690+
2691+void ZmqPublisher::send_message(std::string const& message, std::string const& topic)
2692+{
2693+ std::lock_guard<std::mutex> lock(mutex_);
2694+
2695+ // Write message in the format: "<topic>:<message>"
2696+ message_queue_.push(topic + ':' + message);
2697+ cond_.notify_all();
2698+}
2699+
2700+void ZmqPublisher::publisher_thread()
2701+{
2702+ try
2703+ {
2704+ // Create the publisher socket
2705+ zmqpp::socket pub_socket(zmqpp::socket(*context_, zmqpp::socket_type::publish));
2706+ pub_socket.set(zmqpp::socket_option::linger, 5000);
2707+ safe_bind(pub_socket, endpoint_);
2708+
2709+ // Notify constructor that the thread is now running
2710+ std::unique_lock<std::mutex> lock(mutex_);
2711+ thread_state_ = Running;
2712+ cond_.notify_all();
2713+
2714+ // Wait for send_message or stop
2715+ while (true)
2716+ {
2717+ // mutex_ unlocked
2718+ cond_.wait(lock, [this] { return thread_state_ == Stopping || !message_queue_.empty(); });
2719+ // mutex_ locked
2720+
2721+ // Flush out the message queue before stopping the thread
2722+ if (!message_queue_.empty())
2723+ {
2724+ pub_socket.send(message_queue_.front());
2725+ message_queue_.pop();
2726+ }
2727+ else if (thread_state_ == Stopping)
2728+ {
2729+ break;
2730+ }
2731+ }
2732+
2733+ // Clean up
2734+ pub_socket.close();
2735+ }
2736+ catch (...)
2737+ {
2738+ std::lock_guard<std::mutex> lock(mutex_);
2739+ thread_exception_ = std::current_exception();
2740+ thread_state_ = Failed;
2741+ cond_.notify_all();
2742+ }
2743+}
2744+
2745+} // namespace zmq_middleware
2746+
2747+} // namespace internal
2748+
2749+} // namespace scopes
2750+
2751+} // namespace unity
2752
2753=== added file 'src/scopes/internal/zmq_middleware/ZmqSubscriber.cpp'
2754--- src/scopes/internal/zmq_middleware/ZmqSubscriber.cpp 1970-01-01 00:00:00 +0000
2755+++ src/scopes/internal/zmq_middleware/ZmqSubscriber.cpp 2014-05-21 14:02:43 +0000
2756@@ -0,0 +1,185 @@
2757+/*
2758+ * Copyright (C) 2014 Canonical Ltd
2759+ *
2760+ * This program is free software: you can redistribute it and/or modify
2761+ * it under the terms of the GNU Lesser General Public License version 3 as
2762+ * published by the Free Software Foundation.
2763+ *
2764+ * This program is distributed in the hope that it will be useful,
2765+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2766+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2767+ * GNU Lesser General Public License for more details.
2768+ *
2769+ * You should have received a copy of the GNU Lesser General Public License
2770+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2771+ *
2772+ * Authored by: Marcus Tomlinson <marcus.tomlinson@canonical.com>
2773+ */
2774+
2775+#include <unity/scopes/internal/zmq_middleware/ZmqSubscriber.h>
2776+
2777+#include <unity/scopes/internal/UniqueID.h>
2778+#include <unity/scopes/internal/zmq_middleware/StopPublisher.h>
2779+#include <unity/scopes/ScopeExceptions.h>
2780+
2781+#include <zmqpp/poller.hpp>
2782+#include <zmqpp/socket.hpp>
2783+
2784+namespace unity
2785+{
2786+
2787+namespace scopes
2788+{
2789+
2790+namespace internal
2791+{
2792+
2793+namespace zmq_middleware
2794+{
2795+
2796+ZmqSubscriber::ZmqSubscriber(zmqpp::context* context, std::string const& publisher_id,
2797+ std::string const& endpoint_dir, std::string const& topic)
2798+ : context_(context)
2799+ , endpoint_("ipc://" + endpoint_dir + "/" + publisher_id)
2800+ , topic_(topic)
2801+ , thread_state_(NotRunning)
2802+ , thread_exception_(nullptr)
2803+ , callback_(nullptr)
2804+{
2805+ // Validate publisher_id
2806+ if (publisher_id.find('/') != std::string::npos)
2807+ {
2808+ throw MiddlewareException("ZmqSubscriber(): A publisher cannot contain a '/' in its id");
2809+ }
2810+
2811+ // Start thread_stopper_ publisher (used to send a stop message to the subscriber on destruction)
2812+ try
2813+ {
2814+ UniqueID unique_id;
2815+ thread_stopper_.reset(new StopPublisher(context, unique_id.gen()));
2816+ }
2817+ catch (...)
2818+ {
2819+ throw MiddlewareException("ZmqSubscriber(): thread_stopper_ failed to initialize (adapter: " + publisher_id + ")");
2820+ }
2821+
2822+ // Start the subscriber thread
2823+ thread_ = std::thread(&ZmqSubscriber::subscriber_thread, this);
2824+
2825+ std::unique_lock<std::mutex> lock(mutex_);
2826+ cond_.wait(lock, [this] { return thread_state_ == Running || thread_state_ == Failed; });
2827+
2828+ if (thread_state_ == Failed)
2829+ {
2830+ if (thread_.joinable())
2831+ {
2832+ thread_.join();
2833+ }
2834+ try
2835+ {
2836+ std::rethrow_exception(thread_exception_);
2837+ }
2838+ catch (...)
2839+ {
2840+ throw MiddlewareException("ZmqSubscriber(): subscriber thread failed to start (endpoint: " +
2841+ endpoint_ + ")");
2842+ }
2843+ }
2844+}
2845+
2846+ZmqSubscriber::~ZmqSubscriber()
2847+{
2848+ thread_stopper_->stop();
2849+
2850+ if (thread_.joinable())
2851+ {
2852+ thread_.join();
2853+ }
2854+}
2855+
2856+std::string ZmqSubscriber::endpoint() const
2857+{
2858+ return endpoint_;
2859+}
2860+
2861+void ZmqSubscriber::set_message_callback(SubscriberCallback callback)
2862+{
2863+ std::lock_guard<std::mutex> lock(mutex_);
2864+ callback_ = callback;
2865+}
2866+
2867+void ZmqSubscriber::subscriber_thread()
2868+{
2869+ try
2870+ {
2871+ // Subscribe to our associated publisher socket
2872+ zmqpp::socket sub_socket(*context_, zmqpp::socket_type::subscribe);
2873+ sub_socket.set(zmqpp::socket_option::linger, 0);
2874+ sub_socket.connect(endpoint_);
2875+ sub_socket.subscribe(topic_);
2876+
2877+ // Subscribe to the thread_stopper_ socket
2878+ zmqpp::socket stop_socket = thread_stopper_->subscribe();
2879+
2880+ // Configure the message poller
2881+ zmqpp::poller poller;
2882+ poller.add(sub_socket);
2883+ poller.add(stop_socket);
2884+
2885+ // Notify constructor that the thread is now running
2886+ {
2887+ std::lock_guard<std::mutex> lock(mutex_);
2888+ thread_state_ = Running;
2889+ cond_.notify_all();
2890+ }
2891+
2892+ // Poll for messages
2893+ std::string message;
2894+ while (true)
2895+ {
2896+ poller.poll();
2897+
2898+ // Flush out the message queue before stopping the thread
2899+ if (poller.has_input(sub_socket))
2900+ {
2901+ sub_socket.receive(message);
2902+
2903+ // Discard the message if no callback is set
2904+ std::lock_guard<std::mutex> lock(mutex_);
2905+ if (callback_)
2906+ {
2907+ // Message should arrive in the format: "<topic>:<message>"
2908+ if (message.length() > topic_.length() &&
2909+ message[topic_.length()] == ':')
2910+ {
2911+ callback_(message.substr(topic_.length() + 1));
2912+ }
2913+ }
2914+ }
2915+ else if(poller.has_input(stop_socket))
2916+ {
2917+ break;
2918+ }
2919+ }
2920+
2921+ // Clean up
2922+ poller.remove(sub_socket);
2923+ poller.remove(stop_socket);
2924+ sub_socket.close();
2925+ }
2926+ catch (...)
2927+ {
2928+ std::lock_guard<std::mutex> lock(mutex_);
2929+ thread_exception_ = std::current_exception();
2930+ thread_state_ = Failed;
2931+ cond_.notify_all();
2932+ }
2933+}
2934+
2935+} // namespace zmq_middleware
2936+
2937+} // namespace internal
2938+
2939+} // namespace scopes
2940+
2941+} // namespace unity
2942
2943=== modified file 'test/gtest/scopes/CMakeLists.txt'
2944--- test/gtest/scopes/CMakeLists.txt 2014-05-14 04:50:14 +0000
2945+++ test/gtest/scopes/CMakeLists.txt 2014-05-21 14:02:43 +0000
2946@@ -14,7 +14,9 @@
2947 add_subdirectory(IdleShutdown)
2948 add_subdirectory(Invocation)
2949 add_subdirectory(OptionSelectorFilter)
2950+add_subdirectory(RadioButtonsFilter)
2951 add_subdirectory(RangeInputFilter)
2952+add_subdirectory(RatingFilter)
2953 add_subdirectory(PreviewWidget)
2954 add_subdirectory(QueryMetadata)
2955 add_subdirectory(Registry)
2956
2957=== modified file 'test/gtest/scopes/Filters/Filters_test.cpp'
2958--- test/gtest/scopes/Filters/Filters_test.cpp 2014-05-08 17:08:38 +0000
2959+++ test/gtest/scopes/Filters/Filters_test.cpp 2014-05-21 14:02:43 +0000
2960@@ -18,7 +18,10 @@
2961
2962 #include <unity/scopes/internal/RuntimeImpl.h>
2963 #include <unity/scopes/internal/ScopeImpl.h>
2964+#include <unity/scopes/internal/FilterBaseImpl.h>
2965 #include <unity/scopes/FilterOption.h>
2966+#include <unity/scopes/RadioButtonsFilter.h>
2967+#include <unity/scopes/RatingFilter.h>
2968 #include <unity/scopes/SearchMetadata.h>
2969 #include <unity/UnityExceptions.h>
2970 #include <gtest/gtest.h>
2971@@ -133,3 +136,72 @@
2972 EXPECT_EQ("o1", option1->id());
2973 }
2974 }
2975+
2976+TEST(Filters, deserialize)
2977+{
2978+ // check that FilterBaseImpl::deserialize() creates valid instances of all filter types
2979+ {
2980+ OptionSelectorFilter::SPtr filter1 = OptionSelectorFilter::create("f1", "Options", false);
2981+ auto option1 = filter1->add_option("1", "Option 1");
2982+ auto var = filter1->serialize();
2983+
2984+ auto f = internal::FilterBaseImpl::deserialize(var);
2985+ EXPECT_TRUE(std::dynamic_pointer_cast<OptionSelectorFilter const>(f) != nullptr);
2986+ EXPECT_EQ("option_selector", f->filter_type());
2987+
2988+ const Filters filters {filter1};
2989+ EXPECT_NO_THROW(internal::FilterBaseImpl::validate_filters(filters));
2990+ }
2991+
2992+ {
2993+ RadioButtonsFilter::SPtr filter1 = RadioButtonsFilter::create("f1", "Options");
2994+ auto option1 = filter1->add_option("1", "Option 1");
2995+ auto var = filter1->serialize();
2996+
2997+ auto f = internal::FilterBaseImpl::deserialize(var);
2998+ EXPECT_TRUE(std::dynamic_pointer_cast<RadioButtonsFilter const>(f) != nullptr);
2999+ EXPECT_EQ("radio_buttons", f->filter_type());
3000+
3001+ const Filters filters {filter1};
3002+ EXPECT_NO_THROW(internal::FilterBaseImpl::validate_filters(filters));
3003+ }
3004+
3005+ {
3006+ RatingFilter::SPtr filter1 = RatingFilter::create("f1", "Options", 5);
3007+ auto var = filter1->serialize();
3008+
3009+ auto f = internal::FilterBaseImpl::deserialize(var);
3010+ EXPECT_TRUE(std::dynamic_pointer_cast<RatingFilter const>(f) != nullptr);
3011+ EXPECT_EQ("rating", f->filter_type());
3012+
3013+ const Filters filters {filter1};
3014+ EXPECT_NO_THROW(internal::FilterBaseImpl::validate_filters(filters));
3015+ }
3016+
3017+ {
3018+ // invalid data (no filter_type)
3019+ VariantMap var;
3020+ EXPECT_THROW(internal::FilterBaseImpl::deserialize(var), unity::LogicException);
3021+ }
3022+}
3023+
3024+TEST(Filters, validate)
3025+{
3026+ {
3027+ FilterBase::SPtr filter1 = OptionSelectorFilter::create("f1", "Options", false);
3028+ const Filters filters {filter1};
3029+ EXPECT_THROW(internal::FilterBaseImpl::validate_filters(filters), unity::LogicException);
3030+ }
3031+
3032+ {
3033+ FilterBase::SPtr filter1 = RadioButtonsFilter::create("f1", "Options");
3034+ const Filters filters {filter1};
3035+ EXPECT_THROW(internal::FilterBaseImpl::validate_filters(filters), unity::LogicException);
3036+ }
3037+
3038+ {
3039+ FilterBase::SPtr filter1 = RatingFilter::create("f1", "Options");
3040+ const Filters filters {filter1};
3041+ EXPECT_THROW(internal::FilterBaseImpl::validate_filters(filters), unity::LogicException);
3042+ }
3043+}
3044
3045=== modified file 'test/gtest/scopes/Filters/TestScope.h'
3046--- test/gtest/scopes/Filters/TestScope.h 2014-03-07 01:07:28 +0000
3047+++ test/gtest/scopes/Filters/TestScope.h 2014-05-21 14:02:43 +0000
3048@@ -45,7 +45,7 @@
3049 virtual void run(SearchReplyProxy const& reply) override
3050 {
3051 Filters filters;
3052- auto filter = OptionSelectorFilter::create("f1", "Choose an option", false);
3053+ OptionSelectorFilter::SPtr filter = OptionSelectorFilter::create("f1", "Choose an option", false);
3054 filter->add_option("o1", "Option 1");
3055 filter->add_option("o2", "Option 2");
3056 filters.push_back(filter);
3057
3058=== modified file 'test/gtest/scopes/IdleShutdown/IdleShutdown_test.cpp'
3059--- test/gtest/scopes/IdleShutdown/IdleShutdown_test.cpp 2014-05-14 04:50:14 +0000
3060+++ test/gtest/scopes/IdleShutdown/IdleShutdown_test.cpp 2014-05-21 14:02:43 +0000
3061@@ -40,8 +40,12 @@
3062 {
3063 }
3064
3065- virtual void finished(ListenerBase::Reason /* reason */, string const& /* error_message */) override
3066+ virtual void finished(ListenerBase::Reason reason, string const& error_message) override
3067 {
3068+ EXPECT_EQ(ListenerBase::Reason::Error, reason);
3069+ EXPECT_EQ("unity::scopes::MiddlewareException: unity::scopes::MiddlewareException: "
3070+ "Cannot invoke operations while middleware is stopped",
3071+ error_message);
3072 lock_guard<mutex> lock(mutex_);
3073 query_complete_ = true;
3074 cond_.notify_one();
3075@@ -81,10 +85,10 @@
3076 }
3077
3078 // Check that the scope has indeed timed out. The server shuts down after 2 seconds,
3079- // so we allow between 2 and 3 seconds for it to time out.
3080+ // so we allow between 2 and 4 seconds for it to time out.
3081 auto duration = chrono::steady_clock::now() - start_time;
3082 EXPECT_TRUE(duration > chrono::seconds(2));
3083- EXPECT_TRUE(duration < chrono::seconds(3));
3084+ EXPECT_TRUE(duration < chrono::seconds(4));
3085 }
3086
3087 // Check that the idle timeout for a server waits for synchronous operations
3088@@ -122,11 +126,13 @@
3089
3090 // Check that the run time doesn't shut down until
3091 // the search in the scope has completed, which takes 4 seconds.
3092- // We allow 4 - 5 seconds for things to shut down before failing
3093- // (or hanging).
3094+ // We allow 4 - 6 seconds for things to shut down before failing
3095+ // (or hanging). (On Arm, can be slow to shut down, so we allow
3096+ // a full two seconds for the server to go away before failing
3097+ // the test.)
3098 auto duration = chrono::steady_clock::now() - start_time;
3099 EXPECT_TRUE(duration > chrono::seconds(4));
3100- EXPECT_TRUE(duration < chrono::seconds(5));
3101+ EXPECT_TRUE(duration < chrono::seconds(6));
3102 }
3103
3104 int main(int argc, char **argv)
3105
3106=== modified file 'test/gtest/scopes/IdleShutdown/SlowSearchScope.cpp'
3107--- test/gtest/scopes/IdleShutdown/SlowSearchScope.cpp 2014-05-14 04:50:14 +0000
3108+++ test/gtest/scopes/IdleShutdown/SlowSearchScope.cpp 2014-05-21 14:02:43 +0000
3109@@ -64,7 +64,7 @@
3110
3111 SearchQueryBase::UPtr SlowSearchScope::search(CannedQuery const&, SearchMetadata const &)
3112 {
3113- this_thread::sleep_for(chrono::seconds(4));
3114+ this_thread::sleep_for(chrono::seconds(4));
3115 return SearchQueryBase::UPtr(new TestQuery());
3116 }
3117
3118
3119=== modified file 'test/gtest/scopes/IdleShutdown/Zmq.ini.in'
3120--- test/gtest/scopes/IdleShutdown/Zmq.ini.in 2014-05-14 04:50:14 +0000
3121+++ test/gtest/scopes/IdleShutdown/Zmq.ini.in 2014-05-21 14:02:43 +0000
3122@@ -1,3 +1,7 @@
3123 [Zmq]
3124 EndpointDir = /tmp
3125-Default.Twoway.Timeout = 5000
3126+# We set the idle timeout to something much larger than the expected
3127+# time for the test to finish, so we don't see a bogus completion
3128+# of the slow call due to the timeout on the client side triggering,
3129+# rather than the server shutting down.
3130+Default.Twoway.Timeout = 10000
3131
3132=== modified file 'test/gtest/scopes/OptionSelectorFilter/OptionSelectorFilter_test.cpp'
3133--- test/gtest/scopes/OptionSelectorFilter/OptionSelectorFilter_test.cpp 2014-05-15 08:12:32 +0000
3134+++ test/gtest/scopes/OptionSelectorFilter/OptionSelectorFilter_test.cpp 2014-05-21 14:02:43 +0000
3135@@ -62,10 +62,12 @@
3136
3137 FilterState fstate;
3138 EXPECT_FALSE(fstate.has_filter("f1"));
3139+ EXPECT_FALSE(filter1->has_active_option(fstate));
3140
3141 // enable option1
3142 filter1->update_state(fstate, option1, true);
3143 EXPECT_TRUE(fstate.has_filter("f1"));
3144+ EXPECT_TRUE(filter1->has_active_option(fstate));
3145 auto active = filter1->active_options(fstate);
3146 EXPECT_EQ(1u, active.size());
3147 EXPECT_TRUE(active.find(option1) != active.end());
3148@@ -95,6 +97,7 @@
3149 filter1->update_state(fstate, option1, true);
3150 filter1->update_state(fstate, option2, true);
3151 EXPECT_TRUE(fstate.has_filter("f1"));
3152+ EXPECT_TRUE(filter1->has_active_option(fstate));
3153 auto active = filter1->active_options(fstate);
3154 EXPECT_EQ(2u, active.size());
3155 EXPECT_TRUE(active.find(option1) != active.end());
3156
3157=== added directory 'test/gtest/scopes/RadioButtonsFilter'
3158=== added file 'test/gtest/scopes/RadioButtonsFilter/CMakeLists.txt'
3159--- test/gtest/scopes/RadioButtonsFilter/CMakeLists.txt 1970-01-01 00:00:00 +0000
3160+++ test/gtest/scopes/RadioButtonsFilter/CMakeLists.txt 2014-05-21 14:02:43 +0000
3161@@ -0,0 +1,4 @@
3162+add_executable(RadioButtonsFilter_test RadioButtonsFilter_test.cpp)
3163+target_link_libraries(RadioButtonsFilter_test ${TESTLIBS})
3164+
3165+add_test(RadioButtonsFilter RadioButtonsFilter_test)
3166
3167=== added file 'test/gtest/scopes/RadioButtonsFilter/RadioButtonsFilter_test.cpp'
3168--- test/gtest/scopes/RadioButtonsFilter/RadioButtonsFilter_test.cpp 1970-01-01 00:00:00 +0000
3169+++ test/gtest/scopes/RadioButtonsFilter/RadioButtonsFilter_test.cpp 2014-05-21 14:02:43 +0000
3170@@ -0,0 +1,71 @@
3171+/*
3172+ * Copyright (C) 2014 Canonical Ltd
3173+ *
3174+ * This program is free software: you can redistribute it and/or modify
3175+ * it under the terms of the GNU Lesser General Public License version 3 as
3176+ * published by the Free Software Foundation.
3177+ *
3178+ * This program is distributed in the hope that it will be useful,
3179+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3180+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3181+ * GNU Lesser General Public License for more details.
3182+ *
3183+ * You should have received a copy of the GNU Lesser General Public License
3184+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3185+ *
3186+ * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com>
3187+ */
3188+
3189+#include <gtest/gtest.h>
3190+#include <unity/scopes/FilterState.h>
3191+#include <unity/scopes/RadioButtonsFilter.h>
3192+#include <unity/UnityExceptions.h>
3193+
3194+using namespace unity::scopes;
3195+using namespace unity::scopes::internal;
3196+
3197+TEST(RadioButtonsFilter, basic)
3198+{
3199+ auto filter1 = RadioButtonsFilter::create("f1", "Choose");
3200+ EXPECT_EQ("f1", filter1->id());
3201+ EXPECT_EQ("Choose", filter1->label());
3202+ EXPECT_EQ(0u, filter1->options().size());
3203+
3204+ filter1->add_option("a", "A");
3205+ filter1->add_option("b", "B");
3206+
3207+ auto opts = filter1->options();
3208+ EXPECT_EQ(2u, opts.size());
3209+ EXPECT_EQ("a", opts.front()->id());
3210+ EXPECT_EQ("A", opts.front()->label());
3211+ EXPECT_EQ("b", opts.back()->id());
3212+ EXPECT_EQ("B", opts.back()->label());
3213+}
3214+
3215+TEST(RadioButtonsFilter, selection)
3216+{
3217+ auto filter1 = RadioButtonsFilter::create("f1", "Options");
3218+ auto option1 = filter1->add_option("1", "Option 1");
3219+ auto option2 = filter1->add_option("2", "Option 2");
3220+
3221+ FilterState fstate;
3222+ EXPECT_FALSE(fstate.has_filter("f1"));
3223+ EXPECT_EQ(nullptr, filter1->active_option(fstate));
3224+ EXPECT_FALSE(filter1->has_active_option(fstate));
3225+
3226+ // enable option1
3227+ filter1->update_state(fstate, option1, true);
3228+ EXPECT_TRUE(fstate.has_filter("f1"));
3229+ auto active = filter1->active_option(fstate);
3230+ EXPECT_EQ("1", active->id());
3231+
3232+ // enable option2, option1 get disabled
3233+ filter1->update_state(fstate, option2, true);
3234+ active = filter1->active_option(fstate);
3235+ EXPECT_EQ("2", active->id());
3236+
3237+ // disable option1; filter state remains in the FilterState, just no options are selected
3238+ filter1->update_state(fstate, option2, false);
3239+ EXPECT_TRUE(fstate.has_filter("f1"));
3240+ EXPECT_EQ(nullptr, filter1->active_option(fstate));
3241+}
3242
3243=== added directory 'test/gtest/scopes/RatingFilter'
3244=== added file 'test/gtest/scopes/RatingFilter/CMakeLists.txt'
3245--- test/gtest/scopes/RatingFilter/CMakeLists.txt 1970-01-01 00:00:00 +0000
3246+++ test/gtest/scopes/RatingFilter/CMakeLists.txt 2014-05-21 14:02:43 +0000
3247@@ -0,0 +1,4 @@
3248+add_executable(RatingFilter_test RatingFilter_test.cpp)
3249+target_link_libraries(RatingFilter_test ${TESTLIBS})
3250+
3251+add_test(RatingFilter RatingFilter_test)
3252
3253=== added file 'test/gtest/scopes/RatingFilter/RatingFilter_test.cpp'
3254--- test/gtest/scopes/RatingFilter/RatingFilter_test.cpp 1970-01-01 00:00:00 +0000
3255+++ test/gtest/scopes/RatingFilter/RatingFilter_test.cpp 2014-05-21 14:02:43 +0000
3256@@ -0,0 +1,111 @@
3257+/*
3258+ * Copyright (C) 2014 Canonical Ltd
3259+ *
3260+ * This program is free software: you can redistribute it and/or modify
3261+ * it under the terms of the GNU Lesser General Public License version 3 as
3262+ * published by the Free Software Foundation.
3263+ *
3264+ * This program is distributed in the hope that it will be useful,
3265+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3266+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3267+ * GNU Lesser General Public License for more details.
3268+ *
3269+ * You should have received a copy of the GNU Lesser General Public License
3270+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3271+ *
3272+ * Authored by: Pawel Stolowski <pawel.stolowski@canonical.com>
3273+ */
3274+
3275+#include <gtest/gtest.h>
3276+#include <unity/scopes/FilterState.h>
3277+#include <unity/scopes/RatingFilter.h>
3278+#include <unity/UnityExceptions.h>
3279+
3280+using namespace unity::scopes;
3281+using namespace unity::scopes::internal;
3282+
3283+TEST(RatingFilter, basic)
3284+{
3285+ {
3286+ auto filter1 = RatingFilter::create("f1", "Rating");
3287+ filter1->set_on_icon("foo");
3288+ filter1->set_off_icon("bar");
3289+ EXPECT_EQ("f1", filter1->id());
3290+ EXPECT_EQ("Rating", filter1->label());
3291+ EXPECT_EQ("foo", filter1->on_icon());
3292+ EXPECT_EQ("bar", filter1->off_icon());
3293+ EXPECT_EQ(0u, filter1->options().size());
3294+
3295+ auto o1 = filter1->add_option("a", "A");
3296+ auto o2 = filter1->add_option("b", "B");
3297+ EXPECT_EQ("a", o1->id());
3298+ EXPECT_EQ("b", o2->id());
3299+
3300+ auto opts = filter1->options();
3301+ EXPECT_EQ(2u, opts.size());
3302+ EXPECT_EQ("a", opts.front()->id());
3303+ EXPECT_EQ("A", opts.front()->label());
3304+ EXPECT_EQ("b", opts.back()->id());
3305+ EXPECT_EQ("B", opts.back()->label());
3306+ }
3307+
3308+ {
3309+ auto filter1 = RatingFilter::create("f1", "Rating", 3);
3310+ EXPECT_EQ("f1", filter1->id());
3311+ EXPECT_EQ("Rating", filter1->label());
3312+
3313+ auto opts = filter1->options();
3314+ EXPECT_EQ(3u, opts.size());
3315+ auto it = opts.begin();
3316+ EXPECT_EQ("1", (*it)->id());
3317+ EXPECT_EQ("1+", (*it)->label());
3318+ EXPECT_EQ("2", (*++it)->id());
3319+ EXPECT_EQ("2+", (*it)->label());
3320+ EXPECT_EQ("3", (*++it)->id());
3321+ EXPECT_EQ("3", (*it)->label());
3322+ }
3323+
3324+ {
3325+ EXPECT_THROW(RatingFilter::create("f1", "Rating", 11), unity::LogicException);
3326+ }
3327+
3328+ {
3329+ auto filter1 = RatingFilter::create("f1", "Rating", 10);
3330+ EXPECT_THROW(filter1->add_option("11", "11"), unity::LogicException);
3331+ }
3332+}
3333+
3334+TEST(RatingFilter, selection)
3335+{
3336+ auto filter1 = RatingFilter::create("f1", "Rating", 2);
3337+
3338+ FilterState fstate;
3339+ EXPECT_FALSE(fstate.has_filter("f1"));
3340+ EXPECT_FALSE(filter1->has_active_rating(fstate));
3341+ EXPECT_EQ(nullptr, filter1->active_rating(fstate));
3342+
3343+ auto opts = filter1->options();
3344+ EXPECT_EQ(2u, opts.size());
3345+
3346+ auto it = opts.begin();
3347+ auto option1 = *(it++);
3348+ auto option2 = *it;
3349+
3350+ // enable option1
3351+ filter1->update_state(fstate, option1, true);
3352+ EXPECT_TRUE(fstate.has_filter("f1"));
3353+ EXPECT_TRUE(filter1->has_active_rating(fstate));
3354+ auto active = filter1->active_rating(fstate);
3355+ EXPECT_EQ("1", active->id());
3356+
3357+ // enable option2, option1 get disabled
3358+ filter1->update_state(fstate, option2, true);
3359+ active = filter1->active_rating(fstate);
3360+ EXPECT_EQ("2", active->id());
3361+
3362+ // disable option1; filter state remains in the FilterState, just no options are selected
3363+ filter1->update_state(fstate, option2, false);
3364+ EXPECT_TRUE(fstate.has_filter("f1"));
3365+ EXPECT_FALSE(filter1->has_active_rating(fstate));
3366+ EXPECT_EQ(nullptr, filter1->active_rating(fstate));
3367+}
3368
3369=== modified file 'test/gtest/scopes/Registry/Registry_test.cpp'
3370--- test/gtest/scopes/Registry/Registry_test.cpp 2014-05-06 04:29:02 +0000
3371+++ test/gtest/scopes/Registry/Registry_test.cpp 2014-05-21 14:02:43 +0000
3372@@ -77,25 +77,6 @@
3373 Runtime::UPtr rt = Runtime::create(TEST_RUNTIME_FILE);
3374 RegistryProxy r = rt->registry();
3375
3376- // wait for the registry to become available on middleware
3377- // FIXME: remove this once we have async queries and can set arbitrary timeout when calling registry
3378- const int num_retries = 10;
3379- bool registry_started = false;
3380- for (int i = 0; i < num_retries; ++i)
3381- {
3382- try
3383- {
3384- r->list(); // this will throw if the registry is not yet available on middleware
3385- registry_started = true;
3386- break;
3387- }
3388- catch (std::exception const&)
3389- {
3390- sleep(1);
3391- }
3392- }
3393- ASSERT_TRUE(registry_started);
3394-
3395 auto meta = r->get_metadata("testscopeA");
3396 EXPECT_EQ("testscopeA", meta.scope_id());
3397 EXPECT_EQ("Canonical Ltd.", meta.author());
3398
3399=== modified file 'test/gtest/scopes/Registry/Zmq.ini.in'
3400--- test/gtest/scopes/Registry/Zmq.ini.in 2014-05-06 09:00:45 +0000
3401+++ test/gtest/scopes/Registry/Zmq.ini.in 2014-05-21 14:02:43 +0000
3402@@ -1,2 +1,3 @@
3403 [Zmq]
3404 EndpointDir = /tmp
3405+Default.Twoway.Timeout = 2000
3406
3407=== modified file 'test/gtest/scopes/internal/smartscopes/SmartScopesClient/FakeSss.py'
3408--- test/gtest/scopes/internal/smartscopes/SmartScopesClient/FakeSss.py 2014-05-09 09:56:09 +0000
3409+++ test/gtest/scopes/internal/smartscopes/SmartScopesClient/FakeSss.py 2014-05-21 14:02:43 +0000
3410@@ -60,7 +60,7 @@
3411 [{"base_url": "http://127.0.0.1:' + str(port) + '/fail", "id" : "fail.scope", "name": "Fail Scope", "description": "Fails due to no author.", "icon": "icon" },\
3412 {"base_url": "http://127.0.0.1:' + str(port) + '/demo", "id" : "dummy.scope", "name": "Dummy Demo Scope", "description": "Dummy demo scope.", "author": "Mr.Fake", "icon": "icon" },\
3413 {"base_url": "http://127.0.0.1:' + str(port) + '/fail2", "name": "Fail Scope 2", "description": "Fails due to no id.", "author": "Mr.Fake", "icon": "icon" },\
3414-{"base_url": "http://127.0.0.1:' + str(port) + '/demo2", "id" : "dummy.scope.2", "name": "Dummy Demo Scope 2", "description": "Dummy demo scope 2.", "author": "Mr.Fake", "art": "art", "invisible": true },\
3415+{"base_url": "http://127.0.0.1:' + str(port) + '/demo2", "id" : "dummy.scope.2", "name": "Dummy Demo Scope 2", "description": "Dummy demo scope 2.", "author": "Mr.Fake", "art": "art", "invisible": true, "appearance": {"background": "#00BEEF"} },\
3416 {"id" : "fail.scope.3", "name": "Fail Scope 3", "description": "Fails due to no base_url.", "author": "Mr.Fake", "art": "art" }]'
3417
3418 search_response = '\
3419
3420=== modified file 'test/gtest/scopes/internal/smartscopes/SmartScopesClient/SmartScopesClient_test.cpp'
3421--- test/gtest/scopes/internal/smartscopes/SmartScopesClient/SmartScopesClient_test.cpp 2014-05-09 09:56:09 +0000
3422+++ test/gtest/scopes/internal/smartscopes/SmartScopesClient/SmartScopesClient_test.cpp 2014-05-21 14:02:43 +0000
3423@@ -81,6 +81,7 @@
3424 EXPECT_EQ("icon", *scopes[0].icon);
3425 EXPECT_EQ(nullptr, scopes[0].art);
3426 EXPECT_FALSE(scopes[0].invisible);
3427+ EXPECT_EQ(nullptr, scopes[0].appearance);
3428
3429 EXPECT_EQ("dummy.scope.2", scopes[1].id);
3430 EXPECT_EQ("Dummy Demo Scope 2", scopes[1].name);
3431@@ -90,6 +91,7 @@
3432 EXPECT_EQ(nullptr, scopes[1].icon);
3433 EXPECT_EQ("art", *scopes[1].art);
3434 EXPECT_TRUE(scopes[1].invisible);
3435+ EXPECT_EQ("#00BEEF", (*scopes[1].appearance)["background"].get_string());
3436 }
3437
3438 TEST_F(SmartScopesClientTest, search)
3439
3440=== modified file 'test/gtest/scopes/internal/zmq_middleware/CMakeLists.txt'
3441--- test/gtest/scopes/internal/zmq_middleware/CMakeLists.txt 2014-04-14 23:47:33 +0000
3442+++ test/gtest/scopes/internal/zmq_middleware/CMakeLists.txt 2014-05-21 14:02:43 +0000
3443@@ -1,4 +1,5 @@
3444 add_subdirectory(ObjectAdapter)
3445+add_subdirectory(PubSub)
3446 add_subdirectory(RegistryI)
3447 add_subdirectory(ServantBase)
3448 add_subdirectory(StopPublisher)
3449
3450=== modified file 'test/gtest/scopes/internal/zmq_middleware/ObjectAdapter/ObjectAdapter_test.cpp'
3451--- test/gtest/scopes/internal/zmq_middleware/ObjectAdapter/ObjectAdapter_test.cpp 2014-05-02 00:00:08 +0000
3452+++ test/gtest/scopes/internal/zmq_middleware/ObjectAdapter/ObjectAdapter_test.cpp 2014-05-21 14:02:43 +0000
3453@@ -1071,8 +1071,7 @@
3454 {
3455 EXPECT_STREQ("unity::scopes::MiddlewareException: ObjectAdapter::run_workers(): broker thread failure "
3456 "(adapter: testscope):\n"
3457- " unity::scopes::MiddlewareException: ObjectAdapter: broker thread failure "
3458- "(adapter: testscope): address in use: ipc://testscope", e.what());
3459+ " unity::scopes::MiddlewareException: safe_bind(): address in use: ipc://testscope", e.what());
3460 }
3461
3462 {
3463@@ -1108,8 +1107,7 @@
3464 {
3465 EXPECT_STREQ("unity::scopes::MiddlewareException: ObjectAdapter::run_workers(): broker thread failure "
3466 "(adapter: testscope):\n"
3467- " unity::scopes::MiddlewareException: ObjectAdapter: broker thread failure "
3468- "(adapter: testscope): address in use: ipc://testscope", e.what());
3469+ " unity::scopes::MiddlewareException: safe_bind(): address in use: ipc://testscope", e.what());
3470 }
3471
3472 {
3473
3474=== added directory 'test/gtest/scopes/internal/zmq_middleware/PubSub'
3475=== added file 'test/gtest/scopes/internal/zmq_middleware/PubSub/CMakeLists.txt'
3476--- test/gtest/scopes/internal/zmq_middleware/PubSub/CMakeLists.txt 1970-01-01 00:00:00 +0000
3477+++ test/gtest/scopes/internal/zmq_middleware/PubSub/CMakeLists.txt 2014-05-21 14:02:43 +0000
3478@@ -0,0 +1,6 @@
3479+configure_file(Zmq.ini.in Zmq.ini)
3480+
3481+add_executable(PubSub_test PubSub_test.cpp)
3482+target_link_libraries(PubSub_test ${LIBS} ${TESTLIBS})
3483+
3484+add_test(PubSub PubSub_test)
3485
3486=== added file 'test/gtest/scopes/internal/zmq_middleware/PubSub/PubSub_test.cpp'
3487--- test/gtest/scopes/internal/zmq_middleware/PubSub/PubSub_test.cpp 1970-01-01 00:00:00 +0000
3488+++ test/gtest/scopes/internal/zmq_middleware/PubSub/PubSub_test.cpp 2014-05-21 14:02:43 +0000
3489@@ -0,0 +1,237 @@
3490+/*
3491+ * Copyright (C) 2014 Canonical Ltd
3492+ *
3493+ * This program is free software: you can redistribute it and/or modify
3494+ * it under the terms of the GNU Lesser General Public License version 3 as
3495+ * published by the Free Software Foundation.
3496+ *
3497+ * This program is distributed in the hope that it will be useful,
3498+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3499+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3500+ * GNU Lesser General Public License for more details.
3501+ *
3502+ * You should have received a copy of the GNU Lesser General Public License
3503+ * along with this program. If not, see <http://www.gnu.org/lzmqnses/>.
3504+ *
3505+ * Authored by: Michi Henning <michi.henning@canonical.com>
3506+ */
3507+
3508+#include <scope-api-testconfig.h>
3509+#include <unity/scopes/internal/RuntimeImpl.h>
3510+#include <unity/scopes/internal/zmq_middleware/ZmqMiddleware.h>
3511+#include <unity/scopes/ScopeExceptions.h>
3512+
3513+#include <gtest/gtest.h>
3514+#include <condition_variable>
3515+#include <mutex>
3516+
3517+using namespace std::placeholders;
3518+using namespace unity::scopes;
3519+using namespace unity::scopes::internal;
3520+using namespace unity::scopes::internal::zmq_middleware;
3521+
3522+TEST(PubSub, endpoints)
3523+{
3524+ ZmqMiddleware mw("testscope", (RuntimeImpl*)0x1,
3525+ TEST_BUILD_ROOT "/gtest/scopes/internal/zmq_middleware/ObjectAdapter/Zmq.ini");
3526+
3527+ auto publisher = mw.create_publisher("testpublisher");
3528+ auto subscriber = mw.create_subscriber("testpublisher", "");
3529+
3530+ EXPECT_EQ("ipc:///tmp/testpublisher-p", publisher->endpoint());
3531+ EXPECT_EQ(subscriber->endpoint(), publisher->endpoint());
3532+}
3533+
3534+TEST(PubSub, exceptions)
3535+{
3536+ ZmqMiddleware mw("testscope", (RuntimeImpl*)0x1,
3537+ TEST_BUILD_ROOT "/gtest/scopes/internal/zmq_middleware/ObjectAdapter/Zmq.ini");
3538+
3539+ // Test that only one publisher can be created on a single endpoint
3540+ auto publisher = mw.create_publisher("testpublisher");
3541+ try
3542+ {
3543+ auto publisher2 = mw.create_publisher("testpublisher");
3544+ FAIL();
3545+ }
3546+ catch (MiddlewareException const& e)
3547+ {
3548+ EXPECT_STREQ("unity::scopes::MiddlewareException: ZmqPublisher(): publisher thread failed to start "
3549+ "(endpoint: ipc:///tmp/testpublisher-p):\n unity::scopes::MiddlewareException: "
3550+ "safe_bind(): address in use: ipc:///tmp/testpublisher-p",
3551+ e.what());
3552+ }
3553+
3554+ // Test that multiple subscribers can be created on a single endpoint
3555+ auto subscriber = mw.create_subscriber("testpublisher", "");
3556+ try
3557+ {
3558+ auto subscriber2 = mw.create_subscriber("testpublisher", "testtopic1");
3559+ auto subscriber3 = mw.create_subscriber("testpublisher", "testtopic2");
3560+ auto subscriber4 = mw.create_subscriber("testpublisher", "testtopic3");
3561+ auto subscriber5 = mw.create_subscriber("testpublisher", "testtopic4");
3562+ }
3563+ catch (MiddlewareException const& e)
3564+ {
3565+ FAIL();
3566+ }
3567+
3568+ // Test that an invalid publisher_id throws
3569+ try
3570+ {
3571+ auto publisher2 = mw.create_publisher("/test/");
3572+ FAIL();
3573+ }
3574+ catch (MiddlewareException const& e)
3575+ {
3576+ EXPECT_STREQ("unity::scopes::MiddlewareException: ZmqPublisher(): A publisher cannot contain a '/' in its id",
3577+ e.what());
3578+ }
3579+ try
3580+ {
3581+ auto subscriber2 = mw.create_subscriber("/test/", "testtopic");
3582+ FAIL();
3583+ }
3584+ catch (MiddlewareException const& e)
3585+ {
3586+ EXPECT_STREQ("unity::scopes::MiddlewareException: ZmqSubscriber(): A publisher cannot contain a '/' in its id",
3587+ e.what());
3588+ }
3589+}
3590+
3591+class SubMsgReceiver
3592+{
3593+public:
3594+ void receive1(std::string const& message)
3595+ {
3596+ last_sub_index_ = 1;
3597+ last_message_ = message;
3598+ received();
3599+ }
3600+
3601+ void receive2(std::string const& message)
3602+ {
3603+ last_sub_index_ = 2;
3604+ last_message_ = message;
3605+ received();
3606+ }
3607+
3608+ void receive3(std::string const& message)
3609+ {
3610+ last_sub_index_ = 3;
3611+ last_message_ = message;
3612+ received();
3613+ }
3614+
3615+ void receive4(std::string const& message)
3616+ {
3617+ last_sub_index_ = 4;
3618+ last_message_ = message;
3619+ received();
3620+ }
3621+
3622+ void received()
3623+ {
3624+ // Signal wait_for_message
3625+ std::lock_guard<std::mutex> lock(mutex_);
3626+ message_received_ = true;
3627+ cond_.notify_one();
3628+ }
3629+
3630+ bool wait_for_message()
3631+ {
3632+ std::unique_lock<std::mutex> lock(mutex_);
3633+ bool message_received = cond_.wait_for(lock, std::chrono::milliseconds(500), [this] { return this->message_received_; });
3634+ message_received_ = false;
3635+ return message_received;
3636+ }
3637+
3638+ int last_sub_index_ = 0;
3639+ std::string last_message_;
3640+
3641+ bool message_received_ = false;
3642+ std::mutex mutex_;
3643+ std::condition_variable cond_;
3644+};
3645+
3646+TEST(PubSub, send_receive)
3647+{
3648+ SubMsgReceiver message_receiver;
3649+
3650+ ZmqMiddleware mw("testscope", (RuntimeImpl*)0x1,
3651+ TEST_BUILD_ROOT "/gtest/scopes/internal/zmq_middleware/ObjectAdapter/Zmq.ini");
3652+
3653+ // Create 2 publishers
3654+ auto publisher = mw.create_publisher("testpublisher");
3655+ auto publisher2 = mw.create_publisher("testpublisher2");
3656+
3657+ // Create a few subscribers
3658+ auto subscriber1 = mw.create_subscriber("testpublisher", "testtopic1");
3659+ subscriber1->set_message_callback(std::bind(&SubMsgReceiver::receive1, &message_receiver, _1));
3660+
3661+ auto subscriber2 = mw.create_subscriber("testpublisher", "testtopic2");
3662+ subscriber2->set_message_callback(std::bind(&SubMsgReceiver::receive2, &message_receiver, _1));
3663+
3664+ auto subscriber3 = mw.create_subscriber("testpublisher", "");
3665+ subscriber3->set_message_callback(std::bind(&SubMsgReceiver::receive3, &message_receiver, _1));
3666+
3667+ auto subscriber4 = mw.create_subscriber("testpublisher2", "testtopic4");
3668+ subscriber4->set_message_callback(std::bind(&SubMsgReceiver::receive4, &message_receiver, _1));
3669+
3670+ // Give the subscribers some time to connect
3671+ std::this_thread::sleep_for(std::chrono::milliseconds(500));
3672+
3673+ // Send a "testtopic1" topic message (subscriber1)
3674+ publisher->send_message("hello", "testtopic1");
3675+ EXPECT_TRUE(message_receiver.wait_for_message());
3676+ EXPECT_EQ(1, message_receiver.last_sub_index_);
3677+ EXPECT_EQ("hello", message_receiver.last_message_);
3678+
3679+ // Send a blank "testtopic2" topic message (subscriber2)
3680+ publisher->send_message("", "testtopic2");
3681+ EXPECT_TRUE(message_receiver.wait_for_message());
3682+ EXPECT_EQ(2, message_receiver.last_sub_index_);
3683+ EXPECT_EQ("", message_receiver.last_message_);
3684+
3685+ // Send an empty topic message (subscriber3)
3686+ publisher->send_message("hello again!", "");
3687+ EXPECT_TRUE(message_receiver.wait_for_message());
3688+ EXPECT_EQ(3, message_receiver.last_sub_index_);
3689+ EXPECT_EQ("hello again!", message_receiver.last_message_);
3690+
3691+ // Send a "testtopic4" topic message (subscriber4)
3692+ // (no message should be received as subscriber4 is subscribed to a different publisher)
3693+ publisher->send_message("test", "testtopic4");
3694+ EXPECT_FALSE(message_receiver.wait_for_message());
3695+
3696+ // Now send a "testtopic4" topic message from the correct publisher (subscriber4)
3697+ publisher2->send_message("test", "testtopic4");
3698+ EXPECT_TRUE(message_receiver.wait_for_message());
3699+ EXPECT_EQ(4, message_receiver.last_sub_index_);
3700+ EXPECT_EQ("test", message_receiver.last_message_);
3701+
3702+ // Send a "unknown" topic message
3703+ // (no message should be received as none of the subscribers are listening for "unknown")
3704+ publisher->send_message("hello?", "unknown");
3705+ EXPECT_FALSE(message_receiver.wait_for_message());
3706+
3707+ publisher2->send_message("hello??", "unknown");
3708+ EXPECT_FALSE(message_receiver.wait_for_message());
3709+}
3710+
3711+TEST(PubSub, threading)
3712+{
3713+ ZmqMiddleware mw("testscope", (RuntimeImpl*)0x1,
3714+ TEST_BUILD_ROOT "/gtest/scopes/internal/zmq_middleware/ObjectAdapter/Zmq.ini");
3715+
3716+ {
3717+ // Create a publisher and a subscriber in seperate thread
3718+ auto subscriber_future = std::async(std::launch::async, [&mw]{ return mw.create_subscriber("testpublisher", "testtopic"); });
3719+ auto publisher_future = std::async(std::launch::async, [&mw]{ return mw.create_publisher("testpublisher"); });
3720+
3721+ // Obtain the publisher and subscriber handles
3722+ MWSubscriber::UPtr subscriber = subscriber_future.get();
3723+ MWPublisher::UPtr publisher = publisher_future.get();
3724+ }
3725+ // The publisher and subscriber are now destroyed in this thread (should not hang / crash)
3726+}
3727
3728=== added file 'test/gtest/scopes/internal/zmq_middleware/PubSub/Zmq.ini.in'
3729--- test/gtest/scopes/internal/zmq_middleware/PubSub/Zmq.ini.in 1970-01-01 00:00:00 +0000
3730+++ test/gtest/scopes/internal/zmq_middleware/PubSub/Zmq.ini.in 2014-05-21 14:02:43 +0000
3731@@ -0,0 +1,2 @@
3732+[Zmq]
3733+EndpointDir = /tmp
3734
3735=== modified file 'test/gtest/scopes/internal/zmq_middleware/RegistryI/RegistryI_test.cpp'
3736--- test/gtest/scopes/internal/zmq_middleware/RegistryI/RegistryI_test.cpp 2014-05-09 08:51:19 +0000
3737+++ test/gtest/scopes/internal/zmq_middleware/RegistryI/RegistryI_test.cpp 2014-05-21 14:02:43 +0000
3738@@ -705,7 +705,7 @@
3739 // check that we still have 1 child process
3740 EXPECT_EQ(1, process_count());
3741
3742- std::this_thread::sleep_for(std::chrono::seconds{2});
3743+ std::this_thread::sleep_for(std::chrono::seconds{3});
3744
3745 // check now that the scope has shutdown automatically (timed out after 2s)
3746 EXPECT_FALSE(reg->is_scope_running("testscopeB"));

Subscribers

People subscribed via source and target branches

to all changes: