Merge lp:~brandontschaefer/unity/fix-711199 into lp:unity

Proposed by Brandon Schaefer
Status: Merged
Approved by: Tim Penhey
Approved revision: no longer in the source branch.
Merged at revision: 2093
Proposed branch: lp:~brandontschaefer/unity/fix-711199
Merge into: lp:unity
Diff against target: 300 lines (+147/-6)
5 files modified
plugins/unityshell/src/DashView.cpp (+36/-5)
plugins/unityshell/src/DashView.h (+3/-0)
plugins/unityshell/src/LensView.cpp (+58/-1)
plugins/unityshell/src/LensView.h (+5/-0)
tests/autopilot/autopilot/tests/test_dash.py (+45/-0)
To merge this branch: bzr merge lp:~brandontschaefer/unity/fix-711199
Reviewer Review Type Date Requested Status
Tim Penhey (community) Approve
Alex Launi (community) Approve
Michal Hruby (community) Approve
Marco Trevisan (Treviño) Approve
Brandon Schaefer (community) Approve
Review via email: mp+89192@code.launchpad.net

Description of the change

= Problem description =

If no results are returned from a lens there is no message informing the user so.

= The fix =

In DashView::OnSearchFinished a check is made to see if a message should be
shown.

A default message is used if the lens doesn't provide one.

There is also a timer that waits for 150ms then hides the
message, if the search is taking a while.

= Test coverage =

There is an autopilot test for this now!

To post a comment you must log in.
Revision history for this message
Brandon Schaefer (brandontschaefer) :
review: Needs Fixing
Revision history for this message
Brandon Schaefer (brandontschaefer) :
review: Needs Resubmitting
Revision history for this message
Brandon Schaefer (brandontschaefer) :
review: Needs Fixing
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

Need to not use a work around for the start up problem. Looking into removing the call in LensView:
http://bazaar.launchpad.net/~unity-team/unity/trunk/view/head:/plugins/unityshell/src/LensView.cpp#L350

Removing that if statement which calls Search("") and OnSearchFinished is getting emitted with 0 results for ALL lenses, even though they have them. So far testing shows this code can be removed, but want to do more testing by killing the lenses and restarting them.

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

Why check for
  if (active_lens_view_->lens())
at the start of DashView::OnSearchFinished?
Small style issue, no space before (hints).

plese use:
  nux::color::White
instead of:
  nux::Color(1.0f,1.0f,1.0f,1.0f)

Instead of using += on a std::string, use a string stream.

#include <sstream>

std::stringstream sout;

sout << "<span size='larger' weight='bold'>";
//...
sout << g_variant_get_string(it->second, NULL);
//...
sout << "Sorry, there is nothing that matches your search.";
//...
sout << "</span>";

LOG_DEBUG(logger) << "The no-result-hint is: " << sout.str();

no_results_->SetText(sout.str());

How does the normal results view get shown again?

review: Needs Fixing
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

I was checking active_lens_->lens() because there was a problem before where the active home lens would get passed in with out actually having a lens() which would cause a seg fault. That has now been fix/changed so I remove that! (Tested, now no seg fault yay!)

Fixed style problems (there were other style errors; now fixed!), now using nux::color::White, and now markup uses sstream!

As for the normal results view, it is still getting shown how it normally does. The no-result-message is apart of the same layout so when the results == 0 the layout is empty. Then I change the layouts ContentDistribution to nux::MAJOR_POSITION_CENTER, which draws the text in the middle of the dash. When there are > 0 results I change it back to nux::MAJOR_POSITION_START (default), so the new results get draw back where they should. (Instead of the middle!)

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

89 + markup << g_variant_get_string(it->second, NULL);

Values in the Hints map are instances of unity::glib::Variant (which have a GVariant* operator), please use the GetString method (which is NULL safe).

93 + markup << "Sorry, there is nothing that matches your search.";

This needs to be marked for translation - just use _("Sorry, ...")

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

Also there could be an issue with hiding the message - currently it's only shown or hidden when the SearchFinishes, which means that this can happen:

If you're searching with a lens/scope that is really slow and is adding results one by one and finishes in let's say 5seconds, you can end up seeing the "Sorry, ..." message for the entire 5 seconds while it's searching and just then the message will disappear.

A solution to this would be to hide the message as soon as the search starts, but that again brings an issue that the search might finish in 10ms with no results, and the message will flicker. A proper solution will probably have to use a timer similar to what the search bar spinner is doing (it starts spinning after ~150ms after the search starts).

Revision history for this message
Brandon Schaefer (brandontschaefer) :
review: Approve
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

I also guess you can easily write an autopilot test to check this. Just add a a value for no_results_active_ to the introspection wrapper, and check it with the AP suite ;)

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

84 + g_source_remove(hide_message_delay_id_);
100 + g_source_remove(hide_message_delay_id_);

You should set the id to 0 after these calls.

review: Needs Fixing
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

@Michal opps, I fixed that but forgot to push those changes...like a month ago haha.

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

Tests are good, maybe instead of just searching for 'a' you could make it look for a real default application, so it will also indirectly test that lens is working :)

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

There is still one/two rare corner cases where the message could be displayed while also results are, but that can be solved in a later merge. Approve from me.

review: Approve
Revision history for this message
Alex Launi (alexlauni) wrote :

AP test looks good.

review: Approve
Revision history for this message
Tim Penhey (thumper) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/unityshell/src/DashView.cpp'
2--- plugins/unityshell/src/DashView.cpp 2012-02-14 10:18:15 +0000
3+++ plugins/unityshell/src/DashView.cpp 2012-03-09 02:13:19 +0000
4@@ -82,6 +82,7 @@
5 , searching_timeout_id_(0)
6 , search_in_progress_(false)
7 , activate_on_finish_(false)
8+ , hide_message_delay_id_(0)
9 , visible_(false)
10 {
11 renderer_.SetOwner(this);
12@@ -106,6 +107,8 @@
13 {
14 if (searching_timeout_id_)
15 g_source_remove (searching_timeout_id_);
16+ if (hide_message_delay_id_)
17+ g_source_remove(hide_message_delay_id_);
18 }
19
20 void DashView::SetMonitorOffset(int x, int y)
21@@ -374,6 +377,16 @@
22 return FALSE;
23 }
24
25+gboolean DashView::HideResultMessageCb(gpointer data)
26+{
27+ DashView *self = static_cast<DashView*>(data);
28+
29+ self->active_lens_view_->HideResultsMessage();
30+ self->hide_message_delay_id_ = 0;
31+
32+ return FALSE;
33+}
34+
35 void DashView::OnSearchChanged(std::string const& search_string)
36 {
37 LOG_DEBUG(logger) << "Search changed: " << search_string;
38@@ -385,9 +398,21 @@
39 if (searching_timeout_id_)
40 {
41 g_source_remove (searching_timeout_id_);
42+ searching_timeout_id_ = 0;
43 }
44+
45 // 250ms for the Search method call, rest for the actual search
46 searching_timeout_id_ = g_timeout_add (500, &DashView::ResetSearchStateCb, this);
47+
48+
49+ if (hide_message_delay_id_)
50+ {
51+ g_source_remove(hide_message_delay_id_);
52+ hide_message_delay_id_ = 0;
53+ }
54+
55+ // 150ms to hide the no reults message if its take a while to return results
56+ hide_message_delay_id_ = g_timeout_add (150, &DashView::HideResultMessageCb, this);
57 }
58 }
59
60@@ -450,20 +475,26 @@
61
62 search_bar_->can_refine_search = view->can_refine_search();
63
64+ if (hide_message_delay_id_)
65+ {
66+ g_source_remove(hide_message_delay_id_);
67+ hide_message_delay_id_ = 0;
68+ }
69+
70 view->QueueDraw();
71 QueueDraw();
72 }
73
74 void DashView::OnSearchFinished(Lens::Hints const& hints)
75 {
76- Lens::Hints::const_iterator it;
77- it = hints.find("no-results-hint");
78-
79- if (it != hints.end())
80+ if (hide_message_delay_id_)
81 {
82- LOG_DEBUG(logger) << "We have no-results-hint: " << g_variant_get_string (it->second, NULL);
83+ g_source_remove(hide_message_delay_id_);
84+ hide_message_delay_id_ = 0;
85 }
86
87+ active_lens_view_->CheckNoResults(hints);
88+
89 std::string search_string = search_bar_->search_string;
90 if (active_lens_view_ && active_lens_view_->search_string == search_string)
91 {
92
93=== modified file 'plugins/unityshell/src/DashView.h'
94--- plugins/unityshell/src/DashView.h 2012-02-13 02:15:31 +0000
95+++ plugins/unityshell/src/DashView.h 2012-03-09 02:13:19 +0000
96@@ -108,6 +108,7 @@
97 nux::Area* KeyNavIteration(nux::KeyNavDirection direction);
98
99 static gboolean ResetSearchStateCb(gpointer data);
100+ static gboolean HideResultMessageCb(gpointer data);
101
102 private:
103 UBusManager ubus_manager_;
104@@ -136,6 +137,8 @@
105 bool search_in_progress_;
106 bool activate_on_finish_;
107
108+ guint hide_message_delay_id_;
109+
110 bool visible_;
111 };
112
113
114=== modified file 'plugins/unityshell/src/LensView.cpp'
115--- plugins/unityshell/src/LensView.cpp 2012-02-21 20:10:05 +0000
116+++ plugins/unityshell/src/LensView.cpp 2012-03-09 02:13:19 +0000
117@@ -30,6 +30,8 @@
118 #include "UBusWrapper.h"
119 #include "PlacesVScrollBar.h"
120
121+#include <glib/gi18n-lib.h>
122+
123 namespace unity
124 {
125 namespace dash
126@@ -120,6 +122,7 @@
127 , search_string("")
128 , filters_expanded(false)
129 , can_refine_search(false)
130+ , no_results_active_(false)
131 , fix_renderering_id_(0)
132 {}
133
134@@ -130,6 +133,7 @@
135 , can_refine_search(false)
136 , lens_(lens)
137 , initial_activation_(true)
138+ , no_results_active_(false)
139 , fix_renderering_id_(0)
140 {
141 SetupViews(show_filters);
142@@ -194,6 +198,10 @@
143 scroll_view_->SetLayout(scroll_layout_);
144 scroll_view_->SetRightArea(show_filters);
145
146+ no_results_ = new nux::StaticCairoText("", NUX_TRACKER_LOCATION);
147+ no_results_->SetTextColor(nux::color::White);
148+ scroll_layout_->AddView(no_results_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT);
149+
150 fscroll_view_ = new LensScrollView(new PlacesVScrollBar(NUX_TRACKER_LOCATION),
151 NUX_TRACKER_LOCATION);
152 fscroll_view_->EnableVerticalScrollBar(true);
153@@ -362,6 +370,54 @@
154 return FALSE;
155 }
156
157+void LensView::CheckNoResults(Lens::Hints const& hints)
158+{
159+ gint count = lens_->results()->count();
160+
161+ if (!count && !no_results_active_)
162+ {
163+ std::stringstream markup;
164+ Lens::Hints::const_iterator it;
165+
166+ it = hints.find("no-results-hint");
167+ markup << "<span size='larger' weight='bold'>";
168+
169+ if (it != hints.end())
170+ {
171+ markup << it->second.GetString();
172+ }
173+ else
174+ {
175+ markup << _("Sorry, there is nothing that matches your search.");
176+ }
177+ markup << "</span>";
178+
179+ LOG_DEBUG(logger) << "The no-result-hint is: " << markup.str();
180+
181+ scroll_layout_->SetContentDistribution(nux::MAJOR_POSITION_CENTER);
182+
183+ no_results_active_ = true;
184+ no_results_->SetText(markup.str());
185+ }
186+ else if (count && no_results_active_)
187+ {
188+ scroll_layout_->SetContentDistribution(nux::MAJOR_POSITION_START);
189+
190+ no_results_active_ = false;
191+ no_results_->SetText("");
192+ }
193+}
194+
195+void LensView::HideResultsMessage()
196+{
197+ if (no_results_active_)
198+ {
199+ scroll_layout_->SetContentDistribution(nux::MAJOR_POSITION_START);
200+ no_results_active_ = false;
201+ no_results_->SetText("");
202+ }
203+}
204+
205 void LensView::OnGroupExpanded(PlacesGroup* group)
206 {
207 ResultViewGrid* grid = static_cast<ResultViewGrid*>(group->GetChildView());
208@@ -503,7 +559,8 @@
209 {
210 unity::variant::BuilderWrapper(builder)
211 .add("name", lens_->id)
212- .add("lens-name", lens_->name);
213+ .add("lens-name", lens_->name)
214+ .add("no-results-active", no_results_active_);
215 }
216
217
218
219=== modified file 'plugins/unityshell/src/LensView.h'
220--- plugins/unityshell/src/LensView.h 2012-02-13 12:55:20 +0000
221+++ plugins/unityshell/src/LensView.h 2012-03-09 02:13:19 +0000
222@@ -69,6 +69,9 @@
223
224 sigc::signal<void, std::string const&> uri_activated;
225
226+ void CheckNoResults(Lens::Hints const& hints);
227+ void HideResultsMessage();
228+
229 private:
230 void SetupViews(nux::Area* show_filters);
231 void SetupCategories();
232@@ -101,6 +104,7 @@
233 CategoryGroups categories_;
234 ResultCounts counts_;
235 bool initial_activation_;
236+ bool no_results_active_;
237
238 nux::HLayout* layout_;
239 LensScrollView* scroll_view_;
240@@ -108,6 +112,7 @@
241 LensScrollView* fscroll_view_;
242 nux::VLayout* fscroll_layout_;
243 FilterBar* filter_bar_;
244+ nux::StaticCairoText* no_results_;
245
246 guint fix_renderering_id_;
247
248
249=== modified file 'tests/autopilot/autopilot/tests/test_dash.py'
250--- tests/autopilot/autopilot/tests/test_dash.py 2012-03-07 20:14:43 +0000
251+++ tests/autopilot/autopilot/tests/test_dash.py 2012-03-09 02:13:19 +0000
252@@ -389,3 +389,48 @@
253 searchbar = self.dash.get_searchbar()
254 self.assertEqual("hello world", searchbar.search_string)
255
256+class DashLensResultsTests(AutopilotTestCase):
257+ """ Tests results from the lens view """
258+
259+ def setUp(self):
260+ super(DashLensResultsTests, self).setUp()
261+ self.dash = Dash()
262+
263+ def tearDown(self):
264+ super(DashLensResultsTests, self).tearDown()
265+ self.dash.ensure_hidden()
266+
267+ def test_results_message_empty_search(self):
268+ """ This tests a message is not shown when there is no text"""
269+ self.dash.ensure_hidden()
270+ self.dash.reveal_application_lens()
271+ lens = self.dash.get_current_lens()
272+
273+ lens.refresh_state()
274+ self.assertFalse(lens.no_results_active)
275+
276+ def test_results_message(self):
277+ """ This test no mesage will be shown when results are there"""
278+ self.dash.ensure_hidden()
279+ self.dash.reveal_application_lens()
280+ lens = self.dash.get_current_lens()
281+
282+ kb = Keyboard();
283+ kb.type("Terminal")
284+ sleep(1)
285+
286+ lens.refresh_state()
287+ self.assertFalse(lens.no_results_active)
288+
289+ def test_no_results_message(self):
290+ """ This test shows a message will appear in the lens"""
291+ self.dash.ensure_hidden()
292+ self.dash.reveal_application_lens()
293+ lens = self.dash.get_current_lens()
294+
295+ kb = Keyboard();
296+ kb.type("qwerlkjzvxc")
297+ sleep(1)
298+
299+ lens.refresh_state()
300+ self.assertTrue(lens.no_results_active)