Merge lp:~nick-dedekind/unity/lp1062107.preview-pre-caching into lp:unity

Proposed by Nick Dedekind
Status: Work in progress
Proposed branch: lp:~nick-dedekind/unity/lp1062107.preview-pre-caching
Merge into: lp:unity
Diff against target: 1176 lines (+675/-75)
22 files modified
UnityCore/CMakeLists.txt (+2/-0)
UnityCore/HomeLens.cpp (+2/-2)
UnityCore/HomeLens.h (+1/-1)
UnityCore/Lens.cpp (+25/-25)
UnityCore/Lens.h (+3/-1)
UnityCore/PreviewPreCacher.cpp (+270/-0)
UnityCore/PreviewPreCacher.h (+94/-0)
dash/DashView.cpp (+8/-3)
dash/LensView.cpp (+15/-13)
dash/LensView.h (+7/-3)
dash/previews/ApplicationPreview.cpp (+3/-3)
dash/previews/GenericPreview.cpp (+2/-2)
dash/previews/MoviePreview.cpp (+2/-2)
dash/previews/MusicPreview.cpp (+2/-2)
dash/previews/PreviewContainer.cpp (+1/-1)
dash/previews/PreviewInfoHintWidget.cpp (+1/-1)
dash/previews/SocialPreview.cpp (+3/-3)
dash/previews/SocialPreviewComments.cpp (+1/-1)
dash/previews/SocialPreviewContent.cpp (+4/-4)
tests/CMakeLists.txt (+1/-0)
tests/test_lens.cpp (+4/-8)
tests/test_previews_precacher.cpp (+224/-0)
To merge this branch: bzr merge lp:~nick-dedekind/unity/lp1062107.preview-pre-caching
Reviewer Review Type Date Requested Status
Brandon Schaefer (community) Needs Fixing
Review via email: mp+133446@code.launchpad.net

Commit message

Added dash preview pre-caching. (LP: #1062107)

Description of the change

= Problem description =

https://bugs.launchpad.net/unity/+bug/1062107
Preview content should be speculatively cached

= The fix =

1. When the user opens a preview, results subsequent to the preview start pre-cacheing.

2. Once a user has previewed one content item underneath a category header, as long as the Dash remains open we continue to speculatively cache the preview content for the other items under the category header (even when the user returns to the results view). The pre-caching stops when a) the user closes the Dash b) the user previews the a result from underneath another category header. In this second case the Dash then starts speculatively pre-cacheing the content from underneath this new category header.

= Test coverage =

Unit tests for pre-caching queue execution.

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

530 + virtual ~PreviewPreCacher();
551 + virtual void OnPreCacheComplete();

Could we make those pure virtual fucntions?

Or if not could we just do:
530 + virtual ~PreviewPreCacher() {}
551 + virtual void OnPreCacheComplete() {}

347 + if (index < 0 || index >=(int)GetResultCount())

Does this need to be casted to an int?

758 + int top_social_info_max_width = MAX(details_width - style.GetAppIconAreaWidth() - style.GetSpaceBetweenIconAndDetails(), 0);
772 + int max_width = MAX(0, geo_cr.width - 2*(geo_cr.width*0.1));
773 + int max_height = MAX(0, (geo_cr.height - TAIL_HEIGHT) - 2*((geo_cr.height - TAIL_HEIGHT)*0.1));
786 + title_->SetMaximumWidth(MAX(0, GetGeometry().width - geo.height - style.GetMusicDurationWidth() - layout_spacing*2));

Lets use std::max() here.

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

bschaefer@bschaefer:unity$ bzr merge lp:~nick-dedekind/unity/lp1062107.preview-pre-caching
+N UnityCore/PreviewPreCacher.cpp
+N UnityCore/PreviewPreCacher.h
+N tests/test_previews_precacher.cpp
 M UnityCore/CMakeLists.txt
 M UnityCore/HomeLens.cpp
 M UnityCore/HomeLens.h
 M UnityCore/Lens.cpp
 M UnityCore/Lens.h
 M dash/DashView.cpp
 M dash/LensView.cpp
 M dash/LensView.h
 M dash/previews/PreviewContainer.cpp
 M dash/previews/SocialPreview.cpp
 M dash/previews/SocialPreviewContent.cpp
 M dash/previews/Track.cpp
 M tests/CMakeLists.txt
 M tests/test_lens.cpp
Text conflict in dash/LensView.cpp
Text conflict in dash/previews/Track.cpp
Text conflict in tests/CMakeLists.txt
3 conflicts encountered.

review: Needs Fixing
Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> 530 + virtual ~PreviewPreCacher();
> 551 + virtual void OnPreCacheComplete();
>
> Could we make those pure virtual fucntions?
>
> Or if not could we just do:
> 530 + virtual ~PreviewPreCacher() {}
> 551 + virtual void OnPreCacheComplete() {}
>

Can't be pure virtual because we need to instantiate a PreviewPreCacher.
Don't see any benefit in making them inline.

>
> 347 + if (index < 0 || index >=(int)GetResultCount())
>
> Does this need to be casted to an int?
>

Yes. GetResultCount returns an unsigned int. Comes from the dee model.

>
> 758 + int top_social_info_max_width = MAX(details_width -
> style.GetAppIconAreaWidth() - style.GetSpaceBetweenIconAndDetails(), 0);
> 772 + int max_width = MAX(0, geo_cr.width - 2*(geo_cr.width*0.1));
> 773 + int max_height = MAX(0, (geo_cr.height - TAIL_HEIGHT) -
> 2*((geo_cr.height - TAIL_HEIGHT)*0.1));
> 786 + title_->SetMaximumWidth(MAX(0, GetGeometry().width - geo.height -
> style.GetMusicDurationWidth() - layout_spacing*2));
>
> Lets use std::max() here.

Will do.

2880. By Nick Dedekind

switched preview code to use std::max

2881. By Nick Dedekind

Merged with trunk

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

Use std::max for preview code.
Merged with trunk.

Revision history for this message
Andrea Azzarone (azzar1) wrote :

tests/test_previews_precacher.cpp

I don't like the way you're testing PreviewPreCacher because you're testing a mock of it (MockPreviewPreCacher).

Also PreviewPreCacher should inherit from sigc::trackable.

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

@andyrock: As stated in the description, the supplied test is only meant to check the preview pre-caching sequence (pretty much only the PreviewPreCacher::ContinuePreCaching function).

Getting a lens view into the test harness to test the pre-cacher interaction is somewhat controversial and not suited to unit testing at the moment (Lens Dee related code is "too tight" for testability).
I am hoping to get some refactoring into the lenses soon so they can be properly tested. Once this is done, we can revisit this.

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

Some previews (eg MusicPreview) are stateful inside libunity, therefore asking for subsiquent previews while viewing another will hose the state.
Until this is recitfied, this cannot be merged.

Unmerged revisions

2881. By Nick Dedekind

Merged with trunk

2880. By Nick Dedekind

switched preview code to use std::max

2879. By Nick Dedekind

Preview pre-caching tweaks.

2878. By Nick Dedekind

Removed debuggin code.

2877. By Nick Dedekind

Added precache files.

2876. By Nick Dedekind

Added speculative caching to previews.

2875. By Nick Dedekind

Check for width > 0 in preview layout management.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'UnityCore/CMakeLists.txt'
2--- UnityCore/CMakeLists.txt 2012-11-26 16:09:53 +0000
3+++ UnityCore/CMakeLists.txt 2012-12-10 10:03:24 +0000
4@@ -49,6 +49,7 @@
5 ModelRowAdaptor.h
6 ModelRowAdaptor-inl.h
7 Preview.h
8+ PreviewPreCacher.h
9 RadioOptionFilter.h
10 RatingsFilter.h
11 Result.h
12@@ -88,6 +89,7 @@
13 MusicPreview.cpp
14 ModelRowAdaptor.cpp
15 Preview.cpp
16+ PreviewPreCacher.cpp
17 RatingsFilter.cpp
18 RadioOptionFilter.cpp
19 Result.cpp
20
21=== modified file 'UnityCore/HomeLens.cpp'
22--- UnityCore/HomeLens.cpp 2012-11-14 08:57:56 +0000
23+++ UnityCore/HomeLens.cpp 2012-12-10 10:03:24 +0000
24@@ -1218,14 +1218,14 @@
25 }
26 }
27
28-void HomeLens::Preview(std::string const& uri)
29+void HomeLens::Preview(std::string const& uri, GCancellable* cancellable, PreviewCallback const& slot)
30 {
31 LOG_DEBUG(logger) << "Preview '" << uri << "'";
32
33 Lens::Ptr lens = pimpl->FindLensForUri(uri);
34
35 if (lens)
36- lens->Preview(uri);
37+ lens->Preview(uri, cancellable, slot);
38 else
39 LOG_WARN(logger) << "Unable to find a lens for previewing '" << uri << "'";
40 }
41
42=== modified file 'UnityCore/HomeLens.h'
43--- UnityCore/HomeLens.h 2012-11-12 11:07:23 +0000
44+++ UnityCore/HomeLens.h 2012-12-10 10:03:24 +0000
45@@ -72,7 +72,7 @@
46 void GlobalSearch(std::string const& search_string, SearchFinishedCallback const& cb);
47 void Search(std::string const& search_string, SearchFinishedCallback const& cb);
48 void Activate(std::string const& uri);
49- void Preview(std::string const& uri);
50+ void Preview(std::string const& uri, GCancellable* cancellable, PreviewCallback const& slot);
51
52 std::vector<unsigned> GetCategoriesOrder();
53 glib::Object<DeeModel> GetFilterModelForCategory(unsigned category);
54
55=== modified file 'UnityCore/Lens.cpp'
56--- UnityCore/Lens.cpp 2012-11-14 08:57:56 +0000
57+++ UnityCore/Lens.cpp 2012-12-10 10:03:24 +0000
58@@ -84,8 +84,8 @@
59 void GlobalSearch(std::string const& search_string, SearchFinishedCallback const& cb);
60 void Search(std::string const& search_string, SearchFinishedCallback const& cb);
61 void Activate(std::string const& uri);
62- void ActivationReply(GVariant* parameters);
63- void Preview(std::string const& uri);
64+ void ActivationReply(GVariant* parameters, PreviewCallback const& slot);
65+ void Preview(std::string const& uri, GCancellable* cancellable, PreviewCallback const& slot);
66 void ActivatePreviewAction(std::string const& action_id,
67 std::string const& uri,
68 Hints const& hints);
69@@ -143,7 +143,6 @@
70 glib::DBusProxy* proxy_;
71 glib::Object<GCancellable> search_cancellable_;
72 glib::Object<GCancellable> global_search_cancellable_;
73- glib::Object<GCancellable> preview_cancellable_;
74
75 glib::Variant results_variant_;
76 glib::Variant global_results_variant_;
77@@ -513,18 +512,18 @@
78 LOG_DEBUG(logger) << "Activating '" << uri << "' on '" << id_ << "'";
79
80 if (!proxy_->IsConnected())
81- {
82- LOG_DEBUG(logger) << "Skipping activation. Proxy not connected. ('" << id_ << "')";
83- return;
84- }
85+ {
86+ LOG_DEBUG(logger) << "Skipping activation. Proxy not connected. ('" << id_ << "')";
87+ return;
88+ }
89
90 proxy_->Call("Activate",
91 g_variant_new("(su)", uri.c_str(),
92 UNITY_PROTOCOL_ACTION_TYPE_ACTIVATE_RESULT),
93- sigc::mem_fun(this, &Lens::Impl::ActivationReply));
94+ sigc::bind(sigc::mem_fun(this, &Lens::Impl::ActivationReply), std::nullptr_t()));
95 }
96
97-void Lens::Impl::ActivationReply(GVariant* parameters)
98+void Lens::Impl::ActivationReply(GVariant* parameters, PreviewCallback const& slot)
99 {
100 glib::String uri;
101 guint32 handled;
102@@ -548,7 +547,14 @@
103 // but that's not really doable from here
104 preview->parent_lens = owner_;
105 preview->preview_uri = uri.Str();
106- owner_->preview_ready.emit(uri.Str(), preview);
107+ if (slot)
108+ {
109+ slot(uri.Str(), preview);
110+ }
111+ else
112+ {
113+ owner_->preview_ready.emit(uri.Str(), preview);
114+ }
115 return;
116 }
117 }
118@@ -561,27 +567,21 @@
119 }
120 }
121
122-void Lens::Impl::Preview(std::string const& uri)
123+void Lens::Impl::Preview(std::string const& uri, GCancellable* cancellable, PreviewCallback const& slot)
124 {
125 LOG_DEBUG(logger) << "Previewing '" << uri << "' on '" << id_ << "'";
126
127 if (!proxy_->IsConnected())
128- {
129- LOG_DEBUG(logger) << "Skipping preview. Proxy not connected. ('" << id_ << "')";
130- return;
131- }
132-
133- if (preview_cancellable_)
134 {
135- g_cancellable_cancel(preview_cancellable_);
136+ LOG_DEBUG(logger) << "Skipping preview. Proxy not connected. ('" << id_ << "')";
137+ return;
138 }
139- preview_cancellable_ = g_cancellable_new ();
140
141 proxy_->Call("Activate",
142 g_variant_new("(su)", uri.c_str(),
143 UNITY_PROTOCOL_ACTION_TYPE_PREVIEW_RESULT),
144- sigc::mem_fun(this, &Lens::Impl::ActivationReply),
145- preview_cancellable_);
146+ sigc::bind(sigc::mem_fun(this, &Lens::Impl::ActivationReply), slot),
147+ cancellable);
148 }
149
150 void Lens::Impl::ActivatePreviewAction(std::string const& action_id,
151@@ -608,7 +608,7 @@
152 proxy_->Call("Activate",
153 g_variant_new("(su)", activation_uri.c_str(),
154 UNITY_PROTOCOL_ACTION_TYPE_PREVIEW_ACTION),
155- sigc::mem_fun(this, &Lens::Impl::ActivationReply));
156+ sigc::bind(sigc::mem_fun(this, &Lens::Impl::ActivationReply), std::nullptr_t()));
157 }
158 else
159 {
160@@ -625,7 +625,7 @@
161 g_variant_new("(sua{sv})", activation_uri.c_str(),
162 UNITY_PROTOCOL_ACTION_TYPE_PREVIEW_ACTION,
163 &b),
164- sigc::mem_fun(this, &Lens::Impl::ActivationReply));
165+ sigc::bind(sigc::mem_fun(this, &Lens::Impl::ActivationReply), std::nullptr_t()));
166
167 g_variant_builder_clear(&b);
168 }
169@@ -876,9 +876,9 @@
170 pimpl->Activate(uri);
171 }
172
173-void Lens::Preview(std::string const& uri)
174+void Lens::Preview(std::string const& uri, GCancellable* cancellable, PreviewCallback const& slot)
175 {
176- pimpl->Preview(uri);
177+ pimpl->Preview(uri, cancellable, slot);
178 }
179
180 void Lens::ActivatePreviewAction(std::string const& action_id,
181
182=== modified file 'UnityCore/Lens.h'
183--- UnityCore/Lens.h 2012-11-14 08:57:56 +0000
184+++ UnityCore/Lens.h 2012-12-10 10:03:24 +0000
185@@ -52,6 +52,8 @@
186 LENS_VIEW
187 };
188
189+typedef std::function<void(std::string const&, Preview::Ptr const&)> PreviewCallback;
190+
191 class Lens : public sigc::trackable, boost::noncopyable
192 {
193 public:
194@@ -85,7 +87,7 @@
195 virtual void GlobalSearch(std::string const& search_string, SearchFinishedCallback const& cb = nullptr);
196 virtual void Search(std::string const& search_string, SearchFinishedCallback const& cb = nullptr);
197 virtual void Activate(std::string const& uri);
198- virtual void Preview(std::string const& uri);
199+ virtual void Preview(std::string const& uri, GCancellable* cancellable, PreviewCallback const& slot);
200 virtual void ActivatePreviewAction(std::string const& action_id,
201 std::string const& uri,
202 Hints const& hints);
203
204=== added file 'UnityCore/PreviewPreCacher.cpp'
205--- UnityCore/PreviewPreCacher.cpp 1970-01-01 00:00:00 +0000
206+++ UnityCore/PreviewPreCacher.cpp 2012-12-10 10:03:24 +0000
207@@ -0,0 +1,270 @@
208+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
209+/*
210+ * Copyright (C) 2012 Canonical Ltd
211+ *
212+ * This program is free software: you can redistribute it and/or modify
213+ * it under the terms of the GNU General Public License version 3 as
214+ * published by the Free Software Foundation.
215+ *
216+ * This program is distributed in the hope that it will be useful,
217+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
218+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
219+ * GNU General Public License for more details.
220+ *
221+ * You should have received a copy of the GNU General Public License
222+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
223+ *
224+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
225+ */
226+
227+#include "PreviewPreCacher.h"
228+#include "Category.h"
229+
230+namespace unity
231+{
232+namespace dash
233+{
234+namespace previews
235+{
236+DECLARE_LOGGER(logger, "unity.dash.preview.precacher");
237+
238+const std::string PREVIEW_IDLE = "preview-idle";
239+const std::string CACHE_IDLE = "cache-idle";
240+
241+const unsigned int CACHE_TIMEOUT = 100;
242+
243+PreviewPreCacher::PreviewPreCacher(Lens::Ptr const& lens, int cache_range)
244+: lens_(lens)
245+, cache_center_(0)
246+, cache_delta_(0)
247+, precaching_completeness(0)
248+, cache_range_(cache_range)
249+, category_index_(-1)
250+, cache_cancel_(g_cancellable_new())
251+{
252+ if (lens_)
253+ {
254+ lens_->preview_ready.connect(sigc::mem_fun(this, &PreviewPreCacher::CenterPreview));
255+
256+ Categories::Ptr categories = lens_->categories;
257+ categories->category_added.connect([&](Category const& category) {OnLensCategoryUpdated();});
258+ categories->category_removed.connect([&](Category const& category) {OnLensCategoryUpdated();});
259+ }
260+}
261+
262+PreviewPreCacher::~PreviewPreCacher()
263+{
264+}
265+
266+void PreviewPreCacher::OnLensCategoryUpdated()
267+{
268+ if (category_index_ == -1)
269+ return;
270+ if (lens_)
271+ result_model_ = lens_->GetFilterModelForCategory(category_index_);
272+}
273+
274+void PreviewPreCacher::UpdateCategory(int category_index)
275+{
276+ if (category_index_ != category_index)
277+ {
278+ category_index_ = category_index;
279+ ClearCache();
280+ OnLensCategoryUpdated();
281+ }
282+}
283+
284+void PreviewPreCacher::Preview(std::string const& uri, int category_index)
285+{
286+ UpdateCategory(category_index);
287+
288+ if (preview_cancel_)
289+ g_cancellable_cancel (preview_cancel_);
290+ preview_cancel_ = g_cancellable_new ();
291+
292+ auto iter = preview_uri_cache_.find(uri);
293+ if (iter != preview_uri_cache_.end())
294+ {
295+ Preview::Ptr preview(iter->second);
296+ sources_.Remove(PREVIEW_IDLE);
297+ sources_.AddIdle([&, uri, preview]()
298+ {
299+ preview_ready.emit(uri, preview);
300+
301+ // set the current center point.
302+ ResetPreCachePosition(GetResultIndexForUri(uri));
303+ return FALSE;
304+ }, PREVIEW_IDLE);
305+ }
306+ else if (lens_)
307+ {
308+ lens_->Preview(uri, preview_cancel_, sigc::mem_fun(this, &PreviewPreCacher::CenterPreview));
309+ }
310+}
311+
312+void PreviewPreCacher::ClearCache()
313+{
314+ if (cache_cancel_)
315+ g_cancellable_cancel (cache_cancel_);
316+ cache_cancel_ = g_cancellable_new ();
317+
318+ preview_index_cache_.clear();
319+ preview_uri_cache_.clear();
320+}
321+
322+void PreviewPreCacher::CenterPreview(std::string const& uri, Preview::Ptr const& preview)
323+{
324+ // forward the signal.
325+ preview_ready.emit(uri, preview);
326+
327+ if (category_index_ == -1)
328+ return;
329+
330+ int index = GetResultIndexForUri(uri);
331+ preview_index_cache_[index] = preview;
332+ preview_uri_cache_[uri] = preview;
333+ ResetPreCachePosition(index);
334+}
335+
336+void PreviewPreCacher::RecvPreviewPreCache(std::string const& uri, Preview::Ptr const& preview)
337+{
338+ int index = GetResultIndexForUri(uri);
339+
340+ preview_index_cache_[index] = preview;
341+ preview_uri_cache_[uri] = preview;
342+ QueuePreCache();
343+}
344+
345+void PreviewPreCacher::ResetPreCachePosition(int index)
346+{
347+ if (index < 0 || index >=(int)GetResultCount())
348+ return;
349+
350+ cache_center_ = index;
351+ cache_delta_ = 0;
352+ precaching_completeness = 0;
353+ QueuePreCache();
354+}
355+
356+void PreviewPreCacher::QueuePreCache()
357+{
358+ sources_.AddTimeout(CACHE_TIMEOUT, [&]()
359+ {
360+ ContinuePreCaching();
361+ return FALSE;
362+ }, CACHE_IDLE);
363+}
364+
365+void PreviewPreCacher::ContinuePreCaching()
366+{
367+ if (precaching_completeness > 1)
368+ {
369+ OnPreCacheComplete();
370+ return;
371+ }
372+
373+ if (cache_delta_ > 0)
374+ cache_delta_ = -cache_delta_;
375+ else
376+ cache_delta_ = (-cache_delta_) +1;
377+
378+ int next_position = cache_center_ + cache_delta_;
379+
380+ // get min and max positions away from cache center position.
381+ int min_range = cache_range_ < 0 ? 0 : std::max<int>(0, cache_center_ - cache_range_);
382+ int max_range = cache_range_ < 0 ? GetResultCount() : std::min<int>(GetResultCount(), cache_center_ + cache_range_ + 1);
383+
384+ if (next_position < min_range || next_position >= max_range)
385+ {
386+ precaching_completeness++;
387+ ContinuePreCaching();
388+ return;
389+ }
390+ precaching_completeness=0;
391+
392+ auto iter = preview_index_cache_.find(next_position);
393+ if (iter != preview_index_cache_.end())
394+ {
395+ // position in result may have changed.
396+ std::string uri_at_next_position_current = GetUriForResultIndex(next_position);
397+
398+ auto iter_preview_from_uri = preview_uri_cache_.find(uri_at_next_position_current);
399+ if (iter_preview_from_uri != preview_uri_cache_.end())
400+ {
401+ preview_index_cache_[next_position] = iter_preview_from_uri->second;
402+ }
403+ QueuePreCache();
404+ }
405+ else if (!ExecutePreCache(next_position, GetUriForResultIndex(next_position)))
406+ {
407+ QueuePreCache();
408+ }
409+}
410+
411+void PreviewPreCacher::OnPreCacheComplete()
412+{
413+}
414+
415+bool PreviewPreCacher::ExecutePreCache(int index, std::string const& uri)
416+{
417+ auto iter = preview_uri_cache_.find(uri);
418+ if (iter != preview_uri_cache_.end())
419+ {
420+ preview_index_cache_[index] = iter->second;
421+ return false;
422+ }
423+
424+ LOG_DEBUG(logger) << "Preview pre-cache for '" << uri << "'";
425+ lens_->Preview(uri, cache_cancel_, sigc::mem_fun(this, &PreviewPreCacher::RecvPreviewPreCache));
426+ return true;
427+}
428+
429+unsigned int PreviewPreCacher::GetResultIndexForUri(std::string const& uri)
430+{
431+ unsigned int index = 0;
432+ for (ResultIterator it(GetResultIteratorAtIndex(0)); !it.IsLast(); ++it)
433+ {
434+ if ((*it).uri == uri)
435+ break;
436+
437+ index++;
438+ }
439+
440+ return index;
441+}
442+
443+std::string PreviewPreCacher::GetUriForResultIndex(unsigned int index)
444+{
445+ if (index >= GetResultCount())
446+ return "";
447+
448+ return (*GetResultIteratorAtIndex(index)).uri();
449+}
450+
451+unsigned int PreviewPreCacher::GetResultCount() const
452+{
453+ if (result_model_)
454+ {
455+ return dee_model_get_n_rows(result_model_);
456+ }
457+
458+ return 0;
459+}
460+
461+ResultIterator PreviewPreCacher::GetResultIteratorAtIndex(unsigned index)
462+{
463+ if (!lens_)
464+ return ResultIterator(result_model_);
465+
466+ DeeModelIter* iter = NULL;
467+ if (result_model_)
468+ {
469+ iter = index > 0 ? dee_model_get_iter_at_row(result_model_, index) :
470+ dee_model_get_first_iter(result_model_);
471+ }
472+ return ResultIterator(result_model_, iter, lens_->results()->GetTag());
473+}
474+
475+} // namespace previews
476+} // namespace dash
477+} // namespace unity
478\ No newline at end of file
479
480=== added file 'UnityCore/PreviewPreCacher.h'
481--- UnityCore/PreviewPreCacher.h 1970-01-01 00:00:00 +0000
482+++ UnityCore/PreviewPreCacher.h 2012-12-10 10:03:24 +0000
483@@ -0,0 +1,94 @@
484+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
485+/*
486+ * Copyright 2012 Canonical Ltd.
487+ *
488+ * This program is free software: you can redistribute it and/or modify it
489+ * under the terms of the GNU Lesser General Public License version 3, as
490+ * published by the Free Software Foundation.
491+ *
492+ * This program is distributed in the hope that it will be useful, but
493+ * WITHOUT ANY WARRANTY; without even the implied warranties of
494+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
495+ * PURPOSE. See the applicable version of the GNU Lesser General Public
496+ * License for more details.
497+ *
498+ * You should have received a copy of both the GNU Lesser General Public
499+ * License version 3 along with this program. If not, see
500+ * <http://www.gnu.org/licenses/>
501+ *
502+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
503+ *
504+ */
505+
506+#ifndef PREVIEW_PRECACHER_H
507+#define PREVIEW_PRECACHER_H
508+
509+#include <functional>
510+#include <memory>
511+#include "Preview.h"
512+#include "ResultIterator.h"
513+#include "GLibSource.h"
514+#include "Lens.h"
515+
516+namespace unity
517+{
518+namespace dash
519+{
520+
521+namespace previews
522+{
523+
524+class PreviewPreCacher
525+{
526+public:
527+ typedef std::shared_ptr<PreviewPreCacher> Ptr;
528+
529+ PreviewPreCacher(Lens::Ptr const& lens, int cache_range);
530+ virtual ~PreviewPreCacher();
531+
532+ void Preview(std::string const& uri, int category_index);
533+ void ClearCache();
534+
535+ sigc::signal<void, std::string const&, Preview::Ptr const&> preview_ready;
536+
537+protected:
538+ void CenterPreview(std::string const& uri, Preview::Ptr const& preview);
539+ void RecvPreviewPreCache(std::string const& uri, Preview::Ptr const& preview);
540+
541+protected:
542+ void ResetPreCachePosition(int index);
543+ void ContinuePreCaching();
544+
545+ void UpdateCategory(int category_index);
546+ void OnLensCategoryUpdated();
547+ ResultIterator GetResultIteratorAtIndex(unsigned index);
548+
549+ virtual void QueuePreCache();
550+ virtual bool ExecutePreCache(int index, std::string const& uri);
551+ virtual void OnPreCacheComplete();
552+
553+ // result accessors
554+ virtual unsigned int GetResultCount() const;
555+ virtual unsigned int GetResultIndexForUri(std::string const& uri);
556+ virtual std::string GetUriForResultIndex(unsigned int index);
557+
558+ Lens::Ptr lens_;
559+ std::map<int, Preview::Ptr> preview_index_cache_;
560+ std::map<std::string, Preview::Ptr> preview_uri_cache_;
561+ int cache_center_;
562+ int cache_delta_;
563+ int precaching_completeness;
564+ int cache_range_;
565+
566+ int category_index_;
567+ glib::Object<DeeModel> result_model_;
568+ glib::Object<GCancellable> preview_cancel_;
569+ glib::Object<GCancellable> cache_cancel_;
570+ glib::SourceManager sources_;
571+};
572+
573+} // namespace previews
574+} // namespace dash
575+} // namespace unity
576+
577+#endif // PREVIEW_PRECACHER_H
578
579=== modified file 'dash/DashView.cpp'
580--- dash/DashView.cpp 2012-11-23 23:49:46 +0000
581+++ dash/DashView.cpp 2012-12-10 10:03:24 +0000
582@@ -407,8 +407,13 @@
583 lenses_layout_ = new nux::VLayout();
584 content_layout_->AddView(lenses_layout_, 1, nux::MINOR_POSITION_START);
585
586- home_view_ = new LensView(home_lens_, nullptr);
587+ home_view_ = new LensView(home_lens_, nullptr, NUX_TRACKER_LOCATION);
588 home_view_->uri_activated.connect(sigc::mem_fun(this, &DashView::OnUriActivated));
589+ home_view_->RegisterForPreviews([&] (std::string const& uri, Preview::Ptr const& model)
590+ {
591+ LOG_DEBUG(logger) << "Got home preview for: " << uri;
592+ preview_state_machine_.ActivatePreview(model); // this does not immediately display a preview - we now wait.
593+ });
594
595 AddChild(home_view_);
596 active_lens_view_ = home_view_;
597@@ -935,7 +940,7 @@
598 std::string id = lens->id;
599 lens_bar_->AddLens(lens);
600
601- LensView* view = new LensView(lens, search_bar_->show_filters());
602+ LensView* view = new LensView(lens, search_bar_->show_filters(), NUX_TRACKER_LOCATION);
603 AddChild(view);
604 view->SetVisible(false);
605 view->uri_activated.connect(sigc::mem_fun(this, &DashView::OnUriActivated));
606@@ -957,7 +962,7 @@
607 });
608
609 // Hook up to the new preview infrastructure
610- lens->preview_ready.connect([&] (std::string const& uri, Preview::Ptr model)
611+ view->RegisterForPreviews([&] (std::string const& uri, Preview::Ptr const& model)
612 {
613 LOG_DEBUG(logger) << "Got preview for: " << uri;
614 preview_state_machine_.ActivatePreview(model); // this does not immediately display a preview - we now wait.
615
616=== modified file 'dash/LensView.cpp'
617--- dash/LensView.cpp 2012-11-26 16:09:53 +0000
618+++ dash/LensView.cpp 2012-12-10 10:03:24 +0000
619@@ -137,15 +137,8 @@
620
621 NUX_IMPLEMENT_OBJECT_TYPE(LensView);
622
623-LensView::LensView()
624- : nux::View(NUX_TRACKER_LOCATION)
625- , filters_expanded(false)
626- , can_refine_search(false)
627- , no_results_active_(false)
628-{}
629-
630-LensView::LensView(Lens::Ptr lens, nux::Area* show_filters)
631- : nux::View(NUX_TRACKER_LOCATION)
632+LensView::LensView(Lens::Ptr const& lens, nux::Area* show_filters, NUX_FILE_LINE_DECL)
633+ : nux::View(NUX_FILE_LINE_PARAM)
634 , filters_expanded(false)
635 , can_refine_search(false)
636 , lens_(lens)
637@@ -153,6 +146,7 @@
638 , no_results_active_(false)
639 , last_expanded_group_(nullptr)
640 , last_good_filter_model_(-1)
641+ , preview_precacher_(new previews::PreviewPreCacher(lens, -1))
642 {
643 SetupViews(show_filters);
644 SetupCategories();
645@@ -207,6 +201,10 @@
646
647 }
648
649+LensView::~LensView()
650+{
651+}
652+
653 void LensView::SetupViews(nux::Area* show_filters)
654 {
655 dash::Style& style = dash::Style::Instance();
656@@ -366,7 +364,7 @@
657 grid->expanded = false;
658
659 group->SetRendererName(renderer_name.c_str());
660- grid->UriActivated.connect(sigc::bind([&] (std::string const& uri, ResultView::ActivateType type, GVariant* data, std::string const& view_id)
661+ grid->UriActivated.connect(sigc::bind([&] (std::string const& uri, ResultView::ActivateType type, GVariant* data, std::string const& view_id, int catgory_index)
662 {
663 uri_activated.emit(type, uri, data, view_id);
664 switch (type)
665@@ -377,13 +375,12 @@
666 } break;
667 case ResultView::ActivateType::PREVIEW:
668 {
669- lens_->Preview(uri);
670+ preview_precacher_->Preview(uri, catgory_index);
671 } break;
672 default: break;
673 };
674
675- }, unique_id));
676-
677+ }, unique_id, category.index.Get()));
678
679 /* Set up filter model for this category */
680 Results::Ptr results_model = lens_->results;
681@@ -793,6 +790,11 @@
682 }
683 }
684
685+sigc::connection LensView::RegisterForPreviews(PreviewCallback const& callback)
686+{
687+ return preview_precacher_->preview_ready.connect(callback);
688+}
689+
690 // Keyboard navigation
691 bool LensView::AcceptKeyNavFocus()
692 {
693
694=== modified file 'dash/LensView.h'
695--- dash/LensView.h 2012-11-14 08:57:56 +0000
696+++ dash/LensView.h 2012-12-10 10:03:24 +0000
697@@ -29,6 +29,7 @@
698 #include <Nux/VLayout.h>
699 #include <UnityCore/Lens.h>
700 #include <UnityCore/GLibSource.h>
701+#include "UnityCore/PreviewPreCacher.h"
702
703 #include "FilterBar.h"
704 #include "unity-shared/Introspectable.h"
705@@ -50,8 +51,8 @@
706 typedef std::map<PlacesGroup*, unsigned int> ResultCounts;
707
708 public:
709- LensView();
710- LensView(Lens::Ptr lens, nux::Area* show_filters);
711+ LensView(Lens::Ptr const& lens, nux::Area* show_filters, NUX_FILE_LINE_DECL);
712+ ~LensView();
713
714 CategoryGroups& categories() { return categories_; }
715 FilterBar* filter_bar() const { return filter_bar_; }
716@@ -75,6 +76,8 @@
717 void CheckCategoryExpansion();
718 void HideResultsMessage();
719
720+ sigc::connection RegisterForPreviews(PreviewCallback const& callback);
721+
722 private:
723 void SetupViews(nux::Area* show_filters);
724 void SetupCategories();
725@@ -124,9 +127,10 @@
726 nux::StaticCairoText* no_results_;
727
728 UBusManager ubus_manager_;
729- glib::Source::UniquePtr model_updated_timeout_;
730+ glib::Source::UniquePtr model_updated_timeout_;
731 int last_good_filter_model_;
732 glib::Source::UniquePtr fix_filter_models_idle_;
733+ previews::PreviewPreCacher::Ptr preview_precacher_;
734 };
735
736
737
738=== modified file 'dash/previews/ApplicationPreview.cpp'
739--- dash/previews/ApplicationPreview.cpp 2012-11-26 16:09:53 +0000
740+++ dash/previews/ApplicationPreview.cpp 2012-12-10 10:03:24 +0000
741@@ -305,11 +305,11 @@
742 nux::Geometry geo_art(geo.x, geo.y, style.GetAppImageAspectRatio() * geo.height, geo.height);
743
744 if (geo.width - geo_art.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin() < style.GetDetailsPanelMinimumWidth())
745- geo_art.width = MAX(0, geo.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin() - style.GetDetailsPanelMinimumWidth());
746+ geo_art.width = std::max(0, geo.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin() - style.GetDetailsPanelMinimumWidth());
747 image_->SetMinMaxSize(geo_art.width, geo_art.height);
748
749- int details_width = MAX(0, geo.width - geo_art.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin());
750- int top_app_info_max_width = MAX(0, details_width - style.GetAppIconAreaWidth() - style.GetSpaceBetweenIconAndDetails());
751+ int details_width = std::max(0, geo.width - geo_art.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin());
752+ int top_app_info_max_width = std::max(0, details_width - style.GetAppIconAreaWidth() - style.GetSpaceBetweenIconAndDetails());
753
754 if (title_) { title_->SetMaximumWidth(top_app_info_max_width); }
755 if (subtitle_) { subtitle_->SetMaximumWidth(top_app_info_max_width); }
756
757=== modified file 'dash/previews/GenericPreview.cpp'
758--- dash/previews/GenericPreview.cpp 2012-11-13 21:42:58 +0000
759+++ dash/previews/GenericPreview.cpp 2012-12-10 10:03:24 +0000
760@@ -232,10 +232,10 @@
761 nux::Geometry geo_art(geo.x, geo.y, style.GetAppImageAspectRatio() * geo.height, geo.height);
762
763 if (geo.width - geo_art.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin() < style.GetDetailsPanelMinimumWidth())
764- geo_art.width = MAX(0, geo.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin() - style.GetDetailsPanelMinimumWidth());
765+ geo_art.width = std::max(0, geo.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin() - style.GetDetailsPanelMinimumWidth());
766 image_->SetMinMaxSize(geo_art.width, geo_art.height);
767
768- int details_width = MAX(0, geo.width - geo_art.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin());
769+ int details_width = std::max(0, geo.width - geo_art.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin());
770
771 if (title_) { title_->SetMaximumWidth(details_width); }
772 if (subtitle_) { subtitle_->SetMaximumWidth(details_width); }
773
774=== modified file 'dash/previews/MoviePreview.cpp'
775--- dash/previews/MoviePreview.cpp 2012-11-13 21:42:58 +0000
776+++ dash/previews/MoviePreview.cpp 2012-12-10 10:03:24 +0000
777@@ -250,10 +250,10 @@
778 nux::Geometry geo_art(geo.x, geo.y, style.GetVideoImageAspectRatio() * geo.height, geo.height);
779
780 if (geo.width - geo_art.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin() < style.GetDetailsPanelMinimumWidth())
781- geo_art.width = MAX(0, geo.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin() - style.GetDetailsPanelMinimumWidth());
782+ geo_art.width = std::max(0, geo.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin() - style.GetDetailsPanelMinimumWidth());
783 image_->SetMinMaxSize(geo_art.width, geo_art.height);
784
785- int details_width = MAX(0, geo.width - geo_art.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin());
786+ int details_width = std::max(0, geo.width - geo_art.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin());
787
788 if (title_) { title_->SetMaximumWidth(details_width); }
789 if (subtitle_) { subtitle_->SetMaximumWidth(details_width); }
790
791=== modified file 'dash/previews/MusicPreview.cpp'
792--- dash/previews/MusicPreview.cpp 2012-11-06 18:19:09 +0000
793+++ dash/previews/MusicPreview.cpp 2012-12-10 10:03:24 +0000
794@@ -264,10 +264,10 @@
795 nux::Geometry geo_art(geo.x, geo.y, style.GetAppImageAspectRatio() * geo.height, geo.height);
796
797 if (geo.width - geo_art.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin() < style.GetDetailsPanelMinimumWidth())
798- geo_art.width = MAX(0, geo.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin() - style.GetDetailsPanelMinimumWidth());
799+ geo_art.width = std::max(0, geo.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin() - style.GetDetailsPanelMinimumWidth());
800 image_->SetMinMaxSize(geo_art.width, geo_art.height);
801
802- int details_width = MAX(0, geo.width - geo_art.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin());
803+ int details_width = std::max(0, geo.width - geo_art.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin());
804
805 if (title_) { title_->SetMaximumWidth(details_width); }
806 if (subtitle_) { subtitle_->SetMaximumWidth(details_width); }
807
808=== modified file 'dash/previews/PreviewContainer.cpp'
809--- dash/previews/PreviewContainer.cpp 2012-11-30 20:22:13 +0000
810+++ dash/previews/PreviewContainer.cpp 2012-12-10 10:03:24 +0000
811@@ -412,7 +412,7 @@
812
813 void PreviewContainer::Preview(dash::Preview::Ptr preview_model, Navigation direction)
814 {
815- previews::Preview::Ptr preview_view = previews::Preview::PreviewForModel(preview_model);
816+ previews::Preview::Ptr preview_view = preview_model ? previews::Preview::PreviewForModel(preview_model) : previews::Preview::Ptr();
817
818 if (preview_view)
819 {
820
821=== modified file 'dash/previews/PreviewInfoHintWidget.cpp'
822--- dash/previews/PreviewInfoHintWidget.cpp 2012-11-06 18:19:09 +0000
823+++ dash/previews/PreviewInfoHintWidget.cpp 2012-12-10 10:03:24 +0000
824@@ -209,7 +209,7 @@
825 int info_value_width = geo.width;
826 info_value_width -= layout_spacing;
827 info_value_width -= info_hint_width;
828- info_value_width = MAX(0, info_value_width);
829+ info_value_width = std::max(0, info_value_width);
830
831 for (InfoHint const& info_hint : info_hints_)
832 {
833
834=== modified file 'dash/previews/SocialPreview.cpp'
835--- dash/previews/SocialPreview.cpp 2012-11-26 16:09:53 +0000
836+++ dash/previews/SocialPreview.cpp 2012-12-10 10:03:24 +0000
837@@ -281,12 +281,12 @@
838 nux::Geometry geo_content(geo.x, geo.y, style.GetAppImageAspectRatio() * geo.height, geo.height);
839
840 if (geo.width - geo_content.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin() < style.GetDetailsPanelMinimumWidth())
841- geo_content.width = MAX(0, geo.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin() - style.GetDetailsPanelMinimumWidth());
842+ geo_content.width = std::max(0, geo.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin() - style.GetDetailsPanelMinimumWidth());
843 if (content_) { content_->SetMinMaxSize(geo_content.width, geo_content.height); }
844 if (image_) { image_->SetMinMaxSize(geo_content.width, geo_content.height); }
845
846- int details_width = MAX(0, geo.width - geo_content.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin());
847- int top_social_info_max_width = details_width - style.GetAppIconAreaWidth() - style.GetSpaceBetweenIconAndDetails();
848+ int details_width = std::max(0, geo.width - geo_content.width - style.GetPanelSplitWidth() - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin());
849+ int top_social_info_max_width = std::max(details_width - style.GetAppIconAreaWidth() - style.GetSpaceBetweenIconAndDetails(), 0);
850
851 if (title_) { title_->SetMaximumWidth(top_social_info_max_width); }
852 if (subtitle_) { subtitle_->SetMaximumWidth(top_social_info_max_width); }
853
854=== modified file 'dash/previews/SocialPreviewComments.cpp'
855--- dash/previews/SocialPreviewComments.cpp 2012-11-08 09:12:24 +0000
856+++ dash/previews/SocialPreviewComments.cpp 2012-12-10 10:03:24 +0000
857@@ -102,7 +102,7 @@
858 }
859 }
860
861- int comment_value_width = MAX(0, geo.width - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin());
862+ int comment_value_width = std::max(0, geo.width - style.GetDetailsLeftMargin() - style.GetDetailsRightMargin());
863
864 for (Comment const& comment : comments_)
865 {
866
867=== modified file 'dash/previews/SocialPreviewContent.cpp'
868--- dash/previews/SocialPreviewContent.cpp 2012-11-16 19:22:31 +0000
869+++ dash/previews/SocialPreviewContent.cpp 2012-12-10 10:03:24 +0000
870@@ -149,8 +149,8 @@
871
872 nux::Geometry geo_cr(GetBubbleGeometry(geo));
873
874- int max_width = geo_cr.width - 2*(geo_cr.width*0.1);
875- int max_height = (geo_cr.height - TAIL_HEIGHT) - 2*((geo_cr.height - TAIL_HEIGHT)*0.1);
876+ int max_width = std::max(0, (int)(geo_cr.width - 2*(geo_cr.width*0.1)));
877+ int max_height = std::max(0, (int)((geo_cr.height - TAIL_HEIGHT) - 2*((geo_cr.height - TAIL_HEIGHT)*0.1)));
878
879 // this will update the texture with the actual size of the text.
880 text_->SetMaximumHeight(max_height);
881@@ -169,8 +169,8 @@
882
883 void SocialPreviewContent::RedrawBubble(nux::Geometry const& geom, cairo_t* cr, nux::ButtonVisualState faked_state)
884 {
885- double width = MAX(0, cairo_image_surface_get_width(cairo_get_target(cr)));
886- double height = MAX(0, cairo_image_surface_get_height(cairo_get_target(cr)) - TAIL_HEIGHT);
887+ double width = std::max(0, cairo_image_surface_get_width(cairo_get_target(cr)));
888+ double height = std::max(0, cairo_image_surface_get_height(cairo_get_target(cr)) - TAIL_HEIGHT);
889
890 double tailPosition = width - TAIL_POS_FROM_RIGHT - TAIL_HEIGHT;
891 if (width > 0 && height > 0)
892
893=== modified file 'tests/CMakeLists.txt'
894--- tests/CMakeLists.txt 2012-12-05 09:10:04 +0000
895+++ tests/CMakeLists.txt 2012-12-10 10:03:24 +0000
896@@ -130,6 +130,7 @@
897 test_layout_system.cpp
898 test_model_iterator.cpp
899 test_previews.cpp
900+ test_previews_precacher.cpp
901 test_time_util.cpp
902 test_ubus.cpp
903 test_unityshell_private.cpp
904
905=== modified file 'tests/test_lens.cpp'
906--- tests/test_lens.cpp 2012-11-14 08:57:56 +0000
907+++ tests/test_lens.cpp 2012-12-10 10:03:24 +0000
908@@ -228,9 +228,7 @@
909 previewed = true;
910 };
911
912- lens_->preview_ready.connect(preview_cb);
913-
914- lens_->Preview(uri);
915+ lens_->Preview(uri, NULL, preview_cb);
916 Utils::WaitUntil(previewed);
917 }
918
919@@ -251,8 +249,7 @@
920 previewed = true;
921 };
922
923- lens_->preview_ready.connect(preview_cb);
924- lens_->Preview(uri);
925+ lens_->Preview(uri, NULL, preview_cb);
926
927 Utils::WaitUntil(previewed);
928
929@@ -290,8 +287,7 @@
930 previewed = true;
931 };
932
933- lens_->preview_ready.connect(preview_cb);
934- lens_->Preview(uri);
935+ lens_->Preview(uri, NULL, preview_cb);
936
937 Utils::WaitUntil(previewed);
938
939@@ -336,7 +332,7 @@
940 };
941
942 lens_->preview_ready.connect(preview_cb);
943- lens_->Preview(uri);
944+ lens_->Preview(uri, NULL, std::nullptr_t());
945
946 Utils::WaitUntil(previewed);
947 }
948
949=== added file 'tests/test_previews_precacher.cpp'
950--- tests/test_previews_precacher.cpp 1970-01-01 00:00:00 +0000
951+++ tests/test_previews_precacher.cpp 2012-12-10 10:03:24 +0000
952@@ -0,0 +1,224 @@
953+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
954+/*
955+ * Copyright (C) 2012 Canonical Ltd
956+ *
957+ * This program is free software: you can redistribute it and/or modify
958+ * it under the terms of the GNU General Public License version 3 as
959+ * published by the Free Software Foundation.
960+ *
961+ * This program is distributed in the hope that it will be useful,
962+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
963+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
964+ * GNU General Public License for more details.
965+ *
966+ * You should have received a copy of the GNU General Public License
967+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
968+ *
969+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
970+ */
971+
972+#include <list>
973+#include <gmock/gmock.h>
974+using namespace testing;
975+
976+#include <Nux/Nux.h>
977+
978+#include "UnityCore/PreviewPreCacher.h"
979+
980+using namespace unity;
981+using namespace unity::dash;
982+
983+namespace
984+{
985+
986+class MockPreviewPreCacher : public previews::PreviewPreCacher
987+{
988+public:
989+ MockPreviewPreCacher(int cache_range)
990+ : PreviewPreCacher(NULL, cache_range)
991+ , queue_(true)
992+ {
993+ ON_CALL (*this, GetResultCount()).WillByDefault(Return(10));
994+ ON_CALL (*this, GetUriForResultIndex(_)).WillByDefault(Return("preview"));
995+ ON_CALL (*this, ExecutePreCache(_,_)).WillByDefault(Return(true));
996+ }
997+
998+ MOCK_CONST_METHOD0 (GetResultCount, unsigned int());
999+ MOCK_METHOD1 (GetUriForResultIndex, std::string(int));
1000+ MOCK_METHOD2 (ExecutePreCache, bool(int, std::string const&));
1001+ MOCK_METHOD0 (OnPreCacheComplete, void());
1002+
1003+ void enable_queue() { queue_ = true; }
1004+ void disable_queue() { queue_ = false; }
1005+
1006+ // mock this method so we dont have to wait on idle.
1007+ virtual void QueuePreCache()
1008+ {
1009+ if (queue_)
1010+ {
1011+ PreviewPreCacher::QueuePreCache();
1012+ }
1013+ else
1014+ {
1015+ ContinuePreCaching();
1016+ }
1017+ }
1018+
1019+ using PreviewPreCacher::ResetPreCachePosition;
1020+ using PreviewPreCacher::ContinuePreCaching;
1021+
1022+private:
1023+ bool queue_;
1024+};
1025+
1026+
1027+TEST(TestPreviewPreCacher, TestMathCenterInside)
1028+{
1029+ NiceMock<MockPreviewPreCacher> cacher(10);
1030+ cacher.disable_queue();
1031+
1032+ EXPECT_CALL(cacher, ExecutePreCache(4,_)).Times(1);
1033+ cacher.ResetPreCachePosition(3);
1034+
1035+ EXPECT_CALL(cacher, ExecutePreCache(2,_)).Times(1);
1036+ cacher.ContinuePreCaching();
1037+
1038+ EXPECT_CALL(cacher, ExecutePreCache(5,_)).Times(1);
1039+ cacher.ContinuePreCaching();
1040+
1041+ EXPECT_CALL(cacher, ExecutePreCache(1,_)).Times(1);
1042+ cacher.ContinuePreCaching();
1043+
1044+ EXPECT_CALL(cacher, ExecutePreCache(6,_)).Times(1);
1045+ cacher.ContinuePreCaching();
1046+
1047+ EXPECT_CALL(cacher, ExecutePreCache(0,_)).Times(1);
1048+ cacher.ContinuePreCaching();
1049+
1050+ EXPECT_CALL(cacher, ExecutePreCache(7,_)).Times(1);
1051+ cacher.ContinuePreCaching();
1052+
1053+ EXPECT_CALL(cacher, ExecutePreCache(8,_)).Times(1);
1054+ cacher.ContinuePreCaching();
1055+
1056+ EXPECT_CALL(cacher, ExecutePreCache(9,_)).Times(1);
1057+ cacher.ContinuePreCaching();
1058+
1059+ EXPECT_CALL(cacher, OnPreCacheComplete());
1060+ cacher.ContinuePreCaching();
1061+}
1062+
1063+TEST(TestPreviewPreCacher, TestMathCenterOutsidePositive)
1064+{
1065+ NiceMock<MockPreviewPreCacher> cacher(10);
1066+ cacher.disable_queue();
1067+
1068+ EXPECT_CALL(cacher, ExecutePreCache(_,_)).Times(0);
1069+ cacher.ResetPreCachePosition(11);
1070+}
1071+
1072+TEST(TestPreviewPreCacher, TestMathCenterOutsideNegative)
1073+{
1074+ NiceMock<MockPreviewPreCacher> cacher(10);
1075+ cacher.disable_queue();
1076+
1077+ EXPECT_CALL(cacher, ExecutePreCache(_,_)).Times(0);
1078+ cacher.ResetPreCachePosition(-1);
1079+}
1080+
1081+TEST(TestPreviewPreCacher, TestMathCenterBoundaryZero)
1082+{
1083+ NiceMock<MockPreviewPreCacher> cacher(10);
1084+ cacher.disable_queue();
1085+
1086+ EXPECT_CALL(cacher, ExecutePreCache(1,_)).Times(1);
1087+ cacher.ResetPreCachePosition(0);
1088+
1089+ for (int i = 1; i < (int)cacher.GetResultCount()-1; i++)
1090+ {
1091+ EXPECT_CALL(cacher, ExecutePreCache(i+1,_)).Times(1);
1092+ cacher.ContinuePreCaching();
1093+ }
1094+
1095+ EXPECT_CALL(cacher, OnPreCacheComplete());
1096+ cacher.ContinuePreCaching();
1097+}
1098+
1099+TEST(TestPreviewPreCacher, TestMathCenterBoundaryCount)
1100+{
1101+ NiceMock<MockPreviewPreCacher> cacher(10);
1102+ cacher.disable_queue();
1103+
1104+ EXPECT_CALL(cacher, ExecutePreCache(_,_)).Times(0);
1105+ cacher.ResetPreCachePosition(cacher.GetResultCount());
1106+}
1107+
1108+TEST(TestPreviewPreCacher, TestMathRangedCenterBottom)
1109+{
1110+ NiceMock<MockPreviewPreCacher> cacher(3);
1111+ cacher.disable_queue();
1112+
1113+ EXPECT_CALL(cacher, ExecutePreCache(2,_)).Times(1);
1114+ cacher.ResetPreCachePosition(1);
1115+
1116+ EXPECT_CALL(cacher, ExecutePreCache(0,_)).Times(1);
1117+ cacher.ContinuePreCaching();
1118+
1119+ EXPECT_CALL(cacher, ExecutePreCache(3,_)).Times(1);
1120+ cacher.ContinuePreCaching();
1121+
1122+ EXPECT_CALL(cacher, ExecutePreCache(4,_)).Times(1);
1123+ cacher.ContinuePreCaching();
1124+
1125+ EXPECT_CALL(cacher, ExecutePreCache(5,_)).Times(0);
1126+ EXPECT_CALL(cacher, OnPreCacheComplete());
1127+ cacher.ContinuePreCaching();
1128+}
1129+
1130+TEST(TestPreviewPreCacher, TestMathRangedCenterMiddle)
1131+{
1132+ NiceMock<MockPreviewPreCacher> cacher(2);
1133+ cacher.disable_queue();
1134+
1135+ EXPECT_CALL(cacher, ExecutePreCache(6,_)).Times(1);
1136+ cacher.ResetPreCachePosition(5);
1137+
1138+ EXPECT_CALL(cacher, ExecutePreCache(4,_)).Times(1);
1139+ cacher.ContinuePreCaching();
1140+
1141+ EXPECT_CALL(cacher, ExecutePreCache(7,_)).Times(1);
1142+ cacher.ContinuePreCaching();
1143+
1144+ EXPECT_CALL(cacher, ExecutePreCache(3,_)).Times(1);
1145+ cacher.ContinuePreCaching();
1146+
1147+ EXPECT_CALL(cacher, ExecutePreCache(8,_)).Times(0);
1148+ EXPECT_CALL(cacher, OnPreCacheComplete());
1149+ cacher.ContinuePreCaching();
1150+}
1151+
1152+TEST(TestPreviewPreCacher, TestMathRangedCenterTop)
1153+{
1154+ NiceMock<MockPreviewPreCacher> cacher(3);
1155+ cacher.disable_queue();
1156+
1157+ EXPECT_CALL(cacher, ExecutePreCache(9,_)).Times(1);
1158+ cacher.ResetPreCachePosition(8);
1159+
1160+ EXPECT_CALL(cacher, ExecutePreCache(7,_)).Times(1);
1161+ cacher.ContinuePreCaching();
1162+
1163+ EXPECT_CALL(cacher, ExecutePreCache(6,_)).Times(1);
1164+ cacher.ContinuePreCaching();
1165+
1166+ EXPECT_CALL(cacher, ExecutePreCache(5,_)).Times(1);
1167+ cacher.ContinuePreCaching();
1168+
1169+ EXPECT_CALL(cacher, ExecutePreCache(4,_)).Times(0);
1170+ EXPECT_CALL(cacher, OnPreCacheComplete());
1171+ cacher.ContinuePreCaching();
1172+}
1173+
1174+
1175+
1176+}