Merge lp:~mhr3/unity/home-lens-fixes into lp:unity

Proposed by Michal Hruby
Status: Merged
Approved by: Michal Hruby
Approved revision: no longer in the source branch.
Merged at revision: 2639
Proposed branch: lp:~mhr3/unity/home-lens-fixes
Merge into: lp:unity
Diff against target: 800 lines (+228/-169)
7 files modified
UnityCore/HomeLens.cpp (+83/-65)
UnityCore/Lens.cpp (+99/-29)
UnityCore/Lens.h (+12/-0)
UnityCore/Variant.cpp (+7/-2)
UnityCore/Variant.h (+2/-0)
dash/LensView.cpp (+24/-71)
dash/LensView.h (+1/-2)
To merge this branch: bzr merge lp:~mhr3/unity/home-lens-fixes
Reviewer Review Type Date Requested Status
Paweł Stołowski (community) Approve
Tim Penhey (community) Approve
Review via email: mp+121628@code.launchpad.net

Commit message

Activate proper result if the categories aren't displayed in-order

Description of the change

Fixed one longstanding and one recently introduced bug.

Fixes existing AP test (although depending on your data it might not have been failing in the first place).

To post a comment you must log in.
Revision history for this message
Sam Spilsbury (smspillaz) wrote :

Looks good on style and usage. Don't know about functionality.

Are there any automated unit tests for this area?

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

As mentioned in the description there's AP test for one of the issues, the second one is more tricky as it requires killing and restarting a lens.

Revision history for this message
Tim Penhey (thumper) wrote :

Looks reasonable, minor niggles about * next to vars, but not types, but that is all.

review: Approve
Revision history for this message
Paweł Stołowski (stolowski) wrote :

Looks good and works fine. My only gripe is about implicit conversion of glib::Variant to bool

619 +Variant::operator bool() const
620 +{
621 + return bool(variant_);
622 +}

IMHO it should only be used it if it improves readability, whereas in this case, if you just look at the interface declaration, it's not apparent that it relies on the internal pointer not being null - plus one could expect bool operator to return a boolean value of the variant when it makes sense (i.e. what GetBool() does atm).

Would you mind changing this to something more verbose, e.g. bool Variant::IsNull(); also 'return variant_ == null' would be more clear.

I'm sorry for being picky, I'm now spoiled by other languages ;)

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

> Looks good and works fine. My only gripe is about implicit conversion of
> glib::Variant to bool
>
> 619 +Variant::operator bool() const
> 620 +{
> 621 + return bool(variant_);
> 622 +}
>
> IMHO it should only be used it if it improves readability, whereas in this
> case, if you just look at the interface declaration, it's not apparent that it
> relies on the internal pointer not being null - plus one could expect bool
> operator to return a boolean value of the variant when it makes sense (i.e.
> what GetBool() does atm).
>
> Would you mind changing this to something more verbose, e.g. bool
> Variant::IsNull(); also 'return variant_ == null' would be more clear.
>
> I'm sorry for being picky, I'm now spoiled by other languages ;)

I understand your point, but this is consistent with our other wrappers (glib::Object), plus you really shouldn't be using implicit conversion to get the value out of a variant, that sounds like a very bad idea. Moreover this also consistent with the way shared_ptr and unique_ptr work, so as long as you keep in mind this is a wrapper it's not that ambiguous.

Revision history for this message
Paweł Stołowski (stolowski) wrote :

I wasn't suggesting implicit conversion to get the value out of a variant, just said one could be tricked into thinking it does that by looking at the interface ;); that would indeed be a bad idea.

If it's consistent with other wrappers, then so be it, though that doesn't automatically make me happy :/

review: Approve
Revision history for this message
Unity Merger (unity-merger) wrote :

The Jenkins job https://jenkins.qa.ubuntu.com/job/automerge-unity/1151/console reported an error when processing this lp:~mhr3/unity/home-lens-fixes branch.
Not merging it.

Revision history for this message
Unity Merger (unity-merger) wrote :

The Jenkins job https://jenkins.qa.ubuntu.com/job/automerge-unity/1153/console reported an error when processing this lp:~mhr3/unity/home-lens-fixes branch.
Not merging it.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'UnityCore/HomeLens.cpp'
2--- UnityCore/HomeLens.cpp 2012-08-17 15:59:41 +0000
3+++ UnityCore/HomeLens.cpp 2012-08-29 09:48:20 +0000
4@@ -136,6 +136,21 @@
5 return target_cat_index;
6 }
7
8+ void UnregisterAllForModel(DeeModel* model)
9+ {
10+ auto it = reg_category_map_.begin();
11+
12+ // References and iterators to the erased elements are invalidated.
13+ // Other references and iterators are not affected.
14+ while (it != reg_category_map_.end())
15+ {
16+ if (it->first.first == model)
17+ reg_category_map_.erase(it++);
18+ else
19+ ++it;
20+ }
21+ }
22+
23 void NotifyOrderChanged ()
24 {
25 owner_->categories_reordered();
26@@ -157,17 +172,18 @@
27 ModelMerger(glib::Object<DeeModel> target);
28 virtual ~ModelMerger();
29
30- void AddSource(Lens::Ptr& owner_lens, glib::Object<DeeModel> source);
31+ virtual void AddSource(Lens::Ptr& owner_lens, glib::Object<DeeModel> source);
32+ virtual void RemoveSource(glib::Object<DeeModel> const& old_source);
33
34 protected:
35- virtual void OnSourceRowAdded(DeeModel *model, DeeModelIter *iter);
36+ virtual void OnSourceRowAdded(DeeModel* model, DeeModelIter* iter);
37 virtual void OnSourceRowRemoved(DeeModel* model, DeeModelIter* iter);
38 virtual void OnSourceRowChanged(DeeModel* model, DeeModelIter* iter);
39- void EnsureRowBuf(DeeModel *source);
40+ void EnsureRowBuf(DeeModel* source);
41
42 /* The merge tag lives on the source models, pointing to the mapped
43 * row in the target model */
44- DeeModelTag* FindSourceToTargetTag(DeeModel *model);
45+ DeeModelTag* FindSourceToTargetTag(DeeModel* model);
46
47 protected:
48 std::map<Lens::Ptr, glib::Object<DeeModel> > sources_by_owner_;
49@@ -197,9 +213,9 @@
50 HomeLens::CategoryRegistry* cat_registry);
51
52 protected:
53- void OnSourceRowAdded(DeeModel *model, DeeModelIter *iter);
54- void OnSourceRowRemoved(DeeModel *model, DeeModelIter *iter);
55- void OnSourceRowChanged(DeeModel *model, DeeModelIter *iter);
56+ void OnSourceRowAdded(DeeModel* model, DeeModelIter* iter);
57+ void OnSourceRowRemoved(DeeModel* model, DeeModelIter* iter);
58+ void OnSourceRowChanged(DeeModel* model, DeeModelIter* iter);
59
60 private:
61 HomeLens::CategoryRegistry* cat_registry_;
62@@ -221,10 +237,13 @@
63 HomeLens::CategoryRegistry* cat_registry,
64 MergeMode merge_mode);
65
66- void OnSourceRowAdded(DeeModel *model, DeeModelIter *iter);
67- void OnSourceRowRemoved(DeeModel *model, DeeModelIter *iter);
68-
69- std::vector<unsigned> GetOrder();
70+ void OnSourceRowAdded(DeeModel* model, DeeModelIter* iter);
71+ void OnSourceRowRemoved(DeeModel* model, DeeModelIter* iter);
72+
73+ std::vector<unsigned> GetDefaultOrder();
74+
75+protected:
76+ void RemoveSource(glib::Object<DeeModel> const& old_source);
77
78 private:
79 HomeLens::CategoryRegistry* cat_registry_;
80@@ -241,9 +260,9 @@
81 public:
82 FiltersMerger(glib::Object<DeeModel> target);
83
84- void OnSourceRowAdded(DeeModel *model, DeeModelIter *iter);
85- void OnSourceRowRemoved(DeeModel *model, DeeModelIter *iter);
86- void OnSourceRowChanged(DeeModel *model, DeeModelIter *iter);
87+ void OnSourceRowAdded(DeeModel* model, DeeModelIter* iter);
88+ void OnSourceRowRemoved(DeeModel* model, DeeModelIter* iter);
89+ void OnSourceRowChanged(DeeModel* model, DeeModelIter* iter);
90 };
91
92 /*
93@@ -260,6 +279,7 @@
94 void EnsureCategoryAnnotation(Lens::Ptr& lens, DeeModel* results, DeeModel* categories);
95 Lens::Ptr FindLensForUri(std::string const& uri);
96 std::vector<unsigned> GetCategoriesOrder();
97+ void LensSearchFinished(Lens::Ptr& lens);
98
99 HomeLens* owner_;
100 Lenses::LensList lenses_;
101@@ -324,7 +344,7 @@
102 {
103 if (it->second == source)
104 return; // this model was already added
105- sig_manager_.Disconnect(it->second);
106+ RemoveSource(it->second);
107 }
108 sources_by_owner_[owner_lens] = source;
109
110@@ -344,12 +364,23 @@
111 sigc::mem_fun(this, &HomeLens::ModelMerger::OnSourceRowChanged)));
112 }
113
114-void HomeLens::ModelMerger::OnSourceRowAdded(DeeModel *model, DeeModelIter *iter)
115+void HomeLens::ModelMerger::RemoveSource(glib::Object<DeeModel> const& source)
116+{
117+ if (!source)
118+ {
119+ LOG_ERROR(logger) << "Trying to remove NULL source from ModelMerger";
120+ return;
121+ }
122+
123+ sig_manager_.Disconnect(source);
124+}
125+
126+void HomeLens::ModelMerger::OnSourceRowAdded(DeeModel* model, DeeModelIter* iter)
127 {
128 // Default impl. does nothing.
129 }
130
131-void HomeLens::ResultsMerger::OnSourceRowAdded(DeeModel *model, DeeModelIter *iter)
132+void HomeLens::ResultsMerger::OnSourceRowAdded(DeeModel* model, DeeModelIter* iter)
133 {
134 DeeModelIter* target_iter;
135 int target_cat_offset, source_cat_offset;
136@@ -390,7 +421,7 @@
137 for (unsigned int i = 0; i < n_cols_; i++) g_variant_unref(row_buf_[i]);
138 }
139
140-void HomeLens::CategoryMerger::OnSourceRowAdded(DeeModel *model, DeeModelIter *iter)
141+void HomeLens::CategoryMerger::OnSourceRowAdded(DeeModel* model, DeeModelIter* iter)
142 {
143 DeeModel* results_model;
144 DeeModelIter* target_iter;
145@@ -470,14 +501,14 @@
146 for (unsigned int i = 0; i < n_cols_; i++) g_variant_unref(row_buf_[i]);
147 }
148
149-void HomeLens::FiltersMerger::OnSourceRowAdded(DeeModel *model, DeeModelIter *iter)
150+void HomeLens::FiltersMerger::OnSourceRowAdded(DeeModel* model, DeeModelIter* iter)
151 {
152 /* Supporting filters on the home screen is possible, but *quite* tricky.
153 * So... Discard ALL the rows!
154 */
155 }
156
157-void HomeLens::CategoryMerger::OnSourceRowRemoved(DeeModel *model, DeeModelIter *iter)
158+void HomeLens::CategoryMerger::OnSourceRowRemoved(DeeModel* model, DeeModelIter* iter)
159 {
160 /* We don't support removals of categories.
161 * You can check out any time you like, but you can never leave
162@@ -488,7 +519,7 @@
163 LOG_DEBUG(logger) << "Removal of categories not supported.";
164 }
165
166-void HomeLens::ModelMerger::OnSourceRowRemoved(DeeModel *model, DeeModelIter *iter)
167+void HomeLens::ModelMerger::OnSourceRowRemoved(DeeModel* model, DeeModelIter* iter)
168 {
169 DeeModelIter* target_iter;
170 DeeModelTag* target_tag;
171@@ -506,17 +537,17 @@
172 dee_model_remove(target_, target_iter);
173 }
174
175-void HomeLens::ResultsMerger::OnSourceRowRemoved(DeeModel *model, DeeModelIter *iter)
176+void HomeLens::ResultsMerger::OnSourceRowRemoved(DeeModel* model, DeeModelIter* iter)
177 {
178 ModelMerger::OnSourceRowRemoved(model, iter);
179 }
180
181-void HomeLens::FiltersMerger::OnSourceRowRemoved(DeeModel *model, DeeModelIter *iter)
182+void HomeLens::FiltersMerger::OnSourceRowRemoved(DeeModel* model, DeeModelIter* iter)
183 {
184 /* We aren't adding any rows to the merged model, so nothing to do here */
185 }
186
187-void HomeLens::ModelMerger::OnSourceRowChanged(DeeModel *model, DeeModelIter *iter)
188+void HomeLens::ModelMerger::OnSourceRowChanged(DeeModel* model, DeeModelIter* iter)
189 {
190 DeeModelIter* target_iter;
191 DeeModelTag* target_tag;
192@@ -534,18 +565,18 @@
193 for (unsigned int i = 0; i < n_cols_; i++) g_variant_unref(row_buf_[i]);
194 }
195
196-void HomeLens::ResultsMerger::OnSourceRowChanged(DeeModel *model, DeeModelIter *iter)
197+void HomeLens::ResultsMerger::OnSourceRowChanged(DeeModel* model, DeeModelIter* iter)
198 {
199 // FIXME: We can support this, but we need to re-calculate the category offset
200 LOG_WARN(logger) << "In-line changing of results not supported in the home lens. Sorry.";
201 }
202
203-void HomeLens::FiltersMerger::OnSourceRowChanged(DeeModel *model, DeeModelIter *iter)
204+void HomeLens::FiltersMerger::OnSourceRowChanged(DeeModel* model, DeeModelIter* iter)
205 {
206 /* We aren't adding any rows to the merged model, so nothing to do here */
207 }
208
209-void HomeLens::ModelMerger::EnsureRowBuf(DeeModel *model)
210+void HomeLens::ModelMerger::EnsureRowBuf(DeeModel* model)
211 {
212 if (G_UNLIKELY (n_cols_ == 0))
213 {
214@@ -606,12 +637,20 @@
215 }
216 }
217
218-DeeModelTag* HomeLens::ModelMerger::FindSourceToTargetTag(DeeModel *model)
219+DeeModelTag* HomeLens::ModelMerger::FindSourceToTargetTag(DeeModel* model)
220 {
221 return source_to_target_tags_[model];
222 }
223
224-std::vector<unsigned> HomeLens::CategoryMerger::GetOrder()
225+void HomeLens::CategoryMerger::RemoveSource(glib::Object<DeeModel> const& source)
226+{
227+ // call base()
228+ HomeLens::ModelMerger::RemoveSource(source);
229+
230+ cat_registry_->UnregisterAllForModel(source);
231+}
232+
233+std::vector<unsigned> HomeLens::CategoryMerger::GetDefaultOrder()
234 {
235 std::vector<unsigned> result;
236 for (auto it = category_ordering_.begin(); it != category_ordering_.end(); ++it)
237@@ -746,6 +785,7 @@
238 lens->global_search_finished.connect([&] (Hints const& hints) {
239 running_searches_--;
240
241+ LensSearchFinished(lens);
242 if (running_searches_ <= 0)
243 {
244 owner_->search_finished.emit(Hints());
245@@ -784,41 +824,15 @@
246 filters_merger_.AddSource(lens, filters_prop());
247 }
248
249- /*
250- * We'll assume that the models' swarm names do not change during life cycle
251- * of a lens.
252- * Otherwise we might run into a race where we would associate category
253- * model to a results model that is about to be replaced by a new one.
254- */
255- lens->connected.changed.connect([&] (bool is_connected)
256- {
257- if (is_connected)
258- {
259- EnsureCategoryAnnotation(lens, lens->categories()->model(),
260- lens->global_results()->model());
261- categories_merger_.AddSource(lens, lens->categories()->model());
262- results_merger_.AddSource(lens, lens->global_results()->model());
263- filters_merger_.AddSource(lens, lens->filters()->model());
264- }
265- });
266- /*
267- results_prop.changed.connect([&] (glib::Object<DeeModel> model)
268- {
269- EnsureCategoryAnnotation(lens, lens->categories()->model(), model);
270- results_merger_.AddSource(model);
271- });
272-
273- categories_prop.changed.connect([&] (glib::Object<DeeModel> model)
274- {
275- EnsureCategoryAnnotation(lens, model, lens->global_results()->model());
276- categories_merger_.AddSource(model);
277- });
278-
279- filters_prop.changed.connect([&] (glib::Object<DeeModel> model)
280- {
281- filters_merger_.AddSource(model);
282- });
283- */
284+ /* Make sure the models are properly annotated when they change */
285+ lens->models_changed.connect([&] ()
286+ {
287+ EnsureCategoryAnnotation(lens, lens->categories()->model(),
288+ lens->global_results()->model());
289+ categories_merger_.AddSource(lens, lens->categories()->model());
290+ results_merger_.AddSource(lens, lens->global_results()->model());
291+ filters_merger_.AddSource(lens, lens->filters()->model());
292+ });
293
294 /*
295 * Register pre-existing categories up front
296@@ -838,9 +852,13 @@
297 }
298 }
299
300+void HomeLens::Impl::LensSearchFinished(Lens::Ptr& lens)
301+{
302+}
303+
304 std::vector<unsigned> HomeLens::Impl::GetCategoriesOrder()
305 {
306- return categories_merger_.GetOrder();
307+ return categories_merger_.GetDefaultOrder();
308 }
309
310 HomeLens::HomeLens(std::string const& name,
311
312=== modified file 'UnityCore/Lens.cpp'
313--- UnityCore/Lens.cpp 2012-08-15 21:47:27 +0000
314+++ UnityCore/Lens.cpp 2012-08-29 09:48:20 +0000
315@@ -36,6 +36,8 @@
316 namespace
317 {
318 nux::logging::Logger logger("unity.dash.lens");
319+
320+const unsigned CATEGORY_COLUMN = 2;
321 }
322
323 using std::string;
324@@ -91,6 +93,8 @@
325 glib::Variant const& preview_update,
326 glib::DBusProxy::ReplyCallback reply_cb);
327 std::vector<unsigned> GetCategoriesOrder();
328+ glib::Object<DeeModel> GetFilterModelForCategory(unsigned category);
329+ void GetFilterForCategoryIndex(unsigned category, DeeFilter* filter);
330
331 string const& id() const;
332 string const& dbus_name() const;
333@@ -109,6 +113,9 @@
334 Filters::Ptr const& filters() const;
335 bool connected() const;
336
337+ string const& last_search_string() const { return last_search_string_; }
338+ string const& last_global_search_string() const { return last_global_search_string_; }
339+
340 Lens* owner_;
341
342 string id_;
343@@ -128,14 +135,16 @@
344 bool connected_;
345
346 string private_connection_name_;
347+ string last_search_string_;
348+ string last_global_search_string_;
349
350 glib::DBusProxy* proxy_;
351 glib::Object<GCancellable> search_cancellable_;
352 glib::Object<GCancellable> global_search_cancellable_;
353 glib::Object<GCancellable> preview_cancellable_;
354
355- GVariant *results_variant_;
356- GVariant *global_results_variant_;
357+ glib::Variant results_variant_;
358+ glib::Variant global_results_variant_;
359 };
360
361 Lens::Impl::Impl(Lens* owner,
362@@ -166,8 +175,6 @@
363 , filters_(new Filters(model_type))
364 , connected_(false)
365 , proxy_(NULL)
366- , results_variant_(NULL)
367- , global_results_variant_(NULL)
368 {
369 if (model_type == ModelType::REMOTE)
370 {
371@@ -199,6 +206,8 @@
372 owner_->categories.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::categories));
373 owner_->filters.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::filters));
374 owner_->connected.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::connected));
375+ owner_->last_search_string.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::last_search_string));
376+ owner_->last_global_search_string.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::last_global_search_string));
377 owner_->view_type.changed.connect(sigc::mem_fun(this, &Lens::Impl::OnViewTypeChanged));
378 }
379
380@@ -236,13 +245,11 @@
381 void Lens::Impl::ResultsModelUpdated(unsigned long long begin_seqnum,
382 unsigned long long end_seqnum)
383 {
384- if (results_variant_ != NULL &&
385- end_seqnum >= ExtractModelSeqnum (results_variant_))
386+ if (results_variant_ && end_seqnum >= ExtractModelSeqnum (results_variant_))
387 {
388- glib::Variant dict(results_variant_, glib::StealRef());
389 Hints hints;
390
391- dict.ASVToHints(hints);
392+ results_variant_.ASVToHints(hints);
393
394 owner_->search_finished.emit(hints);
395
396@@ -253,13 +260,12 @@
397 void Lens::Impl::GlobalResultsModelUpdated(unsigned long long begin_seqnum,
398 unsigned long long end_seqnum)
399 {
400- if (global_results_variant_ != NULL &&
401+ if (global_results_variant_ &&
402 end_seqnum >= ExtractModelSeqnum (global_results_variant_))
403 {
404- glib::Variant dict(global_results_variant_, glib::StealRef());
405 Hints hints;
406
407- dict.ASVToHints(hints);
408+ global_results_variant_.ASVToHints(hints);
409
410 owner_->global_search_finished.emit(hints);
411
412@@ -296,8 +302,7 @@
413 if (results_->seqnum < reply_seqnum)
414 {
415 // wait for the end-transaction signal
416- if (results_variant_) g_variant_unref (results_variant_);
417- results_variant_ = g_variant_ref (parameters);
418+ results_variant_ = parameters;
419
420 // ResultsModelUpdated will emit OnSearchFinished
421 return;
422@@ -318,8 +323,7 @@
423 if (global_results_->seqnum < reply_seqnum)
424 {
425 // wait for the end-transaction signal
426- if (global_results_variant_) g_variant_unref (global_results_variant_);
427- global_results_variant_ = g_variant_ref (parameters);
428+ global_results_variant_ = parameters;
429
430 // GlobalResultsModelUpdated will emit OnGlobalSearchFinished
431 return;
432@@ -367,15 +371,27 @@
433 << " Filters: " << filters_model_name << "\n";
434 if (dbus_path.Str() == dbus_path_)
435 {
436+ std::string categories_model_swarm_name(categories_model_name.Str());
437+ std::string filters_model_swarm_name(filters_model_name.Str());
438+ std::string results_model_swarm_name(results_model_name.Str());
439+ std::string global_results_model_swarm_name(global_results_model_name.Str());
440+ bool models_changed =
441+ categories_model_swarm_name != categories_->swarm_name ||
442+ filters_model_swarm_name != filters_->swarm_name ||
443+ results_model_swarm_name != results_->swarm_name ||
444+ global_results_model_swarm_name != global_results_->swarm_name;
445+
446 /* FIXME: We ignore hints for now */
447 UpdateProperties(search_in_global,
448 visible,
449 search_hint.Str(),
450 private_connection_name.Str(),
451- results_model_name.Str(),
452- global_results_model_name.Str(),
453- categories_model_name.Str(),
454- filters_model_name.Str());
455+ results_model_swarm_name,
456+ global_results_model_swarm_name,
457+ categories_model_swarm_name,
458+ filters_model_swarm_name);
459+
460+ if (models_changed) owner_->models_changed.emit();
461 }
462 else
463 {
464@@ -447,11 +463,8 @@
465 g_cancellable_cancel (global_search_cancellable_);
466 global_search_cancellable_ = g_cancellable_new ();
467
468- if (global_results_variant_)
469- {
470- g_variant_unref (global_results_variant_);
471- global_results_variant_ = NULL;
472- }
473+ global_results_variant_ = NULL;
474+ last_global_search_string_ = search_string;
475
476 proxy_->Call("GlobalSearch",
477 g_variant_new("(sa{sv})",
478@@ -478,11 +491,8 @@
479 if (search_cancellable_) g_cancellable_cancel (search_cancellable_);
480 search_cancellable_ = g_cancellable_new ();
481
482- if (results_variant_)
483- {
484- g_variant_unref (results_variant_);
485- results_variant_ = NULL;
486- }
487+ results_variant_ = NULL;
488+ last_search_string_ = search_string;
489
490 proxy_->Call("Search",
491 g_variant_new("(sa{sv})",
492@@ -621,6 +631,61 @@
493 return result;
494 }
495
496+glib::Object<DeeModel> Lens::Impl::GetFilterModelForCategory(unsigned category)
497+{
498+ DeeFilter filter;
499+ GetFilterForCategoryIndex(category, &filter);
500+ glib::Object<DeeModel> filter_model(dee_filter_model_new(results_->model(), &filter));
501+
502+ return filter_model;
503+}
504+
505+static void category_filter_map_func (DeeModel* orig_model,
506+ DeeFilterModel* filter_model,
507+ gpointer user_data)
508+{
509+ DeeModelIter* iter;
510+ DeeModelIter* end;
511+ unsigned index = GPOINTER_TO_UINT(user_data);
512+
513+ iter = dee_model_get_first_iter(orig_model);
514+ end = dee_model_get_last_iter(orig_model);
515+ while (iter != end)
516+ {
517+ unsigned category_index = dee_model_get_uint32(orig_model, iter,
518+ CATEGORY_COLUMN);
519+ if (index == category_index)
520+ {
521+ dee_filter_model_append_iter(filter_model, iter);
522+ }
523+ iter = dee_model_next(orig_model, iter);
524+ }
525+}
526+
527+static gboolean category_filter_notify_func (DeeModel* orig_model,
528+ DeeModelIter* orig_iter,
529+ DeeFilterModel* filter_model,
530+ gpointer user_data)
531+{
532+ unsigned index = GPOINTER_TO_UINT(user_data);
533+ unsigned category_index = dee_model_get_uint32(orig_model, orig_iter,
534+ CATEGORY_COLUMN);
535+
536+ if (index != category_index)
537+ return FALSE;
538+
539+ dee_filter_model_insert_iter_with_original_order(filter_model, orig_iter);
540+ return TRUE;
541+}
542+
543+void Lens::Impl::GetFilterForCategoryIndex(unsigned category, DeeFilter* filter)
544+{
545+ filter->map_func = category_filter_map_func;
546+ filter->map_notify = category_filter_notify_func;
547+ filter->destroy = nullptr;
548+ filter->userdata = GUINT_TO_POINTER(category);
549+}
550+
551 string const& Lens::Impl::id() const
552 {
553 return id_;
554@@ -797,6 +862,11 @@
555 return pimpl->GetCategoriesOrder();
556 }
557
558+glib::Object<DeeModel> Lens::GetFilterModelForCategory(unsigned category)
559+{
560+ return pimpl->GetFilterModelForCategory(category);
561+}
562+
563
564 }
565 }
566
567=== modified file 'UnityCore/Lens.h'
568--- UnityCore/Lens.h 2012-08-15 21:47:27 +0000
569+++ UnityCore/Lens.h 2012-08-29 09:48:20 +0000
570@@ -90,6 +90,13 @@
571 virtual void SignalPreview(std::string const& uri,
572 glib::Variant const& preview_update,
573 glib::DBusProxy::ReplyCallback reply_cb = nullptr);
574+
575+ /**
576+ * Note that this model is only valid for as long as the results model
577+ * doesn't change.
578+ * (you should call this again after models_changed is emitted)
579+ */
580+ virtual glib::Object<DeeModel> GetFilterModelForCategory(unsigned category);
581 virtual std::vector<unsigned> GetCategoriesOrder();
582
583 nux::RWProperty<std::string> id;
584@@ -107,10 +114,15 @@
585 nux::RWProperty<Categories::Ptr> categories;
586 nux::RWProperty<Filters::Ptr> filters;
587 nux::RWProperty<bool> connected;
588+ nux::ROProperty<std::string> last_search_string;
589+ nux::ROProperty<std::string> last_global_search_string;
590
591 nux::Property<ViewType> view_type;
592
593 sigc::signal<void> categories_reordered;
594+ /* Emitted when any of the models' swarm name changes, but collates the name
595+ * changes into a single signal emission (when all are changed) */
596+ sigc::signal<void> models_changed;
597 sigc::signal<void, Hints const&> search_finished;
598 sigc::signal<void, Hints const&> global_search_finished;
599 sigc::signal<void, std::string const&, HandledType, Hints const&> activated;
600
601=== modified file 'UnityCore/Variant.cpp'
602--- UnityCore/Variant.cpp 2012-06-01 14:01:29 +0000
603+++ UnityCore/Variant.cpp 2012-08-29 09:48:20 +0000
604@@ -97,8 +97,8 @@
605
606 Variant& Variant::operator=(GVariant* val)
607 {
608- if (variant_) g_variant_unref (variant_);
609- variant_ = g_variant_ref_sink (val);
610+ if (variant_) g_variant_unref(variant_);
611+ variant_ = val ? g_variant_ref_sink(val) : val;
612
613 return *this;
614 }
615@@ -108,6 +108,11 @@
616 return variant_;
617 }
618
619+Variant::operator bool() const
620+{
621+ return bool(variant_);
622+}
623+
624 } // namespace glib
625
626 namespace variant
627
628=== modified file 'UnityCore/Variant.h'
629--- UnityCore/Variant.h 2012-06-01 14:01:29 +0000
630+++ UnityCore/Variant.h 2012-08-29 09:48:20 +0000
631@@ -55,6 +55,8 @@
632
633 Variant& operator=(GVariant*);
634 operator GVariant*() const;
635+ operator bool() const;
636+
637 private:
638 GVariant* variant_;
639 };
640
641=== modified file 'dash/LensView.cpp'
642--- dash/LensView.cpp 2012-08-28 12:23:15 +0000
643+++ dash/LensView.cpp 2012-08-29 09:48:20 +0000
644@@ -45,8 +45,6 @@
645
646 const int CARD_VIEW_GAP_VERT = 24; // pixels
647 const int CARD_VIEW_GAP_HORIZ = 25; // pixels
648-
649-const unsigned CATEGORY_COLUMN = 2;
650 }
651
652 // This is so we can access some protected members in scrollview.
653@@ -248,11 +246,8 @@
654 {
655 for (unsigned int i = 0; i < categories_.size(); ++i)
656 {
657- PlacesGroup* group = categories_[i];
658- ResultViewGrid* grid = static_cast<ResultViewGrid*>(group->GetChildView());
659- DeeFilter filter;
660- GetFilterForCategoryIndex(i, &filter);
661- glib::Object<DeeModel> filter_model(dee_filter_model_new(model, &filter));
662+ ResultViewGrid* grid = GetGridForCategory(i);
663+ glib::Object<DeeModel> filter_model(lens_->GetFilterModelForCategory(i));
664 Results::Ptr results_model = lens_->results;
665 grid->SetModel(filter_model, results_model->GetTag());
666 }
667@@ -360,9 +355,7 @@
668 Results::Ptr results_model = lens_->results;
669 if (results_model->model())
670 {
671- DeeFilter filter;
672- GetFilterForCategoryIndex(index, &filter);
673- glib::Object<DeeModel> filter_model(dee_filter_model_new(results_model->model(), &filter));
674+ glib::Object<DeeModel> filter_model(lens_->GetFilterModelForCategory(index));
675 grid->SetModel(filter_model, results_model->GetTag());
676 }
677
678@@ -422,62 +415,13 @@
679 }
680 }
681
682-static void category_filter_map_func (DeeModel* orig_model,
683- DeeFilterModel* filter_model,
684- gpointer user_data)
685-{
686- DeeModelIter* iter;
687- DeeModelIter* end;
688- unsigned index = GPOINTER_TO_UINT(user_data);
689-
690- iter = dee_model_get_first_iter(orig_model);
691- end = dee_model_get_last_iter(orig_model);
692- while (iter != end)
693- {
694- unsigned category_index = dee_model_get_uint32(orig_model, iter,
695- CATEGORY_COLUMN);
696- if (index == category_index)
697- {
698- dee_filter_model_append_iter(filter_model, iter);
699- }
700- iter = dee_model_next(orig_model, iter);
701- }
702-}
703-
704-static gboolean category_filter_notify_func (DeeModel* orig_model,
705- DeeModelIter* orig_iter,
706- DeeFilterModel* filter_model,
707- gpointer user_data)
708-{
709- unsigned index = GPOINTER_TO_UINT(user_data);
710- unsigned category_index = dee_model_get_uint32(orig_model, orig_iter,
711- CATEGORY_COLUMN);
712-
713- if (index != category_index)
714- return FALSE;
715-
716- dee_filter_model_insert_iter_with_original_order(filter_model, orig_iter);
717- return TRUE;
718-}
719-
720-void LensView::GetFilterForCategoryIndex(unsigned index, DeeFilter* filter)
721-{
722- filter->map_func = category_filter_map_func;
723- filter->map_notify = category_filter_notify_func;
724- filter->destroy = nullptr;
725- filter->userdata = GUINT_TO_POINTER(index);
726-}
727-
728 bool LensView::ReinitializeFilterModels()
729 {
730 Results::Ptr results_model = lens_->results;
731 for (unsigned i = last_good_filter_model_ + 1; i < categories_.size(); ++i)
732 {
733- PlacesGroup* group = categories_[i];
734- ResultViewGrid* grid = static_cast<ResultViewGrid*>(group->GetChildView());
735- DeeFilter filter;
736- GetFilterForCategoryIndex(i, &filter);
737- glib::Object<DeeModel> filter_model(dee_filter_model_new(results_model->model(), &filter));
738+ ResultViewGrid* grid = GetGridForCategory(i);
739+ glib::Object<DeeModel> filter_model(lens_->GetFilterModelForCategory(i));
740 grid->SetModel(filter_model, results_model->GetTag());
741 }
742
743@@ -486,6 +430,13 @@
744 return false;
745 }
746
747+ResultViewGrid* LensView::GetGridForCategory(unsigned category_index)
748+{
749+ if (category_index >= categories_.size()) return nullptr;
750+ PlacesGroup* group = categories_.at(category_index);
751+ return static_cast<ResultViewGrid*>(group->GetChildView());
752+}
753+
754 void LensView::OnResultAdded(Result const& result)
755 {
756 try {
757@@ -755,18 +706,20 @@
758 Results::Ptr results = lens_->results;
759 if (results->count())
760 {
761- // FIXME: Linear search in the result model, use category grid's model!
762- for (unsigned int c = 0; c < scroll_layout_->GetChildren().size(); ++c)
763+ // the first displayed category might not be categories_[0]
764+ auto category_order = lens_->GetCategoriesOrder();
765+ for (unsigned int i = 0; i < category_order.size(); i++)
766 {
767- for (unsigned int i = 0; i < results->count(); ++i)
768+ unsigned cat_index = category_order.at(i);
769+ ResultViewGrid* grid = GetGridForCategory(cat_index);
770+ if (grid == nullptr) continue;
771+ auto it = grid->GetIteratorAtRow(0);
772+ if (!it.IsLast())
773 {
774- Result result = results->RowAtIndex(i);
775- if (result.category_index == c && result.uri != "")
776- {
777- uri_activated(result.uri);
778- lens_->Activate(result.uri);
779- return;
780- }
781+ Result result(*it);
782+ uri_activated(result.uri);
783+ lens_->Activate(result.uri);
784+ return;
785 }
786 }
787 // Fallback
788
789=== modified file 'dash/LensView.h'
790--- dash/LensView.h 2012-08-28 12:23:15 +0000
791+++ dash/LensView.h 2012-08-29 09:48:20 +0000
792@@ -95,8 +95,7 @@
793 void QueueFixRenderering();
794 bool FixRenderering();
795 bool ReinitializeFilterModels();
796-
797- static void GetFilterForCategoryIndex(unsigned index, DeeFilter* filter);
798+ ResultViewGrid* GetGridForCategory(unsigned category_index);
799
800 void BuildPreview(std::string const& uri, Preview::Ptr model);
801