Merge lp:~osomon/webbrowser-app/thumbnails into lp:webbrowser-app
- thumbnails
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Olivier Tilloy |
Approved revision: | 207 |
Merged at revision: | 220 |
Proposed branch: | lp:~osomon/webbrowser-app/thumbnails |
Merge into: | lp:webbrowser-app |
Diff against target: |
988 lines (+568/-55) 21 files modified
CMakeLists.txt (+0/-2) debian/control (+5/-1) src/Ubuntu/Components/Extras/Browser/CMakeLists.txt (+13/-1) src/Ubuntu/Components/Extras/Browser/PageDelegate.qml (+23/-6) src/Ubuntu/Components/Extras/Browser/TabsList.qml (+8/-6) src/Ubuntu/Components/Extras/Browser/TimelineView.qml (+13/-10) src/Ubuntu/Components/Extras/Browser/UbuntuWebView.qml (+21/-0) src/Ubuntu/Components/Extras/Browser/history-hostlist-model.cpp (+33/-2) src/Ubuntu/Components/Extras/Browser/history-hostlist-model.h (+1/-0) src/Ubuntu/Components/Extras/Browser/plugin.cpp (+7/-0) src/Ubuntu/Components/Extras/Browser/tabs-model.cpp (+1/-5) src/Ubuntu/Components/Extras/Browser/tabs-model.h (+0/-1) src/Ubuntu/Components/Extras/Browser/webthumbnail-provider.cpp (+53/-0) src/Ubuntu/Components/Extras/Browser/webthumbnail-provider.h (+39/-0) src/Ubuntu/Components/Extras/Browser/webthumbnail-utils.cpp (+42/-0) src/Ubuntu/Components/Extras/Browser/webthumbnail-utils.h (+35/-0) src/Ubuntu/Components/Extras/Browser/webview-thumbnailer.cpp (+162/-0) src/Ubuntu/Components/Extras/Browser/webview-thumbnailer.h (+67/-0) tests/autopilot/webbrowser_app/emulators/main_window.py (+1/-1) tests/unittests/history-hostlist-model/CMakeLists.txt (+1/-0) tests/unittests/history-hostlist-model/tst_HistoryHostListModelTests.cpp (+43/-20) |
To merge this branch: | bzr merge lp:~osomon/webbrowser-app/thumbnails |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Bill Filler (community) | Approve | ||
Review via email: mp+173978@code.launchpad.net |
Commit message
Display thumbnails of the web pages in the activity view.
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:204
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 205. By Olivier Tilloy
-
Fix FTBFS in a clean environment.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:205
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
- 206. By Olivier Tilloy
-
Set the original size of the image.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:206
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
Bill Filler (bfiller) wrote : | # |
Looks like there is a jenkins issue causing a failure, but I tested the functionality and it works well and looks good. Before we land this I'd like to understand the impact on memory this has to make sure it is acceptable. And I have a few other questions..
Specifically:
- roughly what is the memory usage associated with generating and loading each thumbnail
- how can we limit the thumbnail cache as this seems it will grow limitlessly as history grows. We probably need some sort of hard limit on disk size or number stored so we don't chew up the users disk space. And a way to recreate if one from the cache doesn't exist.
- Are all thumbnails for the history items loaded in memory when the browser is started?
- Or do we only load thumbnails for images that are visible on the screen? I hope so :)
We should ensure that if you have hundreds/thousands of history items (which is likely) that we're not creating and loading thumbnails for all of these up front but only on demand.
Olivier Tilloy (osomon) wrote : | # |
> Looks like there is a jenkins issue causing a failure, but I tested the
> functionality and it works well and looks good. Before we land this I'd like
> to understand the impact on memory this has to make sure it is acceptable. And
> I have a few other questions..
>
> Specifically:
> - roughly what is the memory usage associated with generating and loading each
> thumbnail
> - how can we limit the thumbnail cache as this seems it will grow limitlessly
> as history grows. We probably need some sort of hard limit on disk size or
> number stored so we don't chew up the users disk space. And a way to recreate
> if one from the cache doesn't exist.
> - Are all thumbnails for the history items loaded in memory when the browser
> is started?
> - Or do we only load thumbnails for images that are visible on the screen? I
> hope so :)
>
> We should ensure that if you have hundreds/thousands of history items (which
> is likely) that we're not creating and loading thumbnails for all of these up
> front but only on demand.
As the timeline view is using nested list views, delegates are created on demand only when needed, and so are images loaded. I haven’t done any specific memory measurements, but I expect the memory consumption related to thumbnails to remain very reasonable (the thumbnails are square PNG images 12×12 grid units), and especially on a small screen such as a phone, where very few delegates are visible at any given time.
We’re not even loading any thumbnail when the application starts, as the timeline view isn’t visible yet, so it doesn’t instantiate any delegate.
Limiting the size of the cache is indeed a problem which this branch doesn’t address at all. I guess we could define a size limit, and when that limit is reached do some cleanup by removing the oldest thumbnails.
There’s also one issue that this branch doesn’t address: if a thumbnail already exists for a page, it’s never going to be re-generated, even if the contents of the page change. An option would be to force re-generating the thumbnail if it’s older than a given interval, e.g. one week.
I believe those two issues can (should) be addressed in other branches.
Bill Filler (bfiller) wrote : | # |
Sounds reasonable. Can you file bugs for those two issues please so we can track? I'll approve this but you need to fix the jenks failure before it can land.
Olivier Tilloy (osomon) wrote : | # |
The jenkins failures are due to bug #1199662, a regression in the UITK, which has been fixed yesterday, I’ll trigger a re-build now.
As soon as this is merged I’ll file bugs to track those two issues. Thanks for the review!
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:206
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
- 207. By Olivier Tilloy
-
Fix autopilot tests.
Olivier Tilloy (osomon) wrote : | # |
Some of the failures were actually a bug in the tests, this should now be fixed.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:207
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Olivier Tilloy (osomon) wrote : | # |
> As soon as this is merged I’ll file bugs to track those two issues.
Filed bug #1200525 (Thumbnails are never updated) and bug #1200526 (The thumbnail cache grows forever).
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2013-06-05 07:55:27 +0000 |
3 | +++ CMakeLists.txt 2013-07-12 06:47:24 +0000 |
4 | @@ -13,8 +13,6 @@ |
5 | find_package(Qt5Widgets REQUIRED) |
6 | find_package(Qt5Quick REQUIRED) |
7 | |
8 | -add_definitions(-DQT_NO_KEYWORDS) |
9 | - |
10 | set(CMAKE_INCLUDE_CURRENT_DIR ON) |
11 | set(CMAKE_AUTOMOC ON) |
12 | |
13 | |
14 | === modified file 'debian/control' |
15 | --- debian/control 2013-07-09 09:55:10 +0000 |
16 | +++ debian/control 2013-07-12 06:47:24 +0000 |
17 | @@ -6,11 +6,15 @@ |
18 | debhelper (>= 9), |
19 | dh-translations, |
20 | python, |
21 | + libqt5sql5-sqlite, |
22 | + libqt5v8-5-private-dev, |
23 | + libqt5webkit5-dev, |
24 | qt5-default, |
25 | qt5-qmake, |
26 | qtbase5-dev, |
27 | + qtbase5-private-dev, |
28 | qtdeclarative5-dev, |
29 | - libqt5sql5-sqlite, |
30 | + qtdeclarative5-private-dev, |
31 | qtdeclarative5-qtquick2-plugin, |
32 | qtdeclarative5-test-plugin, |
33 | qtdeclarative5-ubuntu-ui-toolkit-plugin, |
34 | |
35 | === modified file 'src/Ubuntu/Components/Extras/Browser/CMakeLists.txt' |
36 | --- src/Ubuntu/Components/Extras/Browser/CMakeLists.txt 2013-07-03 12:00:08 +0000 |
37 | +++ src/Ubuntu/Components/Extras/Browser/CMakeLists.txt 2013-07-12 06:47:24 +0000 |
38 | @@ -9,12 +9,24 @@ |
39 | history-host-model.cpp |
40 | history-hostlist-model.cpp |
41 | tabs-model.cpp |
42 | + webthumbnail-utils.cpp |
43 | + webthumbnail-provider.cpp |
44 | + webview-thumbnailer.cpp |
45 | plugin.cpp |
46 | ) |
47 | |
48 | add_library(${PLUGIN} MODULE ${PLUGIN_SRC}) |
49 | |
50 | -qt5_use_modules(${PLUGIN} Core Qml Sql) |
51 | +qt5_use_modules(${PLUGIN} Core Qml Quick Sql WebKit) |
52 | + |
53 | +# work around the lack of a public cmake module for Qt5V8 |
54 | +set(Qt5V8_PRIVATE_INCLUDE_DIRS |
55 | + "/usr/include/qt5/QtV8/${Qt5Qml_VERSION_STRING}" |
56 | + "/usr/include/qt5/QtV8/${Qt5Qml_VERSION_STRING}/QtV8") |
57 | +include_directories(${Qt5Core_PRIVATE_INCLUDE_DIRS} |
58 | + ${Qt5V8_PRIVATE_INCLUDE_DIRS} |
59 | + ${Qt5Quick_PRIVATE_INCLUDE_DIRS} |
60 | + ${Qt5WebKit_PRIVATE_INCLUDE_DIRS}) |
61 | |
62 | file(GLOB QML_FILES *.qml qmldir *.js) |
63 | install(TARGETS ${PLUGIN} DESTINATION ${WEBBROWSER_IMPORTS_DIR}) |
64 | |
65 | === modified file 'src/Ubuntu/Components/Extras/Browser/PageDelegate.qml' |
66 | --- src/Ubuntu/Components/Extras/Browser/PageDelegate.qml 2013-06-05 11:06:28 +0000 |
67 | +++ src/Ubuntu/Components/Extras/Browser/PageDelegate.qml 2013-07-12 06:47:24 +0000 |
68 | @@ -19,17 +19,34 @@ |
69 | import QtQuick 2.0 |
70 | import Ubuntu.Components 0.1 |
71 | |
72 | -UbuntuShape { |
73 | - property alias title: title.text |
74 | +Item { |
75 | + property alias thumbnail: thumbnail.source |
76 | + property alias label: label.text |
77 | + |
78 | + UbuntuShape { |
79 | + id: shape |
80 | + anchors { |
81 | + top: parent.top |
82 | + left: parent.left |
83 | + right: parent.right |
84 | + } |
85 | + height: width |
86 | + |
87 | + image: Image { |
88 | + id: thumbnail |
89 | + } |
90 | + } |
91 | |
92 | Label { |
93 | - id: title |
94 | + id: label |
95 | anchors { |
96 | - fill: parent |
97 | - margins: units.gu(0.5) |
98 | + top: shape.bottom |
99 | + topMargin: units.gu(1) |
100 | + left: parent.left |
101 | + right: parent.right |
102 | } |
103 | + height: units.gu(1) |
104 | fontSize: "small" |
105 | - wrapMode: Text.Wrap |
106 | elide: Text.ElideRight |
107 | } |
108 | } |
109 | |
110 | === modified file 'src/Ubuntu/Components/Extras/Browser/TabsList.qml' |
111 | --- src/Ubuntu/Components/Extras/Browser/TabsList.qml 2013-07-09 05:55:49 +0000 |
112 | +++ src/Ubuntu/Components/Extras/Browser/TabsList.qml 2013-07-12 06:47:24 +0000 |
113 | @@ -1,4 +1,4 @@ |
114 | -/* |
115 | +/* |
116 | * Copyright 2013 Canonical Ltd. |
117 | * |
118 | * This file is part of webbrowser-app. |
119 | @@ -41,7 +41,7 @@ |
120 | right: parent.right |
121 | margins: units.gu(2) |
122 | } |
123 | - height: units.gu(14) |
124 | + height: units.gu(16) |
125 | spacing: units.gu(2) |
126 | orientation: ListView.Horizontal |
127 | currentIndex: model.currentIndex |
128 | @@ -50,7 +50,7 @@ |
129 | width: units.gu(14) |
130 | height: parent.height |
131 | |
132 | - PageDelegate { |
133 | + UbuntuShape { |
134 | objectName: "newTabDelegate" |
135 | width: units.gu(12) |
136 | height: units.gu(12) |
137 | @@ -69,7 +69,7 @@ |
138 | |
139 | delegate: ListItem.Empty { |
140 | width: units.gu(12) |
141 | - height: units.gu(12) |
142 | + height: units.gu(14) |
143 | showDivider: false |
144 | |
145 | // FIXME: http://pad.lv/1187476 makes it impossible to swipe a |
146 | @@ -78,10 +78,12 @@ |
147 | onItemRemoved: tabRemoved(index) |
148 | |
149 | PageDelegate { |
150 | + id: openTabDelegate |
151 | objectName: "openTabDelegate" |
152 | anchors.fill: parent |
153 | - color: (index == currentIndex) ? UbuntuColors.darkAubergine : "white" |
154 | - title: model.title |
155 | + |
156 | + label: model.url |
157 | + thumbnail: model.webview.thumbnail |
158 | } |
159 | |
160 | onClicked: switchToTabClicked(index) |
161 | |
162 | === modified file 'src/Ubuntu/Components/Extras/Browser/TimelineView.qml' |
163 | --- src/Ubuntu/Components/Extras/Browser/TimelineView.qml 2013-07-05 14:37:29 +0000 |
164 | +++ src/Ubuntu/Components/Extras/Browser/TimelineView.qml 2013-07-12 06:47:24 +0000 |
165 | @@ -57,7 +57,7 @@ |
166 | |
167 | header: TabsList { |
168 | width: parent.width |
169 | - height: units.gu(20) |
170 | + height: units.gu(23) |
171 | |
172 | model: tabsModel |
173 | |
174 | @@ -107,7 +107,7 @@ |
175 | right: parent.right |
176 | margins: units.gu(2) |
177 | } |
178 | - height: units.gu(12) |
179 | + height: units.gu(14) |
180 | |
181 | spacing: units.gu(2) |
182 | orientation: ListView.Horizontal |
183 | @@ -160,10 +160,10 @@ |
184 | |
185 | delegate: PageDelegate { |
186 | width: units.gu(12) |
187 | - height: units.gu(12) |
188 | - color: "white" |
189 | + height: units.gu(14) |
190 | |
191 | - title: model.host ? model.host : i18n.tr("(local files)") |
192 | + label: model.host ? model.host : i18n.tr("(local files)") |
193 | + thumbnail: model.thumbnail |
194 | |
195 | MouseArea { |
196 | anchors.fill: parent |
197 | @@ -196,10 +196,12 @@ |
198 | |
199 | delegate: PageDelegate { |
200 | width: units.gu(12) |
201 | - height: units.gu(12) |
202 | - color: "white" |
203 | - |
204 | - title: model.title |
205 | + height: units.gu(14) |
206 | + |
207 | + label: model.title ? model.title : model.url |
208 | + |
209 | + property url thumbnailSource: "image://webthumbnail/" + model.url |
210 | + thumbnail: WebThumbnailer.thumbnailExists(model.url) ? thumbnailSource : "" |
211 | |
212 | MouseArea { |
213 | anchors.fill: parent |
214 | @@ -213,7 +215,8 @@ |
215 | when: timelineIndex == timeline.currentIndex |
216 | PropertyChanges { |
217 | target: entriesView |
218 | - height: units.gu(12) |
219 | + height: units.gu(14) |
220 | + clip: false |
221 | } |
222 | } |
223 | ] |
224 | |
225 | === modified file 'src/Ubuntu/Components/Extras/Browser/UbuntuWebView.qml' |
226 | --- src/Ubuntu/Components/Extras/Browser/UbuntuWebView.qml 2013-06-13 08:36:55 +0000 |
227 | +++ src/Ubuntu/Components/Extras/Browser/UbuntuWebView.qml 2013-07-12 06:47:24 +0000 |
228 | @@ -21,6 +21,7 @@ |
229 | import QtWebKit 3.0 |
230 | import QtWebKit.experimental 1.0 |
231 | import Ubuntu.Components 0.1 |
232 | +import Ubuntu.Components.Extras.Browser 0.1 |
233 | import Ubuntu.Components.Popups 0.1 |
234 | |
235 | WebView { |
236 | @@ -187,4 +188,24 @@ |
237 | flickableItem: _webview |
238 | align: Qt.AlignBottom |
239 | } |
240 | + |
241 | + WebviewThumbnailer { |
242 | + id: thumbnailer |
243 | + webview: _webview |
244 | + targetSize: Qt.size(units.gu(12), units.gu(12)) |
245 | + property url thumbnailSource: "image://webthumbnail/" + _webview.url |
246 | + onThumbnailRendered: { |
247 | + if (url == _webview.url) { |
248 | + _webview.thumbnail = thumbnailer.thumbnailSource |
249 | + } |
250 | + } |
251 | + } |
252 | + property url thumbnail: (url && thumbnailer.thumbnailExists()) ? thumbnailer.thumbnailSource : "" |
253 | + onLoadingChanged: { |
254 | + if (loadRequest.status === WebView.LoadSucceededStatus) { |
255 | + if (!thumbnailer.thumbnailExists()) { |
256 | + thumbnailer.renderThumbnail() |
257 | + } |
258 | + } |
259 | + } |
260 | } |
261 | |
262 | === modified file 'src/Ubuntu/Components/Extras/Browser/history-hostlist-model.cpp' |
263 | --- src/Ubuntu/Components/Extras/Browser/history-hostlist-model.cpp 2013-06-19 14:45:49 +0000 |
264 | +++ src/Ubuntu/Components/Extras/Browser/history-hostlist-model.cpp 2013-07-12 06:47:24 +0000 |
265 | @@ -20,6 +20,7 @@ |
266 | #include "history-model.h" |
267 | #include "history-host-model.h" |
268 | #include "history-timeframe-model.h" |
269 | +#include "webthumbnail-utils.h" |
270 | |
271 | // Qt |
272 | #include <QtCore/QSet> |
273 | @@ -30,8 +31,9 @@ |
274 | \brief List model that exposes history entries grouped by host |
275 | |
276 | HistoryHostListModel is a list model that exposes history entries from a |
277 | - HistoryTimeframeModel grouped by host. Each item in the list has two roles: |
278 | - 'host' for the host name, and 'entries' for the corresponding |
279 | + HistoryTimeframeModel grouped by host. Each item in the list has three |
280 | + roles: 'host' for the host name, 'thumbnail' for a thumbnail picture of a |
281 | + page corresponding to this host, and 'entries' for the corresponding |
282 | HistoryHostModel that contains all entries in this group. |
283 | */ |
284 | HistoryHostListModel::HistoryHostListModel(QObject* parent) |
285 | @@ -50,6 +52,7 @@ |
286 | static QHash<int, QByteArray> roles; |
287 | if (roles.isEmpty()) { |
288 | roles[Host] = "host"; |
289 | + roles[Thumbnail] = "thumbnail"; |
290 | roles[Entries] = "entries"; |
291 | } |
292 | return roles; |
293 | @@ -74,6 +77,20 @@ |
294 | switch (role) { |
295 | case Host: |
296 | return host; |
297 | + case Thumbnail: |
298 | + { |
299 | + // Iterate over all the entries, and return the first valid thumbnail. |
300 | + HistoryHostModel* entries = m_hosts.value(host); |
301 | + int count = entries->rowCount(); |
302 | + for (int i = 0; i < count; ++i) { |
303 | + QUrl url = entries->data(entries->index(i, 0), HistoryModel::Url).toUrl(); |
304 | + QFileInfo thumbnailFile = WebThumbnailUtils::thumbnailFile(url); |
305 | + if (thumbnailFile.exists()) { |
306 | + return thumbnailFile.absoluteFilePath(); |
307 | + } |
308 | + } |
309 | + return QUrl(); |
310 | + } |
311 | case Entries: |
312 | return QVariant::fromValue(m_hosts.value(host)); |
313 | default: |
314 | @@ -130,6 +147,7 @@ |
315 | |
316 | void HistoryHostListModel::onRowsInserted(const QModelIndex& parent, int start, int end) |
317 | { |
318 | + QStringList updated; |
319 | for (int i = start; i <= end; ++i) { |
320 | QString host = getHostFromSourceModel(m_sourceModel->index(i, 0, parent)); |
321 | if (!m_hosts.contains(host)) { |
322 | @@ -144,8 +162,16 @@ |
323 | beginInsertRows(QModelIndex(), insertAt, insertAt); |
324 | insertNewHost(host); |
325 | endInsertRows(); |
326 | + } else { |
327 | + updated.append(host); |
328 | } |
329 | } |
330 | + QVector<int> updatedRoles = QVector<int>() << Thumbnail << Entries; |
331 | + QStringList hosts = m_hosts.keys(); |
332 | + Q_FOREACH(const QString& host, updated) { |
333 | + QModelIndex index = this->index(hosts.indexOf(host), 0); |
334 | + Q_EMIT dataChanged(index, index, updatedRoles); |
335 | + } |
336 | } |
337 | |
338 | void HistoryHostListModel::onRowsRemoved(const QModelIndex& parent, int start, int end) |
339 | @@ -166,6 +192,11 @@ |
340 | delete m_hosts.take(host); |
341 | endRemoveRows(); |
342 | } |
343 | + // XXX: unfortunately there is no way to get a list of hosts that had some |
344 | + // (but not all) entries removed. To ensure the views are correctly updated, |
345 | + // let’s emit the signal for all entries, even those that haven’t changed. |
346 | + Q_EMIT dataChanged(this->index(0, 0), this->index(rowCount() - 1, 0), |
347 | + QVector<int>() << Thumbnail << Entries); |
348 | } |
349 | |
350 | void HistoryHostListModel::onModelReset() |
351 | |
352 | === modified file 'src/Ubuntu/Components/Extras/Browser/history-hostlist-model.h' |
353 | --- src/Ubuntu/Components/Extras/Browser/history-hostlist-model.h 2013-06-19 14:45:49 +0000 |
354 | +++ src/Ubuntu/Components/Extras/Browser/history-hostlist-model.h 2013-07-12 06:47:24 +0000 |
355 | @@ -41,6 +41,7 @@ |
356 | |
357 | enum Roles { |
358 | Host = Qt::UserRole + 1, |
359 | + Thumbnail, |
360 | Entries |
361 | }; |
362 | |
363 | |
364 | === modified file 'src/Ubuntu/Components/Extras/Browser/plugin.cpp' |
365 | --- src/Ubuntu/Components/Extras/Browser/plugin.cpp 2013-07-03 12:00:08 +0000 |
366 | +++ src/Ubuntu/Components/Extras/Browser/plugin.cpp 2013-07-12 06:47:24 +0000 |
367 | @@ -23,6 +23,8 @@ |
368 | #include "history-host-model.h" |
369 | #include "history-hostlist-model.h" |
370 | #include "tabs-model.h" |
371 | +#include "webthumbnail-provider.h" |
372 | +#include "webview-thumbnailer.h" |
373 | |
374 | // Qt |
375 | #include <QtCore/QDir> |
376 | @@ -38,6 +40,10 @@ |
377 | } |
378 | QQmlContext* context = engine->rootContext(); |
379 | context->setContextProperty("dataLocation", dataLocation.absolutePath()); |
380 | + |
381 | + WebThumbnailProvider* thumbnailer = new WebThumbnailProvider; |
382 | + engine->addImageProvider(QLatin1String("webthumbnail"), thumbnailer); |
383 | + context->setContextProperty("WebThumbnailer", thumbnailer); |
384 | } |
385 | |
386 | void UbuntuBrowserPlugin::registerTypes(const char* uri) |
387 | @@ -49,4 +55,5 @@ |
388 | qmlRegisterType<HistoryHostModel>(uri, 0, 1, "HistoryHostModel"); |
389 | qmlRegisterType<HistoryHostListModel>(uri, 0, 1, "HistoryHostListModel"); |
390 | qmlRegisterType<TabsModel>(uri, 0, 1, "TabsModel"); |
391 | + qmlRegisterType<WebviewThumbnailer>(uri, 0, 1, "WebviewThumbnailer"); |
392 | } |
393 | |
394 | === modified file 'src/Ubuntu/Components/Extras/Browser/tabs-model.cpp' |
395 | --- src/Ubuntu/Components/Extras/Browser/tabs-model.cpp 2013-06-06 07:40:22 +0000 |
396 | +++ src/Ubuntu/Components/Extras/Browser/tabs-model.cpp 2013-07-12 06:47:24 +0000 |
397 | @@ -28,7 +28,7 @@ |
398 | |
399 | TabsModel is a list model that stores the list of currently open tabs. |
400 | Each tab holds a pointer to a WebView and associated metadata (URL, title, |
401 | - icon, thumbnail). |
402 | + icon). |
403 | |
404 | The model doesn’t own the WebView, so it is the responsibility of whoever |
405 | adds a tab to instantiate the corresponding WebView, and to destroy it after |
406 | @@ -51,7 +51,6 @@ |
407 | roles[Url] = "url"; |
408 | roles[Title] = "title"; |
409 | roles[Icon] = "icon"; |
410 | - roles[Thumbnail] = "thumbnail"; |
411 | roles[WebView] = "webview"; |
412 | } |
413 | return roles; |
414 | @@ -80,9 +79,6 @@ |
415 | return webview->property("title"); |
416 | case Icon: |
417 | return webview->property("icon"); |
418 | - case Thumbnail: |
419 | - // XXX: not implemented yet |
420 | - return QVariant(); |
421 | case WebView: |
422 | return QVariant::fromValue(webview); |
423 | default: |
424 | |
425 | === modified file 'src/Ubuntu/Components/Extras/Browser/tabs-model.h' |
426 | --- src/Ubuntu/Components/Extras/Browser/tabs-model.h 2013-06-06 07:40:22 +0000 |
427 | +++ src/Ubuntu/Components/Extras/Browser/tabs-model.h 2013-07-12 06:47:24 +0000 |
428 | @@ -43,7 +43,6 @@ |
429 | Url = Qt::UserRole + 1, |
430 | Title, |
431 | Icon, |
432 | - Thumbnail, |
433 | WebView |
434 | }; |
435 | |
436 | |
437 | === added file 'src/Ubuntu/Components/Extras/Browser/webthumbnail-provider.cpp' |
438 | --- src/Ubuntu/Components/Extras/Browser/webthumbnail-provider.cpp 1970-01-01 00:00:00 +0000 |
439 | +++ src/Ubuntu/Components/Extras/Browser/webthumbnail-provider.cpp 2013-07-12 06:47:24 +0000 |
440 | @@ -0,0 +1,53 @@ |
441 | +/* |
442 | + * Copyright 2013 Canonical Ltd. |
443 | + * |
444 | + * This file is part of webbrowser-app. |
445 | + * |
446 | + * webbrowser-app is free software; you can redistribute it and/or modify |
447 | + * it under the terms of the GNU General Public License as published by |
448 | + * the Free Software Foundation; version 3. |
449 | + * |
450 | + * webbrowser-app is distributed in the hope that it will be useful, |
451 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
452 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
453 | + * GNU General Public License for more details. |
454 | + * |
455 | + * You should have received a copy of the GNU General Public License |
456 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
457 | + */ |
458 | + |
459 | +#include "webthumbnail-provider.h" |
460 | +#include "webthumbnail-utils.h" |
461 | + |
462 | +// Qt |
463 | +#include <QtCore/QDebug> |
464 | +#include <QtGui/QImageReader> |
465 | + |
466 | +WebThumbnailProvider::WebThumbnailProvider(QObject* parent) |
467 | + : QObject(parent) |
468 | + , QQuickImageProvider(QQuickImageProvider::Image) |
469 | +{ |
470 | +} |
471 | + |
472 | +QImage WebThumbnailProvider::requestImage(const QString& id, QSize* size, const QSize& requestedSize) |
473 | +{ |
474 | + QImage image; |
475 | + QFileInfo cached = WebThumbnailUtils::thumbnailFile(QUrl(id)); |
476 | + if (cached.exists()) { |
477 | + QImageReader reader(cached.absoluteFilePath(), "PNG"); |
478 | + if (requestedSize.isValid()) { |
479 | + reader.setScaledSize(requestedSize); |
480 | + } |
481 | + *size = reader.size(); |
482 | + reader.read(&image); |
483 | + if (image.isNull()) { |
484 | + qWarning() << "Failed to load cached thumbnail:" << reader.errorString(); |
485 | + } |
486 | + } |
487 | + return image; |
488 | +} |
489 | + |
490 | +bool WebThumbnailProvider::thumbnailExists(const QUrl& url) const |
491 | +{ |
492 | + return WebThumbnailUtils::thumbnailFile(url).exists(); |
493 | +} |
494 | |
495 | === added file 'src/Ubuntu/Components/Extras/Browser/webthumbnail-provider.h' |
496 | --- src/Ubuntu/Components/Extras/Browser/webthumbnail-provider.h 1970-01-01 00:00:00 +0000 |
497 | +++ src/Ubuntu/Components/Extras/Browser/webthumbnail-provider.h 2013-07-12 06:47:24 +0000 |
498 | @@ -0,0 +1,39 @@ |
499 | +/* |
500 | + * Copyright 2013 Canonical Ltd. |
501 | + * |
502 | + * This file is part of webbrowser-app. |
503 | + * |
504 | + * webbrowser-app is free software; you can redistribute it and/or modify |
505 | + * it under the terms of the GNU General Public License as published by |
506 | + * the Free Software Foundation; version 3. |
507 | + * |
508 | + * webbrowser-app is distributed in the hope that it will be useful, |
509 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
510 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
511 | + * GNU General Public License for more details. |
512 | + * |
513 | + * You should have received a copy of the GNU General Public License |
514 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
515 | + */ |
516 | + |
517 | +#ifndef __WEBTHUMBNAIL_PROVIDER_H__ |
518 | +#define __WEBTHUMBNAIL_PROVIDER_H__ |
519 | + |
520 | +// Qt |
521 | +#include <QtCore/QObject> |
522 | +#include <QtCore/QUrl> |
523 | +#include <QtQuick/QQuickImageProvider> |
524 | + |
525 | +class WebThumbnailProvider : public QObject, public QQuickImageProvider |
526 | +{ |
527 | + Q_OBJECT |
528 | + |
529 | +public: |
530 | + WebThumbnailProvider(QObject* parent=0); |
531 | + |
532 | + virtual QImage requestImage(const QString& id, QSize* size, const QSize& requestedSize); |
533 | + |
534 | + Q_INVOKABLE bool thumbnailExists(const QUrl& url) const; |
535 | +}; |
536 | + |
537 | +#endif // __WEBTHUMBNAIL_PROVIDER_H__ |
538 | |
539 | === added file 'src/Ubuntu/Components/Extras/Browser/webthumbnail-utils.cpp' |
540 | --- src/Ubuntu/Components/Extras/Browser/webthumbnail-utils.cpp 1970-01-01 00:00:00 +0000 |
541 | +++ src/Ubuntu/Components/Extras/Browser/webthumbnail-utils.cpp 2013-07-12 06:47:24 +0000 |
542 | @@ -0,0 +1,42 @@ |
543 | +/* |
544 | + * Copyright 2013 Canonical Ltd. |
545 | + * |
546 | + * This file is part of webbrowser-app. |
547 | + * |
548 | + * webbrowser-app is free software; you can redistribute it and/or modify |
549 | + * it under the terms of the GNU General Public License as published by |
550 | + * the Free Software Foundation; version 3. |
551 | + * |
552 | + * webbrowser-app is distributed in the hope that it will be useful, |
553 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
554 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
555 | + * GNU General Public License for more details. |
556 | + * |
557 | + * You should have received a copy of the GNU General Public License |
558 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
559 | + */ |
560 | + |
561 | +#include "webthumbnail-utils.h" |
562 | + |
563 | +// Qt |
564 | +#include <QtCore/QCryptographicHash> |
565 | +#include <QtCore/QStandardPaths> |
566 | + |
567 | +QDir WebThumbnailUtils::cacheLocation() |
568 | +{ |
569 | + return QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/thumbnails"; |
570 | +} |
571 | + |
572 | +void WebThumbnailUtils::ensureCacheLocation() |
573 | +{ |
574 | + QDir cache = cacheLocation(); |
575 | + if (!cache.exists()) { |
576 | + QDir::root().mkpath(cache.absolutePath()); |
577 | + } |
578 | +} |
579 | + |
580 | +QFileInfo WebThumbnailUtils::thumbnailFile(const QUrl& url) |
581 | +{ |
582 | + QString hash(QCryptographicHash::hash(url.toEncoded(), QCryptographicHash::Md5).toHex()); |
583 | + return cacheLocation().absoluteFilePath(hash + ".png"); |
584 | +} |
585 | |
586 | === added file 'src/Ubuntu/Components/Extras/Browser/webthumbnail-utils.h' |
587 | --- src/Ubuntu/Components/Extras/Browser/webthumbnail-utils.h 1970-01-01 00:00:00 +0000 |
588 | +++ src/Ubuntu/Components/Extras/Browser/webthumbnail-utils.h 2013-07-12 06:47:24 +0000 |
589 | @@ -0,0 +1,35 @@ |
590 | +/* |
591 | + * Copyright 2013 Canonical Ltd. |
592 | + * |
593 | + * This file is part of webbrowser-app. |
594 | + * |
595 | + * webbrowser-app is free software; you can redistribute it and/or modify |
596 | + * it under the terms of the GNU General Public License as published by |
597 | + * the Free Software Foundation; version 3. |
598 | + * |
599 | + * webbrowser-app is distributed in the hope that it will be useful, |
600 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
601 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
602 | + * GNU General Public License for more details. |
603 | + * |
604 | + * You should have received a copy of the GNU General Public License |
605 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
606 | + */ |
607 | + |
608 | +#ifndef __WEBTHUMBNAIL_UTILS_H__ |
609 | +#define __WEBTHUMBNAIL_UTILS_H__ |
610 | + |
611 | +// Qt |
612 | +#include <QtCore/QDir> |
613 | +#include <QtCore/QFileInfo> |
614 | +#include <QtCore/QUrl> |
615 | + |
616 | +class WebThumbnailUtils |
617 | +{ |
618 | +public: |
619 | + static QDir cacheLocation(); |
620 | + static void ensureCacheLocation(); |
621 | + static QFileInfo thumbnailFile(const QUrl& url); |
622 | +}; |
623 | + |
624 | +#endif // __WEBTHUMBNAIL_UTILS_H__ |
625 | |
626 | === added file 'src/Ubuntu/Components/Extras/Browser/webview-thumbnailer.cpp' |
627 | --- src/Ubuntu/Components/Extras/Browser/webview-thumbnailer.cpp 1970-01-01 00:00:00 +0000 |
628 | +++ src/Ubuntu/Components/Extras/Browser/webview-thumbnailer.cpp 2013-07-12 06:47:24 +0000 |
629 | @@ -0,0 +1,162 @@ |
630 | +/* |
631 | + * Copyright 2013 Canonical Ltd. |
632 | + * |
633 | + * This file is part of webbrowser-app. |
634 | + * |
635 | + * webbrowser-app is free software; you can redistribute it and/or modify |
636 | + * it under the terms of the GNU General Public License as published by |
637 | + * the Free Software Foundation; version 3. |
638 | + * |
639 | + * webbrowser-app is distributed in the hope that it will be useful, |
640 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
641 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
642 | + * GNU General Public License for more details. |
643 | + * |
644 | + * You should have received a copy of the GNU General Public License |
645 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
646 | + */ |
647 | + |
648 | +#include "webview-thumbnailer.h" |
649 | +#include "webthumbnail-utils.h" |
650 | + |
651 | +// Qt |
652 | +#include <QtCore/QTimer> |
653 | +#include <QtQuick/private/qsgrenderer_p.h> |
654 | +#include <QtWebKit/private/qquickwebpage_p.h> |
655 | +#include <QtWebKit/private/qquickwebview_p.h> |
656 | + |
657 | +class BindableFbo : public QSGBindable |
658 | +{ |
659 | +public: |
660 | + BindableFbo(QOpenGLFramebufferObject* fbo) : m_fbo(fbo) {} |
661 | + virtual void bind() const { m_fbo->bind(); } |
662 | + |
663 | +private: |
664 | + QOpenGLFramebufferObject *m_fbo; |
665 | +}; |
666 | + |
667 | +WebviewThumbnailer::WebviewThumbnailer(QQuickItem* parent) |
668 | + : QQuickItem(parent) |
669 | + , m_webview(0) |
670 | + , m_renderer(0) |
671 | +{ |
672 | +} |
673 | + |
674 | +WebviewThumbnailer::~WebviewThumbnailer() |
675 | +{ |
676 | + delete m_renderer; |
677 | +} |
678 | + |
679 | +QQuickWebView* WebviewThumbnailer::webview() const |
680 | +{ |
681 | + return m_webview; |
682 | +} |
683 | + |
684 | +void WebviewThumbnailer::setWebview(QQuickWebView* webview) |
685 | +{ |
686 | + if (webview != m_webview) { |
687 | + m_webview = webview; |
688 | + setFlag(QQuickItem::ItemHasContents, false); |
689 | + Q_EMIT webviewChanged(); |
690 | + } |
691 | +} |
692 | + |
693 | +const QSize& WebviewThumbnailer::targetSize() const |
694 | +{ |
695 | + return m_targetSize; |
696 | +} |
697 | + |
698 | +void WebviewThumbnailer::setTargetSize(const QSize& targetSize) |
699 | +{ |
700 | + if (targetSize != m_targetSize) { |
701 | + m_targetSize = targetSize; |
702 | + Q_EMIT targetSizeChanged(); |
703 | + } |
704 | +} |
705 | + |
706 | +bool WebviewThumbnailer::thumbnailExists() const |
707 | +{ |
708 | + if (m_webview) { |
709 | + QUrl url = m_webview->url(); |
710 | + if (url.isValid()) { |
711 | + return WebThumbnailUtils::thumbnailFile(url).exists(); |
712 | + } |
713 | + } |
714 | + return false; |
715 | +} |
716 | + |
717 | +void WebviewThumbnailer::renderThumbnail() |
718 | +{ |
719 | + // Delay the actual rendering to give all elements on the page |
720 | + // a chance to be fully rendered. |
721 | + QTimer::singleShot(1000, this, SLOT(doRenderThumbnail())); |
722 | +} |
723 | + |
724 | +void WebviewThumbnailer::doRenderThumbnail() |
725 | +{ |
726 | + if (m_webview) { |
727 | + setFlag(QQuickItem::ItemHasContents); |
728 | + update(); |
729 | + } |
730 | +} |
731 | + |
732 | +QSGNode* WebviewThumbnailer::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* updatePaintNodeData) |
733 | +{ |
734 | + Q_UNUSED(updatePaintNodeData); |
735 | + |
736 | + if (!(m_webview && (flags() & QQuickItem::ItemHasContents))) { |
737 | + return oldNode; |
738 | + } |
739 | + setFlag(QQuickItem::ItemHasContents, false); |
740 | + |
741 | + QQuickWebPage* page = m_webview->page(); |
742 | + qreal min = qMin(page->width(), page->height()); |
743 | + QSize size(min, min); |
744 | + |
745 | + QSGNode* node = QQuickItemPrivate::get(page)->itemNode(); |
746 | + QSGNode* parent = node->QSGNode::parent(); |
747 | + QSGNode* previousSibling = node->previousSibling(); |
748 | + if (parent) { |
749 | + parent->removeChildNode(node); |
750 | + } |
751 | + QSGRootNode root; |
752 | + root.appendChildNode(node); |
753 | + |
754 | + if (m_renderer == 0) { |
755 | + m_renderer = QQuickItemPrivate::get(this)->sceneGraphContext()->createRenderer(); |
756 | + } |
757 | + m_renderer->setRootNode(static_cast<QSGRootNode*>(&root)); |
758 | + |
759 | + QOpenGLFramebufferObject fbo(size); |
760 | + |
761 | + m_renderer->setDeviceRect(size); |
762 | + m_renderer->setViewportRect(size); |
763 | + m_renderer->setProjectionMatrixToRect(QRectF(QPointF(), size)); |
764 | + m_renderer->setClearColor(Qt::transparent); |
765 | + |
766 | + m_renderer->renderScene(BindableFbo(&fbo)); |
767 | + |
768 | + fbo.release(); |
769 | + |
770 | + QImage image = fbo.toImage().scaled(m_targetSize, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); |
771 | + |
772 | + WebThumbnailUtils::ensureCacheLocation(); |
773 | + QUrl url = m_webview->url(); |
774 | + bool saved = image.save(WebThumbnailUtils::thumbnailFile(url).absoluteFilePath()); |
775 | + |
776 | + root.removeChildNode(node); |
777 | + |
778 | + if (parent) { |
779 | + if (previousSibling) { |
780 | + parent->insertChildNodeAfter(node, previousSibling); |
781 | + } else { |
782 | + parent->prependChildNode(node); |
783 | + } |
784 | + } |
785 | + |
786 | + if (saved) { |
787 | + Q_EMIT thumbnailRendered(url); |
788 | + } |
789 | + |
790 | + return oldNode; |
791 | +} |
792 | |
793 | === added file 'src/Ubuntu/Components/Extras/Browser/webview-thumbnailer.h' |
794 | --- src/Ubuntu/Components/Extras/Browser/webview-thumbnailer.h 1970-01-01 00:00:00 +0000 |
795 | +++ src/Ubuntu/Components/Extras/Browser/webview-thumbnailer.h 2013-07-12 06:47:24 +0000 |
796 | @@ -0,0 +1,67 @@ |
797 | +/* |
798 | + * Copyright 2013 Canonical Ltd. |
799 | + * |
800 | + * This file is part of webbrowser-app. |
801 | + * |
802 | + * webbrowser-app is free software; you can redistribute it and/or modify |
803 | + * it under the terms of the GNU General Public License as published by |
804 | + * the Free Software Foundation; version 3. |
805 | + * |
806 | + * webbrowser-app is distributed in the hope that it will be useful, |
807 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
808 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
809 | + * GNU General Public License for more details. |
810 | + * |
811 | + * You should have received a copy of the GNU General Public License |
812 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
813 | + */ |
814 | + |
815 | +#ifndef __WEBVIEW_THUMBNAILER_H__ |
816 | +#define __WEBVIEW_THUMBNAILER_H__ |
817 | + |
818 | +// Qt |
819 | +#include <QtCore/QSize> |
820 | +#include <QtCore/QUrl> |
821 | +#include <QtQuick/private/qquickitem_p.h> |
822 | + |
823 | +class QQuickWebView; |
824 | +class QSGRenderer; |
825 | + |
826 | +class WebviewThumbnailer : public QQuickItem |
827 | +{ |
828 | + Q_OBJECT |
829 | + |
830 | + Q_PROPERTY(QQuickWebView* webview READ webview WRITE setWebview NOTIFY webviewChanged) |
831 | + Q_PROPERTY(QSize targetSize READ targetSize WRITE setTargetSize NOTIFY targetSizeChanged) |
832 | + |
833 | +public: |
834 | + WebviewThumbnailer(QQuickItem* parent=0); |
835 | + ~WebviewThumbnailer(); |
836 | + |
837 | + QQuickWebView* webview() const; |
838 | + void setWebview(QQuickWebView* webview); |
839 | + |
840 | + const QSize& targetSize() const; |
841 | + void setTargetSize(const QSize& targetSize); |
842 | + |
843 | + Q_INVOKABLE bool thumbnailExists() const; |
844 | + Q_INVOKABLE void renderThumbnail(); |
845 | + |
846 | +Q_SIGNALS: |
847 | + void webviewChanged() const; |
848 | + void targetSizeChanged() const; |
849 | + void thumbnailRendered(const QUrl& url) const; |
850 | + |
851 | +protected: |
852 | + virtual QSGNode* updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* updatePaintNodeData); |
853 | + |
854 | +private Q_SLOTS: |
855 | + void doRenderThumbnail(); |
856 | + |
857 | +private: |
858 | + QQuickWebView* m_webview; |
859 | + QSize m_targetSize; |
860 | + QSGRenderer* m_renderer; |
861 | +}; |
862 | + |
863 | +#endif // __WEBVIEW_THUMBNAILER_H__ |
864 | |
865 | === modified file 'tests/autopilot/webbrowser_app/emulators/main_window.py' |
866 | --- tests/autopilot/webbrowser_app/emulators/main_window.py 2013-07-05 11:21:52 +0000 |
867 | +++ tests/autopilot/webbrowser_app/emulators/main_window.py 2013-07-12 06:47:24 +0000 |
868 | @@ -79,7 +79,7 @@ |
869 | return self.get_activity_view().select_single("TabsList") |
870 | |
871 | def get_tabslist_newtab_delegate(self): |
872 | - return self.get_tabslist().select_single("PageDelegate", |
873 | + return self.get_tabslist().select_single("UbuntuShape", |
874 | objectName="newTabDelegate") |
875 | |
876 | def get_tabslist_view(self): |
877 | |
878 | === modified file 'tests/unittests/history-hostlist-model/CMakeLists.txt' |
879 | --- tests/unittests/history-hostlist-model/CMakeLists.txt 2013-07-02 11:29:03 +0000 |
880 | +++ tests/unittests/history-hostlist-model/CMakeLists.txt 2013-07-12 06:47:24 +0000 |
881 | @@ -4,6 +4,7 @@ |
882 | ${webbrowser-plugin_SOURCE_DIR}/history-hostlist-model.cpp |
883 | ${webbrowser-plugin_SOURCE_DIR}/history-model.cpp |
884 | ${webbrowser-plugin_SOURCE_DIR}/history-timeframe-model.cpp |
885 | + ${webbrowser-plugin_SOURCE_DIR}/webthumbnail-utils.cpp |
886 | tst_HistoryHostListModelTests.cpp |
887 | ) |
888 | add_executable(${TEST} ${SOURCES}) |
889 | |
890 | === modified file 'tests/unittests/history-hostlist-model/tst_HistoryHostListModelTests.cpp' |
891 | --- tests/unittests/history-hostlist-model/tst_HistoryHostListModelTests.cpp 2013-07-02 11:29:03 +0000 |
892 | +++ tests/unittests/history-hostlist-model/tst_HistoryHostListModelTests.cpp 2013-07-12 06:47:24 +0000 |
893 | @@ -60,52 +60,75 @@ |
894 | |
895 | void shouldUpdateHostListWhenInsertingEntries() |
896 | { |
897 | - QSignalSpy spy(model, SIGNAL(rowsInserted(const QModelIndex&, int, int))); |
898 | + QSignalSpy spyRowsInserted(model, SIGNAL(rowsInserted(const QModelIndex&, int, int))); |
899 | + qRegisterMetaType<QVector<int> >(); |
900 | + QSignalSpy spyDataChanged(model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&))); |
901 | |
902 | history->add(QUrl("http://example.org/"), "Example Domain", QUrl()); |
903 | - QCOMPARE(spy.count(), 1); |
904 | - QList<QVariant> args = spy.takeFirst(); |
905 | + QVERIFY(spyDataChanged.isEmpty()); |
906 | + QCOMPARE(spyRowsInserted.count(), 1); |
907 | + QList<QVariant> args = spyRowsInserted.takeFirst(); |
908 | QCOMPARE(args.at(1).toInt(), 0); |
909 | QCOMPARE(args.at(2).toInt(), 0); |
910 | QCOMPARE(model->rowCount(), 1); |
911 | QCOMPARE(model->data(model->index(0, 0), HistoryHostListModel::Host).toString(), QString("example.org")); |
912 | |
913 | history->add(QUrl("http://example.com/"), "Example Domain", QUrl()); |
914 | - QCOMPARE(spy.count(), 1); |
915 | - args = spy.takeFirst(); |
916 | + QVERIFY(spyDataChanged.isEmpty()); |
917 | + QCOMPARE(spyRowsInserted.count(), 1); |
918 | + args = spyRowsInserted.takeFirst(); |
919 | QCOMPARE(args.at(1).toInt(), 0); |
920 | QCOMPARE(args.at(2).toInt(), 0); |
921 | QCOMPARE(model->rowCount(), 2); |
922 | QCOMPARE(model->data(model->index(0, 0), HistoryHostListModel::Host).toString(), QString("example.com")); |
923 | |
924 | history->add(QUrl("http://example.org/test.html"), "Test page", QUrl()); |
925 | - QVERIFY(spy.isEmpty()); |
926 | + QVERIFY(spyRowsInserted.isEmpty()); |
927 | + QCOMPARE(spyDataChanged.count(), 1); |
928 | + args = spyDataChanged.takeFirst(); |
929 | + QCOMPARE(args.at(0).toModelIndex().row(), 1); |
930 | + QCOMPARE(args.at(1).toModelIndex().row(), 1); |
931 | QCOMPARE(model->rowCount(), 2); |
932 | } |
933 | |
934 | void shouldUpdateHostListWhenRemovingEntries() |
935 | { |
936 | - QSignalSpy spy(model, SIGNAL(rowsRemoved(const QModelIndex&, int, int))); |
937 | history->add(QUrl("http://example.org/"), "Example Domain", QUrl()); |
938 | QTest::qWait(100); |
939 | QDateTime t0 = QDateTime::currentDateTimeUtc(); |
940 | QTest::qWait(100); |
941 | history->add(QUrl("http://example.com/"), "Example Domain", QUrl()); |
942 | - QCOMPARE(model->rowCount(), 2); |
943 | - |
944 | - timeframe->setEnd(t0); |
945 | - QCOMPARE(spy.count(), 1); |
946 | - QList<QVariant> args = spy.takeFirst(); |
947 | - QCOMPARE(args.at(1).toInt(), 0); |
948 | - QCOMPARE(args.at(2).toInt(), 0); |
949 | - QCOMPARE(model->rowCount(), 1); |
950 | + QTest::qWait(100); |
951 | + QDateTime t1 = QDateTime::currentDateTimeUtc(); |
952 | + QTest::qWait(100); |
953 | + history->add(QUrl("http://example.org/test"), "Example Domain", QUrl()); |
954 | + QCOMPARE(model->rowCount(), 2); |
955 | + |
956 | + QSignalSpy spyRowsRemoved(model, SIGNAL(rowsRemoved(const QModelIndex&, int, int))); |
957 | + qRegisterMetaType<QVector<int> >(); |
958 | + QSignalSpy spyDataChanged(model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&))); |
959 | + |
960 | + timeframe->setEnd(t1); |
961 | + QVERIFY(spyRowsRemoved.isEmpty()); |
962 | + QVERIFY(!spyDataChanged.isEmpty()); |
963 | + QList<QVariant> args; |
964 | + bool changed = false; |
965 | + int expectedIndex = 1; |
966 | + while(!changed && !spyDataChanged.isEmpty()) { |
967 | + args = spyDataChanged.takeFirst(); |
968 | + int start = args.at(0).toModelIndex().row(); |
969 | + int end = args.at(1).toModelIndex().row(); |
970 | + changed = (start <= expectedIndex) && (expectedIndex <= end); |
971 | + } |
972 | + QVERIFY(changed); |
973 | + QCOMPARE(model->rowCount(), 2); |
974 | |
975 | timeframe->setStart(t0); |
976 | - QCOMPARE(spy.count(), 1); |
977 | - args = spy.takeFirst(); |
978 | - QCOMPARE(args.at(1).toInt(), 0); |
979 | - QCOMPARE(args.at(2).toInt(), 0); |
980 | - QCOMPARE(model->rowCount(), 0); |
981 | + QCOMPARE(spyRowsRemoved.count(), 1); |
982 | + args = spyRowsRemoved.takeFirst(); |
983 | + QCOMPARE(args.at(1).toInt(), 1); |
984 | + QCOMPARE(args.at(2).toInt(), 1); |
985 | + QCOMPARE(model->rowCount(), 1); |
986 | } |
987 | |
988 | void shouldUpdateWhenChangingSourceModel() |
FAILED: Continuous integration, rev:204 jenkins. qa.ubuntu. com/job/ webbrowser- app-ci/ 194/ jenkins. qa.ubuntu. com/job/ generic- mediumtests- saucy/952/ console jenkins. qa.ubuntu. com/job/ webbrowser- app-saucy- amd64-ci/ 77/console jenkins. qa.ubuntu. com/job/ webbrowser- app-saucy- armhf-ci/ 77/console jenkins. qa.ubuntu. com/job/ webbrowser- app-saucy- i386-ci/ 77/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- saucy/956/ console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ webbrowser- app-ci/ 194/rebuild
http://