Merge lp:~kamstrup/unity/home-lenses into lp:unity
- home-lenses
- Merge into trunk
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Michal Hruby | ||||||||
Approved revision: | no longer in the source branch. | ||||||||
Merged at revision: | 1868 | ||||||||
Proposed branch: | lp:~kamstrup/unity/home-lenses | ||||||||
Merge into: | lp:unity | ||||||||
Diff against target: |
3591 lines (+1781/-1033) 35 files modified
HACKING (+7/-0) UnityCore/CMakeLists.txt (+2/-0) UnityCore/Categories.cpp (+8/-0) UnityCore/Categories.h (+1/-0) UnityCore/Filters.cpp (+8/-0) UnityCore/Filters.h (+1/-0) UnityCore/GLibDBusProxy.cpp (+11/-0) UnityCore/GLibDBusProxy.h (+1/-0) UnityCore/GLibWrapper.cpp (+5/-0) UnityCore/GLibWrapper.h (+1/-0) UnityCore/HomeLens.cpp (+957/-0) UnityCore/HomeLens.h (+79/-0) UnityCore/Lens.cpp (+128/-55) UnityCore/Lens.h (+17/-6) UnityCore/Model-inl.h (+47/-9) UnityCore/Model.h (+11/-0) UnityCore/Results.cpp (+8/-0) UnityCore/Results.h (+1/-0) com.canonical.Unity.gschema.xml (+10/-3) plugins/unityshell/src/DashView.cpp (+41/-9) plugins/unityshell/src/DashView.h (+4/-2) plugins/unityshell/src/HomeView.cpp (+0/-252) plugins/unityshell/src/HomeView.h (+0/-93) plugins/unityshell/src/LensBar.cpp (+13/-3) plugins/unityshell/src/LensView.cpp (+11/-2) plugins/unityshell/src/PlacesHomeView.cpp (+0/-378) plugins/unityshell/src/PlacesHomeView.h (+0/-72) plugins/unityshell/src/ResultViewGrid.cpp (+13/-2) po/POTFILES.in (+0/-1) po/unity.pot (+0/-120) standalone-clients/CMakeLists.txt (+0/-4) standalone-clients/standalone_dash.cpp (+0/-16) tests/CMakeLists.txt (+7/-6) tests/test_home_lens.cpp (+362/-0) tests/test_utils.h (+27/-0) |
||||||||
To merge this branch: | bzr merge lp:~kamstrup/unity/home-lenses | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michal Hruby (community) | Approve | ||
Andrea Azzarone (community) | Needs Information | ||
Review via email: mp+89669@code.launchpad.net |
Commit message
Description of the change
Replace the Unity home screen tiles with a "merged lens view" where lenses can contribute any categories they see fit.
settings: introduced a new gsettings key in the com.canonical.
libunity-core: Added a HomeLens class that implements Lens and Lenses interfaces. The typical use case is to add a FilesystemLenses to the HomeLens which will make it automatically merge all lenses found on the fs. In testing we implement custom Lenses instances and add those to the HomeLens in stead.
unityshell: Removed the tiled homescreen and use a bog standard LensView to render the HomeLens in stead. Fixed a bunch of places where we assumed that Lenses' categories were always only appended to. This is no longer true with the HomeLens. Also important: Fix the SetViewType() calling semantics to the lenses when showing/hiding the dash and when switching between the lenses.
Testing it out:
For this branch to work you need also: lp:~kamstrup/unity-lens-applications/home-lenses, lp:~kamstrup/unity-lens-files/home-lenses, and lp:~mhr3/unity-lens-music/home-lenses. Add to that latest bamf. Without these you will not see the correct results.
To validate the results: Make sure that bringing up the dash resets the search and shows you a default view with exactly 3 categories in this order: Recent Apps, Recent Files, and Downloads. Then do a search and validate that you have exactly 3 categories in this order Applications, Files & Folders, and Music.
Finally; launch an app that is not a favorite, then bring up the bring up the dash home screen and assert that the running app is *not* in the recent apps category (but showing in the launcher). Then close the app and bring up the dash again. The app should now show under Recent Apps.
Design review:
Home screen without search: https:/
Home screen with search: https:/
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
Sigh. bzr insists that I don't have any diff with trunk wrt the translations. Fun and games.
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
Found it. Amended in r1875.
Michal Hruby (mhr3) wrote : | # |
Just a note: all the lens branches are now merged in respective trunks.
Andrea Azzarone (azzar1) wrote : | # |
Is PlacesHomeView.
Andrea Azzarone (azzar1) : | # |
Michal Hruby (mhr3) wrote : | # |
1519 ~Lens();
I believe this should be virtual now.
1538 template<class RowAdaptor>
1539 Model<RowAdapto
The missing model.SetGetter
One of weird things I noticed is that when using keynav in the home view (specifically the down array) sometimes the "See xx more results" doesn't get highlighted and can't be expanded by pressing enter.
Andrea Azzarone (azzar1) wrote : | # |
> One of weird things I noticed is that when using keynav in the home view
> (specifically the down array) sometimes the "See xx more results" doesn't get
> highlighted and can't be expanded by pressing enter.
Fixed here https:/
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
> Is PlacesHomeView.
Strictly, no. I didn't delete it because technically the home-lens concept is on a trial run. If design ditches it we'll have to revert to the old view and I didn't want to dig it out of the rev history. Although, I probably should delete it, to have a better looking diffstat :-)
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
> 1519 ~Lens();
>
> I believe this should be virtual now.
Right. I wonder why the compiler didn't complain. It usually does in these cases. Fixed.
> 1538 template<class RowAdaptor>
> 1539 Model<RowAdapto
>
> The missing model.SetGetter
> future.
Ah, good catch. I created a new Init() method that gets called from the constructors so they can share the setup code. (my favorite hate-pattern. why oh why can't we chain constructors in C++?!?!?!11). Anyway; fixed.
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
WTF. The diffs seems to be showing that I removed po/unity.pot which I swear I didn't! Let me look into it.
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
Ok, the diff should be clean in r1881. Please re-review
Michal Hruby (mhr3) wrote : | # |
One thing that's still missing is resetting the search entry when dash is hidden (or not-resetting the search sent to lenses as https:/
Either would be fine, but right now the search entry isn't reset, while the search is...
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
Implemented search state retention as requested by design. Please re-review.
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
John acked the design review on IRC
Michal Hruby (mhr3) wrote : | # |
Sorry, but Esc now no longer clears the search entry... I don't think that's desired.
Andrea Azzarone (azzar1) wrote : | # |
> Sorry, but Esc now no longer clears the search entry... I don't think that's
> desired.
1866 - else
1867 - search_
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
> > Sorry, but Esc now no longer clears the search entry... I don't think that's
> > desired.
>
> 1866 - else
> 1867 - search_
I am not sure if you mean to back Michal up, or refute his claim Andrea? :-)
In any case, I think I have the right behavior here... When clicking Esc I see:
a) if there is text in the entry the text is cleared, and the dash shows results for the empty search
b) if there is no search, the dash is hidden
As a Corollary, c) hitting Esc twice clears and hides the dash.
Michal Hruby (mhr3) wrote : | # |
Unfortunately, that's not the behaviour I see (particularly a) doesn't work). Afaict the code Andrea pasted is what handled the "esc and search entry not empty" case, and you removed it...
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
Hmmm, I can see you are correct looking at the code... I wonder how it could work on my box. I must have been running some almost, but not entirely, identical to what I pushed. Nonetheless; pushed a fix.
Michal Hruby (mhr3) wrote : | # |
Yep, it's fine now. Approved from me, but I suppose more people want to go through this...
Neil J. Patel (njpatel) wrote : | # |
237 (and other places): Instead of handling the gchar* yourself, use glib::String from UnityCore/
330: Evil, evil kamstrup.
Apart from that, excellent work :)
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
> 237 (and other places): Instead of handling the gchar* yourself, use
> glib::String from UnityCore/
> from the stack, so you don't need to worry about g_free in multiple places.
Ok, now using glib::String. It required that I add automatic std::string conversion to glib::String in order not to complicate the code - I was wondering if there was a specific reason it wasn't in glib::String already. Seems like a strange omission?
Michal Hruby (mhr3) wrote : | # |
Neil ACKed this as well, so approving...
Preview Diff
1 | === modified file 'HACKING' |
2 | --- HACKING 2012-01-10 16:35:26 +0000 |
3 | +++ HACKING 2012-01-26 08:37:26 +0000 |
4 | @@ -39,5 +39,12 @@ |
5 | |
6 | Testing is handled through GTest, googles test system, we currently have three test targets; test-gtest, test-gtest-xless, test-gtest-dbus. tests that require Nux should be in test-gtest as they require X, tests that can run headless should be in test-gtest-xless and tests that require dbus should be run with test-gtest-dbus, which tests run with our test service. |
7 | |
8 | +To enable debug logging you must set the environment variable UNITY_LOG_SEVERITY to the log domain you |
9 | +want to watch and the log level for that domain. For example: |
10 | + |
11 | + UNITY_LOG_SEVERITY="unity.dash.lens=DEBUG" standalone-clients/dash |
12 | + |
13 | + |
14 | + |
15 | for more information see the README file |
16 | |
17 | |
18 | === modified file 'UnityCore/CMakeLists.txt' |
19 | --- UnityCore/CMakeLists.txt 2012-01-17 16:02:39 +0000 |
20 | +++ UnityCore/CMakeLists.txt 2012-01-26 08:37:26 +0000 |
21 | @@ -21,6 +21,7 @@ |
22 | GLibSignal-inl.h |
23 | GLibWrapper.h |
24 | GLibWrapper-inl.h |
25 | + HomeLens.h |
26 | IndicatorEntry.h |
27 | Indicator.h |
28 | Indicators.h |
29 | @@ -53,6 +54,7 @@ |
30 | GLibDBusProxy.cpp |
31 | GLibSignal.cpp |
32 | GLibWrapper.cpp |
33 | + HomeLens.cpp |
34 | Indicator.cpp |
35 | IndicatorEntry.cpp |
36 | Indicators.cpp |
37 | |
38 | === modified file 'UnityCore/Categories.cpp' |
39 | --- UnityCore/Categories.cpp 2011-07-25 10:54:25 +0000 |
40 | +++ UnityCore/Categories.cpp 2012-01-26 08:37:26 +0000 |
41 | @@ -31,6 +31,14 @@ |
42 | row_removed.connect(sigc::mem_fun(this, &Categories::OnRowRemoved)); |
43 | } |
44 | |
45 | +Categories::Categories(ModelType model_type) |
46 | + : Model<Category>::Model(model_type) |
47 | +{ |
48 | + row_added.connect(sigc::mem_fun(this, &Categories::OnRowAdded)); |
49 | + row_changed.connect(sigc::mem_fun(this, &Categories::OnRowChanged)); |
50 | + row_removed.connect(sigc::mem_fun(this, &Categories::OnRowRemoved)); |
51 | +} |
52 | + |
53 | void Categories::OnRowAdded(Category& category) |
54 | { |
55 | category_added.emit(category); |
56 | |
57 | === modified file 'UnityCore/Categories.h' |
58 | --- UnityCore/Categories.h 2011-07-28 13:34:38 +0000 |
59 | +++ UnityCore/Categories.h 2012-01-26 08:37:26 +0000 |
60 | @@ -36,6 +36,7 @@ |
61 | typedef std::shared_ptr<Categories> Ptr; |
62 | |
63 | Categories(); |
64 | + Categories(ModelType model_type); |
65 | |
66 | sigc::signal<void, Category const&> category_added; |
67 | sigc::signal<void, Category const&> category_changed; |
68 | |
69 | === modified file 'UnityCore/Filters.cpp' |
70 | --- UnityCore/Filters.cpp 2011-08-05 09:55:33 +0000 |
71 | +++ UnityCore/Filters.cpp 2012-01-26 08:37:26 +0000 |
72 | @@ -56,6 +56,14 @@ |
73 | row_removed.connect(sigc::mem_fun(this, &Filters::OnRowRemoved)); |
74 | } |
75 | |
76 | +Filters::Filters(ModelType model_type) |
77 | + : Model<FilterAdaptor>::Model(model_type) |
78 | +{ |
79 | + row_added.connect(sigc::mem_fun(this, &Filters::OnRowAdded)); |
80 | + row_changed.connect(sigc::mem_fun(this, &Filters::OnRowChanged)); |
81 | + row_removed.connect(sigc::mem_fun(this, &Filters::OnRowRemoved)); |
82 | +} |
83 | + |
84 | Filters::~Filters() |
85 | {} |
86 | |
87 | |
88 | === modified file 'UnityCore/Filters.h' |
89 | --- UnityCore/Filters.h 2011-08-05 09:55:33 +0000 |
90 | +++ UnityCore/Filters.h 2012-01-26 08:37:26 +0000 |
91 | @@ -51,6 +51,7 @@ |
92 | typedef std::map<DeeModelIter*, Filter::Ptr> FilterMap; |
93 | |
94 | Filters(); |
95 | + Filters(ModelType model_type); |
96 | ~Filters(); |
97 | |
98 | Filter::Ptr FilterAtIndex(std::size_t index); |
99 | |
100 | === modified file 'UnityCore/GLibDBusProxy.cpp' |
101 | --- UnityCore/GLibDBusProxy.cpp 2012-01-16 15:19:47 +0000 |
102 | +++ UnityCore/GLibDBusProxy.cpp 2012-01-26 08:37:26 +0000 |
103 | @@ -72,6 +72,7 @@ |
104 | int timeout_msec); |
105 | |
106 | void Connect(string const& signal_name, ReplyCallback callback); |
107 | + bool IsConnected(); |
108 | |
109 | static void OnNameAppeared(GDBusConnection* connection, const char* name, |
110 | const char* name_owner, gpointer impl); |
111 | @@ -192,6 +193,11 @@ |
112 | this); |
113 | } |
114 | |
115 | +bool DBusProxy::Impl::IsConnected() |
116 | +{ |
117 | + return connected_; |
118 | +} |
119 | + |
120 | void DBusProxy::Impl::OnProxyConnectCallback(GObject* source, |
121 | GAsyncResult* res, |
122 | gpointer impl) |
123 | @@ -320,5 +326,10 @@ |
124 | pimpl->Connect(signal_name, callback); |
125 | } |
126 | |
127 | +bool DBusProxy::IsConnected() |
128 | +{ |
129 | + return pimpl->IsConnected(); |
130 | +} |
131 | + |
132 | } |
133 | } |
134 | |
135 | === modified file 'UnityCore/GLibDBusProxy.h' |
136 | --- UnityCore/GLibDBusProxy.h 2011-12-06 10:39:36 +0000 |
137 | +++ UnityCore/GLibDBusProxy.h 2012-01-26 08:37:26 +0000 |
138 | @@ -54,6 +54,7 @@ |
139 | int timeout_msec = -1); |
140 | |
141 | void Connect(std::string const& signal_name, ReplyCallback callback); |
142 | + bool IsConnected(); |
143 | |
144 | sigc::signal<void> connected; |
145 | sigc::signal<void> disconnected; |
146 | |
147 | === modified file 'UnityCore/GLibWrapper.cpp' |
148 | --- UnityCore/GLibWrapper.cpp 2011-12-06 10:39:36 +0000 |
149 | +++ UnityCore/GLibWrapper.cpp 2012-01-26 08:37:26 +0000 |
150 | @@ -104,6 +104,11 @@ |
151 | return string_; |
152 | } |
153 | |
154 | +String::operator std::string() |
155 | +{ |
156 | + return Str(); |
157 | +} |
158 | + |
159 | String::operator bool() const |
160 | { |
161 | return bool(string_); |
162 | |
163 | === modified file 'UnityCore/GLibWrapper.h' |
164 | --- UnityCore/GLibWrapper.h 2011-12-14 18:22:23 +0000 |
165 | +++ UnityCore/GLibWrapper.h 2012-01-26 08:37:26 +0000 |
166 | @@ -115,6 +115,7 @@ |
167 | |
168 | operator bool() const; |
169 | operator char*(); |
170 | + operator std::string(); |
171 | gchar* Value(); |
172 | std::string Str() const; |
173 | |
174 | |
175 | === added file 'UnityCore/HomeLens.cpp' |
176 | --- UnityCore/HomeLens.cpp 1970-01-01 00:00:00 +0000 |
177 | +++ UnityCore/HomeLens.cpp 2012-01-26 08:37:26 +0000 |
178 | @@ -0,0 +1,957 @@ |
179 | +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- |
180 | +/* |
181 | + * Copyright (C) 2012 Canonical Ltd |
182 | + * |
183 | + * This program is free software: you can redistribute it and/or modify |
184 | + * it under the terms of the GNU General Public License version 3 as |
185 | + * published by the Free Software Foundation. |
186 | + * |
187 | + * This program is distributed in the hope that it will be useful, |
188 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
189 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
190 | + * GNU General Public License for more details. |
191 | + * |
192 | + * You should have received a copy of the GNU General Public License |
193 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
194 | + * |
195 | + * Authored by: Mikkel Kamstrup Erlandsen <mikkel.kamstrup@canonical.com> |
196 | + */ |
197 | + |
198 | +#include <glib.h> |
199 | +#include <string> |
200 | +#include <stdexcept> |
201 | +#include <map> |
202 | + |
203 | +#include "GLibSignal.h" |
204 | +#include "HomeLens.h" |
205 | +#include "Lens.h" |
206 | +#include "Model.h" |
207 | + |
208 | +#include "config.h" |
209 | + |
210 | +namespace unity |
211 | +{ |
212 | +namespace dash |
213 | +{ |
214 | + |
215 | +namespace |
216 | +{ |
217 | + |
218 | +nux::logging::Logger logger("unity.dash.homelens"); |
219 | + |
220 | +} |
221 | + |
222 | +/* |
223 | + * Helper class that maps category offsets between the merged lens and |
224 | + * source lenses. We also use it to merge categories from different lenses |
225 | + * with the same display name into the same category. |
226 | + * |
227 | + * NOTE: The model pointers passed in are expected to be pointers to the |
228 | + * result source models - and not the category source models! |
229 | + */ |
230 | +class HomeLens::CategoryRegistry |
231 | +{ |
232 | +public: |
233 | + CategoryRegistry(HomeLens* owner) |
234 | + : is_dirty_(false) |
235 | + , owner_(owner) {} |
236 | + |
237 | + int FindCategoryOffset(DeeModel* model, unsigned int source_cat_offset) |
238 | + { |
239 | + glib::String c_id(g_strdup_printf("%u+%p", source_cat_offset, model)); |
240 | + std::map<std::string,unsigned int>::iterator i = reg_by_id_.find(c_id); |
241 | + |
242 | + if (i != reg_by_id_.end()) |
243 | + return i->second; |
244 | + |
245 | + return -1; |
246 | + } |
247 | + |
248 | + int FindCategoryOffset(const gchar* display_name) |
249 | + { |
250 | + std::map<std::string,unsigned int>::iterator i = |
251 | + reg_by_display_name_.find(display_name); |
252 | + if (i != reg_by_display_name_.end()) |
253 | + return i->second; |
254 | + |
255 | + return -1; |
256 | + } |
257 | + |
258 | + /* Register a new category */ |
259 | + void RegisterCategoryOffset(DeeModel* model, |
260 | + unsigned int source_cat_offset, |
261 | + const gchar* display_name, |
262 | + unsigned int target_cat_offset) |
263 | + { |
264 | + glib::String c_id(g_strdup_printf("%u+%p", source_cat_offset, model)); |
265 | + |
266 | + std::map<std::string,unsigned int>::iterator i = reg_by_id_.find(c_id); |
267 | + if (i != reg_by_id_.end()) |
268 | + { |
269 | + LOG_ERROR(logger) << "Category '" << c_id << "' already registered!"; |
270 | + return; |
271 | + } |
272 | + |
273 | + if (display_name != NULL) |
274 | + { |
275 | + i = reg_by_display_name_.find(display_name); |
276 | + if (i != reg_by_display_name_.end()) |
277 | + { |
278 | + LOG_ERROR(logger) << "Category '" << display_name << "' already registered!"; |
279 | + return; |
280 | + } |
281 | + } |
282 | + |
283 | + /* Any existing categories with offsets >= target_cat_offset must be |
284 | + * pushed up. Update both maps by id and display name */ |
285 | + std::map<std::string,unsigned int>::iterator end = reg_by_id_.end(); |
286 | + for (i = reg_by_id_.begin(); i != end; i++) |
287 | + { |
288 | + if (i->second >= target_cat_offset) |
289 | + { |
290 | + i->second = i->second + 1; |
291 | + is_dirty_ = true; |
292 | + } |
293 | + } |
294 | + |
295 | + for (i = reg_by_display_name_.begin(), end = reg_by_display_name_.end(); i != end; i++) |
296 | + { |
297 | + if (i->second >= target_cat_offset) |
298 | + { |
299 | + i->second = i->second + 1; |
300 | + is_dirty_ = true; |
301 | + } |
302 | + } |
303 | + |
304 | + reg_by_id_[c_id] = target_cat_offset; |
305 | + |
306 | + /* Callers pass a NULL display_name when they already have a category |
307 | + * with the right display registered */ |
308 | + if (display_name != NULL) |
309 | + { |
310 | + reg_by_display_name_[display_name] = target_cat_offset; |
311 | + LOG_DEBUG(logger) << "Registered category '" << display_name |
312 | + << "' with source offset " << source_cat_offset |
313 | + << " and target offset " << target_cat_offset |
314 | + << ". Id " << c_id; |
315 | + } |
316 | + else |
317 | + { |
318 | + LOG_DEBUG(logger) << "Registered category with source offset " |
319 | + << source_cat_offset << " and target offset " |
320 | + << target_cat_offset << ". Id " << c_id; |
321 | + } |
322 | + } |
323 | + |
324 | + /* Associate a source results model and category offset with an existing |
325 | + * target category offset */ |
326 | + void AssociateCategoryOffset(DeeModel* model, |
327 | + unsigned int source_cat_offset, |
328 | + unsigned int target_cat_offset) |
329 | + { |
330 | + glib::String c_id(g_strdup_printf("%u+%p", source_cat_offset, model)); |
331 | + |
332 | + std::map<std::string,unsigned int>::iterator i = reg_by_id_.find(c_id); |
333 | + if (i != reg_by_id_.end()) |
334 | + { |
335 | + LOG_ERROR(logger) << "Category '" << c_id << "' already registered!"; |
336 | + return; |
337 | + } |
338 | + |
339 | + reg_by_id_[c_id] = target_cat_offset; |
340 | + } |
341 | + |
342 | + /** |
343 | + * Returns true and resets the dirty state if the registry was dirty. |
344 | + * When you've checked a dirty registry you must either clear the |
345 | + * merged results model or recalibrate all category offset in it |
346 | + * (and Unity probably wont support the latter?). |
347 | + */ |
348 | + bool CheckDirty() |
349 | + { |
350 | + return is_dirty_ ? (is_dirty_ = false, true) : false; |
351 | + } |
352 | + |
353 | +private: |
354 | + std::map<std::string,unsigned int> reg_by_id_; |
355 | + std::map<std::string,unsigned int> reg_by_display_name_; |
356 | + bool is_dirty_; |
357 | + HomeLens* owner_; |
358 | +}; |
359 | + |
360 | +/* |
361 | + * Helper class that merges a set of DeeModels into one super model |
362 | + */ |
363 | +class HomeLens::ModelMerger : public sigc::trackable |
364 | +{ |
365 | +public: |
366 | + ModelMerger(glib::Object<DeeModel> target); |
367 | + virtual ~ModelMerger(); |
368 | + |
369 | + void AddSource(glib::Object<DeeModel> source); |
370 | + |
371 | +protected: |
372 | + virtual void OnSourceRowAdded(DeeModel *model, DeeModelIter *iter); |
373 | + virtual void OnSourceRowRemoved(DeeModel* model, DeeModelIter* iter); |
374 | + virtual void OnSourceRowChanged(DeeModel* model, DeeModelIter* iter); |
375 | + void EnsureRowBuf(DeeModel *source); |
376 | + |
377 | + /* The merge tag lives on the source models, pointing to the mapped |
378 | + * row in the target model */ |
379 | + DeeModelTag* FindSourceToTargetTag(DeeModel *model); |
380 | + |
381 | +protected: |
382 | + glib::SignalManager sig_manager_; |
383 | + GVariant** row_buf_; |
384 | + unsigned int n_cols_; |
385 | + glib::Object<DeeModel> target_; |
386 | + std::map<DeeModel*,DeeModelTag*> source_to_target_tags_; |
387 | +}; |
388 | + |
389 | +/* |
390 | + * Specialized ModelMerger that takes care merging results models. |
391 | + * We need special handling here because rows in each lens' results model |
392 | + * specifies an offset into the lens' categories model where the display |
393 | + * name of the category is defined. |
394 | + * |
395 | + * This class converts the offset of the source lens' categories into |
396 | + * offsets into the merged category model. |
397 | + * |
398 | + * Each row added to the target is tagged with a pointer to the Lens instance |
399 | + * from which it came |
400 | + */ |
401 | +class HomeLens::ResultsMerger : public ModelMerger |
402 | +{ |
403 | +public: |
404 | + ResultsMerger(glib::Object<DeeModel> target, |
405 | + HomeLens::CategoryRegistry* cat_registry); |
406 | + |
407 | +protected: |
408 | + void OnSourceRowAdded(DeeModel *model, DeeModelIter *iter); |
409 | + void OnSourceRowRemoved(DeeModel *model, DeeModelIter *iter); |
410 | + void OnSourceRowChanged(DeeModel *model, DeeModelIter *iter); |
411 | + void CheckCategoryRegistryDirty(); |
412 | + |
413 | +private: |
414 | + HomeLens::CategoryRegistry* cat_registry_; |
415 | +}; |
416 | + |
417 | +/* |
418 | + * Specialized ModelMerger that takes care merging category models. |
419 | + * We need special handling here because rows in each lens' results model |
420 | + * specifies an offset into the lens' categories model where the display |
421 | + * name of the category is defined. |
422 | + * |
423 | + * This class records a map of the offsets from the original source category |
424 | + * models to the offsets in the combined categories model. |
425 | + */ |
426 | +class HomeLens::CategoryMerger : public ModelMerger |
427 | +{ |
428 | +public: |
429 | + CategoryMerger(glib::Object<DeeModel> target, |
430 | + HomeLens::CategoryRegistry* cat_registry); |
431 | + |
432 | + void OnSourceRowAdded(DeeModel *model, DeeModelIter *iter); |
433 | + void OnSourceRowRemoved(DeeModel *model, DeeModelIter *iter); |
434 | + |
435 | +private: |
436 | + HomeLens::CategoryRegistry* cat_registry_; |
437 | + DeeModelTag* priority_tag_; |
438 | +}; |
439 | + |
440 | +/* |
441 | + * Pimpl for HomeLens |
442 | + */ |
443 | +class HomeLens::Impl : public sigc::trackable |
444 | +{ |
445 | +public: |
446 | + Impl(HomeLens* owner); |
447 | + ~Impl(); |
448 | + |
449 | + void OnLensAdded(Lens::Ptr& lens); |
450 | + gsize FindLensPriority (Lens::Ptr& lens); |
451 | + void EnsureCategoryAnnotation(Lens::Ptr& lens, DeeModel* results, DeeModel* categories); |
452 | + Lens::Ptr FindLensForUri(std::string const& uri); |
453 | + |
454 | + HomeLens* owner_; |
455 | + Lenses::LensList lenses_; |
456 | + HomeLens::CategoryRegistry cat_registry_; |
457 | + HomeLens::ResultsMerger results_merger_; |
458 | + HomeLens::CategoryMerger categories_merger_; |
459 | + HomeLens::ModelMerger filters_merger_; |
460 | + int running_searches_; |
461 | + glib::Object<GSettings> settings_; |
462 | +}; |
463 | + |
464 | +/* |
465 | + * IMPLEMENTATION |
466 | + */ |
467 | + |
468 | +HomeLens::ModelMerger::ModelMerger(glib::Object<DeeModel> target) |
469 | + : row_buf_(NULL) |
470 | + , n_cols_(0) |
471 | + , target_(target) |
472 | +{} |
473 | + |
474 | +HomeLens::ResultsMerger::ResultsMerger(glib::Object<DeeModel> target, |
475 | + CategoryRegistry *cat_registry) |
476 | + : HomeLens::ModelMerger::ModelMerger(target) |
477 | + , cat_registry_(cat_registry) |
478 | +{} |
479 | + |
480 | +HomeLens::CategoryMerger::CategoryMerger(glib::Object<DeeModel> target, |
481 | + CategoryRegistry *cat_registry) |
482 | + : HomeLens::ModelMerger::ModelMerger(target) |
483 | + , cat_registry_(cat_registry) |
484 | + , priority_tag_(dee_model_register_tag(target, NULL)) |
485 | +{} |
486 | + |
487 | +HomeLens::ModelMerger::~ModelMerger() |
488 | +{ |
489 | + if (row_buf_) |
490 | + delete row_buf_; |
491 | +} |
492 | + |
493 | +void HomeLens::ModelMerger::AddSource(glib::Object<DeeModel> source) |
494 | +{ |
495 | + typedef glib::Signal<void, DeeModel*, DeeModelIter*> RowSignalType; |
496 | + |
497 | + if (!source) |
498 | + { |
499 | + LOG_ERROR(logger) << "Trying to add NULL source to ModelMerger"; |
500 | + return; |
501 | + } |
502 | + |
503 | + DeeModelTag* merger_tag = dee_model_register_tag(source, NULL); |
504 | + source_to_target_tags_[source.RawPtr()] = merger_tag; |
505 | + |
506 | + sig_manager_.Add(new RowSignalType(source.RawPtr(), |
507 | + "row-added", |
508 | + sigc::mem_fun(this, &HomeLens::ModelMerger::OnSourceRowAdded))); |
509 | + |
510 | + sig_manager_.Add(new RowSignalType(source.RawPtr(), |
511 | + "row-removed", |
512 | + sigc::mem_fun(this, &HomeLens::ModelMerger::OnSourceRowRemoved))); |
513 | + |
514 | + sig_manager_.Add(new RowSignalType(source.RawPtr(), |
515 | + "row-changed", |
516 | + sigc::mem_fun(this, &HomeLens::ModelMerger::OnSourceRowChanged))); |
517 | +} |
518 | + |
519 | +void HomeLens::ModelMerger::OnSourceRowAdded(DeeModel *model, DeeModelIter *iter) |
520 | +{ |
521 | + // Default impl. does nothing. |
522 | + // Note that the filters_merger_ relies on this behavior. Supporting |
523 | + // filters on the home screen is possible, but *quite* tricky. |
524 | + // So... |
525 | + // Discard ALL the rows! |
526 | +} |
527 | + |
528 | +void HomeLens::ResultsMerger::OnSourceRowAdded(DeeModel *model, DeeModelIter *iter) |
529 | +{ |
530 | + DeeModelIter* target_iter; |
531 | + DeeModelTag* target_tag; |
532 | + int target_cat_offset, source_cat_offset; |
533 | + const unsigned int CATEGORY_COLUMN = 2; |
534 | + |
535 | + EnsureRowBuf(model); |
536 | + CheckCategoryRegistryDirty(); |
537 | + |
538 | + dee_model_get_row (model, iter, row_buf_); |
539 | + target_tag = FindSourceToTargetTag(model); |
540 | + |
541 | + /* Update the row with the corrected category offset */ |
542 | + source_cat_offset = dee_model_get_uint32(model, iter, CATEGORY_COLUMN); |
543 | + target_cat_offset = cat_registry_->FindCategoryOffset(model, source_cat_offset); |
544 | + |
545 | + if (target_cat_offset >= 0) |
546 | + { |
547 | + g_variant_unref (row_buf_[CATEGORY_COLUMN]); |
548 | + row_buf_[CATEGORY_COLUMN] = g_variant_new_uint32(target_cat_offset); |
549 | + |
550 | + /* Sink the ref on the new row member. By Dee API contract they must all |
551 | + * be strong refs, not floating */ |
552 | + g_variant_ref_sink(row_buf_[CATEGORY_COLUMN]); |
553 | + |
554 | + target_iter = dee_model_append_row (target_, row_buf_); |
555 | + dee_model_set_tag(model, iter, target_tag, target_iter); |
556 | + |
557 | + LOG_DEBUG(logger) << "Found " << dee_model_get_string(model, iter, 0) |
558 | + << " (source cat " << source_cat_offset << ", target cat " |
559 | + << target_cat_offset << ")"; |
560 | + } |
561 | + else |
562 | + { |
563 | + LOG_ERROR(logger) << "No category registered for model " |
564 | + << model << ", source offset " << source_cat_offset |
565 | + << ": " << dee_model_get_string(model, iter, 0); |
566 | + } |
567 | + |
568 | + for (unsigned int i = 0; i < n_cols_; i++) g_variant_unref(row_buf_[i]); |
569 | +} |
570 | + |
571 | +void HomeLens::CategoryMerger::OnSourceRowAdded(DeeModel *model, DeeModelIter *iter) |
572 | +{ |
573 | + DeeModel* results_model; |
574 | + DeeModelIter* target_iter; |
575 | + DeeModelIter* target_end; |
576 | + DeeModelTag* target_tag; |
577 | + int target_cat_offset, source_cat_offset; |
578 | + const gchar* display_name; |
579 | + const unsigned int DISPLAY_NAME_COLUMN = 0; |
580 | + gsize lens_priority, prio; |
581 | + |
582 | + EnsureRowBuf(model); |
583 | + |
584 | + results_model = static_cast<DeeModel*>(g_object_get_data( |
585 | + G_OBJECT(model), "unity-homelens-results-model")); |
586 | + if (results_model == NULL) |
587 | + { |
588 | + LOG_DEBUG(logger) << "Category model " << model |
589 | + << " does not have a results model yet"; |
590 | + return; |
591 | + } |
592 | + |
593 | + dee_model_get_row (model, iter, row_buf_); |
594 | + target_tag = FindSourceToTargetTag(model); |
595 | + source_cat_offset = dee_model_get_position(model, iter); |
596 | + |
597 | + /* If we already have a category registered with the same display name |
598 | + * then we just use that. Otherwise register a new category for it */ |
599 | + display_name = dee_model_get_string(model, iter, DISPLAY_NAME_COLUMN); |
600 | + target_cat_offset = cat_registry_->FindCategoryOffset(display_name); |
601 | + if (target_cat_offset >= 0) |
602 | + { |
603 | + cat_registry_->AssociateCategoryOffset(results_model, source_cat_offset, |
604 | + target_cat_offset); |
605 | + goto cleanup; |
606 | + } |
607 | + |
608 | + /* |
609 | + * Below we can assume that we have a genuinely new category. |
610 | + * |
611 | + * Our goal is to insert the category at a position suitable for its |
612 | + * priority. We insert it as the last item in the set of items which |
613 | + * have equal priority. |
614 | + * |
615 | + * We allow our selves to do linear inserts as we wont expect a lot |
616 | + * of categories. |
617 | + */ |
618 | + |
619 | + lens_priority = GPOINTER_TO_SIZE(g_object_get_data( |
620 | + G_OBJECT(model), "unity-homelens-priority")); |
621 | + |
622 | + /* Seek correct position in the merged category model */ |
623 | + target_iter = dee_model_get_first_iter(target_); |
624 | + target_end = dee_model_get_last_iter(target_); |
625 | + while (target_iter != target_end) |
626 | + { |
627 | + prio = GPOINTER_TO_SIZE(dee_model_get_tag(target_, target_iter, priority_tag_)); |
628 | + if (lens_priority > prio) |
629 | + break; |
630 | + target_iter = dee_model_next(target_, target_iter); |
631 | + } |
632 | + |
633 | + /* Add the row to the merged categories model and store required metadata */ |
634 | + target_iter = dee_model_insert_row_before(target_, target_iter, row_buf_); |
635 | + dee_model_set_tag(model, iter, target_tag, target_iter); |
636 | + dee_model_set_tag(target_, target_iter, priority_tag_, GSIZE_TO_POINTER(lens_priority)); |
637 | + target_cat_offset = dee_model_get_position(target_, target_iter); |
638 | + cat_registry_->RegisterCategoryOffset(results_model, source_cat_offset, |
639 | + display_name, target_cat_offset); |
640 | + |
641 | + cleanup: |
642 | + for (unsigned int i = 0; i < n_cols_; i++) g_variant_unref(row_buf_[i]); |
643 | +} |
644 | + |
645 | +void HomeLens::CategoryMerger::OnSourceRowRemoved(DeeModel *model, DeeModelIter *iter) |
646 | +{ |
647 | + /* We don't support removals of categories. |
648 | + * You can check out any time you like, but you can never leave |
649 | + * |
650 | + * The category registry code is spaghettified enough already. |
651 | + * No more please. |
652 | + */ |
653 | + LOG_DEBUG(logger) << "Removal of categories not supported."; |
654 | +} |
655 | + |
656 | +void HomeLens::ModelMerger::OnSourceRowRemoved(DeeModel *model, DeeModelIter *iter) |
657 | +{ |
658 | + DeeModelIter* target_iter; |
659 | + DeeModelTag* target_tag; |
660 | + |
661 | + EnsureRowBuf(model); |
662 | + |
663 | + target_tag = FindSourceToTargetTag(model); |
664 | + target_iter = static_cast<DeeModelIter*>(dee_model_get_tag(model, |
665 | + iter, |
666 | + target_tag)); |
667 | + |
668 | + /* We might not have registered a target iter for the row. |
669 | + * This fx. happens if we re-used a category based on display_name */ |
670 | + if (target_iter != NULL) |
671 | + dee_model_remove(target_, target_iter); |
672 | +} |
673 | + |
674 | +void HomeLens::ResultsMerger::OnSourceRowRemoved(DeeModel *model, DeeModelIter *iter) |
675 | +{ |
676 | + CheckCategoryRegistryDirty(); |
677 | + ModelMerger::OnSourceRowRemoved(model, iter); |
678 | +} |
679 | + |
680 | +void HomeLens::ModelMerger::OnSourceRowChanged(DeeModel *model, DeeModelIter *iter) |
681 | +{ |
682 | + DeeModelIter* target_iter; |
683 | + DeeModelTag* target_tag; |
684 | + |
685 | + EnsureRowBuf(model); |
686 | + |
687 | + dee_model_get_row (model, iter, row_buf_); |
688 | + target_tag = FindSourceToTargetTag(model); |
689 | + target_iter = static_cast<DeeModelIter*>(dee_model_get_tag(model, |
690 | + iter, |
691 | + target_tag)); |
692 | + |
693 | + dee_model_set_row (target_, target_iter, row_buf_); |
694 | + |
695 | + for (unsigned int i = 0; i < n_cols_; i++) g_variant_unref(row_buf_[i]); |
696 | +} |
697 | + |
698 | +void HomeLens::ResultsMerger::OnSourceRowChanged(DeeModel *model, DeeModelIter *iter) |
699 | +{ |
700 | + // FIXME: We can support this, but we need to re-calculate the category offset |
701 | + LOG_WARN(logger) << "In-line changing of results not supported in the home lens. Sorry."; |
702 | +} |
703 | + |
704 | +void HomeLens::ModelMerger::EnsureRowBuf(DeeModel *model) |
705 | +{ |
706 | + if (G_UNLIKELY (n_cols_ == 0)) |
707 | + { |
708 | + /* We have two things to accomplish here. |
709 | + * 1) Allocate the row_buf_, and |
710 | + * 2) Make sure that the target model has the correct schema set. |
711 | + * |
712 | + * INVARIANT: n_cols_ == 0 iff row_buf_ == NULL. |
713 | + */ |
714 | + |
715 | + n_cols_ = dee_model_get_n_columns(model); |
716 | + |
717 | + if (n_cols_ == 0) |
718 | + { |
719 | + LOG_ERROR(logger) << "Source model has not provided a schema for the model merger!"; |
720 | + return; |
721 | + } |
722 | + |
723 | + /* Lazily adopt schema from source if we don't have one. |
724 | + * If we do have a schema let's validate that they match the source */ |
725 | + if (dee_model_get_n_columns(target_) == 0) |
726 | + { |
727 | + dee_model_set_schema_full(target_, |
728 | + dee_model_get_schema(model, NULL), |
729 | + n_cols_); |
730 | + } |
731 | + else |
732 | + { |
733 | + unsigned int n_cols1; |
734 | + const gchar* const *schema1 = dee_model_get_schema(target_, &n_cols1); |
735 | + const gchar* const *schema2 = dee_model_get_schema(model, NULL); |
736 | + |
737 | + /* At the very least we should have an equal number of rows */ |
738 | + if (n_cols_ != n_cols1) |
739 | + { |
740 | + LOG_ERROR(logger) << "Schema mismatch between source and target model. Expected " |
741 | + << n_cols1 << " columns, but found " |
742 | + << n_cols_ << "."; |
743 | + n_cols_ = 0; |
744 | + return; |
745 | + } |
746 | + |
747 | + /* Compare schemas */ |
748 | + for (unsigned int i = 0; i < n_cols_; i++) |
749 | + { |
750 | + if (g_strcmp0(schema1[i], schema2[i]) != 0) |
751 | + { |
752 | + LOG_ERROR(logger) << "Schema mismatch between source and target model. Expected column " |
753 | + << i << " to be '" << schema1[i] << "', but found '" |
754 | + << schema2[i] << "'."; |
755 | + n_cols_ = 0; |
756 | + return; |
757 | + } |
758 | + } |
759 | + } |
760 | + |
761 | + row_buf_ = g_new0 (GVariant*, n_cols_); |
762 | + } |
763 | +} |
764 | + |
765 | +DeeModelTag* HomeLens::ModelMerger::FindSourceToTargetTag(DeeModel *model) |
766 | +{ |
767 | + return source_to_target_tags_[model]; |
768 | +} |
769 | + |
770 | +void HomeLens::ResultsMerger::CheckCategoryRegistryDirty() |
771 | +{ |
772 | + DeeModel* source; |
773 | + DeeModelTag* target_tag; |
774 | + const unsigned int CATEGORY_COLUMN = 2; |
775 | + std::map<DeeModel*,DeeModelTag*>::iterator i, end; |
776 | + |
777 | + if (G_LIKELY(!cat_registry_->CheckDirty())) |
778 | + return; |
779 | + |
780 | + LOG_DEBUG(logger) << "Category registry marked dirty. Fixing category offsets."; |
781 | + |
782 | + /* |
783 | + * Iterate over all results in each source model and re-calculate the |
784 | + * the category offset in the corresponding rows in the target model |
785 | + */ |
786 | + for (i = source_to_target_tags_.begin(), end = source_to_target_tags_.end(); |
787 | + i != end; i++) |
788 | + { |
789 | + source = i->first; |
790 | + target_tag = i->second; |
791 | + |
792 | + DeeModelIter* source_iter = dee_model_get_first_iter(source); |
793 | + DeeModelIter* source_end = dee_model_get_last_iter(source); |
794 | + |
795 | + for (source_iter = dee_model_get_first_iter(source), source_end = dee_model_get_last_iter(source); |
796 | + source_iter != source_end; |
797 | + source_iter = dee_model_next(source, source_iter)) |
798 | + { |
799 | + DeeModelIter* target_iter = static_cast<DeeModelIter*>(dee_model_get_tag(source, source_iter, target_tag)); |
800 | + |
801 | + /* No guarantee that rows in the source are mapped to the target */ |
802 | + if (target_iter == NULL) |
803 | + continue; |
804 | + |
805 | + unsigned int source_cat_offset = dee_model_get_uint32(source, source_iter, CATEGORY_COLUMN); |
806 | + int cat_offset = cat_registry_->FindCategoryOffset(source, source_cat_offset); |
807 | + |
808 | + if (G_LIKELY(cat_offset >= 0)) |
809 | + { |
810 | + dee_model_set_value(target_, target_iter, CATEGORY_COLUMN, |
811 | + g_variant_new_uint32(cat_offset)); |
812 | + } |
813 | + else |
814 | + { |
815 | + LOG_ERROR(logger) << "No registered category id for category " |
816 | + << source_cat_offset << " on result source model " |
817 | + << source << "."; |
818 | + /* We can't really recover from this :-( */ |
819 | + } |
820 | + } |
821 | + } |
822 | +} |
823 | + |
824 | +HomeLens::Impl::Impl(HomeLens *owner) |
825 | + : owner_(owner) |
826 | + , cat_registry_(owner) |
827 | + , results_merger_(owner->results()->model(), &cat_registry_) |
828 | + , categories_merger_(owner->categories()->model(), &cat_registry_) |
829 | + , filters_merger_(owner->filters()->model()) |
830 | + , running_searches_(0) |
831 | + , settings_(g_settings_new("com.canonical.Unity.Dash")) |
832 | +{ |
833 | + DeeModel* results = owner->results()->model(); |
834 | + if (dee_model_get_n_columns(results) == 0) |
835 | + { |
836 | + dee_model_set_schema(results, "s", "s", "u", "s", "s", "s", "s", NULL); |
837 | + } |
838 | + |
839 | + DeeModel* categories = owner->categories()->model(); |
840 | + if (dee_model_get_n_columns(categories) == 0) |
841 | + { |
842 | + dee_model_set_schema(categories, "s", "s", "s", "a{sv}", NULL); |
843 | + } |
844 | + |
845 | + DeeModel* filters = owner->filters()->model(); |
846 | + if (dee_model_get_n_columns(filters) == 0) |
847 | + { |
848 | + dee_model_set_schema(filters, "s", "s", "s", "s", "a{sv}", "b", "b", "b", NULL); |
849 | + } |
850 | +} |
851 | + |
852 | +HomeLens::Impl::~Impl() |
853 | +{ |
854 | + |
855 | +} |
856 | + |
857 | +/*void HomeLens::Impl::CheckCategories() |
858 | +{ |
859 | + |
860 | +}*/ |
861 | + |
862 | +gsize HomeLens::Impl::FindLensPriority (Lens::Ptr& lens) |
863 | +{ |
864 | + gchar** lenses = g_settings_get_strv(settings_, "home-lens-ordering"); |
865 | + gsize pos = 0, len = g_strv_length(lenses); |
866 | + |
867 | + for (pos = 0; pos < len; pos++) |
868 | + { |
869 | + if (g_strcmp0(lenses[pos], lens->id().c_str()) == 0) |
870 | + break; |
871 | + } |
872 | + |
873 | + g_strfreev(lenses); |
874 | + |
875 | + return len - pos; |
876 | +} |
877 | + |
878 | +void HomeLens::Impl::EnsureCategoryAnnotation (Lens::Ptr& lens, |
879 | + DeeModel* categories, |
880 | + DeeModel* results) |
881 | +{ |
882 | + if (categories && results) |
883 | + { |
884 | + if (!(DEE_IS_MODEL(results) && DEE_IS_MODEL(categories))) |
885 | + { |
886 | + LOG_ERROR(logger) << "The " |
887 | + << std::string(DEE_IS_MODEL(results) ? "categories" : "results") |
888 | + << " model is not a valid DeeModel. (" |
889 | + << lens->id() << ")"; |
890 | + return; |
891 | + } |
892 | + |
893 | + g_object_set_data(G_OBJECT(categories), |
894 | + "unity-homelens-results-model", |
895 | + results); |
896 | + |
897 | + gsize lens_priority = FindLensPriority(lens); |
898 | + g_object_set_data(G_OBJECT(categories), |
899 | + "unity-homelens-priority", |
900 | + GSIZE_TO_POINTER(lens_priority)); |
901 | + |
902 | + LOG_DEBUG(logger) << "Registering results model " << results |
903 | + << " and lens priority " << lens_priority |
904 | + << " on category model " << categories << ". (" |
905 | + << lens->id() << ")"; |
906 | + } |
907 | +} |
908 | + |
909 | +Lens::Ptr HomeLens::Impl::FindLensForUri(std::string const& uri) |
910 | +{ |
911 | + /* We iterate over all lenses looking for the given uri in their |
912 | + * global results. This might seem like a sucky approach, but it |
913 | + * saves us from a ship load of book keeping */ |
914 | + |
915 | + for (auto lens : lenses_) |
916 | + { |
917 | + DeeModel* results = lens->global_results()->model(); |
918 | + DeeModelIter* iter = dee_model_get_first_iter(results); |
919 | + DeeModelIter* end = dee_model_get_last_iter(results); |
920 | + const int URI_COLUMN = 0; |
921 | + |
922 | + while (iter != end) |
923 | + { |
924 | + if (g_strcmp0(uri.c_str(), dee_model_get_string(results, iter, URI_COLUMN)) == 0) |
925 | + { |
926 | + return lens; |
927 | + } |
928 | + iter = dee_model_next(results, iter); |
929 | + } |
930 | + } |
931 | + |
932 | + return Lens::Ptr(); |
933 | +} |
934 | + |
935 | +// FIXME: Coordinated sorting between the lens bar and home screen categories. Make void FilesystemLenses::Impl::DecrementAndCheckChildrenWaiting() use the gsettings key |
936 | +// FIXME: on no results https://bugs.launchpad.net/unity/+bug/711199 |
937 | + |
938 | +void HomeLens::Impl::OnLensAdded (Lens::Ptr& lens) |
939 | +{ |
940 | + lenses_.push_back (lens); |
941 | + owner_->lens_added.emit(lens); |
942 | + |
943 | + /* When we dispatch a search we inc the search count and when we finish |
944 | + * one we decrease it. When we reach 0 we'll emit search_finished. */ |
945 | + lens->global_search_finished.connect([&] (Hints const& hints) { |
946 | + running_searches_--; |
947 | + |
948 | + if (running_searches_ <= 0) |
949 | + { |
950 | + owner_->search_finished.emit(Hints()); |
951 | + LOG_DEBUG(logger) << "Search finished"; |
952 | + } |
953 | + }); |
954 | + |
955 | + nux::ROProperty<glib::Object<DeeModel>>& results_prop = lens->global_results()->model; |
956 | + nux::ROProperty<glib::Object<DeeModel>>& categories_prop = lens->categories()->model; |
957 | + nux::ROProperty<glib::Object<DeeModel>>& filters_prop = lens->filters()->model; |
958 | + |
959 | + /* |
960 | + * Important: We must ensure that the categories model is annotated |
961 | + * with the results model in the "unity-homelens-results-model" |
962 | + * data slot. We need it later to compute the transfermed offsets |
963 | + * of the categories in the merged category model. |
964 | + */ |
965 | + |
966 | + /* Most lenses add models lazily, but we can't know that; |
967 | + * so try to see if we can add them up front */ |
968 | + if (results_prop().RawPtr()) |
969 | + { |
970 | + EnsureCategoryAnnotation(lens, categories_prop(), results_prop()); |
971 | + results_merger_.AddSource(results_prop()); |
972 | + } |
973 | + |
974 | + if (categories_prop().RawPtr()) |
975 | + { |
976 | + EnsureCategoryAnnotation(lens, categories_prop(), results_prop()); |
977 | + categories_merger_.AddSource(categories_prop()); |
978 | + } |
979 | + |
980 | + if (filters_prop().RawPtr()) |
981 | + filters_merger_.AddSource(filters_prop()); |
982 | + |
983 | + /* |
984 | + * Pick it up when the lens set models lazily. |
985 | + */ |
986 | + results_prop.changed.connect([&] (glib::Object<DeeModel> model) |
987 | + { |
988 | + EnsureCategoryAnnotation(lens, lens->categories()->model(), model); |
989 | + results_merger_.AddSource(model); |
990 | + }); |
991 | + |
992 | + categories_prop.changed.connect([&] (glib::Object<DeeModel> model) |
993 | + { |
994 | + EnsureCategoryAnnotation(lens, model, lens->global_results()->model()); |
995 | + categories_merger_.AddSource(model); |
996 | + }); |
997 | + |
998 | + filters_prop.changed.connect([&] (glib::Object<DeeModel> model) |
999 | + { |
1000 | + filters_merger_.AddSource(model); |
1001 | + }); |
1002 | + |
1003 | + /* |
1004 | + * Register pre-existing categories up front |
1005 | + * FIXME: Do the same for results? |
1006 | + */ |
1007 | + DeeModel* cats = categories_prop(); |
1008 | + DeeModelIter* cats_iter; |
1009 | + DeeModelIter* cats_end; |
1010 | + for (cats_iter = dee_model_get_first_iter(cats), cats_end = dee_model_get_last_iter(cats); |
1011 | + cats_iter != cats_end; |
1012 | + cats_iter = dee_model_next(cats, cats_iter)) |
1013 | + { |
1014 | + categories_merger_.OnSourceRowAdded(cats, cats_iter); |
1015 | + } |
1016 | +} |
1017 | + |
1018 | +HomeLens::HomeLens(std::string const& name, std::string const& description, std::string const& search_hint) |
1019 | + : Lens("home.lens", "", "", name, PKGDATADIR"/lens-nav-home.svg", |
1020 | + description, search_hint, true, "", |
1021 | + ModelType::LOCAL) |
1022 | + , pimpl(new Impl(this)) |
1023 | +{ |
1024 | + count.SetGetterFunction(sigc::mem_fun(&pimpl->lenses_, &Lenses::LensList::size)); |
1025 | + search_in_global = false; |
1026 | +} |
1027 | + |
1028 | +HomeLens::~HomeLens() |
1029 | +{ |
1030 | + delete pimpl; |
1031 | +} |
1032 | + |
1033 | +void HomeLens::AddLenses(Lenses& lenses) |
1034 | +{ |
1035 | + for (auto lens : lenses.GetLenses()) |
1036 | + { |
1037 | + pimpl->OnLensAdded(lens); |
1038 | + } |
1039 | + |
1040 | + lenses.lens_added.connect(sigc::mem_fun(pimpl, &HomeLens::Impl::OnLensAdded)); |
1041 | +} |
1042 | + |
1043 | +Lenses::LensList HomeLens::GetLenses() const |
1044 | +{ |
1045 | + return pimpl->lenses_; |
1046 | +} |
1047 | + |
1048 | +Lens::Ptr HomeLens::GetLens(std::string const& lens_id) const |
1049 | +{ |
1050 | + for (auto lens: pimpl->lenses_) |
1051 | + { |
1052 | + if (lens->id == lens_id) |
1053 | + { |
1054 | + return lens; |
1055 | + } |
1056 | + } |
1057 | + |
1058 | + return Lens::Ptr(); |
1059 | +} |
1060 | + |
1061 | +Lens::Ptr HomeLens::GetLensAtIndex(std::size_t index) const |
1062 | +{ |
1063 | + try |
1064 | + { |
1065 | + return pimpl->lenses_.at(index); |
1066 | + } |
1067 | + catch (std::out_of_range& error) |
1068 | + { |
1069 | + LOG_WARN(logger) << error.what(); |
1070 | + } |
1071 | + |
1072 | + return Lens::Ptr(); |
1073 | +} |
1074 | + |
1075 | +void HomeLens::GlobalSearch(std::string const& search_string) |
1076 | +{ |
1077 | + LOG_WARN(logger) << "Global search not enabled for HomeLens class." |
1078 | + << " Ignoring query '" << search_string << "'"; |
1079 | +} |
1080 | + |
1081 | +void HomeLens::Search(std::string const& search_string) |
1082 | +{ |
1083 | + LOG_DEBUG(logger) << "Search '" << search_string << "'"; |
1084 | + |
1085 | + /* Reset running search counter */ |
1086 | + pimpl->running_searches_ = 0; |
1087 | + |
1088 | + for (auto lens: pimpl->lenses_) |
1089 | + { |
1090 | + if (lens->search_in_global()) |
1091 | + { |
1092 | + LOG_DEBUG(logger) << " - Global search on '" << lens->id() << "' for '" |
1093 | + << search_string << "'"; |
1094 | + lens->view_type = ViewType::HOME_VIEW; |
1095 | + lens->GlobalSearch(search_string); |
1096 | + pimpl->running_searches_++; |
1097 | + } |
1098 | + } |
1099 | +} |
1100 | + |
1101 | +void HomeLens::Activate(std::string const& uri) |
1102 | +{ |
1103 | + LOG_DEBUG(logger) << "Activate '" << uri << "'"; |
1104 | + |
1105 | + Lens::Ptr lens = pimpl->FindLensForUri(uri); |
1106 | + |
1107 | + /* Fall back to default handling of URIs if no lens is found. |
1108 | + * - Although, this shouldn't really happen */ |
1109 | + if (lens) |
1110 | + { |
1111 | + LOG_DEBUG(logger) << "Activation request passed to '" << lens->id() << "'"; |
1112 | + lens->Activate(uri); |
1113 | + } |
1114 | + else |
1115 | + { |
1116 | + LOG_WARN(logger) << "Unable to find a lens for activating '" << uri |
1117 | + << "'. Using fallback activation."; |
1118 | + activated.emit(uri, HandledType::NOT_HANDLED, Hints()); |
1119 | + } |
1120 | +} |
1121 | + |
1122 | +void HomeLens::Preview(std::string const& uri) |
1123 | +{ |
1124 | + LOG_DEBUG(logger) << "Preview '" << uri << "'"; |
1125 | + |
1126 | + Lens::Ptr lens = pimpl->FindLensForUri(uri); |
1127 | + |
1128 | + if (lens) |
1129 | + lens->Preview(uri); |
1130 | + else |
1131 | + LOG_WARN(logger) << "Unable to find a lens for previewing '" << uri << "'"; |
1132 | +} |
1133 | + |
1134 | +} |
1135 | +} |
1136 | |
1137 | === added file 'UnityCore/HomeLens.h' |
1138 | --- UnityCore/HomeLens.h 1970-01-01 00:00:00 +0000 |
1139 | +++ UnityCore/HomeLens.h 2012-01-26 08:37:26 +0000 |
1140 | @@ -0,0 +1,79 @@ |
1141 | +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- |
1142 | +/* |
1143 | + * Copyright (C) 2012 Canonical Ltd |
1144 | + * |
1145 | + * This program is free software: you can redistribute it and/or modify |
1146 | + * it under the terms of the GNU General Public License version 3 as |
1147 | + * published by the Free Software Foundation. |
1148 | + * |
1149 | + * This program is distributed in the hope that it will be useful, |
1150 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1151 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1152 | + * GNU General Public License for more details. |
1153 | + * |
1154 | + * You should have received a copy of the GNU General Public License |
1155 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1156 | + * |
1157 | + * Authored by: Mikkel Kamstrup Erlandsen <mikkel.kamstrup@canonical.com> |
1158 | + */ |
1159 | + |
1160 | +#ifndef UNITY_HOME_LENS_H |
1161 | +#define UNITY_HOME_LENS_H |
1162 | + |
1163 | +#include <vector> |
1164 | +#include <memory> |
1165 | +#include <sigc++/signal.h> |
1166 | +#include <sigc++/trackable.h> |
1167 | + |
1168 | +#include "Lenses.h" |
1169 | +#include "Lens.h" |
1170 | + |
1171 | +namespace unity |
1172 | +{ |
1173 | +namespace dash |
1174 | +{ |
1175 | + |
1176 | +/** |
1177 | + * A special Lens implementation that merges together a set of source Lens |
1178 | + * instances. |
1179 | + * |
1180 | + * NOTE: Changes in the filter models are currently not propagated back to the |
1181 | + * the source lenses. If we want to support filters on the dash home |
1182 | + * screen this needs to be addressed. |
1183 | + */ |
1184 | +class HomeLens : public Lens, public Lenses |
1185 | +{ |
1186 | +public: |
1187 | + typedef std::shared_ptr<HomeLens> Ptr; |
1188 | + |
1189 | + /** |
1190 | + * Should be constructed with i18n arguments: |
1191 | + * _("Home"), _("Home screen"), _("Search") |
1192 | + */ |
1193 | + HomeLens(std::string const& name, std::string const& description, std::string const& search_hint); |
1194 | + virtual ~HomeLens(); |
1195 | + |
1196 | + void AddLenses(Lenses& lenses); |
1197 | + |
1198 | + Lenses::LensList GetLenses() const; |
1199 | + Lens::Ptr GetLens(std::string const& lens_id) const; |
1200 | + Lens::Ptr GetLensAtIndex(std::size_t index) const; |
1201 | + |
1202 | + void GlobalSearch(std::string const& search_string); |
1203 | + void Search(std::string const& search_string); |
1204 | + void Activate(std::string const& uri); |
1205 | + void Preview(std::string const& uri); |
1206 | + |
1207 | +private: |
1208 | + class Impl; |
1209 | + class ModelMerger; |
1210 | + class ResultsMerger; |
1211 | + class CategoryMerger; |
1212 | + class CategoryRegistry; |
1213 | + Impl* pimpl; |
1214 | +}; |
1215 | + |
1216 | +} |
1217 | +} |
1218 | + |
1219 | +#endif |
1220 | |
1221 | === modified file 'UnityCore/Lens.cpp' |
1222 | --- UnityCore/Lens.cpp 2012-01-17 16:02:39 +0000 |
1223 | +++ UnityCore/Lens.cpp 2012-01-26 08:37:26 +0000 |
1224 | @@ -51,11 +51,12 @@ |
1225 | string const& description, |
1226 | string const& search_hint, |
1227 | bool visible, |
1228 | - string const& shortcut); |
1229 | + string const& shortcut, |
1230 | + ModelType model_type); |
1231 | |
1232 | ~Impl(); |
1233 | |
1234 | - void OnProxyConnected(); |
1235 | + void OnProxyConnectionChanged(); |
1236 | void OnProxyDisconnected(); |
1237 | |
1238 | void ResultsModelUpdated(unsigned long long begin_seqnum, |
1239 | @@ -94,6 +95,7 @@ |
1240 | string const& search_hint() const; |
1241 | bool visible() const; |
1242 | bool search_in_global() const; |
1243 | + bool set_search_in_global(bool val); |
1244 | string const& shortcut() const; |
1245 | Results::Ptr const& results() const; |
1246 | Results::Ptr const& global_results() const; |
1247 | @@ -121,7 +123,7 @@ |
1248 | |
1249 | string private_connection_name_; |
1250 | |
1251 | - glib::DBusProxy proxy_; |
1252 | + glib::DBusProxy* proxy_; |
1253 | glib::Object<GCancellable> search_cancellable_; |
1254 | glib::Object<GCancellable> global_search_cancellable_; |
1255 | |
1256 | @@ -138,7 +140,8 @@ |
1257 | string const& description, |
1258 | string const& search_hint, |
1259 | bool visible, |
1260 | - string const& shortcut) |
1261 | + string const& shortcut, |
1262 | + ModelType model_type) |
1263 | : owner_(owner) |
1264 | , id_(id) |
1265 | , dbus_name_(dbus_name) |
1266 | @@ -150,20 +153,46 @@ |
1267 | , visible_(visible) |
1268 | , search_in_global_(false) |
1269 | , shortcut_(shortcut) |
1270 | - , results_(new Results()) |
1271 | - , global_results_(new Results()) |
1272 | - , categories_(new Categories()) |
1273 | - , filters_(new Filters()) |
1274 | + , results_(new Results(model_type)) |
1275 | + , global_results_(new Results(model_type)) |
1276 | + , categories_(new Categories(model_type)) |
1277 | + , filters_(new Filters(model_type)) |
1278 | , connected_(false) |
1279 | - , proxy_(dbus_name, dbus_path, "com.canonical.Unity.Lens") |
1280 | + , proxy_(NULL) |
1281 | , results_variant_(NULL) |
1282 | , global_results_variant_(NULL) |
1283 | { |
1284 | - proxy_.connected.connect(sigc::mem_fun(this, &Lens::Impl::OnProxyConnected)); |
1285 | - proxy_.disconnected.connect(sigc::mem_fun(this, &Lens::Impl::OnProxyDisconnected)); |
1286 | - proxy_.Connect("Changed", sigc::mem_fun(this, &Lens::Impl::OnChanged)); |
1287 | + if (model_type == ModelType::REMOTE) |
1288 | + { |
1289 | + proxy_ = new glib::DBusProxy(dbus_name, dbus_path, "com.canonical.Unity.Lens"); |
1290 | + proxy_->connected.connect(sigc::mem_fun(this, &Lens::Impl::OnProxyConnectionChanged)); |
1291 | + proxy_->disconnected.connect(sigc::mem_fun(this, &Lens::Impl::OnProxyDisconnected)); |
1292 | + proxy_->Connect("Changed", sigc::mem_fun(this, &Lens::Impl::OnChanged)); |
1293 | + } |
1294 | + |
1295 | + /* Technically these signals will only be fired by remote models, but we |
1296 | + * connect them no matter the ModelType. Dee may grow support in the future. |
1297 | + */ |
1298 | results_->end_transaction.connect(sigc::mem_fun(this, &Lens::Impl::ResultsModelUpdated)); |
1299 | global_results_->end_transaction.connect(sigc::mem_fun(this, &Lens::Impl::GlobalResultsModelUpdated)); |
1300 | + |
1301 | + owner_->id.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::id)); |
1302 | + owner_->dbus_name.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::dbus_name)); |
1303 | + owner_->dbus_path.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::dbus_path)); |
1304 | + owner_->name.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::name)); |
1305 | + owner_->icon_hint.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::icon_hint)); |
1306 | + owner_->description.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::description)); |
1307 | + owner_->search_hint.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::search_hint)); |
1308 | + owner_->visible.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::visible)); |
1309 | + owner_->search_in_global.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::search_in_global)); |
1310 | + owner_->search_in_global.SetSetterFunction(sigc::mem_fun(this, &Lens::Impl::set_search_in_global)); |
1311 | + owner_->shortcut.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::shortcut)); |
1312 | + owner_->results.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::results)); |
1313 | + owner_->global_results.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::global_results)); |
1314 | + owner_->categories.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::categories)); |
1315 | + owner_->filters.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::filters)); |
1316 | + owner_->connected.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::connected)); |
1317 | + owner_->view_type.changed.connect(sigc::mem_fun(this, &Lens::Impl::OnViewTypeChanged)); |
1318 | } |
1319 | |
1320 | Lens::Impl::~Impl() |
1321 | @@ -176,13 +205,19 @@ |
1322 | { |
1323 | g_cancellable_cancel (global_search_cancellable_); |
1324 | } |
1325 | + |
1326 | + if (proxy_) |
1327 | + delete proxy_; |
1328 | } |
1329 | |
1330 | -void Lens::Impl::OnProxyConnected() |
1331 | +void Lens::Impl::OnProxyConnectionChanged() |
1332 | { |
1333 | - proxy_.Call("InfoRequest"); |
1334 | - ViewType current_view_type = owner_->view_type; |
1335 | - proxy_.Call("SetViewType", g_variant_new("(u)", current_view_type)); |
1336 | + if (proxy_->IsConnected()) |
1337 | + { |
1338 | + proxy_->Call("InfoRequest"); |
1339 | + ViewType current_view_type = owner_->view_type; |
1340 | + proxy_->Call("SetViewType", g_variant_new("(u)", current_view_type)); |
1341 | + } |
1342 | } |
1343 | |
1344 | void Lens::Impl::OnProxyDisconnected() |
1345 | @@ -387,12 +422,13 @@ |
1346 | |
1347 | void Lens::Impl::OnViewTypeChanged(ViewType view_type) |
1348 | { |
1349 | - proxy_.Call("SetViewType", g_variant_new("(u)", view_type)); |
1350 | + if (proxy_ && proxy_->IsConnected()) |
1351 | + proxy_->Call("SetViewType", g_variant_new("(u)", view_type)); |
1352 | } |
1353 | |
1354 | void Lens::Impl::GlobalSearch(std::string const& search_string) |
1355 | { |
1356 | - LOG_DEBUG(logger) << "Global Searching " << id_ << " for " << search_string; |
1357 | + LOG_DEBUG(logger) << "Global Searching '" << id_ << "' for '" << search_string << "'"; |
1358 | |
1359 | GVariantBuilder b; |
1360 | g_variant_builder_init(&b, G_VARIANT_TYPE("a{sv}")); |
1361 | @@ -407,7 +443,7 @@ |
1362 | global_results_variant_ = NULL; |
1363 | } |
1364 | |
1365 | - proxy_.Call("GlobalSearch", |
1366 | + proxy_->Call("GlobalSearch", |
1367 | g_variant_new("(sa{sv})", |
1368 | search_string.c_str(), |
1369 | &b), |
1370 | @@ -418,7 +454,13 @@ |
1371 | |
1372 | void Lens::Impl::Search(std::string const& search_string) |
1373 | { |
1374 | - LOG_DEBUG(logger) << "Searching " << id_ << " for " << search_string; |
1375 | + LOG_DEBUG(logger) << "Searching '" << id_ << "' for '" << search_string << "'"; |
1376 | + |
1377 | + if (!proxy_->IsConnected()) |
1378 | + { |
1379 | + LOG_DEBUG(logger) << "Skipping search. Proxy not connected. ('" << id_ << "')"; |
1380 | + return; |
1381 | + } |
1382 | |
1383 | GVariantBuilder b; |
1384 | g_variant_builder_init(&b, G_VARIANT_TYPE("a{sv}")); |
1385 | @@ -432,23 +474,29 @@ |
1386 | results_variant_ = NULL; |
1387 | } |
1388 | |
1389 | - proxy_.Call("Search", |
1390 | - g_variant_new("(sa{sv})", |
1391 | - search_string.c_str(), |
1392 | - &b), |
1393 | - sigc::mem_fun(this, &Lens::Impl::OnSearchFinished), |
1394 | - search_cancellable_); |
1395 | + proxy_->Call("Search", |
1396 | + g_variant_new("(sa{sv})", |
1397 | + search_string.c_str(), |
1398 | + &b), |
1399 | + sigc::mem_fun(this, &Lens::Impl::OnSearchFinished), |
1400 | + search_cancellable_); |
1401 | |
1402 | g_variant_builder_clear(&b); |
1403 | } |
1404 | |
1405 | void Lens::Impl::Activate(std::string const& uri) |
1406 | { |
1407 | - LOG_DEBUG(logger) << "Activating " << uri << " on " << id_; |
1408 | - |
1409 | - proxy_.Call("Activate", |
1410 | - g_variant_new("(su)", uri.c_str(), 0), |
1411 | - sigc::mem_fun(this, &Lens::Impl::ActivationReply)); |
1412 | + LOG_DEBUG(logger) << "Activating '" << uri << "' on '" << id_ << "'"; |
1413 | + |
1414 | + if (!proxy_->IsConnected()) |
1415 | + { |
1416 | + LOG_DEBUG(logger) << "Skipping activation. Proxy not connected. ('" << id_ << "')"; |
1417 | + return; |
1418 | + } |
1419 | + |
1420 | + proxy_->Call("Activate", |
1421 | + g_variant_new("(su)", uri.c_str(), 0), |
1422 | + sigc::mem_fun(this, &Lens::Impl::ActivationReply)); |
1423 | } |
1424 | |
1425 | void Lens::Impl::ActivationReply(GVariant* parameters) |
1426 | @@ -468,11 +516,17 @@ |
1427 | |
1428 | void Lens::Impl::Preview(std::string const& uri) |
1429 | { |
1430 | - LOG_DEBUG(logger) << "Previewing " << uri << " on " << id_; |
1431 | - |
1432 | - proxy_.Call("Preview", |
1433 | - g_variant_new("(s)", uri.c_str()), |
1434 | - sigc::mem_fun(this, &Lens::Impl::PreviewReply)); |
1435 | + LOG_DEBUG(logger) << "Previewing '" << uri << "' on '" << id_ << "'"; |
1436 | + |
1437 | + if (!proxy_->IsConnected()) |
1438 | + { |
1439 | + LOG_DEBUG(logger) << "Skipping preview. Proxy not connected. ('" << id_ << "')"; |
1440 | + return; |
1441 | + } |
1442 | + |
1443 | + proxy_->Call("Preview", |
1444 | + g_variant_new("(s)", uri.c_str()), |
1445 | + sigc::mem_fun(this, &Lens::Impl::PreviewReply)); |
1446 | } |
1447 | |
1448 | void Lens::Impl::PreviewReply(GVariant* parameters) |
1449 | @@ -535,6 +589,17 @@ |
1450 | return search_in_global_; |
1451 | } |
1452 | |
1453 | +bool Lens::Impl::set_search_in_global(bool val) |
1454 | +{ |
1455 | + if (search_in_global_ != val) |
1456 | + { |
1457 | + search_in_global_ = val; |
1458 | + owner_->search_in_global.EmitChanged(val); |
1459 | + } |
1460 | + |
1461 | + return search_in_global_; |
1462 | +} |
1463 | + |
1464 | string const& Lens::Impl::shortcut() const |
1465 | { |
1466 | return shortcut_; |
1467 | @@ -584,25 +649,33 @@ |
1468 | description_, |
1469 | search_hint_, |
1470 | visible_, |
1471 | - shortcut_)) |
1472 | -{ |
1473 | - id.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::id)); |
1474 | - dbus_name.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::dbus_name)); |
1475 | - dbus_path.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::dbus_path)); |
1476 | - name.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::name)); |
1477 | - icon_hint.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::icon_hint)); |
1478 | - description.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::description)); |
1479 | - search_hint.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::search_hint)); |
1480 | - visible.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::visible)); |
1481 | - search_in_global.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::search_in_global)); |
1482 | - shortcut.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::shortcut)); |
1483 | - results.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::results)); |
1484 | - global_results.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::global_results)); |
1485 | - categories.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::categories)); |
1486 | - filters.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::filters)); |
1487 | - connected.SetGetterFunction(sigc::mem_fun(pimpl, &Lens::Impl::connected)); |
1488 | - view_type.changed.connect(sigc::mem_fun(pimpl, &Lens::Impl::OnViewTypeChanged)); |
1489 | -} |
1490 | + shortcut_, |
1491 | + ModelType::REMOTE)) |
1492 | +{} |
1493 | + |
1494 | +Lens::Lens(string const& id_, |
1495 | + string const& dbus_name_, |
1496 | + string const& dbus_path_, |
1497 | + string const& name_, |
1498 | + string const& icon_hint_, |
1499 | + string const& description_, |
1500 | + string const& search_hint_, |
1501 | + bool visible_, |
1502 | + string const& shortcut_, |
1503 | + ModelType model_type) |
1504 | + |
1505 | + : pimpl(new Impl(this, |
1506 | + id_, |
1507 | + dbus_name_, |
1508 | + dbus_path_, |
1509 | + name_, |
1510 | + icon_hint_, |
1511 | + description_, |
1512 | + search_hint_, |
1513 | + visible_, |
1514 | + shortcut_, |
1515 | + model_type)) |
1516 | +{} |
1517 | |
1518 | Lens::~Lens() |
1519 | { |
1520 | |
1521 | === modified file 'UnityCore/Lens.h' |
1522 | --- UnityCore/Lens.h 2012-01-17 13:31:52 +0000 |
1523 | +++ UnityCore/Lens.h 2012-01-26 08:37:26 +0000 |
1524 | @@ -67,12 +67,23 @@ |
1525 | bool visible = true, |
1526 | std::string const& shortcut = ""); |
1527 | |
1528 | - ~Lens(); |
1529 | - |
1530 | - void GlobalSearch(std::string const& search_string); |
1531 | - void Search(std::string const& search_string); |
1532 | - void Activate(std::string const& uri); |
1533 | - void Preview(std::string const& uri); |
1534 | + Lens(std::string const& id, |
1535 | + std::string const& dbus_name, |
1536 | + std::string const& dbus_path, |
1537 | + std::string const& name, |
1538 | + std::string const& icon, |
1539 | + std::string const& description, |
1540 | + std::string const& search_hint, |
1541 | + bool visible, |
1542 | + std::string const& shortcut, |
1543 | + ModelType model_type); |
1544 | + |
1545 | + virtual ~Lens(); |
1546 | + |
1547 | + virtual void GlobalSearch(std::string const& search_string); |
1548 | + virtual void Search(std::string const& search_string); |
1549 | + virtual void Activate(std::string const& uri); |
1550 | + virtual void Preview(std::string const& uri); |
1551 | |
1552 | nux::RWProperty<std::string> id; |
1553 | nux::RWProperty<std::string> dbus_name; |
1554 | |
1555 | === modified file 'UnityCore/Model-inl.h' |
1556 | --- UnityCore/Model-inl.h 2012-01-10 14:14:17 +0000 |
1557 | +++ UnityCore/Model-inl.h 2012-01-26 08:37:26 +0000 |
1558 | @@ -34,10 +34,28 @@ |
1559 | |
1560 | template<class RowAdaptor> |
1561 | Model<RowAdaptor>::Model() |
1562 | + : model_type_(ModelType::REMOTE) |
1563 | +{ |
1564 | + Init(); |
1565 | +} |
1566 | + |
1567 | +template<class RowAdaptor> |
1568 | +Model<RowAdaptor>::Model (ModelType model_type) |
1569 | + : model_type_(model_type) |
1570 | +{ |
1571 | + Init(); |
1572 | + |
1573 | + if (model_type == ModelType::LOCAL) |
1574 | + swarm_name = ":local"; |
1575 | +} |
1576 | + |
1577 | +template<class RowAdaptor> |
1578 | +void Model<RowAdaptor>::Init () |
1579 | { |
1580 | swarm_name.changed.connect(sigc::mem_fun(this, &Model<RowAdaptor>::OnSwarmNameChanged)); |
1581 | count.SetGetterFunction(sigc::mem_fun(this, &Model<RowAdaptor>::get_count)); |
1582 | seqnum.SetGetterFunction(sigc::mem_fun(this, &Model<RowAdaptor>::get_seqnum)); |
1583 | + model.SetGetterFunction(sigc::mem_fun(this, &Model<RowAdaptor>::get_model)); |
1584 | } |
1585 | |
1586 | template<class RowAdaptor> |
1587 | @@ -52,7 +70,29 @@ |
1588 | if (model_) |
1589 | dee_model_clear(model_); |
1590 | |
1591 | - model_ = dee_shared_model_new(swarm_name.c_str()); |
1592 | + switch(model_type_) |
1593 | + { |
1594 | + case ModelType::LOCAL: |
1595 | + model_ = dee_sequence_model_new(); |
1596 | + break; |
1597 | + case ModelType::REMOTE: |
1598 | + model_ = dee_shared_model_new(swarm_name.c_str()); |
1599 | + sig_manager_.Add(new TransactionSignalType(model_, |
1600 | + "begin-transaction", |
1601 | + sigc::mem_fun(this, &Model<RowAdaptor>::OnTransactionBegin))); |
1602 | + |
1603 | + sig_manager_.Add(new TransactionSignalType(model_, |
1604 | + "end-transaction", |
1605 | + sigc::mem_fun(this, &Model<RowAdaptor>::OnTransactionEnd))); |
1606 | + break; |
1607 | + default: |
1608 | + LOG_ERROR(_model_inl_logger) << "Unexpected ModelType " << model_type_; |
1609 | + break; |
1610 | + } |
1611 | + |
1612 | + model.EmitChanged(model_); |
1613 | + |
1614 | + |
1615 | renderer_tag_ = dee_model_register_tag(model_, NULL); |
1616 | |
1617 | sig_manager_.Add(new RowSignalType(model_, |
1618 | @@ -66,14 +106,6 @@ |
1619 | sig_manager_.Add(new RowSignalType(model_, |
1620 | "row-removed", |
1621 | sigc::mem_fun(this, &Model<RowAdaptor>::OnRowRemoved))); |
1622 | - |
1623 | - sig_manager_.Add(new TransactionSignalType(model_, |
1624 | - "begin-transaction", |
1625 | - sigc::mem_fun(this, &Model<RowAdaptor>::OnTransactionBegin))); |
1626 | - |
1627 | - sig_manager_.Add(new TransactionSignalType(model_, |
1628 | - "end-transaction", |
1629 | - sigc::mem_fun(this, &Model<RowAdaptor>::OnTransactionEnd))); |
1630 | } |
1631 | |
1632 | template<class RowAdaptor> |
1633 | @@ -148,6 +180,12 @@ |
1634 | return 0; |
1635 | } |
1636 | |
1637 | +template<class RowAdaptor> |
1638 | +glib::Object<DeeModel> Model<RowAdaptor>::get_model() |
1639 | +{ |
1640 | + return model_; |
1641 | +} |
1642 | + |
1643 | } |
1644 | } |
1645 | |
1646 | |
1647 | === modified file 'UnityCore/Model.h' |
1648 | --- UnityCore/Model.h 2012-01-10 14:14:17 +0000 |
1649 | +++ UnityCore/Model.h 2012-01-26 08:37:26 +0000 |
1650 | @@ -35,6 +35,12 @@ |
1651 | namespace dash |
1652 | { |
1653 | |
1654 | +enum ModelType |
1655 | +{ |
1656 | + REMOTE, |
1657 | + LOCAL |
1658 | +}; |
1659 | + |
1660 | /* This template class encapsulates the basics of talking to a DeeSharedModel, |
1661 | * however it is a template as you can choose your own RowAdaptor (see |
1662 | * ResultsRowAdaptor.h for an example) which then presents the data in the rows |
1663 | @@ -47,6 +53,7 @@ |
1664 | typedef std::shared_ptr<Model> Ptr; |
1665 | |
1666 | Model(); |
1667 | + Model (ModelType model_type); |
1668 | virtual ~Model(); |
1669 | |
1670 | const RowAdaptor RowAtIndex(std::size_t index); |
1671 | @@ -54,6 +61,7 @@ |
1672 | nux::Property<std::string> swarm_name; |
1673 | nux::ROProperty<std::size_t> count; |
1674 | nux::ROProperty<unsigned long long> seqnum; |
1675 | + nux::ROProperty<glib::Object<DeeModel>> model; |
1676 | |
1677 | sigc::signal<void, RowAdaptor&> row_added; |
1678 | sigc::signal<void, RowAdaptor&> row_changed; |
1679 | @@ -63,6 +71,7 @@ |
1680 | sigc::signal<void, unsigned long long, unsigned long long> end_transaction; |
1681 | |
1682 | private: |
1683 | + void Init(); |
1684 | void OnRowAdded(DeeModel* model, DeeModelIter* iter); |
1685 | void OnRowChanged(DeeModel* model, DeeModelIter* iter); |
1686 | void OnRowRemoved(DeeModel* model, DeeModelIter* iter); |
1687 | @@ -71,11 +80,13 @@ |
1688 | void OnSwarmNameChanged(std::string const& swarm_name); |
1689 | std::size_t get_count(); |
1690 | unsigned long long get_seqnum(); |
1691 | + glib::Object<DeeModel> get_model(); |
1692 | |
1693 | private: |
1694 | glib::Object<DeeModel> model_; |
1695 | glib::SignalManager sig_manager_; |
1696 | DeeModelTag* renderer_tag_; |
1697 | + ModelType model_type_; |
1698 | }; |
1699 | |
1700 | } |
1701 | |
1702 | === modified file 'UnityCore/Results.cpp' |
1703 | --- UnityCore/Results.cpp 2011-07-25 10:54:25 +0000 |
1704 | +++ UnityCore/Results.cpp 2012-01-26 08:37:26 +0000 |
1705 | @@ -31,6 +31,14 @@ |
1706 | row_removed.connect(sigc::mem_fun(this, &Results::OnRowRemoved)); |
1707 | } |
1708 | |
1709 | +Results::Results(ModelType model_type) |
1710 | + : Model<Result>::Model(model_type) |
1711 | +{ |
1712 | + row_added.connect(sigc::mem_fun(this, &Results::OnRowAdded)); |
1713 | + row_changed.connect(sigc::mem_fun(this, &Results::OnRowChanged)); |
1714 | + row_removed.connect(sigc::mem_fun(this, &Results::OnRowRemoved)); |
1715 | +} |
1716 | + |
1717 | void Results::OnRowAdded(Result& result) |
1718 | { |
1719 | result_added.emit(result); |
1720 | |
1721 | === modified file 'UnityCore/Results.h' |
1722 | --- UnityCore/Results.h 2011-07-28 13:35:05 +0000 |
1723 | +++ UnityCore/Results.h 2012-01-26 08:37:26 +0000 |
1724 | @@ -36,6 +36,7 @@ |
1725 | typedef std::shared_ptr<Results> Ptr; |
1726 | |
1727 | Results(); |
1728 | + Results(ModelType model_type); |
1729 | |
1730 | sigc::signal<void, Result const&> result_added; |
1731 | sigc::signal<void, Result const&> result_changed; |
1732 | |
1733 | === modified file 'com.canonical.Unity.gschema.xml' |
1734 | --- com.canonical.Unity.gschema.xml 2011-12-12 18:18:38 +0000 |
1735 | +++ com.canonical.Unity.gschema.xml 2012-01-26 08:37:26 +0000 |
1736 | @@ -21,7 +21,7 @@ |
1737 | <description>Whether the home screen should be expanded.</description> |
1738 | </key> |
1739 | </schema> |
1740 | - <schema path="/desktop/unity/launcher/" id="com.canonical.Unity.Launcher" gettext-domain="unity"> |
1741 | + <schema path="/desktop/unity/launcher/" id="com.canonical.Unity.Launcher" gettext-domain="unity"> |
1742 | <key type="as" name="favorites"> |
1743 | <default>[ 'ubiquity-gtkui.desktop', 'nautilus-home.desktop', 'firefox.desktop', 'libreoffice-writer.desktop', 'libreoffice-calc.desktop', 'libreoffice-impress.desktop', 'ubuntu-software-center.desktop', 'ubuntuone-installer.desktop', 'gnome-control-center.desktop' ]</default> |
1744 | <summary>List of desktop file ids for favorites on the launcher.</summary> |
1745 | @@ -33,7 +33,7 @@ |
1746 | <description>This is a detection key for the favorite migration script to know whether the needed migration is done or not.</description> |
1747 | </key> |
1748 | </schema> |
1749 | - <schema path="/desktop/unity/panel/" id="com.canonical.Unity.Panel" gettext-domain="unity"> |
1750 | + <schema path="/desktop/unity/panel/" id="com.canonical.Unity.Panel" gettext-domain="unity"> |
1751 | <key type="as" name="systray-whitelist"> |
1752 | <default>[ 'JavaEmbeddedFrame', 'Wine', 'scp-dbus-service', 'Update-notifier' ]</default> |
1753 | <summary>List of client names, resource classes or wm classes to allow in the Panel's systray implementation.</summary> |
1754 | @@ -46,5 +46,12 @@ |
1755 | <summary>List of device uuid for favorites on the launcher.</summary> |
1756 | <description>These devices are shown in the Launcher by default.</description> |
1757 | </key> |
1758 | - </schema> |
1759 | + </schema> |
1760 | + <schema path="/desktop/unity/dash/" id="com.canonical.Unity.Dash" gettext-domain="unity"> |
1761 | + <key type="as" name="home-lens-ordering"> |
1762 | + <default>[ 'applications.lens', 'files.lens', 'music.lens' ]</default> |
1763 | + <summary>List of lens ids specifying how lenses should be ordered in the Dash home screen.</summary> |
1764 | + <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> |
1765 | + </key> |
1766 | + </schema> |
1767 | </schemalist> |
1768 | |
1769 | === modified file 'plugins/unityshell/src/DashView.cpp' |
1770 | --- plugins/unityshell/src/DashView.cpp 2012-01-17 13:31:52 +0000 |
1771 | +++ plugins/unityshell/src/DashView.cpp 2012-01-26 08:37:26 +0000 |
1772 | @@ -47,6 +47,7 @@ |
1773 | |
1774 | DashView::DashView() |
1775 | : nux::View(NUX_TRACKER_LOCATION) |
1776 | + , home_lens_(new HomeLens(_("Home"), _("Home screen"), _("Search"))) |
1777 | , active_lens_view_(0) |
1778 | , last_activated_uri_("") |
1779 | , searching_timeout_id_(0) |
1780 | @@ -67,6 +68,8 @@ |
1781 | mouse_down.connect(sigc::mem_fun(this, &DashView::OnMouseButtonDown)); |
1782 | |
1783 | Relayout(); |
1784 | + |
1785 | + home_lens_->AddLenses(lenses_); |
1786 | lens_bar_->Activate("home.lens"); |
1787 | } |
1788 | |
1789 | @@ -81,6 +84,23 @@ |
1790 | ubus_manager_.SendMessage(UBUS_BACKGROUND_REQUEST_COLOUR_EMIT); |
1791 | visible_ = true; |
1792 | search_bar_->text_entry()->SelectAll(); |
1793 | + |
1794 | + /* Give the lenses a chance to prep data before we map them */ |
1795 | + lens_bar_->Activate(active_lens_view_->lens()->id()); |
1796 | + if (active_lens_view_->lens()->id() == "home.lens") |
1797 | + { |
1798 | + for (auto lens : lenses_.GetLenses()) |
1799 | + { |
1800 | + lens->view_type = ViewType::HOME_VIEW; |
1801 | + LOG_DEBUG(logger) << "Setting ViewType " << ViewType::HOME_VIEW |
1802 | + << " on '" << lens->id() << "'"; |
1803 | + } |
1804 | + |
1805 | + home_lens_->view_type = ViewType::LENS_VIEW; |
1806 | + LOG_DEBUG(logger) << "Setting ViewType " << ViewType::LENS_VIEW |
1807 | + << " on '" << home_lens_->id() << "'"; |
1808 | + } |
1809 | + |
1810 | renderer_.AboutToShow(); |
1811 | } |
1812 | |
1813 | @@ -88,6 +108,17 @@ |
1814 | { |
1815 | visible_ = false; |
1816 | renderer_.AboutToHide(); |
1817 | + |
1818 | + for (auto lens : lenses_.GetLenses()) |
1819 | + { |
1820 | + lens->view_type = ViewType::HIDDEN; |
1821 | + LOG_DEBUG(logger) << "Setting ViewType " << ViewType::HIDDEN |
1822 | + << " on '" << lens->id() << "'"; |
1823 | + } |
1824 | + |
1825 | + home_lens_->view_type = ViewType::HIDDEN; |
1826 | + LOG_DEBUG(logger) << "Setting ViewType " << ViewType::HIDDEN |
1827 | + << " on '" << home_lens_->id() << "'"; |
1828 | } |
1829 | |
1830 | void DashView::SetupViews() |
1831 | @@ -111,9 +142,9 @@ |
1832 | lenses_layout_ = new nux::VLayout(); |
1833 | content_layout_->AddView(lenses_layout_, 1, nux::MINOR_POSITION_LEFT); |
1834 | |
1835 | - home_view_ = new HomeView(); |
1836 | + home_view_ = new LensView(home_lens_); |
1837 | active_lens_view_ = home_view_; |
1838 | - lens_views_["home.lens"] = home_view_; |
1839 | + lens_views_[home_lens_->id] = home_view_; |
1840 | lenses_layout_->AddView(home_view_); |
1841 | |
1842 | lens_bar_ = new LensBar(); |
1843 | @@ -239,7 +270,6 @@ |
1844 | |
1845 | std::string id = AnalyseLensURI(uri.Str()); |
1846 | |
1847 | - home_view_->search_string = ""; |
1848 | lens_bar_->Activate(id); |
1849 | |
1850 | if ((id == "home.lens" && handled_type != GOTO_DASH_URI ) || !visible_) |
1851 | @@ -336,7 +366,6 @@ |
1852 | { |
1853 | std::string id = lens->id; |
1854 | lens_bar_->AddLens(lens); |
1855 | - home_view_->AddLens(lens); |
1856 | |
1857 | LensView* view = new LensView(lens); |
1858 | view->SetVisible(false); |
1859 | @@ -362,15 +391,17 @@ |
1860 | for (auto it: lens_views_) |
1861 | { |
1862 | bool id_matches = it.first == id; |
1863 | + ViewType view_type = id_matches ? LENS_VIEW : (view == home_view_ ? HOME_VIEW : HIDDEN); |
1864 | it.second->SetVisible(id_matches); |
1865 | - it.second->view_type = id_matches ? LENS_VIEW : (view == home_view_ ? HOME_VIEW : HIDDEN); |
1866 | + it.second->view_type = view_type; |
1867 | + |
1868 | + LOG_DEBUG(logger) << "Setting ViewType " << view_type |
1869 | + << " on '" << it.first << "'"; |
1870 | } |
1871 | |
1872 | search_bar_->search_string = view->search_string; |
1873 | - if (view != home_view_) |
1874 | - search_bar_->search_hint = view->lens()->search_hint; |
1875 | - else |
1876 | - search_bar_->search_hint = _("Search"); |
1877 | + search_bar_->search_hint = view->lens()->search_hint; |
1878 | + |
1879 | bool expanded = view->filters_expanded; |
1880 | search_bar_->showing_filters = expanded; |
1881 | |
1882 | @@ -553,6 +584,7 @@ |
1883 | ubus_manager_.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST); |
1884 | else |
1885 | search_bar_->search_string = ""; |
1886 | + |
1887 | return true; |
1888 | } |
1889 | return false; |
1890 | |
1891 | === modified file 'plugins/unityshell/src/DashView.h' |
1892 | --- plugins/unityshell/src/DashView.h 2012-01-16 15:31:59 +0000 |
1893 | +++ plugins/unityshell/src/DashView.h 2012-01-26 08:37:26 +0000 |
1894 | @@ -27,10 +27,10 @@ |
1895 | #include <Nux/View.h> |
1896 | #include <Nux/VLayout.h> |
1897 | #include <UnityCore/FilesystemLenses.h> |
1898 | +#include <UnityCore/HomeLens.h> |
1899 | |
1900 | #include "BackgroundEffectHelper.h" |
1901 | #include "DashSearchBar.h" |
1902 | -#include "HomeView.h" |
1903 | #include "Introspectable.h" |
1904 | #include "LensBar.h" |
1905 | #include "LensView.h" |
1906 | @@ -95,6 +95,7 @@ |
1907 | std::string AnalyseLensURI(std::string const& uri); |
1908 | void UpdateLensFilter(std::string lens, std::string filter, std::string value); |
1909 | void UpdateLensFilterValue(Filter::Ptr filter, std::string value); |
1910 | + void EnsureLensesInitialized(); |
1911 | |
1912 | bool AcceptKeyNavFocus(); |
1913 | bool InspectKeyEvent(unsigned int eventType, unsigned int key_sym, const char* character); |
1914 | @@ -108,6 +109,7 @@ |
1915 | private: |
1916 | UBusManager ubus_manager_; |
1917 | FilesystemLenses lenses_; |
1918 | + HomeLens::Ptr home_lens_; |
1919 | LensViews lens_views_; |
1920 | |
1921 | |
1922 | @@ -118,7 +120,7 @@ |
1923 | nux::VLayout* lenses_layout_; |
1924 | LensBar* lens_bar_; |
1925 | |
1926 | - HomeView* home_view_; |
1927 | + LensView* home_view_; |
1928 | LensView* active_lens_view_; |
1929 | |
1930 | // Drawing related |
1931 | |
1932 | === removed file 'plugins/unityshell/src/HomeView.cpp' |
1933 | --- plugins/unityshell/src/HomeView.cpp 2011-12-21 16:49:59 +0000 |
1934 | +++ plugins/unityshell/src/HomeView.cpp 1970-01-01 00:00:00 +0000 |
1935 | @@ -1,252 +0,0 @@ |
1936 | -/* |
1937 | - * Copyright (C) 2010 Canonical Ltd |
1938 | - * |
1939 | - * This program is free software: you can redistribute it and/or modify |
1940 | - * it under the terms of the GNU General Public License version 3 as |
1941 | - * published by the Free Software Foundation. |
1942 | - * |
1943 | - * This program is distributed in the hope that it will be useful, |
1944 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1945 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1946 | - * GNU General Public License for more details. |
1947 | - * |
1948 | - * You should have received a copy of the GNU General Public License |
1949 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1950 | - * |
1951 | - * Authored by: Neil Jagdish Patel <neil.patel@canonical.com> |
1952 | - */ |
1953 | - |
1954 | -#include "HomeView.h" |
1955 | - |
1956 | -#include <boost/lexical_cast.hpp> |
1957 | - |
1958 | -#include <NuxCore/Logger.h> |
1959 | - |
1960 | -#include "DashStyle.h" |
1961 | -#include "ResultRendererTile.h" |
1962 | -#include "UBusMessages.h" |
1963 | - |
1964 | -namespace unity |
1965 | -{ |
1966 | -namespace dash |
1967 | -{ |
1968 | - |
1969 | -namespace |
1970 | -{ |
1971 | -nux::logging::Logger logger("unity.dash.homeview"); |
1972 | -} |
1973 | - |
1974 | -// This is so we can override the scroll bar for the view. |
1975 | -class HomeScrollView: public nux::ScrollView |
1976 | -{ |
1977 | -public: |
1978 | - HomeScrollView(nux::VScrollBar* scroll_bar, NUX_FILE_LINE_DECL) |
1979 | - : nux::ScrollView(NUX_FILE_LINE_PARAM) |
1980 | - { |
1981 | - SetVScrollBar(scroll_bar); |
1982 | - } |
1983 | -}; |
1984 | - |
1985 | - |
1986 | - |
1987 | -NUX_IMPLEMENT_OBJECT_TYPE(HomeView); |
1988 | - |
1989 | -HomeView::HomeView() |
1990 | - : fix_renderering_id_(0) |
1991 | -{ |
1992 | - SetupViews(); |
1993 | - |
1994 | - search_string.changed.connect([&](std::string const& search) |
1995 | - { |
1996 | - for (auto lens : lenses_) |
1997 | - lens->GlobalSearch(search); |
1998 | - |
1999 | - for (auto group: categories_) |
2000 | - { |
2001 | - group->SetVisible(search != "" && counts_[group]); |
2002 | - } |
2003 | - home_view_->SetVisible(search == ""); |
2004 | - scroll_view_->SetVisible(search != ""); |
2005 | - |
2006 | - QueueDraw(); |
2007 | - }); |
2008 | -} |
2009 | - |
2010 | -HomeView::~HomeView() |
2011 | -{ |
2012 | - if (fix_renderering_id_) |
2013 | - g_source_remove(fix_renderering_id_); |
2014 | -} |
2015 | - |
2016 | -void HomeView::SetupViews() |
2017 | -{ |
2018 | - layout_ = new nux::HLayout(NUX_TRACKER_LOCATION); |
2019 | - layout_->SetHorizontalExternalMargin(7); |
2020 | - |
2021 | - scroll_view_ = new HomeScrollView(new PlacesVScrollBar(NUX_TRACKER_LOCATION), |
2022 | - NUX_TRACKER_LOCATION); |
2023 | - scroll_view_->EnableVerticalScrollBar(true); |
2024 | - scroll_view_->EnableHorizontalScrollBar(false); |
2025 | - scroll_view_->SetVisible(false); |
2026 | - layout_->AddView(scroll_view_); |
2027 | - |
2028 | - scroll_layout_ = new nux::VLayout(); |
2029 | - scroll_view_->SetLayout(scroll_layout_); |
2030 | - |
2031 | - home_view_ = new PlacesHomeView(); |
2032 | - layout_->AddView(home_view_); |
2033 | - |
2034 | - SetLayout(layout_); |
2035 | -} |
2036 | - |
2037 | -void HomeView::AddLens(Lens::Ptr lens) |
2038 | -{ |
2039 | - lenses_.push_back(lens); |
2040 | - |
2041 | - std::string name = lens->name; |
2042 | - std::string icon_hint = lens->icon_hint; |
2043 | - |
2044 | - LOG_DEBUG(logger) << "Lens added " << name; |
2045 | - |
2046 | - PlacesGroup* group = new PlacesGroup(); |
2047 | - group->SetName(name.c_str()); |
2048 | - group->SetIcon(icon_hint.c_str()); |
2049 | - group->SetExpanded(false); |
2050 | - group->SetVisible(false); |
2051 | - group->expanded.connect(sigc::mem_fun(this, &HomeView::OnGroupExpanded)); |
2052 | - categories_.push_back(group); |
2053 | - counts_[group] = 0; |
2054 | - |
2055 | - ResultViewGrid* grid = new ResultViewGrid(NUX_TRACKER_LOCATION); |
2056 | - grid->expanded = false; |
2057 | - grid->SetModelRenderer(new ResultRendererTile(NUX_TRACKER_LOCATION)); |
2058 | - grid->UriActivated.connect([&, lens] (std::string const& uri) { uri_activated.emit(uri); lens->Activate(uri); }); |
2059 | - group->SetChildView(grid); |
2060 | - |
2061 | - Results::Ptr results = lens->global_results; |
2062 | - results->result_added.connect([&, group, grid] (Result const& result) |
2063 | - { |
2064 | - grid->AddResult(const_cast<Result&>(result)); |
2065 | - counts_[group]++; |
2066 | - UpdateCounts(group); |
2067 | - }); |
2068 | - |
2069 | - results->result_removed.connect([&, group, grid] (Result const& result) |
2070 | - { |
2071 | - grid->RemoveResult(const_cast<Result&>(result)); |
2072 | - counts_[group]--; |
2073 | - UpdateCounts(group); |
2074 | - }); |
2075 | - |
2076 | - |
2077 | - scroll_layout_->AddView(group, 0); |
2078 | -} |
2079 | - |
2080 | -void HomeView::UpdateCounts(PlacesGroup* group) |
2081 | -{ |
2082 | - group->SetCounts(dash::Style::Instance().GetDefaultNColumns(), counts_[group]); |
2083 | - group->SetVisible(counts_[group]); |
2084 | - |
2085 | - QueueFixRenderering(); |
2086 | -} |
2087 | - |
2088 | -void HomeView::OnGroupExpanded(PlacesGroup* group) |
2089 | -{ |
2090 | - ResultViewGrid* grid = static_cast<ResultViewGrid*>(group->GetChildView()); |
2091 | - grid->expanded = group->GetExpanded(); |
2092 | - ubus_manager_.SendMessage(UBUS_PLACE_VIEW_QUEUE_DRAW); |
2093 | -} |
2094 | - |
2095 | -void HomeView::OnColumnsChanged() |
2096 | -{ |
2097 | - unsigned int columns = dash::Style::Instance().GetDefaultNColumns(); |
2098 | - |
2099 | - for (auto group: categories_) |
2100 | - { |
2101 | - group->SetCounts(columns, counts_[group]); |
2102 | - } |
2103 | -} |
2104 | - |
2105 | -void HomeView::QueueFixRenderering() |
2106 | -{ |
2107 | - if (fix_renderering_id_) |
2108 | - return; |
2109 | - |
2110 | - fix_renderering_id_ = g_idle_add_full (G_PRIORITY_DEFAULT, (GSourceFunc)FixRenderering, this, NULL); |
2111 | -} |
2112 | - |
2113 | -gboolean HomeView::FixRenderering(HomeView* self) |
2114 | -{ |
2115 | - std::list<Area*> children = self->scroll_layout_->GetChildren(); |
2116 | - std::list<Area*>::reverse_iterator rit; |
2117 | - bool found_one = false; |
2118 | - |
2119 | - for (rit = children.rbegin(); rit != children.rend(); ++rit) |
2120 | - { |
2121 | - PlacesGroup* group = static_cast<PlacesGroup*>(*rit); |
2122 | - |
2123 | - if (group->IsVisible()) |
2124 | - group->SetDrawSeparator(found_one); |
2125 | - |
2126 | - found_one = group->IsVisible(); |
2127 | - } |
2128 | - |
2129 | - self->fix_renderering_id_ = 0; |
2130 | - return FALSE; |
2131 | -} |
2132 | - |
2133 | -void HomeView::Draw(nux::GraphicsEngine& gfx_context, bool force_draw) |
2134 | -{ |
2135 | - nux::Geometry geo = GetGeometry(); |
2136 | - |
2137 | - gfx_context.PushClippingRectangle(geo); |
2138 | - nux::GetPainter().PaintBackground(gfx_context, geo); |
2139 | - gfx_context.PopClippingRectangle(); |
2140 | -} |
2141 | - |
2142 | -void HomeView::DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw) |
2143 | -{ |
2144 | - gfx_context.PushClippingRectangle(GetGeometry()); |
2145 | - |
2146 | - layout_->ProcessDraw(gfx_context, force_draw); |
2147 | - |
2148 | - gfx_context.PopClippingRectangle(); |
2149 | -} |
2150 | - |
2151 | -void HomeView::ActivateFirst() |
2152 | -{ |
2153 | - for (auto lens: lenses_) |
2154 | - { |
2155 | - Results::Ptr results = lens->global_results; |
2156 | - if (results->count()) |
2157 | - { |
2158 | - Result result = results->RowAtIndex(0); |
2159 | - if (result.uri != "") |
2160 | - { |
2161 | - uri_activated(result.uri); |
2162 | - lens->Activate(result.uri); |
2163 | - return; |
2164 | - } |
2165 | - } |
2166 | - } |
2167 | -} |
2168 | - |
2169 | - |
2170 | -// Keyboard navigation |
2171 | -bool HomeView::AcceptKeyNavFocus() |
2172 | -{ |
2173 | - return false; |
2174 | -} |
2175 | - |
2176 | -// Introspectable |
2177 | -std::string HomeView::GetName() const |
2178 | -{ |
2179 | - return "HomeView"; |
2180 | -} |
2181 | - |
2182 | -void HomeView::AddProperties(GVariantBuilder* builder) |
2183 | -{} |
2184 | - |
2185 | - |
2186 | -} |
2187 | -} |
2188 | |
2189 | === removed file 'plugins/unityshell/src/HomeView.h' |
2190 | --- plugins/unityshell/src/HomeView.h 2011-12-16 01:55:42 +0000 |
2191 | +++ plugins/unityshell/src/HomeView.h 1970-01-01 00:00:00 +0000 |
2192 | @@ -1,93 +0,0 @@ |
2193 | -/* |
2194 | - * Copyright (C) 2010 Canonical Ltd |
2195 | - * |
2196 | - * This program is free software: you can redistribute it and/or modify |
2197 | - * it under the terms of the GNU General Public License version 3 as |
2198 | - * published by the Free Software Foundation. |
2199 | - * |
2200 | - * This program is distributed in the hope that it will be useful, |
2201 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2202 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2203 | - * GNU General Public License for more details. |
2204 | - * |
2205 | - * You should have received a copy of the GNU General Public License |
2206 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2207 | - * |
2208 | - * Authored by: Neil Jagdish Patel <neil.patel@canonical.com> |
2209 | - */ |
2210 | - |
2211 | -#ifndef UNITY_HOME_VIEW_H_ |
2212 | -#define UNITY_HOME_VIEW_H_ |
2213 | - |
2214 | -#include <string> |
2215 | - |
2216 | -#include <NuxGraphics/GraphicsEngine.h> |
2217 | -#include <Nux/Nux.h> |
2218 | -#include <Nux/HLayout.h> |
2219 | -#include <Nux/View.h> |
2220 | -#include <Nux/VLayout.h> |
2221 | -#include <UnityCore/Lens.h> |
2222 | - |
2223 | -#include "LensView.h" |
2224 | -#include "PlacesGroup.h" |
2225 | -#include "PlacesHomeView.h" |
2226 | -#include "ResultViewGrid.h" |
2227 | -#include "UBusWrapper.h" |
2228 | - |
2229 | -namespace unity |
2230 | -{ |
2231 | -namespace dash |
2232 | -{ |
2233 | - |
2234 | -class HomeView : public LensView |
2235 | -{ |
2236 | - NUX_DECLARE_OBJECT_TYPE(HomeView, LensView); |
2237 | - typedef std::vector<PlacesGroup*> CategoryGroups; |
2238 | - typedef std::map<PlacesGroup*, unsigned int> ResultCounts; |
2239 | - typedef std::vector<Lens::Ptr> Lenses; |
2240 | - |
2241 | -public: |
2242 | - HomeView(); |
2243 | - ~HomeView(); |
2244 | - |
2245 | - void AddLens(Lens::Ptr lens); |
2246 | - void ActivateFirst(); |
2247 | - |
2248 | -private: |
2249 | - void SetupViews(); |
2250 | - |
2251 | - void OnResultAdded(Result const& result); |
2252 | - void OnResultRemoved(Result const& result); |
2253 | - void UpdateCounts(PlacesGroup* group); |
2254 | - void OnGroupExpanded(PlacesGroup* group); |
2255 | - void OnColumnsChanged(); |
2256 | - void QueueFixRenderering(); |
2257 | - |
2258 | - static gboolean FixRenderering(HomeView* self); |
2259 | - |
2260 | - void Draw(nux::GraphicsEngine& gfx_context, bool force_draw); |
2261 | - void DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw); |
2262 | - |
2263 | - bool AcceptKeyNavFocus(); |
2264 | - std::string GetName() const; |
2265 | - void AddProperties(GVariantBuilder* builder); |
2266 | - |
2267 | -private: |
2268 | - UBusManager ubus_manager_; |
2269 | - CategoryGroups categories_; |
2270 | - ResultCounts counts_; |
2271 | - Lenses lenses_; |
2272 | - |
2273 | - nux::HLayout* layout_; |
2274 | - nux::ScrollView* scroll_view_; |
2275 | - nux::VLayout* scroll_layout_; |
2276 | - |
2277 | - PlacesHomeView* home_view_; |
2278 | - |
2279 | - guint fix_renderering_id_; |
2280 | -}; |
2281 | - |
2282 | - |
2283 | -} |
2284 | -} |
2285 | -#endif |
2286 | |
2287 | === modified file 'plugins/unityshell/src/LensBar.cpp' |
2288 | --- plugins/unityshell/src/LensBar.cpp 2011-12-08 01:23:11 +0000 |
2289 | +++ plugins/unityshell/src/LensBar.cpp 2012-01-26 08:37:26 +0000 |
2290 | @@ -148,10 +148,20 @@ |
2291 | |
2292 | void LensBar::SetActive(LensBarIcon* activated) |
2293 | { |
2294 | + bool state_changed = false; |
2295 | + |
2296 | for (auto icon: icons_) |
2297 | - icon->active = icon == activated; |
2298 | - |
2299 | - lens_activated.emit(activated->id); |
2300 | + { |
2301 | + bool state = icon == activated; |
2302 | + |
2303 | + if (icon->active != state) |
2304 | + state_changed = true; |
2305 | + |
2306 | + icon->active = state; |
2307 | + } |
2308 | + |
2309 | + if (state_changed) |
2310 | + lens_activated.emit(activated->id); |
2311 | } |
2312 | |
2313 | void LensBar::ActivateNext() |
2314 | |
2315 | === modified file 'plugins/unityshell/src/LensView.cpp' |
2316 | --- plugins/unityshell/src/LensView.cpp 2011-12-14 16:18:41 +0000 |
2317 | +++ plugins/unityshell/src/LensView.cpp 2012-01-26 08:37:26 +0000 |
2318 | @@ -219,7 +219,12 @@ |
2319 | group->SetExpanded(false); |
2320 | group->SetVisible(false); |
2321 | group->expanded.connect(sigc::mem_fun(this, &LensView::OnGroupExpanded)); |
2322 | - categories_.push_back(group); |
2323 | + |
2324 | + |
2325 | + /* Add the group at the correct offset into the categories vector */ |
2326 | + categories_.insert(categories_.begin() + index, group); |
2327 | + |
2328 | + /* Reset result count */ |
2329 | counts_[group] = 0; |
2330 | |
2331 | ResultViewGrid* grid = new ResultViewGrid(NUX_TRACKER_LOCATION); |
2332 | @@ -232,7 +237,11 @@ |
2333 | grid->UriActivated.connect([&] (std::string const& uri) { uri_activated.emit(uri); lens_->Activate(uri); }); |
2334 | group->SetChildView(grid); |
2335 | |
2336 | - scroll_layout_->AddView(group, 0); |
2337 | + /* We need the full range of method args so we can specify the offset |
2338 | + * of the group into the layout */ |
2339 | + scroll_layout_->AddView(group, 0, nux::MinorDimensionPosition::eAbove, |
2340 | + nux::MinorDimensionSize::eFull, 100.0f, |
2341 | + (nux::LayoutPosition)index); |
2342 | } |
2343 | |
2344 | void LensView::OnResultAdded(Result const& result) |
2345 | |
2346 | === removed file 'plugins/unityshell/src/PlacesHomeView.cpp' |
2347 | --- plugins/unityshell/src/PlacesHomeView.cpp 2011-12-14 20:04:23 +0000 |
2348 | +++ plugins/unityshell/src/PlacesHomeView.cpp 1970-01-01 00:00:00 +0000 |
2349 | @@ -1,378 +0,0 @@ |
2350 | -// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- |
2351 | -/* |
2352 | - * Copyright (C) 2010 Canonical Ltd |
2353 | - * |
2354 | - * This program is free software: you can redistribute it and/or modify |
2355 | - * it under the terms of the GNU General Public License version 3 as |
2356 | - * published by the Free Software Foundation. |
2357 | - * |
2358 | - * This program is distributed in the hope that it will be useful, |
2359 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2360 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2361 | - * GNU General Public License for more details. |
2362 | - * |
2363 | - * You should have received a copy of the GNU General Public License |
2364 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2365 | - * |
2366 | - * Authored by: Neil Jagdish Patel <neil.patel@canonical.com> |
2367 | - */ |
2368 | - |
2369 | -#include "config.h" |
2370 | - |
2371 | -#include <Nux/Nux.h> |
2372 | -#include <Nux/BaseWindow.h> |
2373 | -#include <Nux/HLayout.h> |
2374 | -#include <Nux/Layout.h> |
2375 | -#include <Nux/WindowCompositor.h> |
2376 | - |
2377 | -#include <NuxImage/CairoGraphics.h> |
2378 | -#include <NuxImage/ImageSurface.h> |
2379 | - |
2380 | -#include <NuxGraphics/GLThread.h> |
2381 | -#include <NuxGraphics/RenderingPipe.h> |
2382 | - |
2383 | -#include <glib.h> |
2384 | -#include <glib/gi18n-lib.h> |
2385 | -#include <gio/gdesktopappinfo.h> |
2386 | -#include "ubus-server.h" |
2387 | -#include "UBusMessages.h" |
2388 | - |
2389 | -#include "PlacesHomeView.h" |
2390 | -#include "PlacesSimpleTile.h" |
2391 | - |
2392 | -#include "DashStyle.h" |
2393 | -#include <UnityCore/GLibWrapper.h> |
2394 | -#include <UnityCore/Variant.h> |
2395 | - |
2396 | -#include <string> |
2397 | -#include <vector> |
2398 | - |
2399 | -#define DELTA_DOUBLE_REQUEST 500000000 |
2400 | - |
2401 | -namespace unity |
2402 | -{ |
2403 | - |
2404 | -enum |
2405 | -{ |
2406 | - TYPE_PLACE = 0, |
2407 | - TYPE_EXEC |
2408 | -}; |
2409 | - |
2410 | -class Shortcut : public PlacesSimpleTile |
2411 | -{ |
2412 | -public: |
2413 | - Shortcut(const char* icon, const char* name, int size) |
2414 | - : PlacesSimpleTile(icon, name, size), |
2415 | - _id(0), |
2416 | - _place_id(NULL), |
2417 | - _place_section(0), |
2418 | - _exec(NULL) |
2419 | - { |
2420 | - SetDndEnabled(false, false); |
2421 | - } |
2422 | - |
2423 | - ~Shortcut() |
2424 | - { |
2425 | - g_free(_place_id); |
2426 | - g_free(_exec); |
2427 | - } |
2428 | - |
2429 | - int _id; |
2430 | - gchar* _place_id; |
2431 | - guint32 _place_section; |
2432 | - char* _exec; |
2433 | -}; |
2434 | - |
2435 | -PlacesHomeView::PlacesHomeView() |
2436 | - : _ubus_handle(0) |
2437 | -{ |
2438 | - dash::Style& style = dash::Style::Instance(); |
2439 | - |
2440 | - SetName(_("Shortcuts")); |
2441 | - SetIcon(PKGDATADIR"/shortcuts_group_icon.png"); |
2442 | - SetDrawSeparator(false); |
2443 | - |
2444 | - _layout = new nux::GridHLayout(NUX_TRACKER_LOCATION); |
2445 | - _layout->SetReconfigureParentLayoutOnGeometryChange(true); |
2446 | - SetChildLayout(_layout); |
2447 | - |
2448 | - _layout->ForceChildrenSize(true); |
2449 | - _layout->SetChildrenSize(style.GetHomeTileWidth(), style.GetHomeTileHeight()); |
2450 | - _layout->EnablePartialVisibility(false); |
2451 | - _layout->MatchContentSize(true); |
2452 | - _layout->SetLeftAndRightPadding(32); |
2453 | - _layout->SetSpaceBetweenChildren(32, 32); |
2454 | - _layout->SetMinMaxSize((style.GetHomeTileWidth() * 4) + (32 * 5), |
2455 | - (style.GetHomeTileHeight() * 2) + 32); |
2456 | - |
2457 | - _ubus_handle = ubus_server_register_interest(ubus_server_get_default(), |
2458 | - UBUS_PLACE_VIEW_SHOWN, |
2459 | - (UBusCallback) &PlacesHomeView::DashVisible, |
2460 | - this); |
2461 | - |
2462 | - //In case the GConf key is invalid (e.g. when an app was uninstalled), we |
2463 | - //rely on a fallback "whitelist" mechanism instead of showing nothing at all |
2464 | - _browser_alternatives.push_back("firefox"); |
2465 | - _browser_alternatives.push_back("chromium-browser"); |
2466 | - _browser_alternatives.push_back("epiphany-browser"); |
2467 | - _browser_alternatives.push_back("midori"); |
2468 | - |
2469 | - _photo_alternatives.push_back("shotwell"); |
2470 | - _photo_alternatives.push_back("f-spot"); |
2471 | - _photo_alternatives.push_back("gthumb"); |
2472 | - _photo_alternatives.push_back("gwenview"); |
2473 | - _photo_alternatives.push_back("eog"); |
2474 | - |
2475 | - _email_alternatives.push_back("evolution"); |
2476 | - _email_alternatives.push_back("thunderbird"); |
2477 | - _email_alternatives.push_back("claws-mail"); |
2478 | - _email_alternatives.push_back("kmail"); |
2479 | - |
2480 | - _music_alternatives.push_back("banshee-1"); |
2481 | - _music_alternatives.push_back("rhythmbox"); |
2482 | - _music_alternatives.push_back("totem"); |
2483 | - _music_alternatives.push_back("vlc"); |
2484 | - |
2485 | - expanded.connect(sigc::mem_fun(this, &PlacesHomeView::Refresh)); |
2486 | - |
2487 | - Refresh(); |
2488 | -} |
2489 | - |
2490 | -PlacesHomeView::~PlacesHomeView() |
2491 | -{ |
2492 | - if (_ubus_handle != 0) |
2493 | - ubus_server_unregister_interest(ubus_server_get_default(), _ubus_handle); |
2494 | -} |
2495 | - |
2496 | -void |
2497 | -PlacesHomeView::DashVisible(GVariant* data, void* val) |
2498 | -{ |
2499 | - PlacesHomeView* self = (PlacesHomeView*)val; |
2500 | - self->Refresh(); |
2501 | -} |
2502 | - |
2503 | -void |
2504 | -PlacesHomeView::Refresh(PlacesGroup*foo) |
2505 | -{ |
2506 | - Shortcut* shortcut = NULL; |
2507 | - gchar* markup = NULL; |
2508 | - const char* temp = "<big>%s</big>"; |
2509 | - int icon_size = dash::Style::Instance().GetHomeTileIconSize(); |
2510 | - |
2511 | - _layout->Clear(); |
2512 | - |
2513 | - // Media Apps |
2514 | - markup = g_strdup_printf(temp, _("Media Apps")); |
2515 | - shortcut = new Shortcut(PKGDATADIR"/find_media_apps.png", |
2516 | - markup, |
2517 | - icon_size); |
2518 | - shortcut->_id = TYPE_PLACE; |
2519 | - shortcut->_place_id = g_strdup("applications.lens?filter_type=media"); |
2520 | - shortcut->_place_section = 9; |
2521 | - _layout->AddView(shortcut, 1, nux::eLeft, nux::eFull); |
2522 | - shortcut->sigClick.connect(sigc::mem_fun(this, &PlacesHomeView::OnShortcutClicked)); |
2523 | - g_free(markup); |
2524 | - |
2525 | - // Internet Apps |
2526 | - markup = g_strdup_printf(temp, _("Internet Apps")); |
2527 | - shortcut = new Shortcut(PKGDATADIR"/find_internet_apps.png", |
2528 | - markup, |
2529 | - icon_size); |
2530 | - shortcut->_id = TYPE_PLACE; |
2531 | - shortcut->_place_id = g_strdup("applications.lens?filter_type=internet"); |
2532 | - shortcut->_place_section = 8; |
2533 | - _layout->AddView(shortcut, 1, nux::eLeft, nux::eFull); |
2534 | - shortcut->sigClick.connect(sigc::mem_fun(this, &PlacesHomeView::OnShortcutClicked)); |
2535 | - g_free(markup); |
2536 | - |
2537 | - // More Apps |
2538 | - markup = g_strdup_printf(temp, _("More Apps")); |
2539 | - shortcut = new Shortcut(PKGDATADIR"/find_more_apps.png", |
2540 | - markup, |
2541 | - icon_size); |
2542 | - shortcut->_id = TYPE_PLACE; |
2543 | - shortcut->_place_id = g_strdup("applications.lens"); |
2544 | - shortcut->_place_section = 0; |
2545 | - _layout->AddView(shortcut, 1, nux::eLeft, nux::eFull); |
2546 | - shortcut->sigClick.connect(sigc::mem_fun(this, &PlacesHomeView::OnShortcutClicked)); |
2547 | - g_free(markup); |
2548 | - |
2549 | - // Find Files |
2550 | - markup = g_strdup_printf(temp, _("Find Files")); |
2551 | - shortcut = new Shortcut(PKGDATADIR"/find_files.png", |
2552 | - markup, |
2553 | - icon_size); |
2554 | - shortcut->_id = TYPE_PLACE; |
2555 | - shortcut->_place_id = g_strdup("files.lens"); |
2556 | - shortcut->_place_section = 0; |
2557 | - _layout->AddView(shortcut, 1, nux::eLeft, nux::eFull); |
2558 | - shortcut->sigClick.connect(sigc::mem_fun(this, &PlacesHomeView::OnShortcutClicked)); |
2559 | - g_free(markup); |
2560 | - |
2561 | - // Browser |
2562 | - CreateShortcutFromMime("x-scheme-handler/http", _("Browse the Web"), _browser_alternatives); |
2563 | - |
2564 | - // Photos |
2565 | - // FIXME: Need to figure out the default |
2566 | - CreateShortcutFromExec("shotwell", _("View Photos"), _photo_alternatives); |
2567 | - |
2568 | - CreateShortcutFromMime("x-scheme-handler/mailto", _("Check Email"), _email_alternatives); |
2569 | - |
2570 | - CreateShortcutFromMime("audio/x-vorbis+ogg", _("Listen to Music"), _music_alternatives); |
2571 | - |
2572 | - SetExpanded(true); |
2573 | - SetCounts(8, 8); |
2574 | - |
2575 | - QueueDraw(); |
2576 | - _layout->QueueDraw(); |
2577 | - QueueRelayout(); |
2578 | -} |
2579 | - |
2580 | -void |
2581 | -PlacesHomeView::CreateShortcutFromExec(const char* exec, |
2582 | - const char* name, |
2583 | - std::vector<std::string>& alternatives) |
2584 | -{ |
2585 | - dash::Style& style = dash::Style::Instance(); |
2586 | - Shortcut* shortcut = NULL; |
2587 | - gchar* id; |
2588 | - gchar* markup; |
2589 | - gchar* icon; |
2590 | - gchar* real_exec; |
2591 | - GDesktopAppInfo* info; |
2592 | - |
2593 | - markup = g_strdup_printf("<big>%s</big>", name); |
2594 | - |
2595 | - // We're going to try and create a desktop id from a exec string. Now, this is hairy at the |
2596 | - // best of times but the following is the closest best-guess without having to do D-Bus |
2597 | - // roundtrips to BAMF. |
2598 | - if (exec) |
2599 | - { |
2600 | - char* basename; |
2601 | - |
2602 | - if (exec[0] == '/') |
2603 | - basename = g_path_get_basename(exec); |
2604 | - else |
2605 | - basename = g_strdup(exec); |
2606 | - |
2607 | - id = g_strdup_printf("%s.desktop", basename); |
2608 | - |
2609 | - g_free(basename); |
2610 | - } |
2611 | - else |
2612 | - { |
2613 | - id = g_strdup_printf("%s.desktop", alternatives[0].c_str()); |
2614 | - } |
2615 | - |
2616 | - info = g_desktop_app_info_new(id); |
2617 | - std::vector<std::string>::iterator iter = alternatives.begin(); |
2618 | - while (iter != alternatives.end()) |
2619 | - { |
2620 | - if (!G_IS_DESKTOP_APP_INFO(info)) |
2621 | - { |
2622 | - id = g_strdup_printf("%s.desktop", (*iter).c_str()); |
2623 | - info = g_desktop_app_info_new(id); |
2624 | - iter++; |
2625 | - } |
2626 | - |
2627 | - if (G_IS_DESKTOP_APP_INFO(info)) |
2628 | - { |
2629 | - icon = g_icon_to_string(g_app_info_get_icon(G_APP_INFO(info))); |
2630 | - real_exec = g_strdup(g_app_info_get_executable(G_APP_INFO(info))); |
2631 | - |
2632 | - shortcut = new Shortcut(icon, markup, style.GetHomeTileIconSize()); |
2633 | - shortcut->_id = TYPE_EXEC; |
2634 | - shortcut->_exec = real_exec; |
2635 | - _layout->AddView(shortcut, 1, nux::eLeft, nux::eFull); |
2636 | - shortcut->sigClick.connect(sigc::mem_fun(this, &PlacesHomeView::OnShortcutClicked)); |
2637 | - |
2638 | - g_free(icon); |
2639 | - |
2640 | - break; |
2641 | - } |
2642 | - } |
2643 | - |
2644 | - g_free(id); |
2645 | - g_free(markup); |
2646 | -} |
2647 | - |
2648 | -void PlacesHomeView::CreateShortcutFromMime(const char* mime, |
2649 | - const char* name, |
2650 | - std::vector<std::string>& alternatives) |
2651 | -{ |
2652 | - dash::Style& style = dash::Style::Instance(); |
2653 | - GAppInfo* info = g_app_info_get_default_for_type(mime, FALSE); |
2654 | - |
2655 | - // If it was invalid check alternatives for backup |
2656 | - if (!G_IS_DESKTOP_APP_INFO(info)) |
2657 | - { |
2658 | - for (auto alt: alternatives) |
2659 | - { |
2660 | - std::string id = alt + ".desktop"; |
2661 | - info = G_APP_INFO(g_desktop_app_info_new(id.c_str())); |
2662 | - |
2663 | - if (G_IS_DESKTOP_APP_INFO(info)) |
2664 | - break; |
2665 | - } |
2666 | - } |
2667 | - |
2668 | - if (G_IS_DESKTOP_APP_INFO(info)) |
2669 | - { |
2670 | - glib::String icon(g_icon_to_string(g_app_info_get_icon(G_APP_INFO(info)))); |
2671 | - glib::String markup(g_strdup_printf("<big>%s</big>", name)); |
2672 | - |
2673 | - Shortcut* shortcut = new Shortcut(icon.Value(), markup.Value(), style.GetHomeTileIconSize()); |
2674 | - shortcut->_id = TYPE_EXEC; |
2675 | - shortcut->_exec = g_strdup (g_app_info_get_executable(G_APP_INFO(info)));; |
2676 | - shortcut->sigClick.connect(sigc::mem_fun(this, &PlacesHomeView::OnShortcutClicked)); |
2677 | - _layout->AddView(shortcut, 1, nux::eLeft, nux::eFull); |
2678 | - |
2679 | - g_object_unref(info); |
2680 | - } |
2681 | -} |
2682 | - |
2683 | -void |
2684 | -PlacesHomeView::OnShortcutClicked(PlacesTile* tile) |
2685 | -{ |
2686 | - Shortcut* shortcut = static_cast<Shortcut*>(tile); |
2687 | - int id = shortcut->_id; |
2688 | - |
2689 | - if (id == TYPE_PLACE) |
2690 | - { |
2691 | - ubus_server_send_message(ubus_server_get_default(), |
2692 | - UBUS_PLACE_ENTRY_ACTIVATE_REQUEST, |
2693 | - g_variant_new("(sus)", |
2694 | - shortcut->_place_id, |
2695 | - shortcut->_place_section, |
2696 | - "")); |
2697 | - } |
2698 | - else if (id == TYPE_EXEC) |
2699 | - { |
2700 | - GError* error = NULL; |
2701 | - |
2702 | - if (!g_spawn_command_line_async(shortcut->_exec, &error)) |
2703 | - { |
2704 | - g_warning("%s: Unable to launch %s: %s", |
2705 | - G_STRFUNC, |
2706 | - shortcut->_exec, |
2707 | - error->message); |
2708 | - g_error_free(error); |
2709 | - } |
2710 | - |
2711 | - ubus_server_send_message(ubus_server_get_default(), |
2712 | - UBUS_PLACE_VIEW_CLOSE_REQUEST, |
2713 | - NULL); |
2714 | - } |
2715 | -} |
2716 | - |
2717 | -std::string PlacesHomeView::GetName() const |
2718 | -{ |
2719 | - return "PlacesHomeView"; |
2720 | -} |
2721 | - |
2722 | -void PlacesHomeView::AddProperties(GVariantBuilder* builder) |
2723 | -{ |
2724 | - unity::variant::BuilderWrapper(builder).add(GetGeometry()); |
2725 | -} |
2726 | - |
2727 | -} // namespace unity |
2728 | |
2729 | === removed file 'plugins/unityshell/src/PlacesHomeView.h' |
2730 | --- plugins/unityshell/src/PlacesHomeView.h 2011-12-14 20:04:23 +0000 |
2731 | +++ plugins/unityshell/src/PlacesHomeView.h 1970-01-01 00:00:00 +0000 |
2732 | @@ -1,72 +0,0 @@ |
2733 | -// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- |
2734 | -/* |
2735 | - * Copyright (C) 2010 Canonical Ltd |
2736 | - * |
2737 | - * This program is free software: you can redistribute it and/or modify |
2738 | - * it under the terms of the GNU General Public License version 3 as |
2739 | - * published by the Free Software Foundation. |
2740 | - * |
2741 | - * This program is distributed in the hope that it will be useful, |
2742 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2743 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2744 | - * GNU General Public License for more details. |
2745 | - * |
2746 | - * You should have received a copy of the GNU General Public License |
2747 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2748 | - * |
2749 | - * Authored by: Neil Jagdish Patel <neil.patel@canonical.com> |
2750 | - */ |
2751 | - |
2752 | -#ifndef PLACES_HOME_VIEW_H |
2753 | -#define PLACES_HOME_VIEW_H |
2754 | - |
2755 | -#include <Nux/View.h> |
2756 | -#include <Nux/Layout.h> |
2757 | -#include <Nux/TextureArea.h> |
2758 | -#include <NuxGraphics/GraphicsEngine.h> |
2759 | - |
2760 | -#include "Introspectable.h" |
2761 | - |
2762 | -#include <Nux/GridHLayout.h> |
2763 | - |
2764 | -#include "PlacesTile.h" |
2765 | -#include "PlacesGroup.h" |
2766 | - |
2767 | -namespace unity |
2768 | -{ |
2769 | - |
2770 | -class PlacesHomeView : public unity::debug::Introspectable, public PlacesGroup |
2771 | -{ |
2772 | -public: |
2773 | - PlacesHomeView(); |
2774 | - ~PlacesHomeView(); |
2775 | - |
2776 | - void Refresh(PlacesGroup* foo =NULL); |
2777 | - |
2778 | -protected: |
2779 | - // Introspectable methods |
2780 | - std::string GetName() const; |
2781 | - void AddProperties(GVariantBuilder* builder); |
2782 | - |
2783 | -private: |
2784 | - static void DashVisible(GVariant* data, void* val); |
2785 | - void OnShortcutClicked(PlacesTile* _tile); |
2786 | - void CreateShortcutFromExec(const char* exec, |
2787 | - const char* name, |
2788 | - std::vector<std::string>& alternatives); |
2789 | - void CreateShortcutFromMime(const char* mime, |
2790 | - const char* name, |
2791 | - std::vector<std::string>& alternatives); |
2792 | - |
2793 | -private: |
2794 | - nux::GridHLayout* _layout; |
2795 | - std::vector<std::string> _browser_alternatives; |
2796 | - std::vector<std::string> _photo_alternatives; |
2797 | - std::vector<std::string> _email_alternatives; |
2798 | - std::vector<std::string> _music_alternatives; |
2799 | - |
2800 | - guint _ubus_handle; |
2801 | -}; |
2802 | - |
2803 | -} |
2804 | -#endif |
2805 | |
2806 | === modified file 'plugins/unityshell/src/ResultViewGrid.cpp' |
2807 | --- plugins/unityshell/src/ResultViewGrid.cpp 2012-01-02 21:39:28 +0000 |
2808 | +++ plugins/unityshell/src/ResultViewGrid.cpp 2012-01-26 08:37:26 +0000 |
2809 | @@ -626,8 +626,19 @@ |
2810 | int half_width = recorded_dash_width_ / 2; |
2811 | int half_height = recorded_dash_height_; |
2812 | |
2813 | - int offset_x = MAX(MIN((x_position - half_width) / (half_width / 10), 5), -5); |
2814 | - int offset_y = MAX(MIN(((y_position + absolute_y) - half_height) / (half_height / 10), 5), -5); |
2815 | + int offset_x, offset_y; |
2816 | + |
2817 | + /* Guard against divide-by-zero. SIGFPEs are not mythological |
2818 | + * contrary to popular belief */ |
2819 | + if (half_width >= 10) |
2820 | + offset_x = MAX(MIN((x_position - half_width) / (half_width / 10), 5), -5); |
2821 | + else |
2822 | + offset_x = 0; |
2823 | + |
2824 | + if (half_height >= 10) |
2825 | + offset_y = MAX(MIN(((y_position + absolute_y) - half_height) / (half_height / 10), 5), -5); |
2826 | + else |
2827 | + offset_y = 0; |
2828 | |
2829 | if (recorded_dash_width_ < 1 || recorded_dash_height_ < 1) |
2830 | { |
2831 | |
2832 | === modified file 'po/POTFILES.in' |
2833 | --- po/POTFILES.in 2012-01-16 16:03:32 +0000 |
2834 | +++ po/POTFILES.in 2012-01-26 08:37:26 +0000 |
2835 | @@ -3,7 +3,6 @@ |
2836 | plugins/unityshell/src/LauncherController.cpp |
2837 | plugins/unityshell/src/PanelMenuView.cpp |
2838 | plugins/unityshell/src/PlacesGroup.cpp |
2839 | -plugins/unityshell/src/PlacesHomeView.cpp |
2840 | plugins/unityshell/src/SpacerLauncherIcon.cpp |
2841 | plugins/unityshell/src/TrashLauncherIcon.cpp |
2842 | plugins/unityshell/src/BFBLauncherIcon.cpp |
2843 | |
2844 | === added file 'po/unity.pot' |
2845 | --- po/unity.pot 1970-01-01 00:00:00 +0000 |
2846 | +++ po/unity.pot 2012-01-26 08:37:26 +0000 |
2847 | @@ -0,0 +1,120 @@ |
2848 | +# SOME DESCRIPTIVE TITLE. |
2849 | +# Copyright (C) YEAR Canonical\ Ltd |
2850 | +# This file is distributed under the same license as the PACKAGE package. |
2851 | +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. |
2852 | +# |
2853 | +#, fuzzy |
2854 | +msgid "" |
2855 | +msgstr "" |
2856 | +"Project-Id-Version: PACKAGE VERSION\n" |
2857 | +"Report-Msgid-Bugs-To: ayatana-dev@lists.launchpad.net\n" |
2858 | +"POT-Creation-Date: 2011-08-23 20:58-0400\n" |
2859 | +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
2860 | +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
2861 | +"Language-Team: LANGUAGE <LL@li.org>\n" |
2862 | +"Language: \n" |
2863 | +"MIME-Version: 1.0\n" |
2864 | +"Content-Type: text/plain; charset=CHARSET\n" |
2865 | +"Content-Transfer-Encoding: 8bit\n" |
2866 | + |
2867 | +msgid "Keep in launcher" |
2868 | +msgstr "" |
2869 | + |
2870 | +msgid "Quit" |
2871 | +msgstr "" |
2872 | + |
2873 | +msgid "Open" |
2874 | +msgstr "" |
2875 | + |
2876 | +msgid "Eject" |
2877 | +msgstr "" |
2878 | + |
2879 | +msgid "Eject parent drive" |
2880 | +msgstr "" |
2881 | + |
2882 | +msgid "Safely remove" |
2883 | +msgstr "" |
2884 | + |
2885 | +msgid "Safely remove parent drive" |
2886 | +msgstr "" |
2887 | + |
2888 | +msgid "Unmount" |
2889 | +msgstr "" |
2890 | + |
2891 | +msgid "The drive has been successfully ejected" |
2892 | +msgstr "" |
2893 | + |
2894 | +msgid "Workspace Switcher" |
2895 | +msgstr "" |
2896 | + |
2897 | +msgid "Search" |
2898 | +msgstr "" |
2899 | + |
2900 | +msgid "Search across all places" |
2901 | +msgstr "" |
2902 | + |
2903 | +msgid "See fewer results" |
2904 | +msgstr "" |
2905 | + |
2906 | +msgid "Shortcuts" |
2907 | +msgstr "" |
2908 | + |
2909 | +#. Media Apps |
2910 | +msgid "Media Apps" |
2911 | +msgstr "" |
2912 | + |
2913 | +#. Internet Apps |
2914 | +msgid "Internet Apps" |
2915 | +msgstr "" |
2916 | + |
2917 | +#. More Apps |
2918 | +msgid "More Apps" |
2919 | +msgstr "" |
2920 | + |
2921 | +#. Find Files |
2922 | +msgid "Find Files" |
2923 | +msgstr "" |
2924 | + |
2925 | +msgid "Browse the Web" |
2926 | +msgstr "" |
2927 | + |
2928 | +#. Photos |
2929 | +#. FIXME: Need to figure out the default |
2930 | +msgid "View Photos" |
2931 | +msgstr "" |
2932 | + |
2933 | +msgid "Check Email" |
2934 | +msgstr "" |
2935 | + |
2936 | +msgid "Listen to Music" |
2937 | +msgstr "" |
2938 | + |
2939 | +msgid "Drop To Add Application" |
2940 | +msgstr "" |
2941 | + |
2942 | +msgid "Trash" |
2943 | +msgstr "" |
2944 | + |
2945 | +msgid "Empty Trash..." |
2946 | +msgstr "" |
2947 | + |
2948 | +msgid "Empty all items from Trash?" |
2949 | +msgstr "" |
2950 | + |
2951 | +msgid "All items in the Trash will be permanently deleted." |
2952 | +msgstr "" |
2953 | + |
2954 | +msgid "Empty Trash" |
2955 | +msgstr "" |
2956 | + |
2957 | +msgid "Launcher & Menus" |
2958 | +msgstr "" |
2959 | + |
2960 | +msgid "<b>Show the launcher when the pointer:</b>" |
2961 | +msgstr "" |
2962 | + |
2963 | +msgid "Pushes the left edge of the screen" |
2964 | +msgstr "" |
2965 | + |
2966 | +msgid "Touches the top left corner of the screen" |
2967 | +msgstr "" |
2968 | |
2969 | === removed file 'po/unity.pot' |
2970 | --- po/unity.pot 2012-01-15 14:03:49 +0000 |
2971 | +++ po/unity.pot 1970-01-01 00:00:00 +0000 |
2972 | @@ -1,120 +0,0 @@ |
2973 | -# SOME DESCRIPTIVE TITLE. |
2974 | -# Copyright (C) YEAR Canonical\ Ltd |
2975 | -# This file is distributed under the same license as the PACKAGE package. |
2976 | -# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. |
2977 | -# |
2978 | -#, fuzzy |
2979 | -msgid "" |
2980 | -msgstr "" |
2981 | -"Project-Id-Version: PACKAGE VERSION\n" |
2982 | -"Report-Msgid-Bugs-To: ayatana-dev@lists.launchpad.net\n" |
2983 | -"POT-Creation-Date: 2011-08-23 20:58-0400\n" |
2984 | -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
2985 | -"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
2986 | -"Language-Team: LANGUAGE <LL@li.org>\n" |
2987 | -"Language: \n" |
2988 | -"MIME-Version: 1.0\n" |
2989 | -"Content-Type: text/plain; charset=CHARSET\n" |
2990 | -"Content-Transfer-Encoding: 8bit\n" |
2991 | - |
2992 | -msgid "Keep in launcher" |
2993 | -msgstr "" |
2994 | - |
2995 | -msgid "Quit" |
2996 | -msgstr "" |
2997 | - |
2998 | -msgid "Open" |
2999 | -msgstr "" |
3000 | - |
3001 | -msgid "Eject" |
3002 | -msgstr "" |
3003 | - |
3004 | -msgid "Eject parent drive" |
3005 | -msgstr "" |
3006 | - |
3007 | -msgid "Safely remove" |
3008 | -msgstr "" |
3009 | - |
3010 | -msgid "Safely remove parent drive" |
3011 | -msgstr "" |
3012 | - |
3013 | -msgid "Unmount" |
3014 | -msgstr "" |
3015 | - |
3016 | -msgid "The drive has been successfully ejected" |
3017 | -msgstr "" |
3018 | - |
3019 | -msgid "Workspace Switcher" |
3020 | -msgstr "" |
3021 | - |
3022 | -msgid "Search" |
3023 | -msgstr "" |
3024 | - |
3025 | -msgid "Search across all places" |
3026 | -msgstr "" |
3027 | - |
3028 | -msgid "See fewer results" |
3029 | -msgstr "" |
3030 | - |
3031 | -msgid "Shortcuts" |
3032 | -msgstr "" |
3033 | - |
3034 | -#. Media Apps |
3035 | -msgid "Media Apps" |
3036 | -msgstr "" |
3037 | - |
3038 | -#. Internet Apps |
3039 | -msgid "Internet Apps" |
3040 | -msgstr "" |
3041 | - |
3042 | -#. More Apps |
3043 | -msgid "More Apps" |
3044 | -msgstr "" |
3045 | - |
3046 | -#. Find Files |
3047 | -msgid "Find Files" |
3048 | -msgstr "" |
3049 | - |
3050 | -msgid "Browse the Web" |
3051 | -msgstr "" |
3052 | - |
3053 | -#. Photos |
3054 | -#. FIXME: Need to figure out the default |
3055 | -msgid "View Photos" |
3056 | -msgstr "" |
3057 | - |
3058 | -msgid "Check Email" |
3059 | -msgstr "" |
3060 | - |
3061 | -msgid "Listen to Music" |
3062 | -msgstr "" |
3063 | - |
3064 | -msgid "Drop To Add Application" |
3065 | -msgstr "" |
3066 | - |
3067 | -msgid "Trash" |
3068 | -msgstr "" |
3069 | - |
3070 | -msgid "Empty Trash..." |
3071 | -msgstr "" |
3072 | - |
3073 | -msgid "Empty all items from Trash?" |
3074 | -msgstr "" |
3075 | - |
3076 | -msgid "All items in the Trash will be permanently deleted." |
3077 | -msgstr "" |
3078 | - |
3079 | -msgid "Empty Trash" |
3080 | -msgstr "" |
3081 | - |
3082 | -msgid "Launcher & Menus" |
3083 | -msgstr "" |
3084 | - |
3085 | -msgid "<b>Show the launcher when the pointer:</b>" |
3086 | -msgstr "" |
3087 | - |
3088 | -msgid "Pushes the left edge of the screen" |
3089 | -msgstr "" |
3090 | - |
3091 | -msgid "Touches the top left corner of the screen" |
3092 | -msgstr "" |
3093 | |
3094 | === modified file 'standalone-clients/CMakeLists.txt' |
3095 | --- standalone-clients/CMakeLists.txt 2012-01-17 11:30:30 +0000 |
3096 | +++ standalone-clients/CMakeLists.txt 2012-01-26 08:37:26 +0000 |
3097 | @@ -76,8 +76,6 @@ |
3098 | ${UNITY_SRC}/FontSettings.h |
3099 | ${UNITY_SRC}/IMTextEntry.cpp |
3100 | ${UNITY_SRC}/IMTextEntry.h |
3101 | - ${UNITY_SRC}/PlacesHomeView.cpp |
3102 | - ${UNITY_SRC}/PlacesHomeView.h |
3103 | ${UNITY_SRC}/PlacesGroup.cpp |
3104 | ${UNITY_SRC}/PlacesGroup.h |
3105 | ${UNITY_SRC}/PlacesTile.cpp |
3106 | @@ -86,8 +84,6 @@ |
3107 | ${UNITY_SRC}/PlacesSimpleTile.h |
3108 | ${UNITY_SRC}/PlacesVScrollBar.cpp |
3109 | ${UNITY_SRC}/PlacesVScrollBar.h |
3110 | - ${UNITY_SRC}/HomeView.cpp |
3111 | - ${UNITY_SRC}/HomeView.h |
3112 | ${UNITY_SRC}/DashStyle.cpp |
3113 | ${UNITY_SRC}/IconLoader.cpp |
3114 | ${UNITY_SRC}/IconLoader.h |
3115 | |
3116 | === modified file 'standalone-clients/standalone_dash.cpp' |
3117 | --- standalone-clients/standalone_dash.cpp 2012-01-15 22:14:35 +0000 |
3118 | +++ standalone-clients/standalone_dash.cpp 2012-01-26 08:37:26 +0000 |
3119 | @@ -77,18 +77,8 @@ |
3120 | self->Init (); |
3121 | } |
3122 | |
3123 | -void |
3124 | -ControlThread (nux::NThread* thread, |
3125 | - void* data) |
3126 | -{ |
3127 | - // sleep for 3 seconds |
3128 | - nux::SleepForMilliseconds (3000); |
3129 | - printf ("ControlThread successfully started\n"); |
3130 | -} |
3131 | - |
3132 | int main(int argc, char **argv) |
3133 | { |
3134 | - nux::SystemThread* st = NULL; |
3135 | nux::WindowThread* wt = NULL; |
3136 | |
3137 | gtk_init (&argc, &argv); |
3138 | @@ -109,13 +99,7 @@ |
3139 | &TestRunner::InitWindowThread, |
3140 | test_runner); |
3141 | |
3142 | - st = nux::CreateSystemThread (NULL, ControlThread, wt); |
3143 | - |
3144 | - if (st) |
3145 | - st->Start (NULL); |
3146 | - |
3147 | wt->Run (NULL); |
3148 | - delete st; |
3149 | delete wt; |
3150 | return 0; |
3151 | } |
3152 | |
3153 | === modified file 'tests/CMakeLists.txt' |
3154 | --- tests/CMakeLists.txt 2012-01-25 17:26:09 +0000 |
3155 | +++ tests/CMakeLists.txt 2012-01-26 08:37:26 +0000 |
3156 | @@ -119,11 +119,12 @@ |
3157 | test_glib_variant.cpp |
3158 | ${CMAKE_CURRENT_BINARY_DIR}/test_glib_signals_utils_marshal.cpp |
3159 | test_favorite_store_gsettings.cpp |
3160 | + test_home_lens.cpp |
3161 | test_shortcut_model.cpp |
3162 | test_shortcut_private.cpp |
3163 | test_introspection.cpp |
3164 | test_main_xless.cpp |
3165 | - test_grabhandle.cpp |
3166 | + test_grabhandle.cpp |
3167 | ${UNITY_SRC}/AbstractLauncherIcon.h |
3168 | ${UNITY_SRC}/AbstractShortcutHint.h |
3169 | ${UNITY_SRC}/Animator.cpp |
3170 | @@ -152,11 +153,11 @@ |
3171 | ${UNITY_SRC}/Timer.h |
3172 | ${UNITY_SRC}/WindowManager.cpp |
3173 | ${UNITY_SRC}/WindowManager.h |
3174 | - ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-grab-handle.cpp |
3175 | - ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-grab-handle-group.cpp |
3176 | - ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-grab-handle-impl-factory.cpp |
3177 | - ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-grab-handle-layout.cpp |
3178 | - ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-texture.cpp |
3179 | + ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-grab-handle.cpp |
3180 | + ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-grab-handle-group.cpp |
3181 | + ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-grab-handle-impl-factory.cpp |
3182 | + ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-grab-handle-layout.cpp |
3183 | + ${CMAKE_SOURCE_DIR}/plugins/unity-mt-grab-handles/src/unity-mt-texture.cpp |
3184 | ) |
3185 | target_link_libraries(test-gtest-xless ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIB} ${GMOCK_MAIN_LIB}) |
3186 | add_test(UnityGTestXless test-gtest-xless) |
3187 | |
3188 | === added file 'tests/test_home_lens.cpp' |
3189 | --- tests/test_home_lens.cpp 1970-01-01 00:00:00 +0000 |
3190 | +++ tests/test_home_lens.cpp 2012-01-26 08:37:26 +0000 |
3191 | @@ -0,0 +1,362 @@ |
3192 | +#include <gtest/gtest.h> |
3193 | +#include <glib-object.h> |
3194 | +#include <dee.h> |
3195 | +#include <string> |
3196 | +#include <iostream> |
3197 | +#include <stdexcept> |
3198 | +#include <map> |
3199 | +#include <memory> |
3200 | +#include <sigc++/signal.h> |
3201 | +#include <sigc++/trackable.h> |
3202 | + |
3203 | +#include <UnityCore/GLibWrapper.h> |
3204 | +#include <UnityCore/Variant.h> |
3205 | +#include <UnityCore/HomeLens.h> |
3206 | +#include <UnityCore/Lens.h> |
3207 | +#include <UnityCore/Lenses.h> |
3208 | + |
3209 | +#include "test_utils.h" |
3210 | + |
3211 | +using namespace std; |
3212 | +using namespace unity::dash; |
3213 | + |
3214 | +namespace |
3215 | +{ |
3216 | + |
3217 | +/* |
3218 | + * FORWARDS |
3219 | + */ |
3220 | + |
3221 | +class StaticTestLens; |
3222 | + |
3223 | +typedef struct { |
3224 | + StaticTestLens* lens; |
3225 | + gchar* search_string; |
3226 | +} LensSearchClosure; |
3227 | + |
3228 | +static gboolean dispatch_global_search(gpointer userdata); |
3229 | + |
3230 | + |
3231 | +/* |
3232 | + * Mock Lens instance that does not use DBus. The default search does like this: |
3233 | + * For input "bar" output: |
3234 | + * |
3235 | + * i = 0 |
3236 | + * for letter in "bar": |
3237 | + * put result row [ "uri+$letter+$lens_id", "icon+$letter+$lens_id", i % 3, "mime+$letter+$lens_id", ...] |
3238 | + * i++ |
3239 | + * |
3240 | + * The mock lens has 3 categories: |
3241 | + * |
3242 | + * 0) "cat0+$lens_id" |
3243 | + * 1) "cat1+$lens_id" |
3244 | + * 2) "Shared cat" |
3245 | + */ |
3246 | +class StaticTestLens : public Lens |
3247 | +{ |
3248 | +public: |
3249 | + typedef std::shared_ptr<StaticTestLens> Ptr; |
3250 | + |
3251 | + StaticTestLens(string const& id, string const& name, string const& description, string const& search_hint) |
3252 | + : Lens(id, "", "", name, "lens-icon.png", |
3253 | + description, search_hint, true, "", |
3254 | + ModelType::LOCAL) |
3255 | + { |
3256 | + search_in_global(true); |
3257 | + |
3258 | + DeeModel* cats = categories()->model(); |
3259 | + DeeModel* results = global_results()->model(); |
3260 | + DeeModel* flters = filters()->model(); |
3261 | + |
3262 | + // Set model schemas |
3263 | + dee_model_set_schema(cats, "s", "s", "s", "a{sv}", NULL); |
3264 | + dee_model_set_schema(results, "s", "s", "u", "s", "s", "s", "s", NULL); |
3265 | + dee_model_set_schema(flters, "s", "s", "s", "s", "a{sv}", "b", "b", "b", NULL); |
3266 | + |
3267 | + // Populate categories model |
3268 | + ostringstream cat0, cat1; |
3269 | + cat0 << "cat0+" << id; |
3270 | + cat1 << "cat1+" << id; |
3271 | + GVariantBuilder b; |
3272 | + g_variant_builder_init(&b, G_VARIANT_TYPE_VARDICT); |
3273 | + GVariant *asv = g_variant_builder_end(&b); |
3274 | + |
3275 | + dee_model_append(cats, cat0.str().c_str(), "icon.png", "tile-vertical", asv); |
3276 | + dee_model_append(cats, cat1.str().c_str(), "icon.png", "tile-vertical", asv); |
3277 | + dee_model_append(cats, "Shared cat", "icon.png", "tile-vertical", asv); |
3278 | + } |
3279 | + |
3280 | + virtual ~StaticTestLens() {} |
3281 | + |
3282 | + virtual void DoGlobalSearch(string const& search_string) |
3283 | + { |
3284 | + DeeModel* model = global_results()->model(); |
3285 | + GVariant** row_buf = g_new(GVariant*, 8); |
3286 | + |
3287 | + row_buf[1] = g_variant_new_string(""); |
3288 | + row_buf[3] = g_variant_new_string(""); |
3289 | + row_buf[4] = g_variant_new_string(""); |
3290 | + row_buf[5] = g_variant_new_string(""); |
3291 | + row_buf[6] = g_variant_new_string(""); |
3292 | + row_buf[7] = NULL; |
3293 | + |
3294 | + unsigned int i; |
3295 | + for (i = 0; i < search_string.size(); i++) |
3296 | + { |
3297 | + ostringstream uri; |
3298 | + uri << "uri+" << search_string.at(i) << "+" << id(); |
3299 | + row_buf[0] = g_variant_new_string(uri.str().c_str()); |
3300 | + row_buf[2] = g_variant_new_uint32(i % 3); |
3301 | + |
3302 | + dee_model_append_row(model, row_buf); |
3303 | + } |
3304 | + |
3305 | + g_free(row_buf); |
3306 | + } |
3307 | + |
3308 | + void GlobalSearch(string const& search_string) |
3309 | + { |
3310 | + /* Dispatch search async, because that's */ |
3311 | + LensSearchClosure* closure = g_new0(LensSearchClosure, 1); |
3312 | + closure->lens = this; |
3313 | + closure->search_string = g_strdup(search_string.c_str()); |
3314 | + g_idle_add(dispatch_global_search, closure); |
3315 | + } |
3316 | + |
3317 | + void Search(string const& search_string) |
3318 | + { |
3319 | + |
3320 | + } |
3321 | + |
3322 | + void Activate(string const& uri) |
3323 | + { |
3324 | + |
3325 | + } |
3326 | + |
3327 | + void Preview(string const& uri) |
3328 | + { |
3329 | + |
3330 | + } |
3331 | + |
3332 | +}; |
3333 | + |
3334 | +static gboolean dispatch_global_search(gpointer userdata) |
3335 | +{ |
3336 | + LensSearchClosure* closure = (LensSearchClosure*) userdata; |
3337 | + |
3338 | + closure->lens->DoGlobalSearch(closure->search_string); |
3339 | + |
3340 | + g_free(closure->search_string); |
3341 | + g_free(closure); |
3342 | + |
3343 | + return FALSE; |
3344 | +} |
3345 | + |
3346 | +/* |
3347 | + * Mock Lenses class |
3348 | + */ |
3349 | +class StaticTestLenses : public Lenses |
3350 | +{ |
3351 | +public: |
3352 | + typedef std::shared_ptr<StaticTestLenses> Ptr; |
3353 | + |
3354 | + StaticTestLenses() |
3355 | + { |
3356 | + count.SetGetterFunction(sigc::mem_fun(&list_, &Lenses::LensList::size)); |
3357 | + } |
3358 | + |
3359 | + virtual ~StaticTestLenses() {} |
3360 | + |
3361 | + Lenses::LensList GetLenses() const |
3362 | + { |
3363 | + return list_; |
3364 | + } |
3365 | + |
3366 | + Lens::Ptr GetLens(std::string const& lens_id) const |
3367 | + { |
3368 | + for (auto lens : list_) |
3369 | + { |
3370 | + if (lens->id() == lens_id) |
3371 | + return lens; |
3372 | + } |
3373 | + return Lens::Ptr(); |
3374 | + } |
3375 | + |
3376 | + Lens::Ptr GetLensAtIndex(std::size_t index) const |
3377 | + { |
3378 | + return list_.at(index); |
3379 | + } |
3380 | + |
3381 | +protected: |
3382 | + Lenses::LensList list_; |
3383 | +}; |
3384 | + |
3385 | +class TwoStaticTestLenses : public StaticTestLenses |
3386 | +{ |
3387 | +public: |
3388 | + TwoStaticTestLenses() |
3389 | + : lens_1_(new StaticTestLens("first.lens", "First Lens", "The very first lens", "First search hint")) |
3390 | + , lens_2_(new StaticTestLens("second.lens", "Second Lens", "The second lens", "Second search hint")) |
3391 | + { |
3392 | + list_.push_back(lens_1_); |
3393 | + list_.push_back(lens_2_); |
3394 | + } |
3395 | + |
3396 | +private: |
3397 | + Lens::Ptr lens_1_; |
3398 | + Lens::Ptr lens_2_; |
3399 | +}; |
3400 | + |
3401 | +TEST(TestHomeLens, TestConstruction) |
3402 | +{ |
3403 | + HomeLens home_lens_("name", "description", "searchhint"); |
3404 | + |
3405 | + EXPECT_EQ(home_lens_.id(), "home.lens"); |
3406 | + EXPECT_EQ(home_lens_.connected, false); |
3407 | + EXPECT_EQ(home_lens_.search_in_global, false); |
3408 | + EXPECT_EQ(home_lens_.name, "name"); |
3409 | + EXPECT_EQ(home_lens_.description, "description"); |
3410 | + EXPECT_EQ(home_lens_.search_hint, "searchhint"); |
3411 | +} |
3412 | + |
3413 | +TEST(TestHomeLens, TestInitiallyEmpty) |
3414 | +{ |
3415 | + HomeLens home_lens_("name", "description", "searchhint"); |
3416 | + DeeModel* results = home_lens_.results()->model(); |
3417 | + DeeModel* categories = home_lens_.categories()->model();; |
3418 | + DeeModel* filters = home_lens_.filters()->model();; |
3419 | + |
3420 | + EXPECT_EQ(dee_model_get_n_rows(results), 0); |
3421 | + EXPECT_EQ(dee_model_get_n_rows(categories), 0); |
3422 | + EXPECT_EQ(dee_model_get_n_rows(filters), 0); |
3423 | + |
3424 | + EXPECT_EQ(home_lens_.count(), 0); |
3425 | +} |
3426 | + |
3427 | +TEST(TestHomeLens, TestTwoStaticLenses) |
3428 | +{ |
3429 | + HomeLens home_lens_("name", "description", "searchhint"); |
3430 | + TwoStaticTestLenses lenses_; |
3431 | + |
3432 | + home_lens_.AddLenses(lenses_); |
3433 | + |
3434 | + EXPECT_EQ(home_lens_.count, (size_t) 2); |
3435 | + |
3436 | + /* Test iteration of registered lensess */ |
3437 | + map<string,string> remaining; |
3438 | + remaining["first.lens"] = ""; |
3439 | + remaining["second.lens"] = ""; |
3440 | + for (auto lens : home_lens_.GetLenses()) |
3441 | + { |
3442 | + remaining.erase(lens->id()); |
3443 | + } |
3444 | + |
3445 | + EXPECT_EQ(remaining.size(), 0); |
3446 | + |
3447 | + /* Test sorting and GetAtIndex */ |
3448 | + EXPECT_EQ(home_lens_.GetLensAtIndex(0)->id(), "first.lens"); |
3449 | + EXPECT_EQ(home_lens_.GetLensAtIndex(1)->id(), "second.lens"); |
3450 | +} |
3451 | + |
3452 | +TEST(TestHomeLens, TestCategoryMerging) |
3453 | +{ |
3454 | + HomeLens home_lens_("name", "description", "searchhint"); |
3455 | + TwoStaticTestLenses lenses_; |
3456 | + DeeModel* cats = home_lens_.categories()->model(); |
3457 | + DeeModelIter* iter; |
3458 | + unsigned int cat0_first = 0, |
3459 | + cat1_first = 1, |
3460 | + cat_shared = 2, |
3461 | + cat0_second = 3, |
3462 | + cat1_second = 4; |
3463 | + const unsigned int NAME_COLUMN = 0; |
3464 | + |
3465 | + home_lens_.AddLenses(lenses_); |
3466 | + |
3467 | + EXPECT_EQ(dee_model_get_n_rows(cats), 5); // 5 because each lens has 3 cats, but 1 is shared between them |
3468 | + |
3469 | + /* Validate the merged categories */ |
3470 | + iter = dee_model_get_iter_at_row(cats, cat0_first); |
3471 | + EXPECT_EQ("cat0+first.lens", string(dee_model_get_string(cats, iter, NAME_COLUMN))); |
3472 | + |
3473 | + iter = dee_model_get_iter_at_row(cats, cat1_first); |
3474 | + EXPECT_EQ("cat1+first.lens", string(dee_model_get_string(cats, iter, NAME_COLUMN))); |
3475 | + |
3476 | + iter = dee_model_get_iter_at_row(cats, cat_shared); |
3477 | + EXPECT_EQ("Shared cat", string(dee_model_get_string(cats, iter, NAME_COLUMN))); |
3478 | + |
3479 | + iter = dee_model_get_iter_at_row(cats, cat0_second); |
3480 | + EXPECT_EQ("cat0+second.lens", string(dee_model_get_string(cats, iter, NAME_COLUMN))); |
3481 | + |
3482 | + iter = dee_model_get_iter_at_row(cats, cat1_second); |
3483 | + EXPECT_EQ("cat1+second.lens", string(dee_model_get_string(cats, iter, NAME_COLUMN))); |
3484 | +} |
3485 | + |
3486 | +// It's not that we must not support filters. It is just not implemented yet. |
3487 | +// But we actively test against it to make sure we don't end up with broken |
3488 | +// filters in the UI. When/if we land support for filters on the home screen |
3489 | +// this test should obviously be removed |
3490 | +TEST(TestHomeLens, TestIgnoreFilters) |
3491 | +{ |
3492 | + HomeLens home_lens_("name", "description", "searchhint"); |
3493 | + TwoStaticTestLenses lenses_; |
3494 | + DeeModel* filters = home_lens_.filters()->model(); |
3495 | + |
3496 | + EXPECT_EQ(dee_model_get_n_rows(filters), 0); |
3497 | +} |
3498 | + |
3499 | +TEST(TestHomeLens, TestOneSearch) |
3500 | +{ |
3501 | + HomeLens home_lens_("name", "description", "searchhint"); |
3502 | + TwoStaticTestLenses lenses_; |
3503 | + DeeModel* results = home_lens_.results()->model(); |
3504 | + DeeModel* cats = home_lens_.categories()->model(); |
3505 | + DeeModel* filters = home_lens_.filters()->model(); |
3506 | + DeeModelIter* iter; |
3507 | + unsigned int cat0_first = 0, |
3508 | + cat1_first = 1, |
3509 | + cat_shared = 2, |
3510 | + cat0_second = 3, |
3511 | + cat1_second = 4; |
3512 | + const unsigned int URI_COLUMN = 0; |
3513 | + const unsigned int CAT_COLUMN = 2; |
3514 | + |
3515 | + home_lens_.AddLenses(lenses_); |
3516 | + |
3517 | + home_lens_.Search("ape"); |
3518 | + |
3519 | + Utils::WaitForTimeoutMSec(); |
3520 | + |
3521 | + /* Validate counts */ |
3522 | + EXPECT_EQ(dee_model_get_n_rows(results), 6); // 3 hits from each lens |
3523 | + EXPECT_EQ(dee_model_get_n_rows(cats), 5); // 5 because each lens has 3 cats, but 1 is shared between them |
3524 | + EXPECT_EQ(dee_model_get_n_rows(filters), 0); // We ignore filters deliberately currently |
3525 | + |
3526 | + /* Validate results. In particular that we get the correct merged |
3527 | + * category offsets assigned */ |
3528 | + iter = dee_model_get_iter_at_row(results, 0); |
3529 | + EXPECT_EQ(string("uri+a+first.lens"), string(dee_model_get_string(results, iter, URI_COLUMN))); |
3530 | + EXPECT_EQ(cat0_first, dee_model_get_uint32(results, iter, CAT_COLUMN)); |
3531 | + |
3532 | + iter = dee_model_get_iter_at_row(results, 1); |
3533 | + EXPECT_EQ(string("uri+p+first.lens"), string(dee_model_get_string(results, iter, URI_COLUMN))); |
3534 | + EXPECT_EQ(cat1_first, dee_model_get_uint32(results, iter, CAT_COLUMN)); |
3535 | + |
3536 | + iter = dee_model_get_iter_at_row(results, 2); |
3537 | + EXPECT_EQ(string("uri+e+first.lens"), string(dee_model_get_string(results, iter, URI_COLUMN))); |
3538 | + EXPECT_EQ(cat_shared, dee_model_get_uint32(results, iter, CAT_COLUMN)); |
3539 | + |
3540 | + iter = dee_model_get_iter_at_row(results, 3); |
3541 | + EXPECT_EQ(string("uri+a+second.lens"), string(dee_model_get_string(results, iter, URI_COLUMN))); |
3542 | + EXPECT_EQ(cat0_second, dee_model_get_uint32(results, iter, CAT_COLUMN)); |
3543 | + |
3544 | + iter = dee_model_get_iter_at_row(results, 4); |
3545 | + EXPECT_EQ(string("uri+p+second.lens"), string(dee_model_get_string(results, iter, URI_COLUMN))); |
3546 | + EXPECT_EQ(cat1_second, dee_model_get_uint32(results, iter, CAT_COLUMN)); |
3547 | + |
3548 | + iter = dee_model_get_iter_at_row(results, 5); |
3549 | + EXPECT_EQ(string("uri+e+second.lens"), string(dee_model_get_string(results, iter, URI_COLUMN))); |
3550 | + EXPECT_EQ(cat_shared, dee_model_get_uint32(results, iter, CAT_COLUMN)); |
3551 | +} |
3552 | + |
3553 | +} |
3554 | |
3555 | === modified file 'tests/test_utils.h' |
3556 | --- tests/test_utils.h 2011-12-02 12:03:27 +0000 |
3557 | +++ tests/test_utils.h 2012-01-26 08:37:26 +0000 |
3558 | @@ -51,6 +51,33 @@ |
3559 | return g_timeout_add_seconds(timeout_duration, TimeoutCallback, timeout_reached); |
3560 | } |
3561 | |
3562 | + static guint32 ScheduleTimeoutMSec(bool* timeout_reached, unsigned int timeout_duration = 10) |
3563 | + { |
3564 | + return g_timeout_add(timeout_duration, TimeoutCallback, timeout_reached); |
3565 | + } |
3566 | + |
3567 | + static void WaitForTimeout(unsigned int timeout_duration = 10) |
3568 | + { |
3569 | + bool timeout_reached = false; |
3570 | + guint32 timeout_id = ScheduleTimeout(&timeout_reached, timeout_duration); |
3571 | + |
3572 | + while (!timeout_reached) |
3573 | + g_main_context_iteration(g_main_context_get_thread_default(), TRUE); |
3574 | + |
3575 | + g_source_remove(timeout_id); |
3576 | + } |
3577 | + |
3578 | + static void WaitForTimeoutMSec(unsigned int timeout_duration = 10) |
3579 | + { |
3580 | + bool timeout_reached = false; |
3581 | + guint32 timeout_id = ScheduleTimeoutMSec(&timeout_reached, timeout_duration); |
3582 | + |
3583 | + while (!timeout_reached) |
3584 | + g_main_context_iteration(g_main_context_get_thread_default(), TRUE); |
3585 | + |
3586 | + g_source_remove(timeout_id); |
3587 | + } |
3588 | + |
3589 | private: |
3590 | static gboolean TimeoutCallback(gpointer data) |
3591 | { |
Meh. Sorry for the i18n noise. No idea how that got here. Will try to remove.