Merge lp:~unity-team/unity/unity-lens.to.scope into lp:unity

Proposed by Nick Dedekind
Status: Work in progress
Proposed branch: lp:~unity-team/unity/unity-lens.to.scope
Merge into: lp:unity
Diff against target: 8181 lines (+4339/-860)
99 files modified
UnityCore/CMakeLists.txt (+12/-7)
UnityCore/Categories.cpp (+1/-0)
UnityCore/Category.cpp (+13/-3)
UnityCore/Category.h (+2/-1)
UnityCore/FilesystemLenses.cpp (+4/-5)
UnityCore/Filter.cpp (+21/-0)
UnityCore/Filter.h (+2/-0)
UnityCore/Filters.cpp (+6/-1)
UnityCore/GLibWrapper.cpp (+1/-5)
UnityCore/GLibWrapper.h (+9/-0)
UnityCore/GSettingsScopes.cpp (+171/-0)
UnityCore/GSettingsScopes.h (+56/-0)
UnityCore/MiscUtils.h (+118/-0)
UnityCore/Model-inl.h (+55/-23)
UnityCore/Model.h (+12/-5)
UnityCore/MusicPreview.cpp (+14/-2)
UnityCore/Preview.cpp (+26/-21)
UnityCore/Preview.h (+8/-8)
UnityCore/Result.cpp (+25/-7)
UnityCore/Result.h (+4/-2)
UnityCore/Results.cpp (+1/-0)
UnityCore/Scope.cpp (+211/-0)
UnityCore/Scope.h (+105/-0)
UnityCore/ScopeData.cpp (+89/-0)
UnityCore/ScopeData.h (+68/-0)
UnityCore/ScopeProxy.cpp (+804/-0)
UnityCore/ScopeProxy.h (+57/-0)
UnityCore/ScopeProxyInterface.h (+96/-0)
UnityCore/Scopes.cpp (+271/-0)
UnityCore/Scopes.h (+94/-0)
UnityCore/SeriesPreview.cpp (+11/-11)
UnityCore/Tracks.cpp (+2/-1)
UnityCore/Variant.cpp (+41/-1)
UnityCore/Variant.h (+2/-0)
com.canonical.Unity.gschema.xml (+10/-0)
dash/DashController.cpp (+3/-3)
dash/DashView.cpp (+162/-207)
dash/DashView.h (+20/-22)
dash/DashViewPrivate.cpp (+2/-2)
dash/DashViewPrivate.h (+3/-1)
dash/FilterBar.cpp (+12/-5)
dash/FilterBar.h (+1/-0)
dash/FilterRatingsButton.cpp (+1/-1)
dash/LensBar.cpp (+41/-55)
dash/LensBar.h (+12/-11)
dash/LensBarIcon.cpp (+9/-9)
dash/LensBarIcon.h (+4/-4)
dash/LensView.cpp (+207/-173)
dash/LensView.h (+27/-16)
dash/PlacesGroup.h (+1/-1)
dash/PreviewStateMachine.cpp (+1/-1)
dash/PreviewStateMachine.h (+1/-1)
dash/ResultRenderer.cpp (+2/-2)
dash/ResultRenderer.h (+2/-2)
dash/ResultRendererTile.cpp (+13/-8)
dash/ResultRendererTile.h (+5/-5)
dash/ResultView.cpp (+19/-38)
dash/ResultView.h (+6/-7)
dash/ResultViewGrid.cpp (+2/-2)
dash/ResultViewGrid.h (+0/-1)
dash/previews/DBusTestRunner.h (+0/-1)
dash/previews/LensDBusTestRunner.h (+10/-9)
dash/previews/StandaloneMusicPreview.cpp (+2/-2)
launcher/BFBLauncherIcon.cpp (+11/-11)
launcher/BFBLauncherIcon.h (+3/-3)
launcher/LauncherController.cpp (+1/-1)
plugins/unityshell/src/unityshell.cpp (+1/-1)
tests/CMakeLists.txt (+17/-7)
tests/autopilot/unity/emulators/dash.py (+15/-15)
tests/autopilot/unity/tests/test_command_lens.py (+2/-2)
tests/autopilot/unity/tests/test_dash.py (+9/-15)
tests/data/unity/scopes/testscope1.scope (+13/-0)
tests/data/unity/scopes/testscope2.scope (+13/-0)
tests/data/unity/scopes/testscope3.scope (+13/-0)
tests/data/unity/scopes/testscope4.scope (+13/-0)
tests/test_categories.cpp (+11/-6)
tests/test_dashview.cpp (+55/-0)
tests/test_dashview_impl.cpp (+6/-6)
tests/test_gsettings_scopes.cpp (+191/-0)
tests/test_hud_view.cpp (+1/-0)
tests/test_lensview.cpp (+17/-17)
tests/test_main.cpp (+6/-2)
tests/test_main_dbus.cpp (+4/-0)
tests/test_main_xless.cpp (+6/-0)
tests/test_mock_scope.h (+142/-0)
tests/test_model_iterator.cpp (+8/-3)
tests/test_result_renderer.cpp (+1/-1)
tests/test_results.cpp (+0/-1)
tests/test_resultviewgrid.cpp (+1/-1)
tests/test_scope.cpp (+120/-0)
tests/test_scope_bar.cpp (+138/-0)
tests/test_scope_proxy.cpp (+197/-0)
tests/test_searchbar.cpp (+0/-63)
tests/test_service_main.c (+4/-4)
tests/test_service_model.c (+17/-7)
tests/test_service_scope.c (+245/-0)
tests/test_service_scope.h (+66/-0)
unity-shared/DashStyle.cpp (+1/-1)
unity-shared/DashStyle.h (+1/-1)
To merge this branch: bzr merge lp:~unity-team/unity/unity-lens.to.scope
Reviewer Review Type Date Requested Status
Unity Team Pending
Review via email: mp+143922@code.launchpad.net

Description of the change

.

To post a comment you must log in.
3010. By Nick Dedekind

more cleanup

3011. By Nick Dedekind

Reverted ModelIterator to ResultIterator

3012. By Nick Dedekind

Reverted more unnecessary changes.

Revision history for this message
Michal Hruby (mhr3) wrote :

334 +const std::string ALWAYS_SEARCH_SETTINGS_KEY = "always-search";

This is only relevant for the home scope implementation, unity doesn't need to know. All it needs are the scopes key, which it displays icons in LensBar for.

3010 + <default>[ 'home.scope' , 'applications.scope' ]</default>

We'll need to change the default before merging (to include files, music etc). Order is already specified by design in bug 1056196.

3013. By Nick Dedekind

removed filter_update for changes in libunity

3014. By Nick Dedekind

Merged with trunk

3015. By Nick Dedekind

Fixed 64bit size_t->unsigned int conversion.

3016. By Nick Dedekind

Connected up client filter updates to scope backend.

3017. By Nick Dedekind

more 64bit fixes

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

320 +// wrapper for raw const gchar*. non-deleteable.
321 +class StringRef : boost::noncopyable

I also wanted to do this before, but I always been suggested to instead just add a function into the glib namespace that takes a gchar* returning a std::string with just a null-check on it...

Revision history for this message
Michal Hruby (mhr3) wrote :

+++ UnityCore/MusicPreview.cpp 2013-01-21 16:58:59 +0000
@@ -70,7 +71,12 @@

+ else
+ g_assert(false);

Nasty, LOG_ERROR() pls.

@@ -81,7 +87,12 @@

+ else
+ g_assert(false);

Same as above

+++ UnityCore/Preview.cpp 2013-01-21 16:58:59 +0000
@@ -229,7 +229,12 @@

+ else
+ g_assert(false);

Same

+++ UnityCore/ScopeData.cpp 2013-01-21 22:19:45 +0000
+ if (error)
+ {
+ data->id = scope_id;
+ LOG_DEBUG(logger) << "Error fetching metadata for scope: " << scope_id << " : " << error.Message();
+ }

This is pretty serious error, perhaps propagate it to the caller? If a .scope file can't be found proxy can't be created and therefore it doesn't even make sense to try to display an icon for the .scope file. Bottom line - invalid scope ids should be completely ignored (and LOG_WARNed)

+void ScopeProxy::Impl::DestroyProxy()
+{
+ scope_proxy_.Release();
+ if (cancel_scope_)
+ {
+ g_cancellable_cancel(cancel_scope_);
+ cancel_scope_ = g_cancellable_new();
+ }
+ cancel_scope_ = g_cancellable_new();

Why the double creation?

+void ScopeProxy::Impl::OnScopeChannelsInvalidated(UnityProtocolScopeProxy* proxy)
+{
+ LOG_WARNING(logger) << "Channels for scope '" << scope_data_->dbus_path() << "' have been invalidated. Attempting proxy re-creation.";
+ DestroyProxy();
+ CreateProxy();
+}

Shouldn't be needed, UnityProtocolScopeProxy is clever, it will try to reconnect to the scope automatically, are we missing notifications when this happens?

+GHashTable* hashtable_from_hintsmap(glib::HintsMap const& hints, GHashTable* hash_table)
+{
+ if (!hash_table)
+ return nullptr;
+
+ for (glib::HintsMap::const_iterator it = hints.begin(); it != hints.end(); ++it)
+ {
+ gchar* key = g_strdup(it->first.c_str());
+ GVariant* ptr = g_variant_ref(it->second);
+
+ g_hash_table_insert(hash_table, key, ptr);
+ }
+ return hash_table;
+}

Too easy to get wrong, the passed hashtable needs to have key_destroy_func set to g_free and value_destroy_func to g_variant_unref. Perhaps just return a hash table without making it an in param?

+++ UnityCore/ScopeProxy.cpp 2013-01-21 20:39:28 +0000
+ GHashTable* hints_table = glib::hashtable_from_hintsmap(hints, g_hash_table_new(g_direct_hash, g_direct_equal));

The poor hashtable is leaking, the proxy doesn't steal it.

3018. By Nick Dedekind

Added cancellable to scope calls

3019. By Nick Dedekind

Removed StringRef. removed always-search

3020. By Nick Dedekind

reverted changes to function declarations.

3021. By Nick Dedekind

Review fixes. Scopes now initialized with ScopeData structure.

3022. By Nick Dedekind

Fixed connections in scope.

3023. By Nick Dedekind

Merge with trunk.

3024. By Nick Dedekind

Fixed filter variant serialization.

3025. By Nick Dedekind

Added category order change connections.

3026. By Nick Dedekind

removed visibility fetching from proxy

3027. By Nick Dedekind

renaming .lens files to .scope

3028. By Nick Dedekind

Implemented re-opening of channel on reconnection.

3029. By Nick Dedekind

Fixed connected property validation.

3030. By Michal Hruby

Fix reconnection

3031. By Nick Dedekind

Merged with trunk

3032. By Nick Dedekind

merge with trunk

Unmerged revisions

3032. By Nick Dedekind

merge with trunk

3031. By Nick Dedekind

Merged with trunk

3030. By Michal Hruby

Fix reconnection

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'UnityCore/CMakeLists.txt'
2--- UnityCore/CMakeLists.txt 2012-12-19 20:53:12 +0000
3+++ UnityCore/CMakeLists.txt 2013-02-21 10:37:29 +0000
4@@ -21,7 +21,6 @@
5 CheckOptionFilter.h
6 DBusIndicators.h
7 DesktopUtilities.h
8- FilesystemLenses.h
9 Filter.h
10 Filters.h
11 GenericPreview.h
12@@ -31,13 +30,12 @@
13 GLibSource.h
14 GLibWrapper.h
15 GLibWrapper-inl.h
16+ GSettingsScopes.h
17 Hud.h
18- HomeLens.h
19 IndicatorEntry.h
20 Indicator.h
21 Indicators.h
22- Lens.h
23- Lenses.h
24+ MiscUtils.h
25 MoviePreview.h
26 MultiRangeFilter.h
27 MusicPreview.h
28@@ -51,6 +49,11 @@
29 Result.h
30 ResultIterator.h
31 Results.h
32+ Scope.h
33+ ScopeData.h
34+ Scopes.h
35+ ScopeProxy.h
36+ ScopeProxyInterface.h
37 SeriesPreview.h
38 SocialPreview.h
39 Track.h
40@@ -66,7 +69,6 @@
41 CheckOptionFilter.cpp
42 DBusIndicators.cpp
43 DesktopUtilities.cpp
44- FilesystemLenses.cpp
45 Filter.cpp
46 Filters.cpp
47 GenericPreview.cpp
48@@ -74,12 +76,11 @@
49 GLibSignal.cpp
50 GLibSource.cpp
51 GLibWrapper.cpp
52+ GSettingsScopes.cpp
53 Hud.cpp
54- HomeLens.cpp
55 Indicator.cpp
56 IndicatorEntry.cpp
57 Indicators.cpp
58- Lens.cpp
59 MoviePreview.cpp
60 MultiRangeFilter.cpp
61 MusicPreview.cpp
62@@ -90,6 +91,10 @@
63 Result.cpp
64 ResultIterator.cpp
65 Results.cpp
66+ Scope.cpp
67+ ScopeData.cpp
68+ Scopes.cpp
69+ ScopeProxy.cpp
70 SeriesPreview.cpp
71 SocialPreview.cpp
72 Track.cpp
73
74=== modified file 'UnityCore/Categories.cpp'
75--- UnityCore/Categories.cpp 2012-03-14 06:24:18 +0000
76+++ UnityCore/Categories.cpp 2013-02-21 10:37:29 +0000
77@@ -25,6 +25,7 @@
78 {
79
80 Categories::Categories()
81+ : Model<Category>::Model(REMOTE)
82 {
83 row_added.connect(sigc::mem_fun(this, &Categories::OnRowAdded));
84 row_changed.connect(sigc::mem_fun(this, &Categories::OnRowChanged));
85
86=== modified file 'UnityCore/Category.cpp'
87--- UnityCore/Category.cpp 2012-11-29 13:28:27 +0000
88+++ UnityCore/Category.cpp 2013-02-21 10:37:29 +0000
89@@ -26,6 +26,15 @@
90 namespace dash
91 {
92
93+enum CategoryColumn
94+{
95+ ID = 0,
96+ DISPLAY_NAME,
97+ ICON_HINT,
98+ RENDERER_NAME,
99+ HINTS
100+};
101+
102 Category::Category(DeeModel* model,
103 DeeModelIter* iter,
104 DeeModelTag* renderer_name_tag)
105@@ -49,10 +58,11 @@
106
107 void Category::SetupGetters()
108 {
109- name.SetGetterFunction(sigc::bind(sigc::mem_fun(this, &RowAdaptorBase::GetStringAt), 0));
110- icon_hint.SetGetterFunction(sigc::bind(sigc::mem_fun(this, &RowAdaptorBase::GetStringAt), 1));
111+ id.SetGetterFunction(sigc::bind(sigc::mem_fun(this, &RowAdaptorBase::GetStringAt), CategoryColumn::ID));
112+ name.SetGetterFunction(sigc::bind(sigc::mem_fun(this, &RowAdaptorBase::GetStringAt), CategoryColumn::DISPLAY_NAME));
113+ icon_hint.SetGetterFunction(sigc::bind(sigc::mem_fun(this, &RowAdaptorBase::GetStringAt), CategoryColumn::ICON_HINT));
114+ renderer_name.SetGetterFunction(sigc::bind(sigc::mem_fun(this, &RowAdaptorBase::GetStringAt), CategoryColumn::RENDERER_NAME));
115 index.SetGetterFunction(sigc::mem_fun(this, &Category::get_index));
116- renderer_name.SetGetterFunction(sigc::bind(sigc::mem_fun(this, &RowAdaptorBase::GetStringAt), 2));
117 }
118
119 std::size_t Category::get_index() const
120
121=== modified file 'UnityCore/Category.h'
122--- UnityCore/Category.h 2011-07-31 08:39:48 +0000
123+++ UnityCore/Category.h 2013-02-21 10:37:29 +0000
124@@ -38,10 +38,11 @@
125 Category(Category const& other);
126 Category& operator=(Category const& other);
127
128+ nux::ROProperty<std::string> id;
129 nux::ROProperty<std::string> name;
130 nux::ROProperty<std::string> icon_hint;
131+ nux::ROProperty<std::string> renderer_name;
132 nux::ROProperty<std::size_t> index;
133- nux::ROProperty<std::string> renderer_name;
134
135 private:
136 void SetupGetters();
137
138=== modified file 'UnityCore/FilesystemLenses.cpp'
139--- UnityCore/FilesystemLenses.cpp 2012-10-29 09:34:54 +0000
140+++ UnityCore/FilesystemLenses.cpp 2013-02-21 10:37:29 +0000
141@@ -81,12 +81,11 @@
142 * /usr/share/unity/lenses
143 * /applications
144 * /applications.lens
145- * /applications.scope
146- * /chromium-webapps.scope
147+ * /chromium-webapps.lens
148 * /files
149 * /files.lens
150- * /zeitgiest.scope
151- * /ubuntuone.scope
152+ * /zeitgiest.lens
153+ * /ubuntuone.lens
154 *
155 * Etc, etc. We therefore need to enumerate these directories and find our
156 * .lens files in them.
157@@ -401,7 +400,7 @@
158 }
159
160 for (Lens::Ptr& lens: lenses_)
161- owner_->lens_added.emit(lens);
162+ owner_->lenses_added.emit(lens);
163
164 owner_->lenses_loaded.emit();
165 }
166
167=== modified file 'UnityCore/Filter.cpp'
168--- UnityCore/Filter.cpp 2012-10-29 09:34:54 +0000
169+++ UnityCore/Filter.cpp 2013-02-21 10:37:29 +0000
170@@ -25,6 +25,7 @@
171 #include "MultiRangeFilter.h"
172 #include "RadioOptionFilter.h"
173 #include "RatingsFilter.h"
174+#include "GLibWrapper.h"
175
176 namespace unity
177 {
178@@ -154,6 +155,26 @@
179 g_variant_unref(row_value);
180 }
181
182+glib::Variant Filter::VariantValue() const
183+{
184+ if (!IsValid())
185+ return glib::Variant();
186+
187+ GVariantBuilder hints;
188+ g_variant_builder_init (&hints, G_VARIANT_TYPE("(ssssa{sv}bbb)"));
189+
190+ g_variant_builder_add(&hints, "s", id().c_str(), NULL);
191+ g_variant_builder_add(&hints, "s", name().c_str(), NULL);
192+ g_variant_builder_add(&hints, "s", icon_hint().c_str(), NULL);
193+ g_variant_builder_add(&hints, "s", renderer_name().c_str(), NULL);
194+ g_variant_builder_add(&hints, "@a{sv}", dee_model_get_value(model_, iter_, FilterColumn::RENDERER_STATE), NULL);
195+ g_variant_builder_add(&hints, "b", visible(), NULL);
196+ g_variant_builder_add(&hints, "b", collapsed(), NULL);
197+ g_variant_builder_add(&hints, "b", filtering(), NULL);
198+
199+ return glib::Variant(g_variant_builder_end(&hints));
200+}
201+
202 std::string Filter::get_id() const
203 {
204 if (IsValid())
205
206=== modified file 'UnityCore/Filter.h'
207--- UnityCore/Filter.h 2012-07-16 11:03:32 +0000
208+++ UnityCore/Filter.h 2013-02-21 10:37:29 +0000
209@@ -77,6 +77,8 @@
210 virtual void Clear() = 0;
211 bool IsValid() const;
212
213+ glib::Variant VariantValue() const;
214+
215 nux::ROProperty<std::string> id;
216 nux::ROProperty<std::string> name;
217 nux::ROProperty<std::string> icon_hint;
218
219=== modified file 'UnityCore/Filters.cpp'
220--- UnityCore/Filters.cpp 2012-03-14 06:24:18 +0000
221+++ UnityCore/Filters.cpp 2013-02-21 10:37:29 +0000
222@@ -50,6 +50,7 @@
223
224
225 Filters::Filters()
226+: Model<FilterAdaptor>::Model(ModelType::REMOTE)
227 {
228 row_added.connect(sigc::mem_fun(this, &Filters::OnRowAdded));
229 row_changed.connect(sigc::mem_fun(this, &Filters::OnRowChanged));
230@@ -57,7 +58,7 @@
231 }
232
233 Filters::Filters(ModelType model_type)
234- : Model<FilterAdaptor>::Model(model_type)
235+: Model<FilterAdaptor>::Model(model_type)
236 {
237 row_added.connect(sigc::mem_fun(this, &Filters::OnRowAdded));
238 row_changed.connect(sigc::mem_fun(this, &Filters::OnRowChanged));
239@@ -70,6 +71,10 @@
240 Filter::Ptr Filters::FilterAtIndex(std::size_t index)
241 {
242 FilterAdaptor adaptor = RowAtIndex(index);
243+ if (filter_map_.find(adaptor.iter()) == filter_map_.end())
244+ {
245+ OnRowAdded(adaptor);
246+ }
247 return filter_map_[adaptor.iter()];
248 }
249
250
251=== modified file 'UnityCore/GLibWrapper.cpp'
252--- UnityCore/GLibWrapper.cpp 2012-03-14 06:24:18 +0000
253+++ UnityCore/GLibWrapper.cpp 2013-02-21 10:37:29 +0000
254@@ -69,7 +69,6 @@
255 return o;
256 }
257
258-
259 String::String()
260 : string_(0)
261 {}
262@@ -116,10 +115,7 @@
263
264 std::string String::Str() const
265 {
266- if (string_)
267- return std::string(string_);
268- else
269- return std::string("");
270+ return glib::gchar_to_string(string_);
271 }
272
273 std::ostream& operator<<(std::ostream& o, String const& s)
274
275=== modified file 'UnityCore/GLibWrapper.h'
276--- UnityCore/GLibWrapper.h 2012-07-04 20:16:06 +0000
277+++ UnityCore/GLibWrapper.h 2013-02-21 10:37:29 +0000
278@@ -105,6 +105,7 @@
279 GError* error_;
280 };
281
282+// wrapper for raw gcha*. auto-deleted.
283 class String : boost::noncopyable
284 {
285 public:
286@@ -125,6 +126,14 @@
287 gchar* string_;
288 };
289
290+inline std::string gchar_to_string(const char* str)
291+{
292+ if (!str)
293+ return std::string("");
294+ else
295+ return std::string(str);
296+}
297+
298 std::ostream& operator<<(std::ostream& o, Error const& e);
299 std::ostream& operator<<(std::ostream& o, String const& s);
300
301
302=== added file 'UnityCore/GSettingsScopes.cpp'
303--- UnityCore/GSettingsScopes.cpp 1970-01-01 00:00:00 +0000
304+++ UnityCore/GSettingsScopes.cpp 2013-02-21 10:37:29 +0000
305@@ -0,0 +1,171 @@
306+/*
307+ * Copyright (C) 2013 Canonical Ltd
308+ *
309+ * This program is free software: you can redistribute it and/or modify
310+ * it under the terms of the GNU General Public License version 3 as
311+ * published by the Free Software Foundation.
312+ *
313+ * This program is distributed in the hope that it will be useful,
314+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
315+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
316+ * GNU General Public License for more details.
317+ *
318+ * You should have received a copy of the GNU General Public License
319+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
320+ *
321+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
322+ */
323+
324+
325+#include "GSettingsScopes.h"
326+
327+#include "Scope.h"
328+
329+namespace unity
330+{
331+namespace dash
332+{
333+DECLARE_LOGGER(logger, "unity.dash.gsettingsscopereader");
334+
335+namespace
336+{
337+const std::string SETTINGS_NAME = "com.canonical.Unity.Dash";
338+const std::string SCOPE_SETTINGS_KEY = "scopes";
339+}
340+
341+class GSettingsScopesReader::Impl
342+{
343+public:
344+ Impl(GSettingsScopesReader* owner);
345+ ~Impl() {}
346+
347+ void LoadScopes();
348+
349+ GSettingsScopesReader* owner_;
350+ bool loaded_;
351+
352+ glib::Object<GSettings> settings_;
353+ glib::Signal<void, GSettings*, gchar*> scopes_changed;
354+
355+ std::vector<std::string> get_string_vector(std::string const& setting)
356+ {
357+ std::vector<std::string> vector;
358+
359+ std::unique_ptr<gchar*[], void(*)(gchar**)> strings(g_settings_get_strv(settings_, setting.c_str()), g_strfreev);
360+
361+ for (int i = 0; strings[i]; ++i)
362+ {
363+ std::string value = strings[i];
364+
365+ if (!value.empty())
366+ vector.push_back(value);
367+ }
368+ return vector;
369+ }
370+
371+ ScopeDataList scopes_order_;
372+};
373+
374+
375+GSettingsScopesReader::Impl::Impl(GSettingsScopesReader* owner)
376+: owner_(owner)
377+, loaded_(false)
378+, settings_(g_settings_new(SETTINGS_NAME.c_str()))
379+{
380+ auto change_func = [&] (GSettings*, gchar*)
381+ {
382+ if (loaded_)
383+ {
384+ LoadScopes();
385+ owner_->scopes_changed.emit(scopes_order_);
386+ }
387+ };
388+
389+ scopes_changed.Connect(settings_, "changed::"+SCOPE_SETTINGS_KEY, change_func);
390+}
391+
392+
393+void GSettingsScopesReader::Impl::LoadScopes()
394+{
395+ std::vector<std::string> tmp_scope_ids = get_string_vector(SCOPE_SETTINGS_KEY);
396+
397+ ScopeDataList old_scopes_order = scopes_order_;
398+ scopes_order_.clear();
399+
400+ // insert new
401+ for (std::string const& scope_id : tmp_scope_ids)
402+ {
403+ auto match_scope_data_to_id = [scope_id](ScopeData::Ptr const& scope_data) { return scope_data->id() == scope_id; };
404+
405+ ScopeData::Ptr scope;
406+ auto scope_position = std::find_if(old_scopes_order.begin(), old_scopes_order.end(), match_scope_data_to_id);
407+ if (scope_position == old_scopes_order.end())
408+ {
409+ glib::Error error;
410+ scope = ScopeData::ReadProtocolDataForId(scope_id, error);
411+ if (error)
412+ {
413+ LOG_WARN(logger) << "Error fetching protocol metadata for scope: " << scope_id << " : " << error.Message();
414+ continue;
415+ }
416+ }
417+ else
418+ {
419+ scope = *scope_position;
420+ }
421+
422+ if (scope)
423+ {
424+ scopes_order_.push_back(scope);
425+ }
426+ }
427+ loaded_ = true;
428+}
429+
430+
431+GSettingsScopesReader::GSettingsScopesReader()
432+: pimpl(new Impl(this))
433+{
434+}
435+
436+void GSettingsScopesReader::LoadScopes()
437+{
438+ pimpl->LoadScopes();
439+}
440+
441+ScopeDataList const& GSettingsScopesReader::GetScopesData() const
442+{
443+ if (!pimpl->loaded_)
444+ pimpl->LoadScopes();
445+ return pimpl->scopes_order_;
446+}
447+
448+ScopeData::Ptr GSettingsScopesReader::GetScopeDataById(std::string const& scope_id) const
449+{
450+ if (!pimpl->loaded_)
451+ pimpl->LoadScopes();
452+
453+ auto match_scope_data_to_id = [scope_id](ScopeData::Ptr const& scope_data) { return scope_data->id() == scope_id; };
454+ auto scope_position = std::find_if(pimpl->scopes_order_.begin(), pimpl->scopes_order_.end(), match_scope_data_to_id);
455+
456+ if (scope_position == pimpl->scopes_order_.end())
457+ return ScopeData::Ptr();
458+
459+ return *scope_position;
460+}
461+
462+GSettingsScopesReader::Ptr GSettingsScopesReader::GetDefault()
463+{
464+ static GSettingsScopesReader::Ptr main_reader(new GSettingsScopesReader());
465+
466+ return main_reader;
467+}
468+
469+GSettingsScopes::GSettingsScopes()
470+: Scopes(GSettingsScopesReader::GetDefault())
471+{
472+
473+}
474+
475+} // namespace dash
476+} // namespace unity
477\ No newline at end of file
478
479=== added file 'UnityCore/GSettingsScopes.h'
480--- UnityCore/GSettingsScopes.h 1970-01-01 00:00:00 +0000
481+++ UnityCore/GSettingsScopes.h 2013-02-21 10:37:29 +0000
482@@ -0,0 +1,56 @@
483+/*
484+ * Copyright (C) 2013 Canonical Ltd
485+ *
486+ * This program is free software: you can redistribute it and/or modify
487+ * it under the terms of the GNU General Public License version 3 as
488+ * published by the Free Software Foundation.
489+ *
490+ * This program is distributed in the hope that it will be useful,
491+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
492+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
493+ * GNU General Public License for more details.
494+ *
495+ * You should have received a copy of the GNU General Public License
496+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
497+ *
498+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
499+ */
500+
501+#ifndef UNITY_GSETTINGS_SCOPES_H
502+#define UNITY_GSETTINGS_SCOPES_H
503+
504+#include "Scopes.h"
505+
506+namespace unity
507+{
508+namespace dash
509+{
510+
511+class GSettingsScopesReader : public ScopesReader
512+{
513+public:
514+ typedef std::shared_ptr<GSettingsScopesReader> Ptr;
515+ GSettingsScopesReader();
516+
517+ virtual void LoadScopes();
518+ virtual ScopeDataList const& GetScopesData() const;
519+ virtual ScopeData::Ptr GetScopeDataById(std::string const& scope_id) const;
520+
521+ static GSettingsScopesReader::Ptr GetDefault();
522+
523+private:
524+ class Impl;
525+ std::unique_ptr<Impl> pimpl;
526+};
527+
528+
529+class GSettingsScopes : public Scopes
530+{
531+public:
532+ GSettingsScopes();
533+};
534+
535+} // namespace dash
536+} // namespace unity
537+
538+#endif // UNITY_GSETTINGS_SCOPES_H
539\ No newline at end of file
540
541=== added file 'UnityCore/MiscUtils.h'
542--- UnityCore/MiscUtils.h 1970-01-01 00:00:00 +0000
543+++ UnityCore/MiscUtils.h 2013-02-21 10:37:29 +0000
544@@ -0,0 +1,118 @@
545+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
546+/*
547+ * Copyright (C) 2011 Canonical Ltd
548+ *
549+ * This program is free software: you can redistribute it and/or modify
550+ * it under the terms of the GNU General Public License version 3 as
551+ * published by the Free Software Foundation.
552+ *
553+ * This program is distributed in the hope that it will be useful,
554+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
555+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
556+ * GNU General Public License for more details.
557+ *
558+ * You should have received a copy of the GNU General Public License
559+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
560+ *
561+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
562+ */
563+
564+#ifndef UNITY_MISC_UTILS_H
565+#define UNITY_MISC_UTILS_H
566+
567+#include <NuxCore/Property.h>
568+
569+namespace unity
570+{
571+namespace utils
572+{
573+
574+template <typename TYPE>
575+std::shared_ptr<sigc::connection> ConnectProperties(nux::ROProperty<TYPE>& local_property, nux::Property<TYPE>& remote_property)
576+{
577+ auto change_connection = std::make_shared<sigc::connection>();
578+ local_property.SetGetterFunction([&remote_property]() { return remote_property.Get(); });
579+ *change_connection = remote_property.changed.connect([&local_property, &remote_property](TYPE const& value) { local_property.EmitChanged(value); });
580+ return change_connection;
581+}
582+
583+template <typename TYPE>
584+std::shared_ptr<sigc::connection> ConnectProperties(nux::ROProperty<TYPE>& local_property, nux::ROProperty<TYPE>& remote_property)
585+{
586+ auto change_connection = std::make_shared<sigc::connection>();
587+ local_property.SetGetterFunction([&remote_property]() { return remote_property.Get(); });
588+ *change_connection = remote_property.changed.connect([&local_property, &remote_property](TYPE const& value) { local_property.EmitChanged(value); });
589+ return change_connection;
590+}
591+
592+template <typename TYPE>
593+std::shared_ptr<sigc::connection> ConnectProperties(nux::RWProperty<TYPE>& local_property, nux::Property<TYPE>& remote_property)
594+{
595+ auto change_connection = std::make_shared<sigc::connection>();
596+ *change_connection = remote_property.changed.connect([&local_property, &remote_property](TYPE const& value)
597+ {
598+ local_property.EmitChanged(value);
599+ });
600+
601+ local_property.SetGetterFunction([&remote_property]() { return remote_property.Get(); });
602+ local_property.SetSetterFunction([&remote_property, &local_property, change_connection](TYPE const& value)
603+ {
604+ TYPE old_value = remote_property.Get();
605+
606+ // block so we doing get a loop.
607+ bool blocked = change_connection->block(true);
608+ bool ret = remote_property.Set(value) != old_value;
609+ change_connection->block(blocked);
610+ return ret;
611+ });
612+ return change_connection;
613+}
614+
615+template <typename TYPE>
616+std::shared_ptr<sigc::connection> ConnectProperties(nux::RWProperty<TYPE>& local_property, nux::RWProperty<TYPE>& remote_property)
617+{
618+ auto change_connection = std::make_shared<sigc::connection>();
619+ *change_connection = remote_property.changed.connect([&local_property, &remote_property](TYPE const& value)
620+ {
621+ local_property.EmitChanged(value);
622+ });
623+
624+ local_property.SetGetterFunction([&remote_property]() { return remote_property.Get(); });
625+ local_property.SetSetterFunction([&remote_property, &local_property, change_connection](TYPE const& value)
626+ {
627+ TYPE old_value = remote_property.Get();
628+
629+ // block so we doing get a loop.
630+ bool blocked = change_connection->block(true);
631+ bool ret = remote_property.Set(value) != old_value;
632+ change_connection->block(blocked);
633+ return ret;
634+ });
635+ return change_connection;
636+}
637+
638+template <class TYPE>
639+class AutoResettingVariable
640+{
641+public:
642+ AutoResettingVariable(TYPE*const variable, TYPE const& new_value)
643+ : variable_(variable)
644+ , original_value_(*variable)
645+ {
646+ *variable_ = new_value;
647+ }
648+
649+ ~AutoResettingVariable()
650+ {
651+ *variable_ = original_value_;
652+ }
653+
654+private:
655+ TYPE*const variable_;
656+ TYPE original_value_;
657+};
658+
659+}
660+}
661+
662+#endif // UNITY_MISC_UTILS_H
663\ No newline at end of file
664
665=== modified file 'UnityCore/Model-inl.h'
666--- UnityCore/Model-inl.h 2012-10-29 09:34:54 +0000
667+++ UnityCore/Model-inl.h 2013-02-21 10:37:29 +0000
668@@ -28,16 +28,6 @@
669 {
670
671 template<class RowAdaptor>
672-Model<RowAdaptor>::Model()
673- : model_type_(ModelType::REMOTE)
674- , cached_adaptor1_(nullptr, nullptr, nullptr)
675- , cached_adaptor2_(nullptr, nullptr, nullptr)
676- , cached_adaptor3_(nullptr, nullptr, nullptr)
677-{
678- Init();
679-}
680-
681-template<class RowAdaptor>
682 Model<RowAdaptor>::Model (ModelType model_type)
683 : model_type_(model_type)
684 , cached_adaptor1_(nullptr, nullptr, nullptr)
685@@ -63,26 +53,66 @@
686 void Model<RowAdaptor>::OnSwarmNameChanged(std::string const& swarm_name)
687 {
688 static nux::logging::Logger local_logger("unity.dash.model");
689-
690+ LOG_DEBUG(local_logger) << "New swarm name: " << swarm_name;
691+
692+ glib::Object<DeeModel> new_model;
693+
694+ switch(model_type_)
695+ {
696+ case ModelType::LOCAL:
697+ new_model = dee_sequence_model_new();
698+ break;
699+
700+ case ModelType::REMOTE:
701+ case ModelType::REMOTE_SHARED:
702+ new_model = dee_shared_model_new(swarm_name.c_str());
703+ break;
704+
705+ case ModelType::UNATTACHED:
706+ break;
707+
708+ default:
709+ LOG_ERROR(local_logger) << "Unexpected ModelType " << model_type_;
710+ break;
711+ }
712+
713+ SetModel(new_model);
714+}
715+
716+template<class RowAdaptor>
717+void Model<RowAdaptor>::SetModel(glib::Object<DeeModel> const& new_model)
718+{
719+ GetDeeTagFunc func = [](glib::Object<DeeModel> const& model) {
720+ return dee_model_register_tag(model, NULL);
721+ };
722+ SetModel(new_model, func);
723+}
724+
725+template<class RowAdaptor>
726+void Model<RowAdaptor>::SetModel(glib::Object<DeeModel> const& new_model, GetDeeTagFunc const& get_dee_tag_func)
727+{
728+ typedef glib::Signal<void, DeeModel*, guint64, guint64> TransactionSignalType;
729 typedef glib::Signal<void, DeeModel*, DeeModelIter*> RowSignalType;
730- typedef glib::Signal<void, DeeModel*, guint64, guint64> TransactionSignalType;
731
732- LOG_DEBUG(local_logger) << "New swarm name: " << swarm_name;
733+ // Check if it's the same as the current model.
734+ if (new_model == model_)
735+ return;
736
737 // Let the views clean up properly
738 if (model_)
739 {
740 dee_model_clear(model_);
741 sig_manager_.Disconnect(model_);
742+ model_.Release();
743 }
744+ model_ = new_model;
745+
746+ if (!model_)
747+ return;
748
749 switch(model_type_)
750 {
751- case ModelType::LOCAL:
752- model_ = dee_sequence_model_new();
753- break;
754- case ModelType::REMOTE:
755- model_ = dee_shared_model_new(swarm_name.c_str());
756+ case ModelType::REMOTE_SHARED:
757 sig_manager_.Add(new TransactionSignalType(model_,
758 "begin-transaction",
759 sigc::mem_fun(this, &Model<RowAdaptor>::OnTransactionBegin)));
760@@ -91,15 +121,15 @@
761 "end-transaction",
762 sigc::mem_fun(this, &Model<RowAdaptor>::OnTransactionEnd)));
763 break;
764+
765+ case ModelType::REMOTE:
766+ case ModelType::LOCAL:
767+ case ModelType::UNATTACHED:
768 default:
769- LOG_ERROR(local_logger) << "Unexpected ModelType " << model_type_;
770 break;
771 }
772
773- model.EmitChanged(model_);
774-
775-
776- renderer_tag_ = dee_model_register_tag(model_, NULL);
777+ renderer_tag_ = get_dee_tag_func(model_);
778
779 sig_manager_.Add(new RowSignalType(model_,
780 "row-added",
781@@ -112,6 +142,8 @@
782 sig_manager_.Add(new RowSignalType(model_,
783 "row-removed",
784 sigc::mem_fun(this, &Model<RowAdaptor>::OnRowRemoved)));
785+
786+ model.EmitChanged(model_);
787 }
788
789 template<class RowAdaptor>
790
791=== modified file 'UnityCore/Model.h'
792--- UnityCore/Model.h 2012-09-02 20:34:37 +0000
793+++ UnityCore/Model.h 2013-02-21 10:37:29 +0000
794@@ -38,7 +38,9 @@
795 enum ModelType
796 {
797 REMOTE,
798- LOCAL
799+ REMOTE_SHARED,
800+ LOCAL,
801+ UNATTACHED
802 };
803
804 /* This template class encapsulates the basics of talking to a DeeSharedModel,
805@@ -52,14 +54,14 @@
806 public:
807 typedef std::shared_ptr<Model> Ptr;
808
809- Model();
810- Model (ModelType model_type);
811+ Model (ModelType model_type = ModelType::REMOTE_SHARED);
812 virtual ~Model();
813
814 const RowAdaptor RowAtIndex(std::size_t index);
815 DeeModelTag* GetTag();
816
817 nux::Property<std::string> swarm_name;
818+
819 nux::ROProperty<std::size_t> count;
820 nux::ROProperty<unsigned long long> seqnum;
821 nux::ROProperty<glib::Object<DeeModel>> model;
822@@ -71,6 +73,11 @@
823 sigc::signal<void, unsigned long long, unsigned long long> begin_transaction;
824 sigc::signal<void, unsigned long long, unsigned long long> end_transaction;
825
826+ typedef std::function<DeeModelTag*(glib::Object<DeeModel> const& model)> GetDeeTagFunc;
827+
828+ void SetModel(glib::Object<DeeModel> const& model);
829+ void SetModel(glib::Object<DeeModel> const& model, GetDeeTagFunc const& func);
830+
831 private:
832 void Init();
833 void OnRowAdded(DeeModel* model, DeeModelIter* iter);
834@@ -94,8 +101,8 @@
835 RowAdaptor cached_adaptor3_;
836 };
837
838-}
839-}
840+} // namespace dash
841+} // namespace unity
842
843 #include "Model-inl.h"
844
845
846=== modified file 'UnityCore/MusicPreview.cpp'
847--- UnityCore/MusicPreview.cpp 2012-07-12 16:36:54 +0000
848+++ UnityCore/MusicPreview.cpp 2013-02-21 10:37:29 +0000
849@@ -22,11 +22,13 @@
850
851 #include "MusicPreview.h"
852 #include "Tracks.h"
853+#include "Scope.h"
854
855 namespace unity
856 {
857 namespace dash
858 {
859+DECLARE_LOGGER(logger, "unity.dash.musicpreview");
860
861 class MusicPreview::Impl
862 {
863@@ -70,7 +72,12 @@
864 unity_protocol_music_preview_play_uri(raw_preview_, uri.c_str());
865 glib::Variant properties(unity_protocol_preview_end_updates(preview),
866 glib::StealRef());
867- owner_->Update(properties);
868+
869+ glib::HintsMap property_hints;
870+ if (properties.ASVToHints(property_hints))
871+ owner_->Update(property_hints);
872+ else
873+ LOG_ERROR(logger) << "PlayUri could not convert property hints to variant for " << uri;
874 }
875
876 void MusicPreview::Impl::PauseUri(std::string const& uri) const
877@@ -81,7 +88,12 @@
878 unity_protocol_music_preview_pause_uri(raw_preview_, uri.c_str());
879 glib::Variant properties(unity_protocol_preview_end_updates(preview),
880 glib::StealRef());
881- owner_->Update(properties);
882+
883+ glib::HintsMap property_hints;
884+ if (properties.ASVToHints(property_hints))
885+ owner_->Update(property_hints);
886+ else
887+ LOG_ERROR(logger) << "PauseUri could not convert property hints to variant for " << uri;
888 }
889
890 MusicPreview::MusicPreview(unity::glib::Object<GObject> const& proto_obj)
891
892=== modified file 'UnityCore/Preview.cpp'
893--- UnityCore/Preview.cpp 2012-10-29 09:34:54 +0000
894+++ UnityCore/Preview.cpp 2013-02-21 10:37:29 +0000
895@@ -21,8 +21,8 @@
896 #include <NuxCore/Logger.h>
897 #include <unity-protocol.h>
898
899-#include "Lens.h"
900 #include "Preview.h"
901+#include "Scope.h"
902
903 #include "ApplicationPreview.h"
904 #include "GenericPreview.h"
905@@ -81,7 +81,7 @@
906 return nullptr;
907 }
908
909-Preview::Ptr Preview::PreviewForVariant(glib::Variant &properties)
910+Preview::Ptr Preview::PreviewForVariant(glib::Variant const& properties)
911 {
912 glib::Object<UnityProtocolPreview> preview(unity_protocol_preview_parse(properties));
913 if (!preview)
914@@ -123,10 +123,10 @@
915 InfoHintPtrList get_info_hints() const { return info_hint_list_; };
916 void EmitClosed() const;
917
918- Lens* get_parent_lens() const { return parent_lens_; };
919- bool set_parent_lens(Lens* lens)
920+ Scope* get_parent_scope() const { return parent_scope_; };
921+ bool set_parent_scope(Scope* scope)
922 {
923- parent_lens_ = lens;
924+ parent_scope_ = scope;
925 return false; // TODO: do we need the notifications here?
926 };
927
928@@ -141,12 +141,12 @@
929 std::string image_source_uri_;
930 ActionPtrList actions_list_;
931 InfoHintPtrList info_hint_list_;
932- Lens* parent_lens_;
933+ Scope* parent_scope_;
934 };
935
936 Preview::Impl::Impl(Preview* owner, glib::Object<GObject> const& proto_obj)
937 : owner_(owner)
938- , parent_lens_(nullptr)
939+ , parent_scope_(nullptr)
940 {
941 if (!proto_obj)
942 {
943@@ -215,10 +215,10 @@
944 owner_->image_source_uri.SetGetterFunction(
945 sigc::mem_fun(this, &Preview::Impl::get_image_source_uri));
946
947- owner_->parent_lens.SetGetterFunction(
948- sigc::mem_fun(this, &Preview::Impl::get_parent_lens));
949- owner_->parent_lens.SetSetterFunction(
950- sigc::mem_fun(this, &Preview::Impl::set_parent_lens));
951+ owner_->parent_scope.SetGetterFunction(
952+ sigc::mem_fun(this, &Preview::Impl::get_parent_scope));
953+ owner_->parent_scope.SetSetterFunction(
954+ sigc::mem_fun(this, &Preview::Impl::set_parent_scope));
955 }
956
957 void Preview::Impl::EmitClosed() const
958@@ -229,7 +229,12 @@
959 unity_protocol_preview_preview_closed(raw_preview_);
960 glib::Variant properties(unity_protocol_preview_end_updates(preview),
961 glib::StealRef());
962- owner_->Update(properties);
963+
964+ glib::HintsMap property_hints;
965+ if (properties.ASVToHints(property_hints))
966+ owner_->Update(property_hints);
967+ else
968+ LOG_ERROR(logger) << "EmitClosed could not convert property hints to variant for " << owner_->preview_uri.Get();
969 }
970
971 Preview::Preview(glib::Object<GObject> const& proto_obj)
972@@ -251,28 +256,28 @@
973 return pimpl->get_info_hints();
974 }
975
976-void Preview::Update(glib::Variant const& properties,
977- glib::DBusProxy::ReplyCallback reply_callback) const
978+void Preview::Update(glib::HintsMap const& property_hints,
979+ std::function<void(glib::HintsMap const&, glib::Error const&)> const& reply_callback) const
980 {
981- if (pimpl->parent_lens_)
982+ if (pimpl->parent_scope_)
983 {
984- pimpl->parent_lens_->SignalPreview(preview_uri, properties, reply_callback);
985+ pimpl->parent_scope_->UpdatePreviewProperty(preview_uri, property_hints, reply_callback);
986 }
987 else
988 {
989- LOG_WARN(logger) << "Unable to update Preview, parent_lens wasn't set!";
990+ LOG_WARN(logger) << "Unable to update Preview, parent_scope_ wasn't set!";
991 }
992 }
993
994-void Preview::PerformAction(std::string const& id, Lens::Hints const& hints) const
995+void Preview::PerformAction(std::string const& id, glib::HintsMap const& hints) const
996 {
997- if (pimpl->parent_lens_)
998+ if (pimpl->parent_scope_)
999 {
1000- pimpl->parent_lens_->ActivatePreviewAction(id, preview_uri, hints);
1001+ pimpl->parent_scope_->ActivatePreviewAction(id, preview_uri, hints);
1002 }
1003 else
1004 {
1005- LOG_WARN(logger) << "Unable to perform action '" << id << "', parent_lens wasn't set!";
1006+ LOG_WARN(logger) << "Unable to perform action '" << id << "', parent_scope_ wasn't set!";
1007 }
1008 }
1009
1010
1011=== modified file 'UnityCore/Preview.h'
1012--- UnityCore/Preview.h 2012-09-13 10:56:42 +0000
1013+++ UnityCore/Preview.h 2013-02-21 10:37:29 +0000
1014@@ -40,7 +40,7 @@
1015 namespace dash
1016 {
1017
1018-class Lens;
1019+class Scope;
1020
1021 enum LayoutHint
1022 {
1023@@ -110,7 +110,7 @@
1024
1025 virtual ~Preview();
1026
1027- static Preview::Ptr PreviewForVariant(glib::Variant& properties);
1028+ static Preview::Ptr PreviewForVariant(glib::Variant const& properties);
1029 static Preview::Ptr PreviewForProtocolObject(glib::Object<GObject> const& proto_obj);
1030
1031 nux::ROProperty<std::string> renderer_name;
1032@@ -120,24 +120,24 @@
1033 nux::ROProperty<unity::glib::Object<GIcon>> image;
1034 nux::ROProperty<std::string> image_source_uri;
1035
1036- // can't use Lens::Ptr to avoid circular dependency
1037- nux::RWProperty<Lens*> parent_lens;
1038+ // can't use Scope::Ptr to avoid circular dependency
1039+ nux::RWProperty<Scope*> parent_scope;
1040 nux::Property<std::string> preview_uri;
1041
1042 ActionPtrList GetActions() const;
1043 InfoHintPtrList GetInfoHints() const;
1044
1045 void PerformAction(std::string const& id,
1046- std::map<std::string, glib::Variant> const& hints =
1047- std::map<std::string, glib::Variant>()) const;
1048+ glib::HintsMap const& hints =
1049+ glib::HintsMap()) const;
1050 void EmitClosed() const;
1051
1052 protected:
1053 // this should be UnityProtocolPreview, but we want to keep the usage
1054 // of libunity-protocol-private private to unity-core
1055 Preview(glib::Object<GObject> const& proto_obj);
1056- void Update(glib::Variant const& properties,
1057- glib::DBusProxy::ReplyCallback reply_callback = nullptr) const;
1058+ void Update(glib::HintsMap const& property_hints,
1059+ std::function<void(glib::HintsMap const&, glib::Error const&)> const& reply_callback = nullptr) const;
1060 static glib::Object<GIcon> IconForString(std::string const& icon_hint);
1061
1062 private:
1063
1064=== modified file 'UnityCore/Result.cpp'
1065--- UnityCore/Result.cpp 2012-12-06 17:41:07 +0000
1066+++ UnityCore/Result.cpp 2013-02-21 10:37:29 +0000
1067@@ -25,6 +25,22 @@
1068 namespace dash
1069 {
1070
1071+namespace
1072+{
1073+enum ResultColumn
1074+{
1075+ URI,
1076+ ICON_HINT,
1077+ CATEGORY,
1078+ RESULT_TYPE,
1079+ MIMETYPE,
1080+ TITLE,
1081+ COMMENT,
1082+ DND_URI,
1083+ METADATA
1084+};
1085+}
1086+
1087 Result::Result(DeeModel* model,
1088 DeeModelIter* iter,
1089 DeeModelTag* renderer_tag)
1090@@ -51,19 +67,21 @@
1091 uri.SetGetterFunction(sigc::mem_fun(this, &Result::GetURI));
1092 icon_hint.SetGetterFunction(sigc::mem_fun(this, &Result::GetIconHint));
1093 category_index.SetGetterFunction(sigc::mem_fun(this, &Result::GetCategoryIndex));
1094+ result_type.SetGetterFunction(sigc::mem_fun(this, &Result::GetResultType));
1095 mimetype.SetGetterFunction(sigc::mem_fun(this, &Result::GetMimeType));
1096 name.SetGetterFunction(sigc::mem_fun(this, &Result::GetName));
1097 comment.SetGetterFunction(sigc::mem_fun(this, &Result::GetComment));
1098 dnd_uri.SetGetterFunction(sigc::mem_fun(this, &Result::GetDndURI));
1099 }
1100
1101-std::string Result::GetURI() const { return GetStringAt(0); }
1102-std::string Result::GetIconHint() const { return GetStringAt(1); }
1103-std::size_t Result::GetCategoryIndex() const { return GetUIntAt(2); }
1104-std::string Result::GetMimeType() const { return GetStringAt(3); }
1105-std::string Result::GetName() const { return GetStringAt(4); }
1106-std::string Result::GetComment() const { return GetStringAt(5); }
1107-std::string Result::GetDndURI() const { return GetStringAt(6); }
1108+std::string Result::GetURI() const { return GetStringAt(ResultColumn::URI); }
1109+std::string Result::GetIconHint() const { return GetStringAt(ResultColumn::ICON_HINT); }
1110+unsigned Result::GetCategoryIndex() const { return GetUIntAt(ResultColumn::CATEGORY); }
1111+unsigned Result::GetResultType() const { return GetUIntAt(ResultColumn::RESULT_TYPE); }
1112+std::string Result::GetMimeType() const { return GetStringAt(ResultColumn::MIMETYPE); }
1113+std::string Result::GetName() const { return GetStringAt(ResultColumn::TITLE); }
1114+std::string Result::GetComment() const { return GetStringAt(ResultColumn::COMMENT); }
1115+std::string Result::GetDndURI() const { return GetStringAt(ResultColumn::DND_URI); }
1116
1117 }
1118 }
1119
1120=== modified file 'UnityCore/Result.h'
1121--- UnityCore/Result.h 2012-12-06 17:41:07 +0000
1122+++ UnityCore/Result.h 2013-02-21 10:37:29 +0000
1123@@ -45,7 +45,8 @@
1124
1125 nux::ROProperty<std::string> uri;
1126 nux::ROProperty<std::string> icon_hint;
1127- nux::ROProperty<std::size_t> category_index;
1128+ nux::ROProperty<unsigned> category_index;
1129+ nux::ROProperty<unsigned> result_type;
1130 nux::ROProperty<std::string> mimetype;
1131 nux::ROProperty<std::string> name;
1132 nux::ROProperty<std::string> comment;
1133@@ -54,7 +55,8 @@
1134 protected:
1135 virtual std::string GetURI() const;
1136 virtual std::string GetIconHint() const;
1137- virtual std::size_t GetCategoryIndex() const;
1138+ virtual unsigned GetCategoryIndex() const;
1139+ virtual unsigned GetResultType() const;
1140 virtual std::string GetMimeType() const;
1141 virtual std::string GetName() const;
1142 virtual std::string GetComment() const;
1143
1144=== modified file 'UnityCore/Results.cpp'
1145--- UnityCore/Results.cpp 2012-04-23 12:29:20 +0000
1146+++ UnityCore/Results.cpp 2013-02-21 10:37:29 +0000
1147@@ -25,6 +25,7 @@
1148 {
1149
1150 Results::Results()
1151+: Model<Result>::Model(ModelType::REMOTE_SHARED)
1152 {
1153 row_added.connect(sigc::mem_fun(this, &Results::OnRowAdded));
1154 row_changed.connect(sigc::mem_fun(this, &Results::OnRowChanged));
1155
1156=== added file 'UnityCore/Scope.cpp'
1157--- UnityCore/Scope.cpp 1970-01-01 00:00:00 +0000
1158+++ UnityCore/Scope.cpp 2013-02-21 10:37:29 +0000
1159@@ -0,0 +1,211 @@
1160+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1161+/*
1162+ * Copyright (C) 2013 Canonical Ltd
1163+ *
1164+ * This program is free software: you can redistribute it and/or modify
1165+ * it under the terms of the GNU General Public License version 3 as
1166+ * published by the Free Software Foundation.
1167+ *
1168+ * This program is distributed in the hope that it will be useful,
1169+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1170+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1171+ * GNU General Public License for more details.
1172+ *
1173+ * You should have received a copy of the GNU General Public License
1174+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1175+ *
1176+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
1177+ *
1178+ */
1179+
1180+#include "Scope.h"
1181+#include "MiscUtils.h"
1182+#include "ScopeProxy.h"
1183+#include <unity-protocol.h>
1184+
1185+
1186+namespace unity
1187+{
1188+namespace dash
1189+{
1190+DECLARE_LOGGER(logger, "unity.dash.scope");
1191+
1192+class Scope::Impl
1193+{
1194+public:
1195+ Impl(Scope* owner, ScopeData::Ptr const& scope_data);
1196+ ~Impl();
1197+
1198+ void Init();
1199+
1200+ void Activate(std::string const& uri, guint action_type, glib::HintsMap const& hints, ActivateCallback const& callback, GCancellable* cancellable);
1201+ void OnActivateReply(std::string const& uri, ScopeHandledType handled_type, glib::HintsMap const& hints, glib::Error const& error);
1202+
1203+ DeeFilter* GetFilterForCategory(unsigned category, DeeFilter* filter) const;
1204+
1205+ Scope* owner_;
1206+ ScopeData::Ptr scope_data_;
1207+ ScopeProxyInterface::Ptr proxy_;
1208+
1209+ typedef std::shared_ptr<sigc::connection> ConnectionPtr;
1210+ std::vector<ConnectionPtr> property_connections;
1211+};
1212+
1213+Scope::Impl::Impl(Scope* owner, ScopeData::Ptr const& scope_data)
1214+: owner_(owner)
1215+, scope_data_(scope_data)
1216+{
1217+ property_connections.push_back(utils::ConnectProperties(owner_->id, scope_data_->id));
1218+}
1219+
1220+Scope::Impl::~Impl()
1221+{
1222+ for_each(property_connections.begin(), property_connections.end(), [](ConnectionPtr const& con) { con->disconnect(); });
1223+ property_connections.clear();
1224+}
1225+
1226+void Scope::Impl::Init()
1227+{
1228+ proxy_ = owner_->CreateProxyInterface();
1229+
1230+ if (proxy_)
1231+ {
1232+ property_connections.push_back(utils::ConnectProperties(owner_->connected, proxy_->connected));
1233+ property_connections.push_back(utils::ConnectProperties(owner_->is_master, proxy_->is_master));
1234+ property_connections.push_back(utils::ConnectProperties(owner_->search_in_global, proxy_->search_in_global));
1235+ property_connections.push_back(utils::ConnectProperties(owner_->search_hint, proxy_->search_hint));
1236+ property_connections.push_back(utils::ConnectProperties(owner_->view_type, proxy_->view_type));
1237+ property_connections.push_back(utils::ConnectProperties(owner_->results, proxy_->results));
1238+ property_connections.push_back(utils::ConnectProperties(owner_->filters, proxy_->filters));
1239+ property_connections.push_back(utils::ConnectProperties(owner_->categories, proxy_->categories));
1240+ property_connections.push_back(utils::ConnectProperties(owner_->category_order, proxy_->category_order));
1241+
1242+ property_connections.push_back(utils::ConnectProperties(owner_->name, proxy_->name));
1243+ property_connections.push_back(utils::ConnectProperties(owner_->description, proxy_->description));
1244+ property_connections.push_back(utils::ConnectProperties(owner_->icon_hint, proxy_->icon_hint));
1245+ property_connections.push_back(utils::ConnectProperties(owner_->category_icon_hint, proxy_->category_icon_hint));
1246+ property_connections.push_back(utils::ConnectProperties(owner_->keywords, proxy_->keywords));
1247+ property_connections.push_back(utils::ConnectProperties(owner_->type, proxy_->type));
1248+ property_connections.push_back(utils::ConnectProperties(owner_->query_pattern, proxy_->query_pattern));
1249+ property_connections.push_back(utils::ConnectProperties(owner_->shortcut, proxy_->shortcut));
1250+ property_connections.push_back(utils::ConnectProperties(owner_->visible, proxy_->visible));
1251+
1252+ property_connections.push_back(utils::ConnectProperties(owner_->results, proxy_->results));
1253+ property_connections.push_back(utils::ConnectProperties(owner_->filters, proxy_->filters));
1254+ property_connections.push_back(utils::ConnectProperties(owner_->categories, proxy_->categories));
1255+ }
1256+}
1257+
1258+void Scope::Impl::Activate(std::string const& uri, guint action_type, glib::HintsMap const& hints, ActivateCallback const& callback, GCancellable* cancellable)
1259+{
1260+ proxy_->Activate(uri,
1261+ action_type,
1262+ hints,
1263+ [this, callback] (std::string const& uri, ScopeHandledType handled_type, glib::HintsMap const& hints, glib::Error const& error) {
1264+ if (callback)
1265+ callback(uri, handled_type, error);
1266+ OnActivateReply(uri, handled_type, hints, error);
1267+ },
1268+ cancellable);
1269+}
1270+
1271+
1272+void Scope::Impl::OnActivateReply(std::string const& uri, ScopeHandledType handled, glib::HintsMap const& hints, glib::Error const& error)
1273+{
1274+ LOG_DEBUG(logger) << "Activation reply (handled:" << handled << ", error: " << (error ? "true" : "false") << ") for " << uri;
1275+
1276+ if (static_cast<UnityProtocolHandledType>(handled) == UNITY_PROTOCOL_HANDLED_TYPE_SHOW_PREVIEW)
1277+ {
1278+ auto iter = hints.find("preview");
1279+ if (iter != hints.end())
1280+ {
1281+ glib::Variant v = iter->second;
1282+
1283+ Preview::Ptr preview(Preview::PreviewForVariant(v));
1284+ if (preview)
1285+ {
1286+ // would be nice to make parent_scope_ a shared_ptr,
1287+ // but that's not really doable from here
1288+ preview->parent_scope = owner_;
1289+ preview->preview_uri = uri;
1290+ owner_->preview_ready.emit(uri, preview);
1291+ return;
1292+ }
1293+ }
1294+
1295+ LOG_WARNING(logger) << "Unable to deserialize Preview";
1296+ }
1297+ else
1298+ {
1299+ owner_->activated.emit(uri, handled, hints);
1300+ }
1301+}
1302+
1303+Scope::Scope(ScopeData::Ptr const& scope_data)
1304+: pimpl(new Impl(this, scope_data))
1305+{
1306+}
1307+
1308+Scope::~Scope()
1309+{
1310+}
1311+
1312+void Scope::Init()
1313+{
1314+ pimpl->Init();
1315+}
1316+
1317+void Scope::Connect()
1318+{
1319+ if (pimpl->proxy_->connected())
1320+ return;
1321+
1322+ pimpl->proxy_->CreateProxy();
1323+}
1324+
1325+void Scope::Search(std::string const& search_hint, SearchCallback const& callback, GCancellable* cancellable)
1326+{
1327+ return pimpl->proxy_->Search(search_hint, callback, cancellable);
1328+}
1329+
1330+void Scope::Activate(std::string const& uri, ActivateCallback const& callback, GCancellable* cancellable)
1331+{
1332+ pimpl->Activate(uri, UNITY_PROTOCOL_ACTION_TYPE_ACTIVATE_RESULT, glib::HintsMap(), callback, cancellable);
1333+}
1334+
1335+void Scope::Preview(std::string const& uri, ActivateCallback const& callback, GCancellable* cancellable)
1336+{
1337+ pimpl->Activate(uri, UNITY_PROTOCOL_ACTION_TYPE_PREVIEW_RESULT, glib::HintsMap(), callback, cancellable);
1338+}
1339+
1340+void Scope::ActivatePreviewAction(std::string const& action_id,
1341+ std::string const& uri,
1342+ glib::HintsMap const& hints,
1343+ ActivateCallback const& callback,
1344+ GCancellable* cancellable)
1345+{
1346+ std::string activation_uri(action_id);
1347+ activation_uri += ":";
1348+ activation_uri += uri;
1349+
1350+ pimpl->Activate(activation_uri, UNITY_PROTOCOL_ACTION_TYPE_PREVIEW_ACTION, hints, callback, cancellable);
1351+}
1352+
1353+void Scope::UpdatePreviewProperty(std::string const& uri, glib::HintsMap const& hints, UpdatePreviewPropertyCallback const& callback, GCancellable* cancellable)
1354+{
1355+ pimpl->proxy_->UpdatePreviewProperty(uri, glib::HintsMap(), callback, cancellable);
1356+}
1357+
1358+Results::Ptr Scope::GetResultsForCategory(unsigned category) const
1359+{
1360+ return pimpl->proxy_->GetResultsForCategory(category);
1361+}
1362+
1363+ScopeProxyInterface::Ptr Scope::CreateProxyInterface() const
1364+{
1365+ return ScopeProxyInterface::Ptr(new ScopeProxy(pimpl->scope_data_));
1366+}
1367+
1368+
1369+} // namespace dash
1370+} // namespace unity
1371
1372=== added file 'UnityCore/Scope.h'
1373--- UnityCore/Scope.h 1970-01-01 00:00:00 +0000
1374+++ UnityCore/Scope.h 2013-02-21 10:37:29 +0000
1375@@ -0,0 +1,105 @@
1376+/*
1377+ * Copyright (C) 2013 Canonical Ltd
1378+ *
1379+ * This program is free software: you can redistribute it and/or modify
1380+ * it under the terms of the GNU General Public License version 3 as
1381+ * published by the Free Software Foundation.
1382+ *
1383+ * This program is distributed in the hope that it will be useful,
1384+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1385+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1386+ * GNU General Public License for more details.
1387+ *
1388+ * You should have received a copy of the GNU General Public License
1389+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1390+ *
1391+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
1392+ */
1393+
1394+#ifndef UNITY_SCOPE_H
1395+#define UNITY_SCOPE_H
1396+
1397+#include <boost/noncopyable.hpp>
1398+#include <sigc++/trackable.h>
1399+
1400+#include "ScopeProxyInterface.h"
1401+#include "Preview.h"
1402+#include "Result.h"
1403+
1404+namespace unity
1405+{
1406+namespace dash
1407+{
1408+
1409+class Scope : public sigc::trackable, boost::noncopyable
1410+{
1411+public:
1412+ typedef std::shared_ptr<Scope> Ptr;
1413+
1414+ Scope(ScopeData::Ptr const& scope_data);
1415+ virtual ~Scope();
1416+
1417+ // Must call this function after construction.
1418+ virtual void Init();
1419+
1420+ void Connect();
1421+
1422+ nux::ROProperty<std::string> id;
1423+ nux::ROProperty<bool> connected;
1424+
1425+ nux::ROProperty<bool> visible;
1426+ nux::ROProperty<bool> is_master;
1427+ nux::ROProperty<bool> search_in_global;
1428+ nux::ROProperty<std::string> search_hint;
1429+ nux::RWProperty<ScopeViewType> view_type;
1430+
1431+ nux::ROProperty<Results::Ptr> results;
1432+ nux::ROProperty<Filters::Ptr> filters;
1433+ nux::ROProperty<Categories::Ptr> categories;
1434+ nux::ROProperty<std::vector<int>> category_order;
1435+
1436+ nux::ROProperty<std::string> name;
1437+ nux::ROProperty<std::string> description;
1438+ nux::ROProperty<std::string> icon_hint;
1439+ nux::ROProperty<std::string> category_icon_hint;
1440+ nux::ROProperty<std::vector<std::string>> keywords;
1441+ nux::ROProperty<std::string> type;
1442+ nux::ROProperty<std::string> query_pattern;
1443+ nux::ROProperty<std::string> shortcut;
1444+
1445+ typedef std::function<void(glib::HintsMap const&, glib::Error const&)> SearchCallback;
1446+ virtual void Search(std::string const& search_hint, SearchCallback const& callback = nullptr, GCancellable* cancellable = nullptr);
1447+
1448+ typedef std::function<void(std::string const&, ScopeHandledType, glib::Error const&)> ActivateCallback;
1449+
1450+ virtual void Activate(std::string const& uri, ActivateCallback const& callback = nullptr, GCancellable* cancellable = nullptr);
1451+
1452+ virtual void Preview(std::string const& uri, ActivateCallback const& callback = nullptr, GCancellable* cancellable = nullptr);
1453+
1454+ virtual void ActivatePreviewAction(std::string const& action_id,
1455+ std::string const& uri,
1456+ glib::HintsMap const& hints,
1457+ ActivateCallback const& callback = nullptr,
1458+ GCancellable* cancellable = nullptr);
1459+
1460+ typedef std::function<void(glib::HintsMap const&, glib::Error const&)> UpdatePreviewPropertyCallback;
1461+ virtual void UpdatePreviewProperty(std::string const& uri, glib::HintsMap const& hints, UpdatePreviewPropertyCallback const& callback = nullptr, GCancellable* cancellable = nullptr);
1462+
1463+ virtual Results::Ptr GetResultsForCategory(unsigned category) const;
1464+
1465+
1466+ sigc::signal<void, std::string const&, ScopeHandledType, glib::HintsMap const&> activated;
1467+ sigc::signal<void, std::string const&, Preview::Ptr const&> preview_ready;
1468+
1469+protected:
1470+ virtual ScopeProxyInterface::Ptr CreateProxyInterface() const;
1471+
1472+private:
1473+ class Impl;
1474+ std::unique_ptr<Impl> pimpl;
1475+};
1476+
1477+} // namespace dash
1478+} // namespace unity
1479+
1480+#endif // UNITY_SCOPE_H
1481\ No newline at end of file
1482
1483=== added file 'UnityCore/ScopeData.cpp'
1484--- UnityCore/ScopeData.cpp 1970-01-01 00:00:00 +0000
1485+++ UnityCore/ScopeData.cpp 2013-02-21 10:37:29 +0000
1486@@ -0,0 +1,89 @@
1487+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1488+/*
1489+ * Copyright (C) 2013 Canonical Ltd
1490+ *
1491+ * This program is free software: you can redistribute it and/or modify
1492+ * it under the terms of the GNU General Public License version 3 as
1493+ * published by the Free Software Foundation.
1494+ *
1495+ * This program is distributed in the hope that it will be useful,
1496+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1497+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1498+ * GNU General Public License for more details.
1499+ *
1500+ * You should have received a copy of the GNU General Public License
1501+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1502+ *
1503+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
1504+ */
1505+
1506+
1507+#include "ScopeData.h"
1508+#include <unity-protocol.h>
1509+#include <NuxCore/Logger.h>
1510+
1511+#include "GLibWrapper.h"
1512+
1513+namespace unity
1514+{
1515+namespace dash
1516+{
1517+
1518+namespace
1519+{
1520+ static void safe_delete_scope_metadata(UnityProtocolScopeRegistryScopeMetadata* data)
1521+ {
1522+ if (!data) return;
1523+ unity_protocol_scope_registry_scope_metadata_unref(data);
1524+ }
1525+}
1526+
1527+ScopeData::ScopeData()
1528+: visible(true)
1529+{
1530+}
1531+
1532+ScopeData::Ptr ScopeData::ReadProtocolDataForId(std::string const& scope_id, glib::Error& error)
1533+{
1534+ ScopeData::Ptr data(new ScopeData());
1535+
1536+ std::shared_ptr<UnityProtocolScopeRegistryScopeMetadata> meta_data(unity_protocol_scope_registry_scope_metadata_for_id(scope_id.c_str(), &error),
1537+ safe_delete_scope_metadata);
1538+
1539+ if (error)
1540+ {
1541+ data->id = scope_id;
1542+ }
1543+ else if (meta_data)
1544+ {
1545+ data->dbus_name = glib::gchar_to_string(meta_data->dbus_name);
1546+ data->dbus_path = glib::gchar_to_string(meta_data->dbus_path);
1547+
1548+ data->id = glib::gchar_to_string(meta_data->id);
1549+ data->full_path = glib::gchar_to_string(meta_data->full_path);
1550+ data->name = glib::gchar_to_string(meta_data->name);
1551+ data->icon_hint = glib::gchar_to_string(meta_data->icon);
1552+ data->category_icon_hint = glib::gchar_to_string(meta_data->category_icon);
1553+ data->type = meta_data->type;
1554+ data->description = glib::gchar_to_string(meta_data->description);
1555+ data->shortcut = glib::gchar_to_string(meta_data->shortcut);
1556+ data->search_hint = glib::gchar_to_string(meta_data->search_hint);
1557+ data->is_master = meta_data->is_master;
1558+ data->query_pattern = glib::gchar_to_string(meta_data->query_pattern);
1559+
1560+ std::vector<std::string> keywords;
1561+ for (GSList* v = meta_data->keywords; v; v = g_slist_next(v))
1562+ {
1563+ std::string value(static_cast<gchar*>(v->data));
1564+ if (value.empty())
1565+ continue;
1566+
1567+ keywords.push_back(value);
1568+ }
1569+ data->keywords = keywords;
1570+ }
1571+ return data;
1572+}
1573+
1574+}
1575+}
1576\ No newline at end of file
1577
1578=== added file 'UnityCore/ScopeData.h'
1579--- UnityCore/ScopeData.h 1970-01-01 00:00:00 +0000
1580+++ UnityCore/ScopeData.h 2013-02-21 10:37:29 +0000
1581@@ -0,0 +1,68 @@
1582+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1583+/*
1584+ * Copyright (C) 2013 Canonical Ltd
1585+ *
1586+ * This program is free software: you can redistribute it and/or modify
1587+ * it under the terms of the GNU General Public License version 3 as
1588+ * published by the Free Software Foundation.
1589+ *
1590+ * This program is distributed in the hope that it will be useful,
1591+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1592+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1593+ * GNU General Public License for more details.
1594+ *
1595+ * You should have received a copy of the GNU General Public License
1596+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1597+ *
1598+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
1599+ */
1600+
1601+
1602+#ifndef UNITY_SCOPE_DATA_H
1603+#define UNITY_SCOPE_DATA_H
1604+
1605+#include <NuxCore/Property.h>
1606+#include "GLibWrapper.h"
1607+
1608+namespace unity
1609+{
1610+namespace dash
1611+{
1612+
1613+enum ScopeViewType
1614+{
1615+ HIDDEN=0,
1616+ HOME_VIEW,
1617+ SCOPE_VIEW
1618+};
1619+
1620+class ScopeData
1621+{
1622+public:
1623+ typedef std::shared_ptr<ScopeData> Ptr;
1624+ ScopeData();
1625+
1626+ nux::Property<std::string> id;
1627+ nux::Property<std::string> full_path;
1628+ nux::Property<std::string> dbus_name;
1629+ nux::Property<std::string> dbus_path;
1630+ nux::Property<bool> is_master;
1631+ nux::Property<std::string> icon_hint;
1632+ nux::Property<std::string> category_icon_hint;
1633+ nux::Property<std::vector<std::string>> keywords;
1634+ nux::Property<std::string> type;
1635+ nux::Property<std::string> query_pattern;
1636+ nux::Property<std::string> name;
1637+ nux::Property<std::string> description;
1638+ nux::Property<std::string> shortcut;
1639+ nux::Property<std::string> search_hint;
1640+
1641+ nux::Property<bool> visible; // FIXME!
1642+
1643+ static ScopeData::Ptr ReadProtocolDataForId(std::string const& scope_id, glib::Error& error);
1644+};
1645+
1646+}
1647+}
1648+
1649+#endif
1650\ No newline at end of file
1651
1652=== added file 'UnityCore/ScopeProxy.cpp'
1653--- UnityCore/ScopeProxy.cpp 1970-01-01 00:00:00 +0000
1654+++ UnityCore/ScopeProxy.cpp 2013-02-21 10:37:29 +0000
1655@@ -0,0 +1,804 @@
1656+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1657+/*
1658+ * Copyright (C) 2012 Canonical Ltd
1659+ *
1660+ * This program is free software: you can redistribute it and/or modify
1661+ * it under the terms of the GNU General Public License version 3 as
1662+ * published by the Free Software Foundation.
1663+ *
1664+ * This program is distributed in the hope that it will be useful,
1665+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1666+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1667+ * GNU General Public License for more details.
1668+ *
1669+ * You should have received a copy of the GNU General Public License
1670+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1671+ *
1672+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
1673+ */
1674+
1675+#include "ScopeProxy.h"
1676+#include "GLibSignal.h"
1677+#include "MiscUtils.h"
1678+
1679+#include <unity-protocol.h>
1680+#include <NuxCore/Logger.h>
1681+#include "GLibSource.h"
1682+
1683+namespace unity
1684+{
1685+namespace dash
1686+{
1687+
1688+namespace
1689+{
1690+const int PROXY_CONNECT_TIMEOUT = 2000;
1691+
1692+const unsigned CATEGORY_COLUMN = 2;
1693+}
1694+
1695+
1696+DECLARE_LOGGER(logger, "unity.dash.scopeproxy");
1697+
1698+class ScopeProxy::Impl
1699+{
1700+public:
1701+ Impl(ScopeProxy*const owner, ScopeData::Ptr const& scope_data);
1702+ ~Impl();
1703+
1704+ static ScopeData::Ptr CreateData(std::string const& dbus_name, std::string const& dbus_path);
1705+
1706+ void CreateProxy();
1707+ void OnNewScope(GObject *source_object, GAsyncResult *res);
1708+ void DestroyProxy();
1709+
1710+ void OpenChannel();
1711+ void OnChannelOpened(GObject *source_object, GAsyncResult *res);
1712+
1713+ void CloseChannel();
1714+ static void OnCloseChannel(GObject *source_object, GAsyncResult *res, gpointer user_data);
1715+
1716+ void Search(std::string const& search_string, glib::HintsMap const& hints, SearchCallback const& callback, GCancellable* cancel);
1717+ void Activate(std::string const& uri, uint activate_type, glib::HintsMap const& hints, ScopeProxy::ActivateCallback const& callback, GCancellable* cancellable);
1718+ void UpdatePreviewProperty(std::string const& uri, glib::HintsMap const& hints, UpdatePreviewPropertyCallback const& callback, GCancellable* cancellable);
1719+
1720+ bool set_view_type(ScopeViewType const& view_type)
1721+ {
1722+ if (scope_proxy_ && unity_protocol_scope_proxy_get_view_type(scope_proxy_) != static_cast<UnityProtocolViewType>(view_type))
1723+ {
1724+ unity_protocol_scope_proxy_set_view_type(scope_proxy_, static_cast<UnityProtocolViewType>(view_type));
1725+ return true;
1726+ }
1727+ return false;
1728+ }
1729+
1730+ Results::Ptr results() { return results_; }
1731+ Filters::Ptr filters() { return filters_; }
1732+ Categories::Ptr categories() { return categories_; }
1733+
1734+ DeeFilter* GetFilterForCategory(unsigned category, DeeFilter* filter) const;
1735+
1736+ ScopeProxy*const owner_;
1737+ ScopeData::Ptr scope_data_;
1738+
1739+ // scope proxy properties
1740+ nux::Property<bool> search_in_global;
1741+ nux::Property<ScopeViewType> view_type;
1742+
1743+ nux::Property<bool> connected;
1744+ nux::Property<std::string> channel;
1745+ nux::Property<std::vector<int>> category_order;
1746+ std::string last_search_;
1747+
1748+ glib::Object<UnityProtocolScopeProxy> scope_proxy_;
1749+ glib::Object<GCancellable> cancel_scope_;
1750+ bool proxy_created_;
1751+ bool scope_proxy_connected_;
1752+ bool searching_;
1753+
1754+ Results::Ptr results_;
1755+ Filters::Ptr filters_;
1756+ Categories::Ptr categories_;
1757+
1758+ typedef std::shared_ptr<sigc::connection> ConnectionPtr;
1759+ std::vector<ConnectionPtr> property_connections;
1760+ sigc::connection filters_change_connection;
1761+
1762+ /////////////////////////////////////////////////
1763+ // DBus property signals.
1764+ glib::Signal<void, UnityProtocolScopeProxy*, GParamSpec*> connected_signal_;
1765+ glib::Signal<void, UnityProtocolScopeProxy*, GParamSpec*> search_in_global_signal_;
1766+ glib::Signal<void, UnityProtocolScopeProxy*, GParamSpec*> is_master_signal_;
1767+ glib::Signal<void, UnityProtocolScopeProxy*, GParamSpec*> search_hint_signal_;
1768+ glib::Signal<void, UnityProtocolScopeProxy*, GParamSpec*> view_type_signal_;
1769+ glib::Signal<void, UnityProtocolScopeProxy*, GParamSpec*> filters_signal_;
1770+ glib::Signal<void, UnityProtocolScopeProxy*, GParamSpec*> categories_signal_;
1771+ glib::Signal<void, UnityProtocolScopeProxy*, GParamSpec*> metadata_signal_;
1772+ glib::Signal<void, UnityProtocolScopeProxy*, GParamSpec*> optional_metadata_signal_;
1773+ glib::Signal<void, UnityProtocolScopeProxy*, const gchar*, guint32*, int> category_order_signal_;
1774+ /////////////////////////////////////////////////
1775+
1776+private:
1777+ /////////////////////////////////////////////////
1778+ // Signal Connections
1779+ void OnScopeConnectedChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param);
1780+ void OnScopeIsMasterChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param);
1781+ void OnScopeSearchInGlobalChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param);
1782+ void OnScopeSearchHintChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param);
1783+ void OnScopeViewTypeChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param);
1784+ void OnScopeFiltersChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param);
1785+ void OnScopeCategoriesChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param);
1786+ void OnScopeMetadataChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param);
1787+ void OnScopeOptionalMetadataChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param);
1788+ void OnScopeCategoryOrderChanged(UnityProtocolScopeProxy* sender, const gchar* channel_id, guint32* new_order, int new_order_length1);
1789+ /////////////////////////////////////////////////
1790+
1791+ void WaitForProxyConnection(GCancellable* cancellable,
1792+ int timeout_msec,
1793+ std::function<void(glib::Error const&)> const& callback);
1794+
1795+ /////////////////////////////////////
1796+ // Search Callback
1797+ struct SearchData
1798+ {
1799+ SearchCallback callback;
1800+ };
1801+
1802+ static void OnScopeSearchCallback(GObject *source_object, GAsyncResult *res, gpointer user_data)
1803+ {
1804+ std::unique_ptr<SearchData> data(static_cast<SearchData*>(user_data));
1805+ glib::Error error;
1806+ GHashTable* hint_ret = unity_protocol_scope_proxy_search_finish(UNITY_PROTOCOL_SCOPE_PROXY(source_object), res, &error);
1807+
1808+ glib::HintsMap hints;
1809+ glib::hintsmap_from_hashtable(hint_ret, hints);
1810+
1811+ if (data->callback)
1812+ data->callback(hints, error);
1813+ if (hint_ret) { g_hash_table_destroy(hint_ret); }
1814+ }
1815+ /////////////////////////////////////
1816+
1817+ /////////////////////////////////////
1818+ // Search Callback
1819+ struct UpdatePreviewPropertyData
1820+ {
1821+ UpdatePreviewPropertyCallback callback;
1822+ };
1823+
1824+ static void OnScopeUpdatePreviewPropertyCallback(GObject *source_object, GAsyncResult *res, gpointer user_data)
1825+ {
1826+ std::unique_ptr<UpdatePreviewPropertyData> data(static_cast<UpdatePreviewPropertyData*>(user_data));
1827+ glib::Error error;
1828+ GHashTable* hint_ret = unity_protocol_scope_proxy_update_preview_property_finish(UNITY_PROTOCOL_SCOPE_PROXY(source_object), res, &error);
1829+
1830+ glib::HintsMap hints;
1831+ glib::hintsmap_from_hashtable(hint_ret, hints);
1832+
1833+ if (data->callback)
1834+ data->callback(hints, error);
1835+
1836+ if (hint_ret) { g_hash_table_destroy(hint_ret); }
1837+ }
1838+ /////////////////////////////////////
1839+
1840+ /////////////////////////////////////
1841+ // Activation Callback
1842+ struct ActivateData
1843+ {
1844+ ScopeProxy::ActivateCallback callback;
1845+ };
1846+ static void OnScopeActivateCallback(GObject *source_object, GAsyncResult *res, gpointer user_data)
1847+ {
1848+ std::unique_ptr<ActivateData> data(static_cast<ActivateData*>(user_data));
1849+ UnityProtocolActivationReplyRaw result;
1850+ glib::Error error;
1851+ unity_protocol_scope_proxy_activate_finish(UNITY_PROTOCOL_SCOPE_PROXY(source_object), res, &result, &error);
1852+
1853+ if (data->callback)
1854+ {
1855+ std::string uri;
1856+ ScopeHandledType handled = ScopeHandledType::NOT_HANDLED;
1857+
1858+ uri = result.uri;
1859+ handled = static_cast<ScopeHandledType>(result.handled);
1860+
1861+ glib::HintsMap hints;
1862+ glib::hintsmap_from_hashtable(result.hints, hints);
1863+
1864+ data->callback(uri, handled, hints, error);
1865+ }
1866+ }
1867+ /////////////////////////////////////
1868+
1869+ /////////////////////////////////////
1870+ // Async Calls
1871+ struct ScopeAyncReplyData
1872+ {
1873+ typedef std::function<void(GObject *source_object, GAsyncResult *res)> ScopeAsyncReplyCallback;
1874+ ScopeAyncReplyData(ScopeAsyncReplyCallback const& callback): callback(callback) {}
1875+
1876+ ScopeAsyncReplyCallback callback;
1877+ };
1878+ static void OnScopeAsyncCallback(GObject *source_object, GAsyncResult *res, gpointer user_data)
1879+ {
1880+ std::unique_ptr<ScopeAyncReplyData> data(static_cast<ScopeAyncReplyData*>(user_data));
1881+ if (data->callback)
1882+ data->callback(source_object, res);
1883+ }
1884+ /////////////////////////////////////
1885+};
1886+
1887+
1888+ScopeProxy::Impl::Impl(ScopeProxy*const owner, ScopeData::Ptr const& scope_data)
1889+: owner_(owner)
1890+, scope_data_(scope_data)
1891+, search_in_global(false)
1892+, view_type(ScopeViewType::HIDDEN)
1893+, connected(false)
1894+, cancel_scope_(g_cancellable_new())
1895+, proxy_created_(false)
1896+, scope_proxy_connected_(false)
1897+, searching_(false)
1898+, results_(new Results())
1899+, filters_(new Filters())
1900+, categories_(new Categories())
1901+{
1902+ // remote properties
1903+ property_connections.push_back(utils::ConnectProperties(owner_->connected, connected));
1904+ property_connections.push_back(utils::ConnectProperties(owner_->channel, channel));
1905+ property_connections.push_back(utils::ConnectProperties(owner_->search_in_global, search_in_global));
1906+ property_connections.push_back(utils::ConnectProperties(owner_->view_type, view_type));
1907+ property_connections.push_back(utils::ConnectProperties(owner_->category_order, category_order));
1908+
1909+ // shared properties
1910+ property_connections.push_back(utils::ConnectProperties(owner_->is_master, scope_data_->is_master));
1911+ property_connections.push_back(utils::ConnectProperties(owner_->search_hint, scope_data_->search_hint));
1912+ // local properties
1913+ property_connections.push_back(utils::ConnectProperties(owner_->dbus_name, scope_data_->dbus_name));
1914+ property_connections.push_back(utils::ConnectProperties(owner_->dbus_path, scope_data_->dbus_path));
1915+ property_connections.push_back(utils::ConnectProperties(owner_->name, scope_data_->name));
1916+ property_connections.push_back(utils::ConnectProperties(owner_->description, scope_data_->description));
1917+ property_connections.push_back(utils::ConnectProperties(owner_->shortcut, scope_data_->shortcut));
1918+ property_connections.push_back(utils::ConnectProperties(owner_->icon_hint, scope_data_->icon_hint));
1919+ property_connections.push_back(utils::ConnectProperties(owner_->category_icon_hint, scope_data_->category_icon_hint));
1920+ property_connections.push_back(utils::ConnectProperties(owner_->keywords, scope_data_->keywords));
1921+ property_connections.push_back(utils::ConnectProperties(owner_->type, scope_data_->type));
1922+ property_connections.push_back(utils::ConnectProperties(owner_->query_pattern, scope_data_->query_pattern));
1923+ property_connections.push_back(utils::ConnectProperties(owner_->visible, scope_data_->visible));
1924+
1925+ owner_->filters.SetGetterFunction(sigc::mem_fun(this, &Impl::filters));
1926+ owner_->categories.SetGetterFunction(sigc::mem_fun(this, &Impl::categories));
1927+ owner_->results.SetGetterFunction(sigc::mem_fun(this, &Impl::results));
1928+}
1929+
1930+ScopeProxy::Impl::~Impl()
1931+{
1932+ filters_change_connection.disconnect();
1933+ for_each(property_connections.begin(), property_connections.end(), [](ConnectionPtr const& con) { con->disconnect(); });
1934+ property_connections.clear();
1935+
1936+ g_cancellable_cancel(cancel_scope_);
1937+
1938+ if (scope_proxy_ && connected)
1939+ unity_protocol_scope_proxy_close_channel(scope_proxy_, channel().c_str(), nullptr, Impl::OnCloseChannel, nullptr);
1940+}
1941+
1942+ScopeData::Ptr ScopeProxy::Impl::CreateData(std::string const& dbus_name, std::string const& dbus_path)
1943+{
1944+ ScopeData::Ptr data(new ScopeData);
1945+ data->dbus_path = dbus_path;
1946+ data->dbus_name = dbus_name;
1947+
1948+ return data;
1949+}
1950+
1951+void ScopeProxy::Impl::DestroyProxy()
1952+{
1953+ scope_proxy_.Release();
1954+ if (cancel_scope_)
1955+ g_cancellable_cancel(cancel_scope_);
1956+
1957+ cancel_scope_ = g_cancellable_new();
1958+ connected = false;
1959+ proxy_created_ = false;
1960+}
1961+
1962+void ScopeProxy::Impl::CreateProxy()
1963+{
1964+ if (proxy_created_)
1965+ return;
1966+
1967+ proxy_created_ = true;
1968+ unity_protocol_scope_proxy_new_from_dbus(scope_data_->dbus_name().c_str(),
1969+ scope_data_->dbus_path().c_str(),
1970+ cancel_scope_,
1971+ Impl::OnScopeAsyncCallback,
1972+ new ScopeAyncReplyData(sigc::mem_fun(this, &Impl::OnNewScope)));
1973+}
1974+
1975+void ScopeProxy::Impl::OnNewScope(GObject *source_object, GAsyncResult *res)
1976+{
1977+ glib::Object<UnityProtocolScopeProxy> scope_proxy;
1978+ glib::Error error;
1979+ scope_proxy = unity_protocol_scope_proxy_new_from_dbus_finish(res, &error);
1980+
1981+ search_in_global_signal_.Disconnect();
1982+ is_master_signal_.Disconnect();
1983+ search_hint_signal_.Disconnect();
1984+ view_type_signal_.Disconnect();
1985+ filters_signal_.Disconnect();
1986+ categories_signal_.Disconnect();
1987+ metadata_signal_.Disconnect();
1988+ optional_metadata_signal_.Disconnect();
1989+
1990+
1991+ if (error || !scope_proxy)
1992+ {
1993+ scope_proxy_.Release();
1994+ LOG_ERROR(logger) << "Failed to create scope proxy for " << scope_data_->id();
1995+ return;
1996+ }
1997+
1998+ LOG_DEBUG(logger) << "Created scope proxy for " << scope_data_->id();
1999+
2000+ scope_proxy_ = scope_proxy;
2001+
2002+ // shared properties
2003+ scope_data_->is_master = unity_protocol_scope_proxy_get_is_master(scope_proxy_);
2004+ scope_data_->search_hint = glib::gchar_to_string(unity_protocol_scope_proxy_get_search_hint(scope_proxy_));
2005+ // remote properties
2006+ search_in_global = unity_protocol_scope_proxy_get_search_in_global(scope_proxy_);
2007+ view_type = static_cast<ScopeViewType>(unity_protocol_scope_proxy_get_view_type(scope_proxy_));
2008+
2009+ connected_signal_.Connect(scope_proxy_, "notify::connected", sigc::mem_fun(this, &Impl::OnScopeConnectedChanged));
2010+ search_in_global_signal_.Connect(scope_proxy_, "notify::search-in-global", sigc::mem_fun(this, &Impl::OnScopeSearchInGlobalChanged));
2011+ is_master_signal_.Connect(scope_proxy_, "notify::is-master", sigc::mem_fun(this, &Impl::OnScopeIsMasterChanged));
2012+ search_hint_signal_.Connect(scope_proxy_, "notify::search-hint", sigc::mem_fun(this, &Impl::OnScopeSearchHintChanged));
2013+ view_type_signal_.Connect(scope_proxy_, "notify::view-type", sigc::mem_fun(this, &Impl::OnScopeViewTypeChanged));
2014+ filters_signal_.Connect(scope_proxy_, "notify::filters-model", sigc::mem_fun(this, &Impl::OnScopeFiltersChanged));
2015+ categories_signal_.Connect(scope_proxy_, "notify::categories-model", sigc::mem_fun(this, &Impl::OnScopeCategoriesChanged));
2016+ metadata_signal_.Connect(scope_proxy_, "notify::metadata", sigc::mem_fun(this, &Impl::OnScopeMetadataChanged));
2017+ optional_metadata_signal_.Connect(scope_proxy_, "notify::optional-metadata", sigc::mem_fun(this, &Impl::OnScopeOptionalMetadataChanged));
2018+ category_order_signal_.Connect(scope_proxy_, "category-order-changed", sigc::mem_fun(this, &Impl::OnScopeCategoryOrderChanged));
2019+
2020+ scope_proxy_connected_ = unity_protocol_scope_proxy_get_connected(scope_proxy_);
2021+
2022+ if (scope_proxy_connected_)
2023+ OpenChannel();
2024+ else
2025+ LOG_WARN(logger) << "Proxy scope not connected for " << scope_data_->id();
2026+}
2027+
2028+void ScopeProxy::Impl::OpenChannel()
2029+{
2030+ if (channel != "")
2031+ return;
2032+
2033+ unity_protocol_scope_proxy_open_channel(scope_proxy_,
2034+ UNITY_PROTOCOL_CHANNEL_TYPE_DEFAULT,
2035+ UNITY_PROTOCOL_CHANNEL_FLAGS_NONE,
2036+ cancel_scope_,
2037+ OnScopeAsyncCallback,
2038+ new ScopeAyncReplyData(sigc::mem_fun(this, &Impl::OnChannelOpened)));
2039+}
2040+
2041+void ScopeProxy::Impl::OnChannelOpened(GObject *source_object, GAsyncResult *res)
2042+{
2043+ if (!UNITY_PROTOCOL_IS_SCOPE_PROXY(source_object))
2044+ return;
2045+
2046+ glib::Object<UnityProtocolScopeProxy> scope_proxy;
2047+ glib::Error error;
2048+ DeeSerializableModel* serialisable_model = nullptr;
2049+ glib::String tmp_channel(unity_protocol_scope_proxy_open_channel_finish(UNITY_PROTOCOL_SCOPE_PROXY(source_object), res, &serialisable_model, &error));
2050+
2051+ glib::Object<DeeModel> results_dee_model(DEE_MODEL(serialisable_model));
2052+ results_->SetModel(results_dee_model);
2053+
2054+ glib::Object<DeeModel> filters_dee_model(DEE_MODEL(unity_protocol_scope_proxy_get_filters_model(scope_proxy_)), glib::AddRef());
2055+ filters_->SetModel(filters_dee_model);
2056+ filters_change_connection.disconnect();
2057+ filters_change_connection = filters_->filter_changed.connect([this](Filter::Ptr const& filter)
2058+ {
2059+ glib::HintsMap hints;
2060+ hints["changed-filter-row"] = filter->VariantValue();
2061+ Search(last_search_, hints, nullptr, cancel_scope_);
2062+ });
2063+
2064+ glib::Object<DeeModel> categories_dee_model(DEE_MODEL(unity_protocol_scope_proxy_get_categories_model(scope_proxy_)), glib::AddRef());
2065+ categories_->SetModel(categories_dee_model);
2066+
2067+ if (tmp_channel.Str().empty() || error)
2068+ {
2069+ channel = "";
2070+ connected = false;
2071+
2072+ LOG_ERROR(logger) << "Failed to open channel for " << scope_data_->id();
2073+ return;
2074+ }
2075+
2076+ channel = tmp_channel.Str();
2077+ LOG_DEBUG(logger) << "Opened channel:" << channel() << " for " << scope_data_->id();
2078+ connected = true;
2079+
2080+ if (!searching_)
2081+ {
2082+ // If a search hasn't initiated this channel opening, perform the search to get the results.
2083+ Search(last_search_, glib::HintsMap(), nullptr, cancel_scope_);
2084+ }
2085+}
2086+
2087+void ScopeProxy::Impl::CloseChannel()
2088+{
2089+ if (channel != "")
2090+ {
2091+ unity_protocol_scope_proxy_close_channel(scope_proxy_,
2092+ channel.Get().c_str(),
2093+ nullptr,
2094+ OnCloseChannel,
2095+ nullptr);
2096+ channel = "";
2097+ }
2098+}
2099+
2100+void ScopeProxy::Impl::OnCloseChannel(GObject *source_object, GAsyncResult *res, gpointer user_data)
2101+{
2102+ glib::Error err;
2103+ unity_protocol_scope_proxy_close_channel_finish(UNITY_PROTOCOL_SCOPE_PROXY(source_object), res, &err);
2104+}
2105+
2106+void ScopeProxy::Impl::WaitForProxyConnection(GCancellable* cancellable,
2107+ int timeout_msec,
2108+ std::function<void(glib::Error const&)> const& callback)
2109+{
2110+ if (!connected)
2111+ {
2112+ auto con = std::make_shared<sigc::connection>();
2113+ auto canc = glib::Object<GCancellable>(cancellable, glib::AddRef());
2114+
2115+ // add a timeout
2116+ auto timeout = std::make_shared<glib::Timeout>(timeout_msec < 0 ? 30000 : timeout_msec, [con, canc, callback] ()
2117+ {
2118+ if (!g_cancellable_is_cancelled(canc))
2119+ {
2120+ glib::Error err;
2121+ GError** real_err = &err;
2122+ *real_err = g_error_new_literal(G_DBUS_ERROR, G_DBUS_ERROR_TIMED_OUT,
2123+ "Timed out waiting for scope proxy connection");
2124+ callback(err);
2125+ }
2126+ con->disconnect();
2127+ return false;
2128+ });
2129+ // wait for the signal
2130+ *con = connected.changed.connect([con, canc, timeout, callback] (bool connected)
2131+ {
2132+ if (!connected)
2133+ return;
2134+
2135+ if (!g_cancellable_is_cancelled(canc)) callback(glib::Error());
2136+ timeout->Remove();
2137+ con->disconnect();
2138+ });
2139+ }
2140+ else
2141+ {
2142+ callback(glib::Error());
2143+ }
2144+}
2145+
2146+void ScopeProxy::Impl::Search(std::string const& search_string, glib::HintsMap const& hints, SearchCallback const& callback, GCancellable* cancellable)
2147+{
2148+ // Activate a guard against performing a "on channel open search" if we're not connected.
2149+ utils::AutoResettingVariable<bool> searching(&searching_, true);
2150+
2151+ GCancellable* target_canc = cancellable != NULL ? cancellable : cancel_scope_;
2152+
2153+ if (!scope_proxy_)
2154+ {
2155+ if (!proxy_created_)
2156+ CreateProxy();
2157+
2158+ glib::Object<GCancellable> canc(target_canc, glib::AddRef());
2159+ WaitForProxyConnection(canc, PROXY_CONNECT_TIMEOUT, [this, search_string, hints, callback, canc] (glib::Error const& err)
2160+ {
2161+ if (err)
2162+ {
2163+ callback(glib::HintsMap(), err);
2164+ LOG_WARNING(logger) << "Could not search '" << search_string
2165+ << "' on " << scope_data_->id() << " => " << err;
2166+ }
2167+ else
2168+ {
2169+ Search(search_string, hints, callback, canc);
2170+ }
2171+ });
2172+ return;
2173+ }
2174+
2175+ SearchData* data = new SearchData();
2176+ data->callback = callback;
2177+
2178+ GHashTable* hints_table = glib::hashtable_from_hintsmap(hints);
2179+
2180+ last_search_ = search_string.c_str();
2181+ unity_protocol_scope_proxy_search(scope_proxy_,
2182+ channel().c_str(),
2183+ search_string.c_str(),
2184+ hints_table,
2185+ target_canc,
2186+ Impl::OnScopeSearchCallback,
2187+ data);
2188+
2189+ g_hash_table_unref(hints_table);
2190+}
2191+
2192+void ScopeProxy::Impl::Activate(std::string const& uri, uint activate_type, glib::HintsMap const& hints, ScopeProxy::ActivateCallback const& callback, GCancellable* cancellable)
2193+{
2194+ GCancellable* target_canc = cancellable != NULL ? cancellable : cancel_scope_;
2195+
2196+ if (!scope_proxy_)
2197+ {
2198+ if (!proxy_created_)
2199+ CreateProxy();
2200+
2201+ glib::Object<GCancellable> canc(target_canc, glib::AddRef());
2202+ WaitForProxyConnection(canc, PROXY_CONNECT_TIMEOUT, [this, uri, activate_type, hints, callback, canc] (glib::Error const& err)
2203+ {
2204+ if (err)
2205+ {
2206+ callback(uri, ScopeHandledType::NOT_HANDLED, glib::HintsMap(), err);
2207+ LOG_WARNING(logger) << "Could not activate '" << uri
2208+ << "' on " << scope_data_->id() << " => " << err;
2209+ }
2210+ else
2211+ {
2212+ Activate(uri, activate_type, hints, callback, canc);
2213+ }
2214+ });
2215+ return;
2216+ }
2217+
2218+ ActivateData* data = new ActivateData();
2219+ data->callback = callback;
2220+
2221+ GHashTable* hints_table = glib::hashtable_from_hintsmap(hints);
2222+
2223+ unity_protocol_scope_proxy_activate(scope_proxy_,
2224+ channel().c_str(),
2225+ uri.c_str(),
2226+ (UnityProtocolActionType)activate_type,
2227+ hints_table,
2228+ target_canc,
2229+ Impl::OnScopeActivateCallback,
2230+ data);
2231+ g_hash_table_unref(hints_table);
2232+}
2233+
2234+void ScopeProxy::Impl::UpdatePreviewProperty(std::string const& uri, glib::HintsMap const& hints, ScopeProxy::UpdatePreviewPropertyCallback const& callback, GCancellable* cancellable)
2235+{
2236+ GCancellable* target_canc = cancellable != NULL ? cancellable : cancel_scope_;
2237+
2238+ if (!scope_proxy_)
2239+ {
2240+ if (!proxy_created_)
2241+ CreateProxy();
2242+
2243+ glib::Object<GCancellable> canc(target_canc, glib::AddRef());
2244+ WaitForProxyConnection(canc, PROXY_CONNECT_TIMEOUT, [this, uri, hints, callback, canc] (glib::Error const& err)
2245+ {
2246+ if (err)
2247+ {
2248+ callback(glib::HintsMap(), err);
2249+ LOG_WARNING(logger) << "Could not update preview property '" << uri
2250+ << "' on " << scope_data_->id() << " => " << err;
2251+ }
2252+ else
2253+ {
2254+ UpdatePreviewProperty(uri, hints, callback, canc);
2255+ }
2256+ });
2257+ return;
2258+ }
2259+
2260+ UpdatePreviewPropertyData* data = new UpdatePreviewPropertyData();
2261+ data->callback = callback;
2262+
2263+ GHashTable* hints_table = glib::hashtable_from_hintsmap(hints);
2264+
2265+ unity_protocol_scope_proxy_update_preview_property(scope_proxy_,
2266+ channel().c_str(),
2267+ uri.c_str(),
2268+ hints_table,
2269+ target_canc,
2270+ Impl::OnScopeUpdatePreviewPropertyCallback,
2271+ data);
2272+
2273+ g_hash_table_unref(hints_table);
2274+}
2275+
2276+void ScopeProxy::Impl::OnScopeConnectedChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param)
2277+{
2278+ bool tmp_scope_proxy_connected = unity_protocol_scope_proxy_get_connected(scope_proxy_);
2279+ if (tmp_scope_proxy_connected != scope_proxy_connected_)
2280+ {
2281+ scope_proxy_connected_ = tmp_scope_proxy_connected;
2282+
2283+ LOG_WARN(logger) << "Connection state changed for " << scope_data_->id() << " => " << (scope_proxy_connected_ ? "connected" : "disconnected");
2284+
2285+ CloseChannel();
2286+ if (tmp_scope_proxy_connected)
2287+ {
2288+ OpenChannel();
2289+ }
2290+ }
2291+}
2292+
2293+void ScopeProxy::Impl::OnScopeIsMasterChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param)
2294+{
2295+ scope_data_->is_master = unity_protocol_scope_proxy_get_is_master(proxy);
2296+}
2297+
2298+void ScopeProxy::Impl::OnScopeSearchInGlobalChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param)
2299+{
2300+ search_in_global = unity_protocol_scope_proxy_get_search_in_global(proxy);
2301+}
2302+
2303+void ScopeProxy::Impl::OnScopeSearchHintChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param)
2304+{
2305+ scope_data_->search_hint = unity_protocol_scope_proxy_get_search_hint(proxy);
2306+}
2307+
2308+void ScopeProxy::Impl::OnScopeViewTypeChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param)
2309+{
2310+ view_type = static_cast<ScopeViewType>(unity_protocol_scope_proxy_get_view_type(proxy));
2311+}
2312+
2313+void ScopeProxy::Impl::OnScopeFiltersChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param)
2314+{
2315+ LOG_DEBUG(logger) << scope_data_->id() << " - Filter changed by server";
2316+ bool blocked = filters_change_connection.block(true);
2317+
2318+ glib::Object<DeeModel> filters_dee_model(DEE_MODEL(unity_protocol_scope_proxy_get_filters_model(scope_proxy_)), glib::AddRef());
2319+ categories_->SetModel(filters_dee_model);
2320+
2321+ filters_change_connection.block(blocked);
2322+
2323+ owner_->filters.EmitChanged(filters());
2324+}
2325+
2326+void ScopeProxy::Impl::OnScopeCategoriesChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param)
2327+{
2328+ glib::Object<DeeModel> categories_dee_model(DEE_MODEL(unity_protocol_scope_proxy_get_categories_model(scope_proxy_)), glib::AddRef());
2329+ categories_->SetModel(categories_dee_model);
2330+
2331+ owner_->categories.EmitChanged(categories());
2332+}
2333+
2334+void ScopeProxy::Impl::OnScopeMetadataChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param)
2335+{
2336+}
2337+
2338+void ScopeProxy::Impl::OnScopeOptionalMetadataChanged(UnityProtocolScopeProxy* proxy, GParamSpec* param)
2339+{
2340+}
2341+
2342+void ScopeProxy::Impl::OnScopeCategoryOrderChanged(UnityProtocolScopeProxy* sender, const gchar* channel_id, guint32* new_order, int new_order_length1)
2343+{
2344+ if (channel() != glib::gchar_to_string(channel_id))
2345+ return;
2346+
2347+ std::vector<int> order;
2348+ for (int i = 0; i < new_order_length1; i++)
2349+ {
2350+ order.push_back(new_order[i]);
2351+ }
2352+
2353+ category_order = order;
2354+}
2355+
2356+static void category_filter_map_func (DeeModel* orig_model,
2357+ DeeFilterModel* filter_model,
2358+ gpointer user_data)
2359+{
2360+ DeeModelIter* iter;
2361+ DeeModelIter* end;
2362+ unsigned index = GPOINTER_TO_UINT(user_data);
2363+
2364+ iter = dee_model_get_first_iter(orig_model);
2365+ end = dee_model_get_last_iter(orig_model);
2366+ while (iter != end)
2367+ {
2368+ unsigned category_index = dee_model_get_uint32(orig_model, iter,
2369+ CATEGORY_COLUMN);
2370+ if (index == category_index)
2371+ {
2372+ dee_filter_model_append_iter(filter_model, iter);
2373+ }
2374+ iter = dee_model_next(orig_model, iter);
2375+ }
2376+}
2377+
2378+static gboolean category_filter_notify_func (DeeModel* orig_model,
2379+ DeeModelIter* orig_iter,
2380+ DeeFilterModel* filter_model,
2381+ gpointer user_data)
2382+{
2383+ unsigned index = GPOINTER_TO_UINT(user_data);
2384+ unsigned category_index = dee_model_get_uint32(orig_model, orig_iter,
2385+ CATEGORY_COLUMN);
2386+
2387+ if (index != category_index)
2388+ return FALSE;
2389+
2390+ dee_filter_model_insert_iter_with_original_order(filter_model, orig_iter);
2391+ return TRUE;
2392+}
2393+
2394+DeeFilter* ScopeProxy::Impl::GetFilterForCategory(unsigned category, DeeFilter* filter) const
2395+{
2396+ filter->map_func = category_filter_map_func;
2397+ filter->map_notify = category_filter_notify_func;
2398+ filter->destroy = nullptr;
2399+ filter->userdata = GUINT_TO_POINTER(category);
2400+
2401+ return filter;
2402+}
2403+
2404+ScopeProxy::ScopeProxy(ScopeData::Ptr const& scope_data)
2405+: pimpl(new Impl(this, scope_data))
2406+{
2407+}
2408+
2409+
2410+ScopeProxy::ScopeProxy(std::string const& dbus_name, std::string const& dbus_path)
2411+: pimpl(new Impl(this, Impl::CreateData(dbus_name, dbus_path)))
2412+{
2413+}
2414+
2415+ScopeProxy::~ScopeProxy()
2416+{
2417+}
2418+
2419+void ScopeProxy::CreateProxy()
2420+{
2421+ pimpl->CreateProxy();
2422+}
2423+
2424+void ScopeProxy::Search(std::string const& search_string, SearchCallback const& callback, GCancellable* cancellable)
2425+{
2426+ pimpl->Search(search_string, glib::HintsMap(), callback, cancellable);
2427+}
2428+
2429+void ScopeProxy::Activate(std::string const& uri, uint activate_type, glib::HintsMap const& hints, ScopeProxy::ActivateCallback const& callback, GCancellable* cancellable)
2430+{
2431+ pimpl->Activate(uri, activate_type, hints, callback, cancellable);
2432+}
2433+
2434+void ScopeProxy::UpdatePreviewProperty(std::string const& uri, glib::HintsMap const& hints, ScopeProxy::UpdatePreviewPropertyCallback const& callback, GCancellable* cancellable)
2435+{
2436+ pimpl->UpdatePreviewProperty(uri, hints, callback, cancellable);
2437+}
2438+
2439+Results::Ptr ScopeProxy::GetResultsForCategory(unsigned category) const
2440+{
2441+ Results::Ptr all_results = results;
2442+
2443+ if (!all_results || !all_results->model())
2444+ return Results::Ptr();
2445+
2446+ DeeFilter filter;
2447+ pimpl->GetFilterForCategory(category, &filter);
2448+ glib::Object<DeeModel> filter_model(dee_filter_model_new(all_results->model(), &filter));
2449+
2450+ auto func = [all_results](glib::Object<DeeModel> const& model) { return all_results->GetTag(); };
2451+
2452+ Results::Ptr results_category_model(new Results(ModelType::UNATTACHED));
2453+ results_category_model->SetModel(filter_model, func);
2454+ return results_category_model;
2455+}
2456+
2457+
2458+} // namespace dash
2459+} // namespace unity
2460
2461=== added file 'UnityCore/ScopeProxy.h'
2462--- UnityCore/ScopeProxy.h 1970-01-01 00:00:00 +0000
2463+++ UnityCore/ScopeProxy.h 2013-02-21 10:37:29 +0000
2464@@ -0,0 +1,57 @@
2465+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
2466+/*
2467+ * Copyright (C) 2013 Canonical Ltd
2468+ *
2469+ * This program is free software: you can redistribute it and/or modify
2470+ * it under the terms of the GNU General Public License version 3 as
2471+ * published by the Free Software Foundation.
2472+ *
2473+ * This program is distributed in the hope that it will be useful,
2474+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2475+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2476+ * GNU General Public License for more details.
2477+ *
2478+ * You should have received a copy of the GNU General Public License
2479+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2480+ *
2481+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
2482+ */
2483+
2484+#ifndef UNITY_SCOPE_PROXY_H
2485+#define UNITY_SCOPE_PROXY_H
2486+
2487+#include "ScopeProxyInterface.h"
2488+
2489+namespace unity
2490+{
2491+namespace dash
2492+{
2493+
2494+class ScopeProxy : public ScopeProxyInterface
2495+{
2496+public:
2497+ ScopeProxy(ScopeData::Ptr const& scope_data);
2498+ ~ScopeProxy();
2499+
2500+ virtual void CreateProxy();
2501+
2502+ virtual void Search(std::string const& search_hint, SearchCallback const& callback, GCancellable* cancellable);
2503+
2504+ virtual void Activate(std::string const& uri, uint activate_type, glib::HintsMap const& hints, ActivateCallback const& callback, GCancellable* cancellable);
2505+
2506+ virtual void UpdatePreviewProperty(std::string const& uri, glib::HintsMap const& hints, UpdatePreviewPropertyCallback const& callback, GCancellable* cancellable);
2507+
2508+ Results::Ptr GetResultsForCategory(unsigned category) const;
2509+
2510+protected:
2511+ ScopeProxy(std::string const& dbus_name, std::string const& dbus_path);
2512+
2513+private:
2514+ class Impl;
2515+ std::unique_ptr<Impl> pimpl;
2516+};
2517+
2518+} // namespace dash
2519+} // namespace unity
2520+
2521+#endif // UNITY_SCOPE_PROXY_H
2522
2523=== added file 'UnityCore/ScopeProxyInterface.h'
2524--- UnityCore/ScopeProxyInterface.h 1970-01-01 00:00:00 +0000
2525+++ UnityCore/ScopeProxyInterface.h 2013-02-21 10:37:29 +0000
2526@@ -0,0 +1,96 @@
2527+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
2528+/*
2529+ * Copyright (C) 2013 Canonical Ltd
2530+ *
2531+ * This program is free software: you can redistribute it and/or modify
2532+ * it under the terms of the GNU General Public License version 3 as
2533+ * published by the Free Software Foundation.
2534+ *
2535+ * This program is distributed in the hope that it will be useful,
2536+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2537+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2538+ * GNU General Public License for more details.
2539+ *
2540+ * You should have received a copy of the GNU General Public License
2541+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2542+ *
2543+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
2544+ */
2545+
2546+#ifndef UNITY_SCOPE_PROXY_INTERFACE_H
2547+#define UNITY_SCOPE_PROXY_INTERFACE_H
2548+
2549+#include "GLibWrapper.h"
2550+#include <NuxCore/Property.h>
2551+#include <dee.h>
2552+
2553+#include "Results.h"
2554+#include "Filters.h"
2555+#include "Categories.h"
2556+#include "GLibWrapper.h"
2557+#include "ScopeData.h"
2558+
2559+namespace unity
2560+{
2561+namespace dash
2562+{
2563+
2564+enum ScopeHandledType
2565+{
2566+ NOT_HANDLED=0,
2567+ SHOW_DASH,
2568+ HIDE_DASH,
2569+ GOTO_DASH_URI,
2570+ SHOW_PREVIEW
2571+};
2572+
2573+class ScopeProxyInterface : public sigc::trackable, boost::noncopyable
2574+{
2575+public:
2576+ typedef std::shared_ptr<ScopeProxyInterface> Ptr;
2577+
2578+ virtual ~ScopeProxyInterface() {}
2579+
2580+ nux::ROProperty<std::string> dbus_name;
2581+ nux::ROProperty<std::string> dbus_path;
2582+ nux::ROProperty<bool> connected;
2583+ nux::ROProperty<std::string> channel;
2584+
2585+ nux::ROProperty<bool> visible;
2586+ nux::ROProperty<bool> is_master;
2587+ nux::ROProperty<bool> search_in_global;
2588+ nux::ROProperty<std::string> search_hint;
2589+ nux::RWProperty<ScopeViewType> view_type;
2590+
2591+ nux::ROProperty<Results::Ptr> results;
2592+ nux::ROProperty<Filters::Ptr> filters;
2593+ nux::ROProperty<Categories::Ptr> categories;
2594+ nux::ROProperty<std::vector<int>> category_order;
2595+
2596+ nux::ROProperty<std::string> name;
2597+ nux::ROProperty<std::string> description;
2598+ nux::ROProperty<std::string> icon_hint;
2599+ nux::ROProperty<std::string> category_icon_hint;
2600+ nux::ROProperty<std::vector<std::string>> keywords;
2601+ nux::ROProperty<std::string> type;
2602+ nux::ROProperty<std::string> query_pattern;
2603+ nux::ROProperty<std::string> shortcut;
2604+
2605+ virtual void CreateProxy() {}
2606+
2607+ typedef std::function<void(glib::HintsMap const&, glib::Error const&)> SearchCallback;
2608+ virtual void Search(std::string const& search_hint, SearchCallback const& callback, GCancellable* cancellable) = 0;
2609+
2610+ typedef std::function<void(std::string const&, ScopeHandledType, glib::HintsMap const&, glib::Error const&)> ActivateCallback;
2611+ virtual void Activate(std::string const& uri, uint activate_type, glib::HintsMap const& hints, ActivateCallback const& callback, GCancellable* cancellable) = 0;
2612+
2613+ typedef std::function<void(glib::HintsMap const&, glib::Error const&)> UpdatePreviewPropertyCallback;
2614+ virtual void UpdatePreviewProperty(std::string const& uri, glib::HintsMap const& hints, UpdatePreviewPropertyCallback const& callback, GCancellable* cancellable) = 0;
2615+
2616+ virtual Results::Ptr GetResultsForCategory(unsigned category) const = 0;
2617+};
2618+
2619+} // namespace dash
2620+} // namespace unity
2621+
2622+#endif // UNITY_SCOPE_PROXY_INTERFACE_H
2623\ No newline at end of file
2624
2625=== added file 'UnityCore/Scopes.cpp'
2626--- UnityCore/Scopes.cpp 1970-01-01 00:00:00 +0000
2627+++ UnityCore/Scopes.cpp 2013-02-21 10:37:29 +0000
2628@@ -0,0 +1,271 @@
2629+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
2630+/*
2631+ * Copyright (C) 2011 Canonical Ltd
2632+ *
2633+ * This program is free software: you can redistribute it and/or modify
2634+ * it under the terms of the GNU General Public License version 3 as
2635+ * published by the Free Software Foundation.
2636+ *
2637+ * This program is distributed in the hope that it will be useful,
2638+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2639+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2640+ * GNU General Public License for more details.
2641+ *
2642+ * You should have received a copy of the GNU General Public License
2643+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2644+ *
2645+ * Authored by: Nick Dedekind <nick.dedeknd@canoncial.com>
2646+ */
2647+
2648+#include "Scopes.h"
2649+#include <stdexcept>
2650+
2651+namespace unity
2652+{
2653+namespace dash
2654+{
2655+DECLARE_LOGGER(logger, "unity.dash.scopes");
2656+
2657+class Scopes::Impl
2658+{
2659+public:
2660+ Impl(Scopes* owner, ScopesReader::Ptr scopes_reader);
2661+ ~Impl();
2662+
2663+ void LoadScopes();
2664+ void InsertScope(ScopeData::Ptr const& data, unsigned index);
2665+ void RemoveScope(std::string const& scope);
2666+
2667+ ScopeList const& GetScopes() const;
2668+ Scope::Ptr GetScope(std::string const& scope_id, int* index = nullptr) const;
2669+ Scope::Ptr GetScopeAtIndex(std::size_t index) const;
2670+ Scope::Ptr GetScopeForShortcut(std::string const& scope_shortcut) const;
2671+
2672+ Scopes* owner_;
2673+ ScopesReader::Ptr scopes_reader_;
2674+ ScopeList scopes_;
2675+ sigc::connection scope_changed_signal;
2676+
2677+ std::size_t get_count() const { return scopes_.size(); }
2678+
2679+ void UpdateScopes(ScopeDataList const& scopes_list);
2680+};
2681+
2682+Scopes::Impl::Impl(Scopes* owner, ScopesReader::Ptr scopes_reader)
2683+: owner_(owner)
2684+, scopes_reader_(scopes_reader)
2685+{
2686+}
2687+
2688+Scopes::Impl::~Impl()
2689+{
2690+ scope_changed_signal.disconnect();
2691+}
2692+
2693+void Scopes::Impl::UpdateScopes(ScopeDataList const& scopes_list)
2694+{
2695+ // insert new.
2696+ int index = 0;
2697+ for (ScopeData::Ptr const& scope_data: scopes_list)
2698+ {
2699+ InsertScope(scope_data, index++);
2700+ }
2701+
2702+ // remove old.
2703+ std::vector<std::string> remove_scopes;
2704+ for (Scope::Ptr const& scope: scopes_)
2705+ {
2706+ auto scope_data_position = std::find_if(scopes_list.begin(),
2707+ scopes_list.end(),
2708+ [scope](ScopeData::Ptr const& data) { return data->id() == scope->id(); });
2709+ if (scope_data_position == scopes_list.end())
2710+ {
2711+ remove_scopes.push_back(scope->id());
2712+ }
2713+ }
2714+ for (std::string const& scope: remove_scopes)
2715+ {
2716+ RemoveScope(scope);
2717+ }
2718+}
2719+
2720+void Scopes::Impl::LoadScopes()
2721+{
2722+ if (!scopes_reader_)
2723+ return;
2724+
2725+ scope_changed_signal.disconnect();
2726+ scope_changed_signal = scopes_reader_->scopes_changed.connect(sigc::mem_fun(this, &Impl::UpdateScopes));
2727+ UpdateScopes(scopes_reader_->GetScopesData());
2728+}
2729+
2730+void Scopes::Impl::InsertScope(ScopeData::Ptr const& scope_data, unsigned index)
2731+{
2732+ if (!scope_data)
2733+ return;
2734+
2735+ index = std::min(index, static_cast<unsigned>(scopes_.size()));
2736+
2737+ auto start = scopes_.begin();
2738+ auto scope_position = std::find_if(scopes_.begin(),
2739+ scopes_.end(),
2740+ [scope_data](Scope::Ptr const& value) { return value->id() == scope_data->id(); });
2741+ if (scope_position == scopes_.end())
2742+ {
2743+ Scope::Ptr scope(owner_->CreateScope(scope_data));
2744+ if (scope)
2745+ {
2746+ scopes_.insert(start+index, scope);
2747+
2748+ owner_->scope_added.emit(scope, index);
2749+ }
2750+ }
2751+ else
2752+ {
2753+ Scope::Ptr scope = *scope_position;
2754+ if (scope_position > (start + index))
2755+ {
2756+ scopes_.erase(scope_position);
2757+ scopes_.insert(start + index, scope);
2758+
2759+ owner_->scopes_reordered.emit(GetScopes());
2760+ }
2761+ else if (index > 0 && scope_position < (start + index - 1))
2762+ {
2763+ scopes_.erase(scope_position);
2764+
2765+ scopes_.insert(start + index - 1, scope);
2766+
2767+ owner_->scopes_reordered.emit(GetScopes());
2768+ }
2769+ }
2770+}
2771+
2772+void Scopes::Impl::RemoveScope(std::string const& scope_id)
2773+{
2774+ auto scope_position = std::find_if(scopes_.begin(),
2775+ scopes_.end(),
2776+ [scope_id](Scope::Ptr const& value) { return value->id() == scope_id; });
2777+
2778+ if (scope_position != scopes_.end())
2779+ {
2780+ Scope::Ptr scope = *scope_position;
2781+ scopes_.erase(scope_position);
2782+
2783+ owner_->scope_removed.emit(scope);
2784+ }
2785+}
2786+
2787+Scopes::ScopeList const& Scopes::Impl::GetScopes() const
2788+{
2789+ return scopes_;
2790+}
2791+
2792+Scope::Ptr Scopes::Impl::GetScope(std::string const& scope_id, int* index) const
2793+{
2794+ int tmp_index = 0;
2795+ for (auto scope: scopes_)
2796+ {
2797+ if (scope->id == scope_id)
2798+ {
2799+ if (index)
2800+ *index = tmp_index;
2801+ return scope;
2802+ }
2803+ tmp_index++;
2804+ }
2805+ if (index)
2806+ *index = -1;
2807+ return Scope::Ptr();
2808+}
2809+
2810+Scope::Ptr Scopes::Impl::GetScopeAtIndex(std::size_t index) const
2811+{
2812+ try
2813+ {
2814+ return scopes_.at(index);
2815+ }
2816+ catch (std::out_of_range& error)
2817+ {
2818+ LOG_WARN(logger) << error.what();
2819+ }
2820+ return Scope::Ptr();
2821+}
2822+
2823+Scope::Ptr Scopes::Impl::GetScopeForShortcut(std::string const& scope_shortcut) const
2824+{
2825+ for (auto scope: scopes_)
2826+ {
2827+ if (scope->shortcut == scope_shortcut)
2828+ {
2829+ return scope;
2830+ }
2831+ }
2832+
2833+ return Scope::Ptr();
2834+}
2835+
2836+Scopes::Scopes(ScopesReader::Ptr scopes_reader)
2837+: pimpl(new Impl(this, scopes_reader))
2838+{
2839+ count.SetGetterFunction(sigc::mem_fun(pimpl.get(), &Impl::get_count));
2840+}
2841+
2842+Scopes::~Scopes()
2843+{
2844+}
2845+
2846+void Scopes::LoadScopes()
2847+{
2848+ pimpl->LoadScopes();
2849+}
2850+
2851+Scopes::ScopeList const& Scopes::GetScopes() const
2852+{
2853+ return pimpl->GetScopes();
2854+}
2855+
2856+Scope::Ptr Scopes::GetScope(std::string const& scope_id, int* position) const
2857+{
2858+ return pimpl->GetScope(scope_id, position);
2859+}
2860+
2861+Scope::Ptr Scopes::GetScopeAtIndex(std::size_t index) const
2862+{
2863+ return pimpl->GetScopeAtIndex(index);
2864+}
2865+
2866+Scope::Ptr Scopes::GetScopeForShortcut(std::string const& scope_shortcut) const
2867+{
2868+ return pimpl->GetScopeForShortcut(scope_shortcut);
2869+}
2870+
2871+void Scopes::InsertScope(std::string const& scope_id, unsigned index)
2872+{
2873+ if (!pimpl->scopes_reader_)
2874+ return;
2875+
2876+ ScopeData::Ptr scope_data(pimpl->scopes_reader_->GetScopeDataById(scope_id));
2877+ if (scope_data)
2878+ pimpl->InsertScope(scope_data, index);
2879+}
2880+
2881+void Scopes::RemoveScope(std::string const& scope_id)
2882+{
2883+ pimpl->RemoveScope(scope_id);
2884+}
2885+
2886+Scope::Ptr Scopes::CreateScope(ScopeData::Ptr const& scope_data)
2887+{
2888+ if (!scope_data)
2889+ return Scope::Ptr();
2890+
2891+ LOG_DEBUG(logger) << "Creating scope: " << scope_data->id() << " (" << scope_data->dbus_path() << " @ " << scope_data->dbus_name() << ")";
2892+ Scope::Ptr scope(new Scope(scope_data));
2893+ scope->Init();
2894+ return scope;
2895+}
2896+
2897+
2898+} // namespace dash
2899+} // namespace unity
2900
2901=== added file 'UnityCore/Scopes.h'
2902--- UnityCore/Scopes.h 1970-01-01 00:00:00 +0000
2903+++ UnityCore/Scopes.h 2013-02-21 10:37:29 +0000
2904@@ -0,0 +1,94 @@
2905+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
2906+/*
2907+ * Copyright (C) 2011 Canonical Ltd
2908+ *
2909+ * This program is free software: you can redistribute it and/or modify
2910+ * it under the terms of the GNU General Public License version 3 as
2911+ * published by the Free Software Foundation.
2912+ *
2913+ * This program is distributed in the hope that it will be useful,
2914+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2915+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2916+ * GNU General Public License for more details.
2917+ *
2918+ * You should have received a copy of the GNU General Public License
2919+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2920+ *
2921+ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
2922+ Nick Dedekind <nick.dedeknd@canoncial.com>
2923+ */
2924+
2925+#ifndef UNITY_SCOPES_H
2926+#define UNITY_SCOPES_H
2927+
2928+#include <sigc++/trackable.h>
2929+#include <sigc++/signal.h>
2930+
2931+#include "Scope.h"
2932+
2933+namespace unity
2934+{
2935+namespace dash
2936+{
2937+
2938+typedef std::vector<ScopeData::Ptr> ScopeDataList;
2939+
2940+class ScopesReader : public sigc::trackable, boost::noncopyable
2941+{
2942+public:
2943+ typedef std::shared_ptr<ScopesReader> Ptr;
2944+ virtual ~ScopesReader() {}
2945+
2946+ virtual void LoadScopes() = 0;
2947+ virtual ScopeDataList const& GetScopesData() const = 0;
2948+
2949+ virtual ScopeData::Ptr GetScopeDataById(std::string const& scope_id) const = 0;
2950+
2951+ sigc::signal<void, ScopeDataList const&> scopes_changed;
2952+};
2953+
2954+class Scopes : public sigc::trackable, boost::noncopyable
2955+{
2956+public:
2957+ typedef std::shared_ptr<Scopes> Ptr;
2958+ typedef std::vector<Scope::Ptr> ScopeList;
2959+
2960+ Scopes(ScopesReader::Ptr scope_reader);
2961+ virtual ~Scopes();
2962+
2963+ virtual void LoadScopes();
2964+
2965+ /**
2966+ * Get the currently loaded Scopess. This is necessary as some of the consumers
2967+ * of this object employ a lazy-loading technique to reduce the overhead of
2968+ * starting Unity. Therefore, the Scopes may already have been loaded by the time
2969+ * the objects have been initiated (and so just connecting to the signals is not
2970+ * enough)
2971+ */
2972+ virtual ScopeList const& GetScopes() const;
2973+ virtual Scope::Ptr GetScope(std::string const& scope_id, int* position = nullptr) const;
2974+ virtual Scope::Ptr GetScopeAtIndex(std::size_t index) const;
2975+ virtual Scope::Ptr GetScopeForShortcut(std::string const& scope_shortcut) const;
2976+
2977+ nux::ROProperty<std::size_t> count;
2978+
2979+ sigc::signal<void, Scope::Ptr const&, int> scope_added;
2980+ sigc::signal<void, Scope::Ptr const&> scope_removed;
2981+
2982+ sigc::signal<void, ScopeList const&> scopes_reordered;
2983+
2984+protected:
2985+ virtual void InsertScope(std::string const& scope_id, unsigned index);
2986+ virtual void RemoveScope(std::string const& scope_id);
2987+
2988+ virtual Scope::Ptr CreateScope(ScopeData::Ptr const& scope_data);
2989+
2990+private:
2991+ class Impl;
2992+ std::unique_ptr<Impl> pimpl;
2993+};
2994+
2995+} // namespace dash
2996+} // namespace unity
2997+
2998+#endif // UNITY_SCOPES_H
2999
3000=== modified file 'UnityCore/SeriesPreview.cpp'
3001--- UnityCore/SeriesPreview.cpp 2012-07-12 16:36:54 +0000
3002+++ UnityCore/SeriesPreview.cpp 2013-02-21 10:37:29 +0000
3003@@ -33,14 +33,14 @@
3004 Impl(SeriesPreview* owner, glib::Object<GObject> const& proto_obj);
3005
3006 void SetupGetters();
3007- void selected_item_reply(GVariant* reply);
3008+ void selected_item_reply(glib::HintsMap const&, glib::Error const&);
3009 int get_selected_item_index() const { return selected_item_index_; };
3010 bool set_selected_item_index(int index);
3011 SeriesItemPtrList get_items() const { return items_list_; };
3012 Preview::Ptr get_child_preview() const
3013 {
3014- if (!child_preview_->parent_lens)
3015- child_preview_->parent_lens = owner_->parent_lens();
3016+ if (!child_preview_->parent_scope)
3017+ child_preview_->parent_scope = owner_->parent_scope();
3018 if (child_preview_->preview_uri().empty())
3019 child_preview_->preview_uri = owner_->preview_uri();
3020 return child_preview_;
3021@@ -101,24 +101,24 @@
3022 unity_protocol_series_preview_set_selected_item(raw_preview_, index);
3023 glib::Variant properties(unity_protocol_preview_end_updates(preview),
3024 glib::StealRef());
3025- owner_->Update(properties, sigc::mem_fun(this, &SeriesPreview::Impl::selected_item_reply));
3026- return true;
3027+
3028+ glib::HintsMap property_hints;
3029+ if (properties.ASVToHints(property_hints))
3030+ owner_->Update(property_hints, sigc::mem_fun(this, &SeriesPreview::Impl::selected_item_reply));
3031+ else
3032+ g_assert(false);
3033 }
3034
3035 return false;
3036 }
3037
3038-void SeriesPreview::Impl::selected_item_reply(GVariant *reply)
3039+void SeriesPreview::Impl::selected_item_reply(glib::HintsMap const& hints, glib::Error const&)
3040 {
3041- glib::Variant dict(reply);
3042- glib::HintsMap hints;
3043- dict.ASVToHints(hints);
3044-
3045 auto iter = hints.find("preview");
3046 if (iter != hints.end())
3047 {
3048 Preview::Ptr new_child = Preview::PreviewForVariant(iter->second);
3049- new_child->parent_lens = owner_->parent_lens();
3050+ new_child->parent_scope = owner_->parent_scope();
3051 new_child->preview_uri = owner_->preview_uri(); // FIXME: really?
3052 child_preview_ = new_child;
3053 owner_->child_preview_changed.emit(new_child);
3054
3055=== modified file 'UnityCore/Tracks.cpp'
3056--- UnityCore/Tracks.cpp 2012-06-19 16:47:56 +0000
3057+++ UnityCore/Tracks.cpp 2013-02-21 10:37:29 +0000
3058@@ -25,6 +25,7 @@
3059 {
3060
3061 Tracks::Tracks()
3062+: Model<Track>::Model(ModelType::REMOTE_SHARED)
3063 {
3064 row_added.connect(sigc::mem_fun(this, &Tracks::OnRowAdded));
3065 row_changed.connect(sigc::mem_fun(this, &Tracks::OnRowChanged));
3066@@ -32,7 +33,7 @@
3067 }
3068
3069 Tracks::Tracks(ModelType model_type)
3070- : Model<Track>::Model(model_type)
3071+: Model<Track>::Model(model_type)
3072 {
3073 row_added.connect(sigc::mem_fun(this, &Tracks::OnRowAdded));
3074 row_changed.connect(sigc::mem_fun(this, &Tracks::OnRowChanged));
3075
3076=== modified file 'UnityCore/Variant.cpp'
3077--- UnityCore/Variant.cpp 2012-11-06 18:19:09 +0000
3078+++ UnityCore/Variant.cpp 2013-02-21 10:37:29 +0000
3079@@ -125,6 +125,47 @@
3080 return bool(variant_);
3081 }
3082
3083+static void g_variant_unref0 (gpointer var)
3084+{
3085+ if (var)
3086+ g_variant_unref((GVariant*)var);
3087+}
3088+
3089+GHashTable* hashtable_from_hintsmap(glib::HintsMap const& hints)
3090+{
3091+ GHashTable* hash_table = g_hash_table_new_full(g_str_hash, g_direct_equal, g_free, g_variant_unref0);
3092+
3093+ if (!hash_table)
3094+ return nullptr;
3095+
3096+ for (glib::HintsMap::const_iterator it = hints.begin(); it != hints.end(); ++it)
3097+ {
3098+ gchar* key = g_strdup(it->first.c_str());
3099+ GVariant* ptr = g_variant_ref(it->second);
3100+
3101+ g_hash_table_insert(hash_table, key, ptr);
3102+ }
3103+ return hash_table;
3104+}
3105+
3106+HintsMap const& hintsmap_from_hashtable(GHashTable* hashtable, HintsMap& hints)
3107+{
3108+ if (!hashtable)
3109+ return hints;
3110+
3111+ GHashTableIter hints_iter;
3112+ gpointer key, value;
3113+ g_hash_table_iter_init (&hints_iter, hashtable);
3114+ while (g_hash_table_iter_next (&hints_iter, &key, &value))
3115+ {
3116+ std::string hint_key(static_cast<gchar*>(key));
3117+ glib::Variant hint_value(static_cast<GVariant*>(value));
3118+
3119+ hints[hint_key] = hint_value;
3120+ }
3121+ return hints;
3122+}
3123+
3124 } // namespace glib
3125
3126 namespace variant
3127@@ -220,6 +261,5 @@
3128 return *this;
3129 }
3130
3131-
3132 }
3133 }
3134
3135=== modified file 'UnityCore/Variant.h'
3136--- UnityCore/Variant.h 2012-11-06 18:19:09 +0000
3137+++ UnityCore/Variant.h 2013-02-21 10:37:29 +0000
3138@@ -33,6 +33,8 @@
3139
3140 class Variant;
3141 typedef std::map<std::string, Variant> HintsMap;
3142+GHashTable* hashtable_from_hintsmap(HintsMap const& hints);
3143+HintsMap const& hintsmap_from_hashtable(GHashTable* hashtable, HintsMap& hints);
3144
3145 struct StealRef {};
3146
3147
3148=== modified file 'com.canonical.Unity.gschema.xml'
3149--- com.canonical.Unity.gschema.xml 2013-02-06 11:07:00 +0000
3150+++ com.canonical.Unity.gschema.xml 2013-02-21 10:37:29 +0000
3151@@ -67,5 +67,15 @@
3152 <summary>List of lens ids specifying how lenses should be ordered in the Dash home screen.</summary>
3153 <description>The categories listed on the Dash home screen will be ordered according to this list. Lenses not appearing in this list will not have any particular ordering and will always sort after lenses specified in this list.</description>
3154 </key>
3155+ <key type="as" name="scopes">
3156+ <default>[ 'home.scope' , 'applications.scope' ]</default>
3157+ <summary>List of scope ids specifying which scopes should be created and the order to display them in.</summary>
3158+ <description>The scopes listed in the scope bar will be ordered according to this list.</description>
3159+ </key>
3160+ <key type="as" name="always-search">
3161+ <default>[ 'applications.lens' ]</default>
3162+ <summary>List of scope ids which are always searched when the search string changes.</summary>
3163+ <description></description>
3164+ </key>
3165 </schema>
3166 </schemalist>
3167
3168=== modified file 'dash/DashController.cpp'
3169--- dash/DashController.cpp 2013-01-30 02:11:19 +0000
3170+++ dash/DashController.cpp 2013-02-21 10:37:29 +0000
3171@@ -403,14 +403,14 @@
3172 gboolean Controller::CheckShortcutActivation(const char* key_string)
3173 {
3174 EnsureDash();
3175- std::string lens_id = view_->GetIdForShortcutActivation(std::string(key_string));
3176- if (lens_id != "")
3177+ std::string scope_id = view_->GetIdForShortcutActivation(std::string(key_string));
3178+ if (scope_id != "")
3179 {
3180 WindowManager& wm = WindowManager::Default();
3181 if (wm.IsScaleActive())
3182 wm.TerminateScale();
3183
3184- GVariant* args = g_variant_new("(sus)", lens_id.c_str(), dash::GOTO_DASH_URI, "");
3185+ GVariant* args = g_variant_new("(sus)", scope_id.c_str(), dash::GOTO_DASH_URI, "");
3186 OnActivateRequest(args);
3187 g_variant_unref(args);
3188 return true;
3189
3190=== modified file 'dash/DashView.cpp'
3191--- dash/DashView.cpp 2013-02-14 22:12:50 +0000
3192+++ dash/DashView.cpp 2013-02-21 10:37:29 +0000
3193@@ -31,6 +31,7 @@
3194 #include <NuxCore/Logger.h>
3195 #include <UnityCore/GLibWrapper.h>
3196 #include <UnityCore/RadioOptionFilter.h>
3197+#include <UnityCore/GSettingsScopes.h>
3198
3199 #include "unity-shared/DashStyle.h"
3200 #include "unity-shared/KeyboardUtil.h"
3201@@ -110,9 +111,8 @@
3202
3203 NUX_IMPLEMENT_OBJECT_TYPE(DashView);
3204
3205-DashView::DashView()
3206+DashView::DashView(ScopesCreator scopes_creator)
3207 : nux::View(NUX_TRACKER_LOCATION)
3208- , home_lens_(new HomeLens(_("Home"), _("Home screen"), _("Search your computer and online sources")))
3209 , preview_container_(nullptr)
3210 , preview_displaying_(false)
3211 , preview_navigation_mode_(previews::Navigation::NONE)
3212@@ -137,32 +137,34 @@
3213 SetupViews();
3214 SetupUBusConnections();
3215
3216- lenses_.lens_added.connect(sigc::mem_fun(this, &DashView::OnLensAdded));
3217 mouse_down.connect(sigc::mem_fun(this, &DashView::OnMouseButtonDown));
3218 preview_state_machine_.PreviewActivated.connect(sigc::mem_fun(this, &DashView::BuildPreview));
3219 Relayout();
3220
3221- home_lens_->AddLenses(lenses_);
3222- lens_bar_->Activate("home.lens");
3223-
3224- // we will special case when applications lens finishes global search
3225- // because we want to be able to launch applications immediately
3226- // without waiting for the search finished signal which will
3227- // be delayed by all the lenses we're searching
3228- home_lens_->lens_search_finished.connect(sigc::mem_fun(this, &DashView::OnAppsGlobalSearchFinished));
3229-
3230 // We are interested in the color of the desktop background.
3231 ubus_manager_.RegisterInterest(UBUS_BACKGROUND_COLOR_CHANGED, sigc::mem_fun(this, &DashView::OnBGColorChanged));
3232
3233 // request the latest colour from bghash
3234 ubus_manager_.SendMessage(UBUS_BACKGROUND_REQUEST_COLOUR_EMIT);
3235
3236+ if (scopes_creator == nullptr)
3237+ {
3238+ scopes_creator = [this]() { scopes_.reset(new GSettingsScopes()); };
3239+ }
3240+
3241+ scopes_creator();
3242+ if (scopes_)
3243+ {
3244+ scopes_->scope_added.connect(sigc::mem_fun(this, &DashView::OnScopeAdded));
3245+ scopes_->LoadScopes();
3246+ }
3247 }
3248
3249 DashView::~DashView()
3250 {
3251+ scope_can_refine_connection_.disconnect();
3252 // Do this explicitely, otherwise dee will complain about invalid access
3253- // to the lens models
3254+ // to the scope models
3255 RemoveLayout();
3256 }
3257
3258@@ -220,12 +222,12 @@
3259 StartPreviewAnimation();
3260
3261 content_view_->SetPresentRedirectedView(false);
3262- preview_lens_view_ = active_lens_view_;
3263- if (preview_lens_view_)
3264+ preview_scope_view_ = active_scope_view_;
3265+ if (preview_scope_view_)
3266 {
3267- preview_lens_view_->ForceCategoryExpansion(stored_activated_unique_id_, true);
3268- preview_lens_view_->EnableResultTextures(true);
3269- preview_lens_view_->PushFilterExpansion(false);
3270+ preview_scope_view_->ForceCategoryExpansion(stored_activated_unique_id_, true);
3271+ preview_scope_view_->EnableResultTextures(true);
3272+ preview_scope_view_->PushFilterExpansion(false);
3273 }
3274
3275 if (!preview_container_)
3276@@ -237,7 +239,7 @@
3277 }
3278 preview_container_->Preview(model, previews::Navigation::NONE); // no swipe left or right
3279
3280- preview_container_->SetGeometry(lenses_layout_->GetGeometry());
3281+ preview_container_->SetGeometry(scopes_layout_->GetGeometry());
3282 preview_displaying_ = true;
3283
3284 // connect to nav left/right signals to request nav left/right movement.
3285@@ -354,8 +356,8 @@
3286 preview_container_animation_->Start();
3287 }
3288
3289- if (preview_lens_view_)
3290- preview_lens_view_->SetResultsPreviewAnimationValue(animate_split_value_);
3291+ if (preview_scope_view_)
3292+ preview_scope_view_->SetResultsPreviewAnimationValue(animate_split_value_);
3293 });
3294
3295 split_animation_->finished.connect(sigc::mem_fun(this, &DashView::OnPreviewAnimationFinished));
3296@@ -415,8 +417,8 @@
3297 split_animation_->finished.connect(sigc::mem_fun(this, &DashView::OnPreviewAnimationFinished));
3298 split_animation_->Start();
3299
3300- // if (preview_lens_view_)
3301- // preview_lens_view_->PopFilterExpansion();
3302+ // if (preview_scope_view_)
3303+ // preview_scope_view_->PopFilterExpansion();
3304 }
3305 });
3306
3307@@ -445,14 +447,14 @@
3308 }
3309
3310 // reset the saturation.
3311- if (preview_lens_view_.IsValid())
3312+ if (preview_scope_view_.IsValid())
3313 {
3314- preview_lens_view_->SetResultsPreviewAnimationValue(0.0);
3315- preview_lens_view_->ForceCategoryExpansion(stored_activated_unique_id_, false);
3316- preview_lens_view_->EnableResultTextures(false);
3317- preview_lens_view_->PopFilterExpansion();
3318+ preview_scope_view_->SetResultsPreviewAnimationValue(0.0);
3319+ preview_scope_view_->ForceCategoryExpansion(stored_activated_unique_id_, false);
3320+ preview_scope_view_->EnableResultTextures(false);
3321+ preview_scope_view_->PopFilterExpansion();
3322 }
3323- preview_lens_view_.Release();
3324+ preview_scope_view_.Release();
3325 content_view_->SetPresentRedirectedView(true);
3326 }
3327
3328@@ -462,31 +464,13 @@
3329 visible_ = true;
3330 search_bar_->text_entry()->SelectAll();
3331
3332- /* Give the lenses a chance to prep data before we map them */
3333- lens_bar_->Activate(active_lens_view_->lens()->id());
3334- if (active_lens_view_)
3335- {
3336- active_lens_view_->SetVisible(true);
3337-
3338- if (active_lens_view_->lens()->id() == "home.lens")
3339- {
3340- for (auto lens : lenses_.GetLenses())
3341- {
3342- lens->view_type = ViewType::HOME_VIEW;
3343- LOG_DEBUG(logger) << "Setting ViewType " << ViewType::HOME_VIEW
3344- << " on '" << lens->id() << "'";
3345- }
3346-
3347- home_lens_->view_type = ViewType::LENS_VIEW;
3348- LOG_DEBUG(logger) << "Setting ViewType " << ViewType::LENS_VIEW
3349- << " on '" << home_lens_->id() << "'";
3350- }
3351- else
3352- {
3353- // careful here, the lens_view's view_type doesn't get reset when the dash
3354- // hides, but lens' view_type does, so we need to update the lens directly
3355- active_lens_view_->lens()->view_type = ViewType::LENS_VIEW;
3356- }
3357+ /* Give the scopes a chance to prep data before we map them */
3358+ if (active_scope_view_)
3359+ {
3360+ scope_bar_->Activate(active_scope_view_->scope()->id());
3361+
3362+ active_scope_view_->SetVisible(true);
3363+ active_scope_view_->scope()->view_type = ScopeViewType::SCOPE_VIEW;
3364 }
3365
3366 // this will make sure the spinner animates if the search takes a while
3367@@ -508,19 +492,18 @@
3368 visible_ = false;
3369 renderer_.AboutToHide();
3370
3371- for (auto lens : lenses_.GetLenses())
3372+ if (scopes_)
3373 {
3374- lens->view_type = ViewType::HIDDEN;
3375- LOG_DEBUG(logger) << "Setting ViewType " << ViewType::HIDDEN
3376- << " on '" << lens->id() << "'";
3377+ for (auto scope : scopes_->GetScopes())
3378+ {
3379+ scope->view_type = ScopeViewType::HIDDEN;
3380+ LOG_DEBUG(logger) << "Setting ViewType " << ScopeViewType::HIDDEN
3381+ << " on '" << scope->id() << "'";
3382+ }
3383 }
3384
3385- home_lens_->view_type = ViewType::HIDDEN;
3386- LOG_DEBUG(logger) << "Setting ViewType " << ViewType::HIDDEN
3387- << " on '" << home_lens_->id() << "'";
3388-
3389- if (active_lens_view_.IsValid())
3390- active_lens_view_->SetVisible(false);
3391+ if (active_scope_view_.IsValid())
3392+ active_scope_view_->SetVisible(false);
3393
3394 // if a preview is open, close it
3395 if (preview_displaying_)
3396@@ -562,30 +545,22 @@
3397 search_bar_->live_search_reached.connect(sigc::mem_fun(this, &DashView::OnLiveSearchReached));
3398 search_bar_->showing_filters.changed.connect([&] (bool showing)
3399 {
3400- if (active_lens_view_)
3401+ if (active_scope_view_)
3402 {
3403- active_lens_view_->filters_expanded = showing;
3404+ active_scope_view_->filters_expanded = showing;
3405 QueueDraw();
3406 }
3407 });
3408 search_bar_layout_->AddView(search_bar_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL);
3409 content_layout_->SetSpecialArea(search_bar_->show_filters());
3410
3411- lenses_layout_ = new nux::VLayout();
3412- content_layout_->AddLayout(lenses_layout_, 1, nux::MINOR_POSITION_START);
3413-
3414- home_view_ = new LensView(home_lens_, nullptr);
3415- home_view_->uri_activated.connect(sigc::mem_fun(this, &DashView::OnUriActivated));
3416-
3417- AddChild(home_view_.GetPointer());
3418- active_lens_view_ = home_view_;
3419- lens_views_[home_lens_->id] = home_view_;
3420- lenses_layout_->AddView(home_view_.GetPointer());
3421-
3422- lens_bar_ = new LensBar();
3423- AddChild(lens_bar_);
3424- lens_bar_->lens_activated.connect(sigc::mem_fun(this, &DashView::OnLensBarActivated));
3425- content_layout_->AddView(lens_bar_, 0, nux::MINOR_POSITION_CENTER);
3426+ scopes_layout_ = new nux::VLayout();
3427+ content_layout_->AddLayout(scopes_layout_, 1, nux::MINOR_POSITION_START);
3428+
3429+ scope_bar_ = new ScopeBar();
3430+ AddChild(scope_bar_);
3431+ scope_bar_->scope_activated.connect(sigc::mem_fun(this, &DashView::OnScopeBarActivated));
3432+ content_layout_->AddView(scope_bar_, 0, nux::MINOR_POSITION_CENTER);
3433 }
3434
3435 void DashView::SetupUBusConnections()
3436@@ -609,8 +584,8 @@
3437 // kinda hacky, but it makes sure the content isn't so big that it throws
3438 // the bottom of the dash off the screen
3439 // not hugely happy with this, so FIXME
3440- lenses_layout_->SetMaximumHeight (std::max(0, content_geo_.height - search_bar_->GetGeometry().height - lens_bar_->GetGeometry().height - style.GetDashViewTopPadding()));
3441- lenses_layout_->SetMinimumHeight (std::max(0, content_geo_.height - search_bar_->GetGeometry().height - lens_bar_->GetGeometry().height - style.GetDashViewTopPadding()));
3442+ scopes_layout_->SetMaximumHeight (std::max(0, content_geo_.height - search_bar_->GetGeometry().height - scope_bar_->GetGeometry().height - style.GetDashViewTopPadding()));
3443+ scopes_layout_->SetMinimumHeight (std::max(0, content_geo_.height - search_bar_->GetGeometry().height - scope_bar_->GetGeometry().height - style.GetDashViewTopPadding()));
3444
3445 layout_->SetMinMaxSize(content_geo_.width, content_geo_.y + content_geo_.height);
3446
3447@@ -653,7 +628,7 @@
3448 height += style.GetDashViewTopPadding();
3449 height += search_bar_->GetGeometry().height;
3450 height += category_height * DASH_DEFAULT_CATEGORY_COUNT; // adding three categories
3451- height += lens_bar_->GetGeometry().height;
3452+ height += scope_bar_->GetGeometry().height;
3453
3454 // width/height shouldn't be bigger than the geo available.
3455 width = std::min(width, for_geo.width); // launcher width is taken into account in for_geo.
3456@@ -715,7 +690,7 @@
3457
3458 graphics_engine.PushClippingRectangle(geo_split_clip);
3459
3460- if (preview_lens_view_.IsValid())
3461+ if (preview_scope_view_.IsValid())
3462 {
3463 DrawPreviewResultTextures(graphics_engine, force_draw);
3464 }
3465@@ -762,29 +737,29 @@
3466 texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD);
3467 texxform.FlipVCoord(true);
3468
3469- // Lens Bar
3470- texxform.uoffset = (lens_bar_->GetX() - content_view_->GetX())/(float)content_view_->GetWidth();
3471- texxform.voffset = (lens_bar_->GetY() - content_view_->GetY())/(float)content_view_->GetHeight();
3472+ // Scope Bar
3473+ texxform.uoffset = (scope_bar_->GetX() - content_view_->GetX())/(float)content_view_->GetWidth();
3474+ texxform.voffset = (scope_bar_->GetY() - content_view_->GetY())/(float)content_view_->GetHeight();
3475
3476- int start_y = lens_bar_->GetY();
3477+ int start_y = scope_bar_->GetY();
3478 int final_y = geo_layout.y + geo_layout.height + PREVIEW_ICON_SPLIT_OFFSCREEN_OFFSET;
3479
3480- int lens_y = (1.0f - animate_split_value_) * start_y + (animate_split_value_ * final_y);
3481+ int scope_y = (1.0f - animate_split_value_) * start_y + (animate_split_value_ * final_y);
3482
3483 graphics_engine.QRP_1Tex
3484 (
3485- lens_bar_->GetX(),
3486- lens_y,
3487- lens_bar_->GetWidth(),
3488- lens_bar_->GetHeight(),
3489+ scope_bar_->GetX(),
3490+ scope_y,
3491+ scope_bar_->GetWidth(),
3492+ scope_bar_->GetHeight(),
3493 content_view_->BackupTexture(),
3494 texxform,
3495 nux::Color((1.0-animate_split_value_), (1.0-animate_split_value_), (1.0-animate_split_value_), (1.0-animate_split_value_))
3496 );
3497
3498- split_clip.height = std::min(lens_y, geo_layout.height);
3499+ split_clip.height = std::min(scope_y, geo_layout.height);
3500
3501- if (active_lens_view_ && active_lens_view_->GetPushedFilterExpansion())
3502+ if (active_scope_view_ && active_scope_view_->GetPushedFilterExpansion())
3503 {
3504 // Search Bar
3505 texxform.uoffset = (search_bar_->GetX() - content_view_->GetX())/(float)content_view_->GetWidth();
3506@@ -797,7 +772,7 @@
3507 (
3508 search_bar_->GetX(),
3509 (1.0f - animate_split_value_) * start_y + (animate_split_value_ * final_y),
3510- search_bar_->GetWidth() - active_lens_view_->filter_bar()->GetWidth(),
3511+ search_bar_->GetWidth() - active_scope_view_->filter_bar()->GetWidth(),
3512 search_bar_->GetHeight(),
3513 content_view_->BackupTexture(),
3514 texxform,
3515@@ -805,10 +780,10 @@
3516 );
3517
3518 // Filter Bar
3519- texxform.uoffset = (active_lens_view_->filter_bar()->GetX() -content_view_->GetX())/(float)content_view_->GetWidth();
3520+ texxform.uoffset = (active_scope_view_->filter_bar()->GetX() -content_view_->GetX())/(float)content_view_->GetWidth();
3521 texxform.voffset = (search_bar_->GetY() - content_view_->GetY())/(float)content_view_->GetHeight();
3522
3523- int start_x = active_lens_view_->filter_bar()->GetX();
3524+ int start_x = active_scope_view_->filter_bar()->GetX();
3525 int final_x = content_view_->GetX() + content_view_->GetWidth() + PREVIEW_ICON_SPLIT_OFFSCREEN_OFFSET;
3526
3527 int filter_x = (1.0f - animate_split_value_) * start_x + (animate_split_value_ * final_x);
3528@@ -817,8 +792,8 @@
3529 (
3530 filter_x,
3531 search_bar_->GetY(),
3532- active_lens_view_->filter_bar()->GetWidth(),
3533- active_lens_view_->filter_bar()->GetY() + active_lens_view_->filter_bar()->GetHeight(),
3534+ active_scope_view_->filter_bar()->GetWidth(),
3535+ active_scope_view_->filter_bar()->GetY() + active_scope_view_->filter_bar()->GetHeight(),
3536 content_view_->BackupTexture(),
3537 texxform,
3538 nux::Color((1.0-animate_split_value_), (1.0-animate_split_value_), (1.0-animate_split_value_), (1.0-animate_split_value_))
3539@@ -935,7 +910,7 @@
3540 texxform.voffset = 0.0f;
3541 texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD);
3542
3543- std::vector<ResultViewTexture::Ptr> result_textures = preview_lens_view_->GetResultTextureContainers();
3544+ std::vector<ResultViewTexture::Ptr> result_textures = preview_scope_view_->GetResultTextureContainers();
3545 std::vector<ResultViewTexture::Ptr> top_textures;
3546
3547 int height_concat_below = 0;
3548@@ -973,7 +948,7 @@
3549 // off the bottom
3550 if (geo_tex_top.y <= geo_layout.y + geo_layout.height)
3551 {
3552- preview_lens_view_->RenderResultTexture(result_texture);
3553+ preview_scope_view_->RenderResultTexture(result_texture);
3554 // If we haven't got it now, we're not going to get it
3555 if (!result_texture->texture.IsValid())
3556 continue;
3557@@ -1014,7 +989,7 @@
3558 // off the top
3559 if (geo_tex_top.y + geo_tex_top.height >= geo_layout.y)
3560 {
3561- preview_lens_view_->RenderResultTexture(result_texture);
3562+ preview_scope_view_->RenderResultTexture(result_texture);
3563 // If we haven't got it now, we're not going to get it
3564 if (!result_texture->texture.IsValid())
3565 continue;
3566@@ -1106,11 +1081,11 @@
3567 {
3568 glib::String uri;
3569 glib::String search_string;
3570- dash::HandledType handled_type;
3571+ ScopeHandledType handled_type;
3572
3573 g_variant_get(args, "(sus)", &uri, &handled_type, &search_string);
3574
3575- std::string id(AnalyseLensURI(uri.Str()));
3576+ std::string id(AnalyseScopeURI(uri.Str()));
3577
3578 // we got an activation request, we should probably close the preview
3579 if (preview_displaying_)
3580@@ -1120,43 +1095,43 @@
3581
3582 if (!visible_)
3583 {
3584- lens_bar_->Activate(id);
3585+ scope_bar_->Activate(id);
3586 ubus_manager_.SendMessage(UBUS_DASH_EXTERNAL_ACTIVATION);
3587 }
3588- else if (/* visible_ && */ handled_type == NOT_HANDLED)
3589+ else if (/* visible_ && */ handled_type == ScopeHandledType::NOT_HANDLED)
3590 {
3591 ubus_manager_.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST, NULL,
3592 glib::Source::Priority::HIGH);
3593 }
3594- else if (/* visible_ && */ handled_type == GOTO_DASH_URI)
3595+ else if (/* visible_ && */ handled_type == ScopeHandledType::GOTO_DASH_URI)
3596 {
3597- lens_bar_->Activate(id);
3598+ scope_bar_->Activate(id);
3599 }
3600 }
3601
3602-std::string DashView::AnalyseLensURI(std::string const& uri)
3603+std::string DashView::AnalyseScopeURI(std::string const& uri)
3604 {
3605- impl::LensFilter filter = impl::parse_lens_uri(uri);
3606+ impl::ScopeFilter filter = impl::parse_scope_uri(uri);
3607
3608 if (!filter.filters.empty())
3609 {
3610- lens_views_[filter.id]->filters_expanded = true;
3611- // update the lens for each filter
3612+ scope_views_[filter.id]->filters_expanded = true;
3613+ // update the scope for each filter
3614 for (auto p : filter.filters) {
3615- UpdateLensFilter(filter.id, p.first, p.second);
3616+ UpdateScopeFilter(filter.id, p.first, p.second);
3617 }
3618 }
3619
3620 return filter.id;
3621 }
3622
3623-void DashView::UpdateLensFilter(std::string lens_id, std::string filter_name, std::string value)
3624+void DashView::UpdateScopeFilter(std::string scope_id, std::string filter_name, std::string value)
3625 {
3626- if (lenses_.GetLens(lens_id))
3627+ if (scopes_ && scopes_->GetScope(scope_id))
3628 {
3629- Lens::Ptr lens = lenses_.GetLens(lens_id);
3630+ Scope::Ptr scope = scopes_->GetScope(scope_id);
3631
3632- Filters::Ptr filters = lens->filters;
3633+ Filters::Ptr filters = scope->filters;
3634
3635 for (unsigned int i = 0; i < filters->count(); ++i)
3636 {
3637@@ -1164,13 +1139,13 @@
3638
3639 if (filter->id() == filter_name)
3640 {
3641- UpdateLensFilterValue(filter, value);
3642+ UpdateScopeFilterValue(filter, value);
3643 }
3644 }
3645 }
3646 }
3647
3648-void DashView::UpdateLensFilterValue(Filter::Ptr filter, std::string value)
3649+void DashView::UpdateScopeFilterValue(Filter::Ptr filter, std::string value)
3650 {
3651 if (filter->renderer_name == "filter-radiooption")
3652 {
3653@@ -1186,7 +1161,7 @@
3654 void DashView::OnSearchChanged(std::string const& search_string)
3655 {
3656 LOG_DEBUG(logger) << "Search changed: " << search_string;
3657- if (active_lens_view_)
3658+ if (active_scope_view_)
3659 {
3660 search_in_progress_ = true;
3661 // it isn't guaranteed that we get a SearchFinished signal, so we need
3662@@ -1201,7 +1176,7 @@
3663
3664 // 150ms to hide the no reults message if its take a while to return results
3665 hide_message_delay_.reset(new glib::Timeout(150, [&] () {
3666- active_lens_view_->HideResultsMessage();
3667+ active_scope_view_->HideResultsMessage();
3668 return false;
3669 }));
3670 }
3671@@ -1210,67 +1185,63 @@
3672 void DashView::OnLiveSearchReached(std::string const& search_string)
3673 {
3674 LOG_DEBUG(logger) << "Live search reached: " << search_string;
3675- if (active_lens_view_)
3676+ if (active_scope_view_)
3677 {
3678- active_lens_view_->PerformSearch(search_string,
3679+ active_scope_view_->PerformSearch(search_string,
3680 sigc::mem_fun(this, &DashView::OnSearchFinished));
3681 }
3682 }
3683
3684-void DashView::OnLensAdded(Lens::Ptr& lens)
3685+void DashView::OnScopeAdded(Scope::Ptr const& scope, int position)
3686 {
3687- std::string id = lens->id;
3688- lens_bar_->AddLens(lens);
3689-
3690- nux::ObjectPtr<LensView> view(new LensView(lens, search_bar_->show_filters()));
3691+ LOG_DEBUG(logger) << "Scope Added: " << scope->id();
3692+
3693+ std::string id = scope->id;
3694+ scope_bar_->AddScope(scope);
3695+
3696+ nux::ObjectPtr<ScopeView> view(new ScopeView(scope, search_bar_->show_filters()));
3697 AddChild(view.GetPointer());
3698 view->SetVisible(false);
3699 view->uri_activated.connect(sigc::mem_fun(this, &DashView::OnUriActivated));
3700
3701- lenses_layout_->AddView(view.GetPointer(), 1);
3702- lens_views_[lens->id] = view;
3703+ scopes_layout_->AddView(view.GetPointer(), 1);
3704+ scope_views_[scope->id] = view;
3705
3706- lens->activated.connect(sigc::mem_fun(this, &DashView::OnUriActivatedReply));
3707- lens->connected.changed.connect([&] (bool value)
3708- {
3709- std::string const& search_string = search_bar_->search_string;
3710- if (value && lens->search_in_global && active_lens_view_ == home_view_
3711- && !search_string.empty())
3712- {
3713- // force a (global!) search with the correct string
3714- lens->GlobalSearch(search_bar_->search_string,
3715- sigc::mem_fun(this, &DashView::OnSearchFinished));
3716- }
3717- });
3718+ scope->activated.connect(sigc::mem_fun(this, &DashView::OnUriActivatedReply));
3719+ scope->connected.changed.connect([&] (bool value) { });
3720
3721 // Hook up to the new preview infrastructure
3722- lens->preview_ready.connect([&] (std::string const& uri, Preview::Ptr model)
3723+ scope->preview_ready.connect([&] (std::string const& uri, Preview::Ptr model)
3724 {
3725 LOG_DEBUG(logger) << "Got preview for: " << uri;
3726 preview_state_machine_.ActivatePreview(model); // this does not immediately display a preview - we now wait.
3727 });
3728+
3729+ if (!active_scope_view_)
3730+ OnScopeBarActivated(scope->id());
3731 }
3732
3733-void DashView::OnLensBarActivated(std::string const& id)
3734+void DashView::OnScopeBarActivated(std::string const& id)
3735 {
3736- if (lens_views_.find(id) == lens_views_.end())
3737+ if (scope_views_.find(id) == scope_views_.end())
3738 {
3739- LOG_WARN(logger) << "Unable to find Lens " << id;
3740+ LOG_WARN(logger) << "Unable to find Scope " << id;
3741 return;
3742 }
3743
3744- if (active_lens_view_.IsValid())
3745- active_lens_view_->SetVisible(false);
3746+ if (active_scope_view_.IsValid())
3747+ active_scope_view_->SetVisible(false);
3748+ scope_can_refine_connection_.disconnect();
3749
3750- nux::ObjectPtr<LensView> view = active_lens_view_ = lens_views_[id];
3751+ nux::ObjectPtr<ScopeView> view = active_scope_view_ = scope_views_[id];
3752
3753 view->SetVisible(true);
3754 view->AboutToShow();
3755
3756- for (auto it: lens_views_)
3757+ for (auto it: scope_views_)
3758 {
3759 bool id_matches = it.first == id;
3760- ViewType view_type = id_matches ? LENS_VIEW : (view == home_view_ ? HOME_VIEW : HIDDEN);
3761+ ScopeViewType view_type = id_matches ? ScopeViewType::SCOPE_VIEW : ScopeViewType::HIDDEN;
3762 it.second->SetVisible(id_matches);
3763 it.second->view_type = view_type;
3764
3765@@ -1281,8 +1252,8 @@
3766 search_bar_->SetVisible(true);
3767 QueueRelayout();
3768 search_bar_->search_string = view->search_string;
3769- search_bar_->search_hint = view->lens()->search_hint;
3770- // lenses typically return immediately from Search() if the search query
3771+ search_bar_->search_hint = view->scope()->search_hint;
3772+ // scopes typically return immediately from Search() if the search query
3773 // doesn't change, so SearchFinished will be called in a few ms
3774 // FIXME: if we're forcing a search here, why don't we get rid of view types?
3775 search_bar_->ForceSearchChanged();
3776@@ -1294,23 +1265,26 @@
3777
3778 search_bar_->text_entry()->SelectAll();
3779 search_bar_->can_refine_search = view->can_refine_search();
3780+ scope_can_refine_connection_ = view->can_refine_search.changed.connect([this] (bool can_refine_search) {
3781+ search_bar_->can_refine_search = can_refine_search;
3782+ });
3783 hide_message_delay_.reset();
3784
3785 view->QueueDraw();
3786 QueueDraw();
3787 }
3788
3789-void DashView::OnSearchFinished(Lens::Hints const& hints, glib::Error const& err)
3790+void DashView::OnSearchFinished(glib::HintsMap const& hints, glib::Error const& err)
3791 {
3792 hide_message_delay_.reset();
3793
3794- if (!active_lens_view_.IsValid()) return;
3795+ if (!active_scope_view_.IsValid()) return;
3796
3797- // FIXME: bind the lens_view in PerformSearch
3798- active_lens_view_->CheckNoResults(hints);
3799+ // FIXME: bind the scope_view in PerformSearch
3800+ active_scope_view_->CheckNoResults(hints);
3801 std::string const& search_string = search_bar_->search_string;
3802
3803- if (active_lens_view_->search_string == search_string)
3804+ if (active_scope_view_->search_string == search_string)
3805 {
3806 search_bar_->SearchFinished();
3807 search_in_progress_ = false;
3808@@ -1319,29 +1293,7 @@
3809 }
3810 }
3811
3812-void DashView::OnGlobalSearchFinished(Lens::Hints const& hints, glib::Error const& error)
3813-{
3814- if (active_lens_view_ == home_view_)
3815- OnSearchFinished(hints, error);
3816-}
3817-
3818-void DashView::OnAppsGlobalSearchFinished(Lens::Ptr const& lens)
3819-{
3820- if (active_lens_view_ == home_view_ && lens->id() == "applications.lens")
3821- {
3822- /* HACKITY HACK! We're resetting the state of search_in_progress when
3823- * doing searches in the home lens and we get results from apps lens.
3824- * This way typing a search query and pressing enter immediately will
3825- * wait for the apps lens results and will run correct application.
3826- * See lp:966417 and lp:856206 for more info about why we do this.
3827- */
3828- search_in_progress_ = false;
3829- if (activate_on_finish_)
3830- this->OnEntryActivated();
3831- }
3832-}
3833-
3834-void DashView::OnUriActivatedReply(std::string const& uri, HandledType type, Lens::Hints const&)
3835+void DashView::OnUriActivatedReply(std::string const& uri, ScopeHandledType type, glib::HintsMap const&)
3836 {
3837 // We don't want to close the dash if there was another activation pending
3838 if (type == NOT_HANDLED)
3839@@ -1362,11 +1314,11 @@
3840 size_t pos = fake_uri.find(":");
3841 std::string uri = fake_uri.substr(++pos);
3842
3843- LOG_DEBUG(logger) << "Fallback activating " << uri;
3844-
3845 if (g_str_has_prefix(uri.c_str(), "application://"))
3846 {
3847 std::string appname = uri.substr(14);
3848+
3849+ printf("Actrivating app: %s", appname.c_str());
3850 return LaunchApp(appname);
3851 }
3852 else if (g_str_has_prefix(uri.c_str(), "unity-runner://"))
3853@@ -1436,9 +1388,9 @@
3854 }
3855 void DashView::OnEntryActivated()
3856 {
3857- if (active_lens_view_.IsValid() && !search_in_progress_)
3858+ if (active_scope_view_.IsValid() && !search_in_progress_)
3859 {
3860- active_lens_view_->ActivateFirst();
3861+ active_scope_view_->ActivateFirst();
3862 }
3863 // delay the activation until we get the SearchFinished signal
3864 activate_on_finish_ = search_in_progress_;
3865@@ -1452,9 +1404,9 @@
3866
3867 std::string const DashView::GetIdForShortcutActivation(std::string const& shortcut) const
3868 {
3869- Lens::Ptr lens = lenses_.GetLensForShortcut(shortcut);
3870- if (lens)
3871- return lens->id;
3872+ Scope::Ptr scope = scopes_ ? scopes_->GetScopeForShortcut(shortcut) : Scope::Ptr();
3873+ if (scope)
3874+ return scope->id;
3875 return "";
3876 }
3877
3878@@ -1462,11 +1414,14 @@
3879 {
3880 std::vector<char> result;
3881
3882- for (Lens::Ptr lens: lenses_.GetLenses())
3883+ if (scopes_)
3884 {
3885- std::string shortcut = lens->shortcut;
3886- if(shortcut.size() > 0)
3887- result.push_back(shortcut.at(0));
3888+ for (Scope::Ptr scope: scopes_->GetScopes())
3889+ {
3890+ std::string shortcut = scope->shortcut;
3891+ if(shortcut.size() > 0)
3892+ result.push_back(shortcut.at(0));
3893+ }
3894 }
3895 return result;
3896 }
3897@@ -1505,8 +1460,8 @@
3898 dash::Style& style = dash::Style::Instance();
3899 int num_rows = 1; // The search bar
3900
3901- if (active_lens_view_.IsValid())
3902- num_rows += active_lens_view_->GetNumRows();
3903+ if (active_scope_view_.IsValid())
3904+ num_rows += active_scope_view_->GetNumRows();
3905
3906 std::string form_factor("unknown");
3907
3908@@ -1533,17 +1488,17 @@
3909 {
3910 return preview_container_->KeyNavIteration(direction);
3911 }
3912- else if (direction == nux::KEY_NAV_DOWN && search_bar_ && active_lens_view_.IsValid())
3913+ else if (direction == nux::KEY_NAV_DOWN && search_bar_ && active_scope_view_.IsValid())
3914 {
3915 auto show_filters = search_bar_->show_filters();
3916- auto fscroll_view = active_lens_view_->fscroll_view();
3917+ auto fscroll_view = active_scope_view_->fscroll_view();
3918
3919 if (show_filters && show_filters->HasKeyFocus())
3920 {
3921 if (fscroll_view->IsVisible() && fscroll_view)
3922 return fscroll_view->KeyNavIteration(direction);
3923 else
3924- return active_lens_view_->KeyNavIteration(direction);
3925+ return active_scope_view_->KeyNavIteration(direction);
3926 }
3927 }
3928 return this;
3929@@ -1621,9 +1576,9 @@
3930 if (direction != KEY_NAV_NONE && key_symbol == nux::NUX_KEYDOWN && !search_bar_->im_preedit)
3931 {
3932 std::list<nux::Area*> tabs;
3933- if (active_lens_view_.IsValid())
3934+ if (active_scope_view_.IsValid())
3935 {
3936- for (auto category : active_lens_view_->categories())
3937+ for (auto category : active_scope_view_->categories())
3938 {
3939 if (category->IsVisible())
3940 tabs.push_back(category);
3941@@ -1636,11 +1591,11 @@
3942 tabs.push_back(search_bar_->show_filters());
3943 }
3944
3945- if (active_lens_view_.IsValid() &&
3946- active_lens_view_->filter_bar() && active_lens_view_->fscroll_view() &&
3947- active_lens_view_->fscroll_view()->IsVisible())
3948+ if (active_scope_view_.IsValid() &&
3949+ active_scope_view_->filter_bar() && active_scope_view_->fscroll_view() &&
3950+ active_scope_view_->fscroll_view()->IsVisible())
3951 {
3952- for (auto child : active_lens_view_->filter_bar()->GetLayout()->GetChildren())
3953+ for (auto child : active_scope_view_->filter_bar()->GetLayout()->GetChildren())
3954 {
3955 FilterExpanderLabel* filter = dynamic_cast<FilterExpanderLabel*>(child);
3956 if (filter)
3957@@ -1652,7 +1607,7 @@
3958 {
3959 if (ctrl)
3960 {
3961- lens_bar_->ActivatePrevious();
3962+ scope_bar_->ActivatePrevious();
3963 }
3964 else
3965 {
3966@@ -1679,7 +1634,7 @@
3967 {
3968 if (ctrl)
3969 {
3970- lens_bar_->ActivateNext();
3971+ scope_bar_->ActivateNext();
3972 }
3973 else
3974 {
3975
3976=== modified file 'dash/DashView.h'
3977--- dash/DashView.h 2013-01-28 23:57:38 +0000
3978+++ dash/DashView.h 2013-02-21 10:37:29 +0000
3979@@ -24,8 +24,7 @@
3980 #include <Nux/View.h>
3981 #include <Nux/VLayout.h>
3982
3983-#include <UnityCore/FilesystemLenses.h>
3984-#include <UnityCore/HomeLens.h>
3985+#include <UnityCore/Scopes.h>
3986 #include <UnityCore/GLibSource.h>
3987
3988 #include "LensBar.h"
3989@@ -55,10 +54,12 @@
3990 class DashView : public nux::View, public unity::debug::Introspectable
3991 {
3992 NUX_DECLARE_OBJECT_TYPE(DashView, nux::View);
3993- typedef std::map<std::string, nux::ObjectPtr<LensView>> LensViews;
3994+ typedef std::map<std::string, nux::ObjectPtr<ScopeView>> ScopeViews;
3995
3996 public:
3997- DashView();
3998+ typedef std::function<void()> ScopesCreator;
3999+
4000+ DashView(ScopesCreator scopes_creator = nullptr);
4001 ~DashView();
4002
4003 void AboutToShow();
4004@@ -108,20 +109,17 @@
4005 void OnBackgroundColorChanged(GVariant* args);
4006 void OnSearchChanged(std::string const& search_string);
4007 void OnLiveSearchReached(std::string const& search_string);
4008- void OnLensAdded(Lens::Ptr& lens);
4009- void OnLensBarActivated(std::string const& id);
4010- void OnSearchFinished(Lens::Hints const& hints, glib::Error const& error);
4011- void OnGlobalSearchFinished(Lens::Hints const& hints, glib::Error const& error);
4012- void OnAppsGlobalSearchFinished(Lens::Ptr const& lens);
4013+ void OnScopeAdded(Scope::Ptr const& scope, int position);
4014+ void OnScopeBarActivated(std::string const& id);
4015+ void OnSearchFinished(glib::HintsMap const& hints, glib::Error const& error);
4016 void OnUriActivated(ResultView::ActivateType type, std::string const& uri, GVariant* data, std::string const& unique_id);
4017- void OnUriActivatedReply(std::string const& uri, HandledType type, Lens::Hints const&);
4018+ void OnUriActivatedReply(std::string const& uri, ScopeHandledType type, glib::HintsMap const& hints);
4019 bool DoFallbackActivation(std::string const& uri);
4020 bool LaunchApp(std::string const& appname);
4021 void OnEntryActivated();
4022- std::string AnalyseLensURI(std::string const& uri);
4023- void UpdateLensFilter(std::string lens, std::string filter, std::string value);
4024- void UpdateLensFilterValue(Filter::Ptr filter, std::string value);
4025- void EnsureLensesInitialized();
4026+ std::string AnalyseScopeURI(std::string const& uri);
4027+ void UpdateScopeFilter(std::string scope_id, std::string filter, std::string value);
4028+ void UpdateScopeFilterValue(Filter::Ptr filter, std::string value);
4029
4030 bool AcceptKeyNavFocus();
4031 bool InspectKeyEvent(unsigned int eventType, unsigned int key_sym, const char* character);
4032@@ -131,9 +129,8 @@
4033 nux::Area* KeyNavIteration(nux::KeyNavDirection direction);
4034
4035 UBusManager ubus_manager_;
4036- FilesystemLenses lenses_;
4037- HomeLens::Ptr home_lens_;
4038- LensViews lens_views_;
4039+ Scopes::Ptr scopes_;
4040+ ScopeViews scope_views_;
4041
4042 // View related
4043 PreviewStateMachine preview_state_machine_;
4044@@ -147,12 +144,12 @@
4045 nux::View* content_view_;
4046 nux::HLayout* search_bar_layout_;
4047 SearchBar* search_bar_;
4048- nux::VLayout* lenses_layout_;
4049- LensBar* lens_bar_;
4050+ nux::VLayout* scopes_layout_;
4051+ ScopeBar* scope_bar_;
4052
4053- nux::ObjectPtr<LensView> home_view_;
4054- nux::ObjectPtr<LensView> active_lens_view_;
4055- nux::ObjectPtr<LensView> preview_lens_view_;
4056+ nux::ObjectPtr<ScopeView> active_scope_view_;
4057+ nux::ObjectPtr<ScopeView> preview_scope_view_;
4058+ sigc::connection scope_can_refine_connection_;
4059
4060 // Drawing related
4061 nux::Geometry content_geo_;
4062@@ -165,6 +162,7 @@
4063
4064 bool visible_;
4065
4066+ glib::Source::UniquePtr init_timeout_;
4067 glib::Source::UniquePtr searching_timeout_;
4068 glib::Source::UniquePtr hide_message_delay_;
4069
4070
4071=== modified file 'dash/DashViewPrivate.cpp'
4072--- dash/DashViewPrivate.cpp 2012-05-06 23:48:38 +0000
4073+++ dash/DashViewPrivate.cpp 2013-02-21 10:37:29 +0000
4074@@ -28,9 +28,9 @@
4075 namespace impl
4076 {
4077
4078-LensFilter parse_lens_uri(std::string const& uri)
4079+ScopeFilter parse_scope_uri(std::string const& uri)
4080 {
4081- LensFilter filter;
4082+ ScopeFilter filter;
4083
4084 filter.id = uri;
4085 std::size_t pos = uri.find("?");
4086
4087=== modified file 'dash/DashViewPrivate.h'
4088--- dash/DashViewPrivate.h 2012-05-06 23:48:38 +0000
4089+++ dash/DashViewPrivate.h 2013-02-21 10:37:29 +0000
4090@@ -35,7 +35,9 @@
4091 std::map<std::string, std::string> filters;
4092 };
4093
4094-LensFilter parse_lens_uri(std::string const& uri);
4095+typedef LensFilter ScopeFilter;
4096+
4097+ScopeFilter parse_scope_uri(std::string const& uri);
4098
4099 } // namespace impl
4100 } // namespace dash
4101
4102=== modified file 'dash/FilterBar.cpp'
4103--- dash/FilterBar.cpp 2012-11-27 23:37:20 +0000
4104+++ dash/FilterBar.cpp 2013-02-21 10:37:29 +0000
4105@@ -33,17 +33,13 @@
4106 {
4107 namespace dash
4108 {
4109-DECLARE_LOGGER(logger, "unity.dash.filter.bar");
4110+DECLARE_LOGGER(logger, "unity.dash.filterbar");
4111
4112 NUX_IMPLEMENT_OBJECT_TYPE(FilterBar);
4113
4114 FilterBar::FilterBar(NUX_FILE_LINE_DECL)
4115 : View(NUX_FILE_LINE_PARAM)
4116 {
4117- // TODO - does the filterbar associate itself with a model of some sort?
4118- // does libunity provide a Lens.Filters model or something that we can update on?
4119- // don't want to associate a Filterbar with just a lens model, its a filter bar not a
4120- // lens parser
4121 Init();
4122 }
4123
4124@@ -95,6 +91,17 @@
4125 }
4126 }
4127
4128+void FilterBar::ClearFilters()
4129+{
4130+ for (auto iter: filter_map_)
4131+ {
4132+ FilterExpanderLabel* filter_view = iter.second;
4133+ RemoveChild(filter_view);
4134+ GetLayout()->RemoveChildObject(filter_view);
4135+ }
4136+ filter_map_.clear();
4137+}
4138+
4139 void FilterBar::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw)
4140 {
4141
4142
4143=== modified file 'dash/FilterBar.h'
4144--- dash/FilterBar.h 2012-09-13 13:15:29 +0000
4145+++ dash/FilterBar.h 2013-02-21 10:37:29 +0000
4146@@ -48,6 +48,7 @@
4147
4148 void AddFilter(Filter::Ptr const& filter);
4149 void RemoveFilter(Filter::Ptr const& filter);
4150+ void ClearFilters();
4151
4152 protected:
4153 virtual bool AcceptKeyNavFocus();
4154
4155=== modified file 'dash/FilterRatingsButton.cpp'
4156--- dash/FilterRatingsButton.cpp 2012-12-18 11:41:38 +0000
4157+++ dash/FilterRatingsButton.cpp 2013-02-21 10:37:29 +0000
4158@@ -90,7 +90,7 @@
4159 // FIXME: 9/26/2011
4160 // We should probably support an API for saying whether the ratings
4161 // should or shouldn't support half stars...but our only consumer at
4162- // the moment is the applications lens which according to design
4163+ // the moment is the applications scope which according to design
4164 // (Bug #839759) shouldn't. So for now just force rounding.
4165 // int total_half_stars = rating % 2;
4166 // int total_full_stars = rating / 2;
4167
4168=== modified file 'dash/LensBar.cpp'
4169--- dash/LensBar.cpp 2012-12-17 18:00:40 +0000
4170+++ dash/LensBar.cpp 2013-02-21 10:37:29 +0000
4171@@ -27,25 +27,24 @@
4172 #include "unity-shared/StaticCairoText.h"
4173 #include "unity-shared/CairoTexture.h"
4174 #include "unity-shared/GraphicsUtils.h"
4175-#include "LensBar.h"
4176 #include "unity-shared/UBusMessages.h"
4177
4178 namespace unity
4179 {
4180 namespace dash
4181 {
4182-DECLARE_LOGGER(logger, "unity.dash.lensbar");
4183+DECLARE_LOGGER(logger, "unity.dash.scopebar");
4184 namespace
4185 {
4186-// according to Q design the inner area of the lensbar should be 40px
4187+// according to Q design the inner area of the scopebar should be 40px
4188 // (without any borders)
4189-const int LENSBAR_HEIGHT = 41;
4190+const int SCOPEBAR_HEIGHT = 41;
4191
4192 }
4193
4194-NUX_IMPLEMENT_OBJECT_TYPE(LensBar);
4195+NUX_IMPLEMENT_OBJECT_TYPE(ScopeBar);
4196
4197-LensBar::LensBar()
4198+ScopeBar::ScopeBar()
4199 : nux::View(NUX_TRACKER_LOCATION)
4200 , info_previously_shown_(false)
4201 {
4202@@ -55,10 +54,9 @@
4203
4204 SetupBackground();
4205 SetupLayout();
4206- SetupHomeLens();
4207 }
4208
4209-void LensBar::SetupBackground()
4210+void ScopeBar::SetupBackground()
4211 {
4212 nux::ROPConfig rop;
4213 rop.Blend = true;
4214@@ -67,7 +65,7 @@
4215 bg_layer_.reset(new nux::ColorLayer(nux::Color(0.0f, 0.0f, 0.0f, 0.2f), true, rop));
4216 }
4217
4218-void LensBar::SetupLayout()
4219+void ScopeBar::SetupLayout()
4220 {
4221 legal_layout_ = new nux::HLayout(NUX_TRACKER_LOCATION);
4222 std::string legal_text("<span underline='single'>");
4223@@ -113,24 +111,11 @@
4224
4225 SetLayout(layered_layout_);
4226
4227- SetMinimumHeight(LENSBAR_HEIGHT);
4228- SetMaximumHeight(LENSBAR_HEIGHT);
4229-}
4230-
4231-void LensBar::SetupHomeLens()
4232-{
4233- LensBarIcon* icon = new LensBarIcon("home.lens", PKGDATADIR"/lens-nav-home.svg");
4234- icon->SetVisible(true);
4235- icon->active = true;
4236- icons_.push_back(icon);
4237- layout_->AddView(icon, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL);
4238- AddChild(icon);
4239-
4240- icon->mouse_click.connect([&, icon] (int x, int y, unsigned long button, unsigned long keyboard) { SetActive(icon); });
4241- icon->key_nav_focus_activate.connect([&, icon](nux::Area*){ SetActive(icon); });
4242-}
4243-
4244-void LensBar::DoOpenLegalise()
4245+ SetMinimumHeight(SCOPEBAR_HEIGHT);
4246+ SetMaximumHeight(SCOPEBAR_HEIGHT);
4247+}
4248+
4249+void ScopeBar::DoOpenLegalise()
4250 {
4251 glib::Error error;
4252 std::string legal_file_path = "file://";
4253@@ -147,11 +132,12 @@
4254 ubus_.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST);
4255 }
4256
4257-void LensBar::AddLens(Lens::Ptr& lens)
4258+void ScopeBar::AddScope(Scope::Ptr const& scope)
4259 {
4260- LensBarIcon* icon = new LensBarIcon(lens->id, lens->icon_hint);
4261- icon->SetVisible(lens->visible);
4262- lens->visible.changed.connect([icon](bool visible) { icon->SetVisible(visible); } );
4263+ ScopeBarIcon* icon = new ScopeBarIcon(scope->id, scope->icon_hint);
4264+
4265+ icon->SetVisible(scope->visible);
4266+ scope->visible.changed.connect([icon](bool visible) { icon->SetVisible(visible); } );
4267 icons_.push_back(icon);
4268 layout_->AddView(icon, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FIX);
4269 AddChild(icon);
4270@@ -160,7 +146,7 @@
4271 icon->key_nav_focus_activate.connect([&, icon](nux::Area*){ SetActive(icon); });
4272 }
4273
4274-void LensBar::Activate(std::string id)
4275+void ScopeBar::Activate(std::string id)
4276 {
4277 for (auto icon: icons_)
4278 {
4279@@ -172,7 +158,7 @@
4280 }
4281 }
4282
4283-void LensBar::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw)
4284+void ScopeBar::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw)
4285 {
4286 nux::Geometry const& base = GetGeometry();
4287
4288@@ -190,7 +176,7 @@
4289 graphics_engine.PopClippingRectangle();
4290 }
4291
4292-void LensBar::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw)
4293+void ScopeBar::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw)
4294 {
4295 nux::Geometry const& base = GetGeometry();
4296
4297@@ -201,7 +187,7 @@
4298 {
4299 if (RedirectedAncestor())
4300 {
4301- // Whole Lens bar needs to be cleared because the PaintAll forces redraw.
4302+ // Whole Scope bar needs to be cleared because the PaintAll forces redraw.
4303 graphics::ClearGeometry(base);
4304 }
4305
4306@@ -251,10 +237,10 @@
4307 graphics_engine.PopClippingRectangle();
4308 }
4309
4310-nux::Area* LensBar::FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type)
4311+nux::Area* ScopeBar::FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type)
4312 {
4313 //LayeredLayout is acting a little screwy, events are not passing past the first layout like instructed,
4314- //so we manually override if the cursor is on the right hand side of the lensbar
4315+ //so we manually override if the cursor is on the right hand side of the scopebar
4316 auto geo = GetAbsoluteGeometry();
4317 int info_width = (info_previously_shown_) ? info_icon_->GetGeometry().width : legal_->GetGeometry().width;
4318
4319@@ -272,7 +258,7 @@
4320
4321 }
4322
4323-void LensBar::SetActive(LensBarIcon* activated)
4324+void ScopeBar::SetActive(ScopeBarIcon* activated)
4325 {
4326 bool state_changed = false;
4327
4328@@ -287,13 +273,13 @@
4329 }
4330
4331 if (state_changed)
4332- lens_activated.emit(activated->id);
4333+ scope_activated.emit(activated->id);
4334 }
4335
4336-void LensBar::ActivateNext()
4337+void ScopeBar::ActivateNext()
4338 {
4339- // Special case when switching from the command lens.
4340- if (GetActiveLensId() == "commands.lens")
4341+ // Special case when switching from the command scope.
4342+ if (GetActiveScopeId() == "commands.scope")
4343 {
4344 SetActive(icons_[0]);
4345 return;
4346@@ -304,7 +290,7 @@
4347 it < icons_.end();
4348 it++)
4349 {
4350- LensBarIcon *icon = *it;
4351+ ScopeBarIcon *icon = *it;
4352
4353 if (activate_next && icon->IsVisible())
4354 {
4355@@ -318,10 +304,10 @@
4356
4357 }
4358
4359-void LensBar::ActivatePrevious()
4360+void ScopeBar::ActivatePrevious()
4361 {
4362- // Special case when switching from the command lens.
4363- if (GetActiveLensId() == "commands.lens")
4364+ // Special case when switching from the command scope.
4365+ if (GetActiveScopeId() == "commands.scope")
4366 {
4367 SetActive(icons_.back());
4368 return;
4369@@ -332,7 +318,7 @@
4370 it < icons_.rend();
4371 ++it)
4372 {
4373- LensBarIcon *icon = *it;
4374+ ScopeBarIcon *icon = *it;
4375
4376 if (activate_previous && icon->IsVisible())
4377 {
4378@@ -347,34 +333,34 @@
4379 }
4380
4381 // Keyboard navigation
4382-bool LensBar::AcceptKeyNavFocus()
4383+bool ScopeBar::AcceptKeyNavFocus()
4384 {
4385 return false;
4386 }
4387
4388 // Introspectable
4389-std::string LensBar::GetName() const
4390+std::string ScopeBar::GetName() const
4391 {
4392- return "LensBar";
4393+ return "ScopeBar";
4394 }
4395
4396-void LensBar::AddProperties(GVariantBuilder* builder)
4397+void ScopeBar::AddProperties(GVariantBuilder* builder)
4398 {
4399 unity::variant::BuilderWrapper wrapper(builder);
4400
4401- wrapper.add("focused-lens-icon", "");
4402+ wrapper.add("focused-scope-icon", "");
4403
4404 for( auto icon : icons_)
4405 {
4406 if (icon->active)
4407- wrapper.add("active-lens", icon->id.Get());
4408+ wrapper.add("active-scope", icon->id.Get());
4409
4410 if (icon->HasKeyFocus())
4411- wrapper.add("focused-lens-icon", icon->id.Get());
4412+ wrapper.add("focused-scope-icon", icon->id.Get());
4413 }
4414 }
4415
4416-std::string LensBar::GetActiveLensId() const
4417+std::string ScopeBar::GetActiveScopeId() const
4418 {
4419 for (auto icon : icons_)
4420 {
4421
4422=== modified file 'dash/LensBar.h'
4423--- dash/LensBar.h 2012-12-14 12:14:34 +0000
4424+++ dash/LensBar.h 2013-02-21 10:37:29 +0000
4425@@ -27,7 +27,7 @@
4426 #include <Nux/Nux.h>
4427 #include <Nux/PaintLayer.h>
4428 #include <Nux/View.h>
4429-#include <UnityCore/Lens.h>
4430+#include <UnityCore/Scope.h>
4431
4432 #include "unity-shared/IconTexture.h"
4433 #include "unity-shared/Introspectable.h"
4434@@ -49,25 +49,24 @@
4435 namespace dash
4436 {
4437
4438-class LensBar : public nux::View, public unity::debug::Introspectable
4439+class ScopeBar : public nux::View, public unity::debug::Introspectable
4440 {
4441- NUX_DECLARE_OBJECT_TYPE(LensBar, nux::View);
4442- typedef std::vector<LensBarIcon*> LensIcons;
4443+ NUX_DECLARE_OBJECT_TYPE(ScopeBar, nux::View);
4444+ typedef std::vector<ScopeBarIcon*> ScopeIcons;
4445
4446 public:
4447- LensBar();
4448+ ScopeBar();
4449
4450- void AddLens(Lens::Ptr& lens);
4451+ void AddScope(Scope::Ptr const& scope);
4452 void Activate(std::string id);
4453 void ActivateNext();
4454 void ActivatePrevious();
4455
4456- sigc::signal<void, std::string const&> lens_activated;
4457+ sigc::signal<void, std::string const&> scope_activated;
4458
4459 private:
4460 void SetupBackground();
4461 void SetupLayout();
4462- void SetupHomeLens();
4463 void DoOpenLegalise();
4464
4465 void Draw(nux::GraphicsEngine& gfx_context, bool force_draw);
4466@@ -75,16 +74,16 @@
4467
4468 nux::Area* FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type);
4469
4470- void SetActive(LensBarIcon* icon);
4471+ void SetActive(ScopeBarIcon* icon);
4472
4473 bool AcceptKeyNavFocus();
4474 std::string GetName() const;
4475 void AddProperties(GVariantBuilder* builder);
4476
4477- std::string GetActiveLensId() const;
4478+ std::string GetActiveScopeId() const;
4479 typedef std::unique_ptr<nux::AbstractPaintLayer> LayerPtr;
4480
4481- LensIcons icons_;
4482+ ScopeIcons icons_;
4483
4484 UBusManager ubus_;
4485
4486@@ -97,6 +96,8 @@
4487
4488 bool info_previously_shown_;
4489 std::string legal_seen_file_path_;
4490+
4491+ friend class TestScopeBar;
4492 };
4493
4494 } // namespace dash
4495
4496=== modified file 'dash/LensBarIcon.cpp'
4497--- dash/LensBarIcon.cpp 2012-12-17 09:28:31 +0000
4498+++ dash/LensBarIcon.cpp 2013-02-21 10:37:29 +0000
4499@@ -35,9 +35,9 @@
4500
4501 }
4502
4503-NUX_IMPLEMENT_OBJECT_TYPE(LensBarIcon);
4504+NUX_IMPLEMENT_OBJECT_TYPE(ScopeBarIcon);
4505
4506-LensBarIcon::LensBarIcon(std::string id_, std::string icon_hint)
4507+ScopeBarIcon::ScopeBarIcon(std::string id_, std::string icon_hint)
4508 : IconTexture(icon_hint, 24)
4509 , id(id_)
4510 , active(false)
4511@@ -56,14 +56,14 @@
4512 SetAcceptKeyNavFocusOnMouseDown(false);
4513 SetAcceptKeyNavFocusOnMouseEnter(true);
4514
4515- active.changed.connect(sigc::mem_fun(this, &LensBarIcon::OnActiveChanged));
4516+ active.changed.connect(sigc::mem_fun(this, &ScopeBarIcon::OnActiveChanged));
4517 key_nav_focus_change.connect([&](nux::Area*, bool, nux::KeyNavDirection){ QueueDraw(); });
4518 }
4519
4520-LensBarIcon::~LensBarIcon()
4521+ScopeBarIcon::~ScopeBarIcon()
4522 {}
4523
4524-void LensBarIcon::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw)
4525+void ScopeBarIcon::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw)
4526 {
4527 nux::Geometry const& geo = GetGeometry();
4528
4529@@ -109,18 +109,18 @@
4530 graphics_engine.PopClippingRectangle();
4531 }
4532
4533-void LensBarIcon::OnActiveChanged(bool is_active)
4534+void ScopeBarIcon::OnActiveChanged(bool is_active)
4535 {
4536 QueueDraw();
4537 }
4538
4539 // Introspectable
4540-std::string LensBarIcon::GetName() const
4541+std::string ScopeBarIcon::GetName() const
4542 {
4543- return "LensBarIcon";
4544+ return "ScopeBarIcon";
4545 }
4546
4547-void LensBarIcon::AddProperties(GVariantBuilder* builder)
4548+void ScopeBarIcon::AddProperties(GVariantBuilder* builder)
4549 {
4550 unity::variant::BuilderWrapper wrapper(builder);
4551
4552
4553=== modified file 'dash/LensBarIcon.h'
4554--- dash/LensBarIcon.h 2012-05-06 23:48:38 +0000
4555+++ dash/LensBarIcon.h 2013-02-21 10:37:29 +0000
4556@@ -33,12 +33,12 @@
4557 namespace dash
4558 {
4559
4560-class LensBarIcon : public IconTexture
4561+class ScopeBarIcon : public IconTexture
4562 {
4563- NUX_DECLARE_OBJECT_TYPE(LensBarIcon, IconTexture);
4564+ NUX_DECLARE_OBJECT_TYPE(ScopeBarIcon, IconTexture);
4565 public:
4566- LensBarIcon(std::string id, std::string icon_hint);
4567- ~LensBarIcon();
4568+ ScopeBarIcon(std::string id, std::string icon_hint);
4569+ ~ScopeBarIcon();
4570
4571 nux::Property<std::string> id;
4572 nux::Property<bool> active;
4573
4574=== modified file 'dash/LensView.cpp'
4575--- dash/LensView.cpp 2013-01-15 21:53:55 +0000
4576+++ dash/LensView.cpp 2013-02-21 10:37:29 +0000
4577@@ -43,7 +43,7 @@
4578 {
4579 namespace dash
4580 {
4581-DECLARE_LOGGER(logger, "unity.dash.lensview");
4582+DECLARE_LOGGER(logger, "unity.dash.scopeview");
4583 namespace
4584 {
4585 const int CARD_VIEW_GAP_VERT = 24; // pixels
4586@@ -51,10 +51,10 @@
4587 }
4588
4589 // This is so we can access some protected members in scrollview.
4590-class LensScrollView: public nux::ScrollView
4591+class ScopeScrollView: public nux::ScrollView
4592 {
4593 public:
4594- LensScrollView(nux::VScrollBar* scroll_bar, NUX_FILE_LINE_DECL)
4595+ ScopeScrollView(nux::VScrollBar* scroll_bar, NUX_FILE_LINE_DECL)
4596 : nux::ScrollView(NUX_FILE_LINE_PARAM)
4597 , right_area_(nullptr)
4598 , up_area_(nullptr)
4599@@ -146,37 +146,36 @@
4600 };
4601
4602
4603-NUX_IMPLEMENT_OBJECT_TYPE(LensView);
4604+NUX_IMPLEMENT_OBJECT_TYPE(ScopeView);
4605
4606-LensView::LensView(Lens::Ptr lens, nux::Area* show_filters)
4607- : nux::View(NUX_TRACKER_LOCATION)
4608- , filters_expanded(false)
4609- , can_refine_search(false)
4610- , lens_(lens)
4611- , initial_activation_(true)
4612- , no_results_active_(false)
4613- , last_expanded_group_(nullptr)
4614- , last_good_filter_model_(-1)
4615- , filter_expansion_pushed_(false)
4616+ScopeView::ScopeView(Scope::Ptr scope, nux::Area* show_filters)
4617+: nux::View(NUX_TRACKER_LOCATION)
4618+, filters_expanded(false)
4619+, can_refine_search(false)
4620+, scope_(scope)
4621+, cancellable_(g_cancellable_new())
4622+, initial_activation_(true)
4623+, no_results_active_(false)
4624+, last_expanded_group_(nullptr)
4625+, last_good_filter_model_(-1)
4626+, filter_expansion_pushed_(false)
4627 {
4628 SetupViews(show_filters);
4629 SetupCategories();
4630 SetupResults();
4631 SetupFilters();
4632
4633- dash::Style::Instance().columns_changed.connect(sigc::mem_fun(this, &LensView::OnColumnsChanged));
4634+ dash::Style::Instance().columns_changed.connect(sigc::mem_fun(this, &ScopeView::OnColumnsChanged));
4635
4636- search_string.SetGetterFunction(sigc::mem_fun(this, &LensView::get_search_string));
4637- filters_expanded.changed.connect(sigc::mem_fun(this, &LensView::OnLensFilterExpanded));
4638- view_type.changed.connect(sigc::mem_fun(this, &LensView::OnViewTypeChanged));
4639- if (lens_)
4640+ search_string.SetGetterFunction(sigc::mem_fun(this, &ScopeView::get_search_string));
4641+ filters_expanded.changed.connect(sigc::mem_fun(this, &ScopeView::OnScopeFilterExpanded));
4642+ view_type.changed.connect(sigc::mem_fun(this, &ScopeView::OnViewTypeChanged));
4643+ if (scope_)
4644 {
4645- lens_->connected.changed.connect([&](bool is_connected)
4646- {
4647+ scope_->connected.changed.connect([&](bool is_connected) {
4648 if (is_connected)
4649 initial_activation_ = true;
4650 });
4651- lens_->categories_reordered.connect(sigc::mem_fun(this, &LensView::OnCategoryOrderChanged));
4652 }
4653
4654 ubus_manager_.RegisterInterest(UBUS_RESULT_VIEW_KEYNAV_CHANGED, [&] (GVariant* data) {
4655@@ -209,17 +208,28 @@
4656 OnVisibleChanged.connect([&] (nux::Area* area, bool visible) {
4657 scroll_view_->SetVisible(visible);
4658 });
4659-
4660-}
4661-
4662-void LensView::SetupViews(nux::Area* show_filters)
4663+}
4664+
4665+ScopeView::~ScopeView()
4666+{
4667+ result_added_connection.disconnect();
4668+ result_removed_connection.disconnect();
4669+ category_added_connection.disconnect();
4670+ category_removed_connection.disconnect();
4671+ filter_added_connection.disconnect();
4672+ filter_removed_connection.disconnect();
4673+
4674+ g_cancellable_cancel(cancellable_);
4675+}
4676+
4677+void ScopeView::SetupViews(nux::Area* show_filters)
4678 {
4679 dash::Style& style = dash::Style::Instance();
4680
4681 layout_ = new nux::HLayout(NUX_TRACKER_LOCATION);
4682- layout_->SetSpaceBetweenChildren(style.GetSpaceBetweenLensAndFilters());
4683+ layout_->SetSpaceBetweenChildren(style.GetSpaceBetweenScopeAndFilters());
4684
4685- scroll_view_ = new LensScrollView(new PlacesOverlayVScrollBar(NUX_TRACKER_LOCATION),
4686+ scroll_view_ = new ScopeScrollView(new PlacesOverlayVScrollBar(NUX_TRACKER_LOCATION),
4687 NUX_TRACKER_LOCATION);
4688 scroll_view_->EnableVerticalScrollBar(true);
4689 scroll_view_->EnableHorizontalScrollBar(false);
4690@@ -239,7 +249,7 @@
4691 no_results_->SetVisible(false);
4692 scroll_layout_->AddView(no_results_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT);
4693
4694- fscroll_view_ = new LensScrollView(new PlacesVScrollBar(NUX_TRACKER_LOCATION), NUX_TRACKER_LOCATION);
4695+ fscroll_view_ = new ScopeScrollView(new PlacesVScrollBar(NUX_TRACKER_LOCATION), NUX_TRACKER_LOCATION);
4696 fscroll_view_->EnableVerticalScrollBar(true);
4697 fscroll_view_->EnableHorizontalScrollBar(false);
4698 fscroll_view_->SetVisible(false);
4699@@ -264,35 +274,48 @@
4700 SetLayout(layout_);
4701 }
4702
4703-void LensView::SetupCategories()
4704+void ScopeView::SetupCategories()
4705 {
4706- if (!lens_)
4707+ if (!scope_)
4708 return;
4709
4710- Categories::Ptr categories = lens_->categories;
4711- categories->category_added.connect(sigc::mem_fun(this, &LensView::OnCategoryAdded));
4712-
4713- for (unsigned int i = 0; i < categories->count(); ++i)
4714- OnCategoryAdded(categories->RowAtIndex(i));
4715+ Categories::Ptr categories = scope_->categories;
4716+ category_added_connection = categories->category_added.connect(sigc::mem_fun(this, &ScopeView::OnCategoryAdded));
4717+ category_removed_connection = categories->category_removed.connect(sigc::mem_fun(this, &ScopeView::OnCategoryRemoved));
4718+
4719+ auto resync_categories = [categories, this] (glib::Object<DeeModel> model)
4720+ {
4721+ ClearCategories();
4722+ for (unsigned int i = 0; i < categories->count(); ++i)
4723+ OnCategoryAdded(categories->RowAtIndex(i));
4724+ };
4725+
4726+ categories->model.changed.connect(resync_categories);
4727+ resync_categories(categories->model());
4728+
4729+ scope_->category_order.changed.connect([this](std::vector<int> const& category_order) {
4730+ LOG_DEBUG(logger) << scope_->id() << ": category order changed";
4731+ });
4732 }
4733
4734-void LensView::SetupResults()
4735+void ScopeView::SetupResults()
4736 {
4737- if (!lens_)
4738+ if (!scope_)
4739 return;
4740
4741- Results::Ptr results = lens_->results;
4742- results->result_added.connect(sigc::mem_fun(this, &LensView::OnResultAdded));
4743- results->result_removed.connect(sigc::mem_fun(this, &LensView::OnResultRemoved));
4744+ Results::Ptr results = scope_->results;
4745+ result_added_connection = results->result_added.connect(sigc::mem_fun(this, &ScopeView::OnResultAdded));
4746+ result_added_connection = results->result_removed.connect(sigc::mem_fun(this, &ScopeView::OnResultRemoved));
4747
4748 results->model.changed.connect([this] (glib::Object<DeeModel> model)
4749 {
4750 for (unsigned int i = 0; i < categories_.size(); ++i)
4751 {
4752 ResultViewGrid* grid = GetGridForCategory(i);
4753- glib::Object<DeeModel> filter_model(lens_->GetFilterModelForCategory(i));
4754- Results::Ptr results_model = lens_->results;
4755- grid->SetModel(filter_model, results_model->GetTag());
4756+ if (grid)
4757+ {
4758+ grid->SetResultsModel(scope_->GetResultsForCategory(i));
4759+ }
4760 }
4761 });
4762
4763@@ -300,20 +323,31 @@
4764 OnResultAdded(results->RowAtIndex(i));
4765 }
4766
4767-void LensView::SetupFilters()
4768+void ScopeView::SetupFilters()
4769 {
4770- if (!lens_)
4771+ if (!scope_)
4772 return;
4773
4774- Filters::Ptr filters = lens_->filters;
4775- filters->filter_added.connect(sigc::mem_fun(this, &LensView::OnFilterAdded));
4776- filters->filter_removed.connect(sigc::mem_fun(this, &LensView::OnFilterRemoved));
4777-
4778- for (unsigned int i = 0; i < filters->count(); ++i)
4779- OnFilterAdded(filters->FilterAtIndex(i));
4780+ Filters::Ptr filters = scope_->filters;
4781+ filter_added_connection = filters->filter_added.connect(sigc::mem_fun(this, &ScopeView::OnFilterAdded));
4782+ filter_removed_connection = filters->filter_removed.connect(sigc::mem_fun(this, &ScopeView::OnFilterRemoved));
4783+
4784+ auto resync_filters = [filters, this] (glib::Object<DeeModel> model)
4785+ {
4786+ bool blocked = filter_added_connection.block(true);
4787+
4788+ filter_bar_->ClearFilters();
4789+ for (unsigned int i = 0; i < filters->count(); ++i)
4790+ OnFilterAdded(filters->FilterAtIndex(i));
4791+
4792+ filter_added_connection.block(blocked);
4793+ };
4794+
4795+ filters->model.changed.connect(resync_filters);
4796+ resync_filters(filters->model());
4797 }
4798
4799-void LensView::OnCategoryAdded(Category const& category)
4800+void ScopeView::OnCategoryAdded(Category const& category)
4801 {
4802 std::string name = category.name;
4803 std::string icon_hint = category.icon_hint;
4804@@ -328,10 +362,11 @@
4805
4806 if (index < categories_.size())
4807 {
4808- // the lens might have restarted and we don't want to create
4809+ // the scope might have restarted and we don't want to create
4810 // new PlacesGroup if we can reuse the old one
4811 PlacesGroup* existing_group = categories_.at(index);
4812- if (existing_group->GetCategoryIndex() == index) return;
4813+ if (existing_group->GetCategoryIndex() == index)
4814+ return;
4815 }
4816
4817 PlacesGroup* group = CreatePlacesGroup();
4818@@ -341,7 +376,7 @@
4819 group->SetCategoryIndex(index);
4820 group->SetExpanded(false);
4821 group->SetVisible(false);
4822- group->expanded.connect(sigc::mem_fun(this, &LensView::OnGroupExpanded));
4823+ group->expanded.connect(sigc::mem_fun(this, &ScopeView::OnGroupExpanded));
4824
4825 reset_filter_models = index < categories_.size();
4826 /* Add the group at the correct offset into the categories vector */
4827@@ -375,9 +410,9 @@
4828 }
4829 group->SetChildView(grid);
4830
4831- if (lens_)
4832+ if (scope_)
4833 {
4834- std::string unique_id = name + lens_->name();
4835+ std::string unique_id = name + scope_->name();
4836 grid->unique_id = unique_id;
4837 grid->expanded = false;
4838
4839@@ -389,24 +424,21 @@
4840 {
4841 case ResultView::ActivateType::DIRECT:
4842 {
4843- lens_->Activate(uri);
4844+ scope_->Activate(uri, nullptr, cancellable_);
4845 } break;
4846 case ResultView::ActivateType::PREVIEW:
4847 {
4848- lens_->Preview(uri);
4849+ scope_->Preview(uri, nullptr, cancellable_);
4850 } break;
4851 default: break;
4852 };
4853 });
4854
4855-
4856 /* Set up filter model for this category */
4857- Results::Ptr results_model = lens_->results;
4858- if (results_model->model())
4859- {
4860- glib::Object<DeeModel> filter_model(lens_->GetFilterModelForCategory(index));
4861- grid->SetModel(filter_model, results_model->GetTag());
4862- }
4863+ Results::Ptr results_model = scope_->GetResultsForCategory(index);
4864+ counts_[group] = results_model ? results_model->count() : 0;
4865+
4866+ grid->SetResultsModel(results_model);
4867
4868 if (reset_filter_models)
4869 {
4870@@ -416,7 +448,7 @@
4871 for (auto it = categories_.begin() + (index + 1); it != categories_.end(); ++it)
4872 {
4873 grid = static_cast<ResultViewGrid*>((*it)->GetChildView());
4874- grid->SetModel(glib::Object<DeeModel>(), NULL);
4875+ grid->SetResultsModel(Results::Ptr());
4876 }
4877
4878 if (static_cast<int>(index) < last_good_filter_model_ || last_good_filter_model_ < 0)
4879@@ -425,7 +457,7 @@
4880 }
4881 if (!fix_filter_models_idle_)
4882 {
4883- fix_filter_models_idle_.reset(new glib::Idle(sigc::mem_fun(this, &LensView::ReinitializeFilterModels), glib::Source::Priority::HIGH));
4884+ fix_filter_models_idle_.reset(new glib::Idle(sigc::mem_fun(this, &ScopeView::ReinitializeFilterModels), glib::Source::Priority::HIGH));
4885 }
4886 }
4887 }
4888@@ -435,50 +467,59 @@
4889 scroll_layout_->AddView(group, 0, nux::MinorDimensionPosition::MINOR_POSITION_START,
4890 nux::MinorDimensionSize::MINOR_SIZE_FULL, 100.0f,
4891 (nux::LayoutPosition)index);
4892-}
4893-
4894-void LensView::OnCategoryOrderChanged()
4895-{
4896- LOG_DEBUG(logger) << "Reordering categories for " << lens_->name();
4897-
4898- // need references so that the Layout doesn't destroy the views
4899- std::vector<nux::ObjectPtr<PlacesGroup> > child_views;
4900- for (unsigned i = 0; i < categories_.size(); i++)
4901- {
4902- child_views.push_back(nux::ObjectPtr<PlacesGroup>(categories_.at(i)));
4903- scroll_layout_->RemoveChildObject(categories_.at(i));
4904- }
4905-
4906- if (lens_)
4907- {
4908- // there should be ~10 categories, so this shouldn't be too big of a deal
4909- std::vector<unsigned> order(lens_->GetCategoriesOrder());
4910- for (unsigned i = 0; i < order.size(); i++)
4911- {
4912- unsigned desired_category_index = order[i];
4913- for (unsigned j = 0; j < child_views.size(); j++)
4914- {
4915- if (child_views[j]->GetCategoryIndex() == desired_category_index)
4916- {
4917- scroll_layout_->AddView(child_views[j].GetPointer(), 0);
4918- break;
4919- }
4920- }
4921- }
4922- }
4923-}
4924-
4925-bool LensView::ReinitializeFilterModels()
4926-{
4927- if (!lens_)
4928+
4929+ UpdateCounts(group);
4930+}
4931+
4932+void ScopeView::OnCategoryRemoved(Category const& category)
4933+{
4934+ std::string name = category.name;
4935+ std::string icon_hint = category.icon_hint;
4936+ std::string renderer_name = category.renderer_name;
4937+ unsigned index = (category.index == unsigned(-1)) ? categories_.size() : category.index;
4938+
4939+ LOG_DEBUG(logger) << "Category removed: " << name
4940+ << "(" << icon_hint
4941+ << ", " << renderer_name
4942+ << ", " << boost::lexical_cast<int>(index) << ")";
4943+
4944+ if (index >= categories_.size())
4945+ return;
4946+
4947+ auto category_position = categories_.begin() + index;
4948+ PlacesGroup* existing_group = *category_position;
4949+ categories_.erase(category_position);
4950+ counts_.erase(existing_group);
4951+
4952+ RemoveChild(existing_group);
4953+ scroll_layout_->RemoveChildObject(existing_group);
4954+ QueueRelayout();
4955+}
4956+
4957+void ScopeView::ClearCategories()
4958+{
4959+ for (auto category_position = categories_.begin(), end = categories_.end(); category_position != end; ++category_position)
4960+ {
4961+ PlacesGroup* group = *category_position;
4962+ RemoveChild(group);
4963+ scroll_layout_->RemoveChildObject(group);
4964+ }
4965+ counts_.clear();
4966+ categories_.clear();
4967+ QueueRelayout();
4968+}
4969+
4970+bool ScopeView::ReinitializeFilterModels()
4971+{
4972+ if (!scope_)
4973 return false;
4974
4975- Results::Ptr results_model = lens_->results;
4976+ Results::Ptr results_model = scope_->results;
4977 for (unsigned i = last_good_filter_model_ + 1; i < categories_.size(); ++i)
4978 {
4979 ResultViewGrid* grid = GetGridForCategory(i);
4980- glib::Object<DeeModel> filter_model(lens_->GetFilterModelForCategory(i));
4981- grid->SetModel(filter_model, results_model->GetTag());
4982+ if (grid)
4983+ grid->SetResultsModel(scope_->GetResultsForCategory(i));
4984 }
4985
4986 last_good_filter_model_ = -1;
4987@@ -486,21 +527,21 @@
4988 return false;
4989 }
4990
4991-ResultViewGrid* LensView::GetGridForCategory(unsigned category_index)
4992+ResultViewGrid* ScopeView::GetGridForCategory(unsigned category_index)
4993 {
4994 if (category_index >= categories_.size()) return nullptr;
4995 PlacesGroup* group = categories_.at(category_index);
4996 return static_cast<ResultViewGrid*>(group->GetChildView());
4997 }
4998
4999-ResultView* LensView::GetResultViewForCategory(unsigned category_index)
5000+ResultView* ScopeView::GetResultViewForCategory(unsigned category_index)
The diff has been truncated for viewing.