Merge lp:~fboucault/webbrowser-app/downloads_emblem into lp:webbrowser-app/staging
- downloads_emblem
- Merge into staging
Status: | Needs review |
---|---|
Proposed branch: | lp:~fboucault/webbrowser-app/downloads_emblem |
Merge into: | lp:webbrowser-app/staging |
Prerequisite: | lp:~osomon/webbrowser-app/qmltests |
Diff against target: |
659 lines (+345/-23) 17 files modified
src/app/browserapplication.cpp (+2/-1) src/app/config.h.in (+2/-2) src/app/webbrowser/Browser.qml (+10/-1) src/app/webbrowser/Chrome.qml (+1/-0) src/app/webbrowser/CountEmblem.qml (+66/-0) src/app/webbrowser/DownloadHandler.qml (+61/-0) src/app/webbrowser/NavigationBar.qml (+28/-1) src/app/webbrowser/TabComponent.qml (+0/-1) src/app/webbrowser/downloads-model.cpp (+21/-0) src/app/webbrowser/downloads-model.h (+1/-0) src/app/webbrowser/webbrowser-app.cpp (+1/-1) src/app/webbrowser/webbrowser-app.qml (+16/-0) tests/qmltests/webbrowser-app/SingleWindowTestCase.qml (+3/-3) tests/qmltests/webbrowser-app/WebbrowserAppTestCase.qml (+1/-1) tests/qmltests/webbrowser-app/tst_Downloads.qml (+117/-11) tests/qmltests/webbrowser-app/webbrowser-app-qmltests-launcher.cpp (+2/-1) tests/unittests/downloads-model/tst_DownloadsModelTests.cpp (+13/-0) |
To merge this branch: | bzr merge lp:~fboucault/webbrowser-app/downloads_emblem |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Olivier Tilloy | Pending | ||
Review via email: mp+321453@code.launchpad.net |
This proposal supersedes a proposal from 2017-03-10.
Commit message
Description of the change
Download UX: when initiating a download do not take the user to the downloads page but display a download emblem instead.
Olivier Tilloy (osomon) wrote : Posted in a previous version of this proposal | # |
Olivier Tilloy (osomon) wrote : Posted in a previous version of this proposal | # |
If I initiate a long-running download (try the daily-live ubuntu ISO image), then open the downloads page before the download has completed, and cancel the download, after closing the page I’m seeing a green emblem. That’s probably related to the issue I pointed out above, but it’s slightly worse because a cancelled download shouldn’t be advertised as finished, I think.
Olivier Tilloy (osomon) wrote : Posted in a previous version of this proposal | # |
One really cool thing is that if I initiate a long-running download and then close the browser, when I open it again the animated emblem is still there to remind me that I have an ongoing download.
Olivier Tilloy (osomon) wrote : Posted in a previous version of this proposal | # |
If I initiate a download in a browser window, I get the animated blue emblem. If I then open another browser window before the download has completed, the other window also has the emblem. When the download completes, the animation finishes and the emblem turns green in both windows.
However if I open the downloads page in one of the windows and then close it, the emblem goes away in that window, but not in the other one. I would expect it to go away in all windows.
Florian Boucault (fboucault) wrote : Posted in a previous version of this proposal | # |
All 3 issues were fixed.
Olivier Tilloy (osomon) wrote : Posted in a previous version of this proposal | # |
Overall, LGTM. I have a few minor comments, please see inline.
- 1652. By Florian Boucault
-
Cleanup
Unmerged revisions
- 1652. By Florian Boucault
-
Cleanup
- 1651. By Florian Boucault
-
Added download count emblem related tests
- 1650. By Florian Boucault
- 1649. By Florian Boucault
- 1648. By Florian Boucault
- 1647. By Florian Boucault
-
Merged staging
- 1646. By Florian Boucault
-
Readonly properties when it makes sense
- 1645. By Florian Boucault
-
Fixed typo: added 'n' to 'dowloads'
- 1644. By Florian Boucault
-
Synchronise finished downloads accross windows.
Discard finished downloads if the downloads view is opened. - 1643. By Florian Boucault
-
Merged from staging
Preview Diff
1 | === modified file 'src/app/browserapplication.cpp' |
2 | --- src/app/browserapplication.cpp 2016-10-31 10:53:51 +0000 |
3 | +++ src/app/browserapplication.cpp 2017-03-30 13:48:57 +0000 |
4 | @@ -183,6 +183,7 @@ |
5 | if (!isRunningInstalled()) { |
6 | m_engine->addImportPath(UbuntuBrowserImportsDirectory()); |
7 | } |
8 | + m_engine->setBaseUrl(QUrl::fromLocalFile(UbuntuBrowserDirectory())); |
9 | qmlEngineCreated(m_engine); |
10 | |
11 | QQmlContext* context = m_engine->rootContext(); |
12 | @@ -190,7 +191,7 @@ |
13 | context->setContextProperty("unversionedAppId", unversionedAppId); |
14 | |
15 | m_component = new QQmlComponent(m_engine); |
16 | - m_component->loadUrl(QUrl::fromLocalFile(UbuntuBrowserDirectory() + "/" + qmlFileSubPath)); |
17 | + m_component->loadUrl(qmlFileSubPath); |
18 | if (!m_component->isReady()) { |
19 | qWarning() << m_component->errorString(); |
20 | return false; |
21 | |
22 | === modified file 'src/app/config.h.in' |
23 | --- src/app/config.h.in 2016-07-12 11:54:37 +0000 |
24 | +++ src/app/config.h.in 2017-03-30 13:48:57 +0000 |
25 | @@ -35,9 +35,9 @@ |
26 | inline QString UbuntuBrowserDirectory() |
27 | { |
28 | if (isRunningInstalled()) { |
29 | - return qgetenv("SNAP").append("@CMAKE_INSTALL_FULL_DATADIR@/webbrowser-app"); |
30 | + return qgetenv("SNAP").append("@CMAKE_INSTALL_FULL_DATADIR@/webbrowser-app/"); |
31 | } else { |
32 | - return QStringLiteral("@CMAKE_SOURCE_DIR@/src/app"); |
33 | + return QStringLiteral("@CMAKE_SOURCE_DIR@/src/app/"); |
34 | } |
35 | } |
36 | |
37 | |
38 | === modified file 'src/app/webbrowser/Browser.qml' |
39 | --- src/app/webbrowser/Browser.qml 2017-03-30 13:48:56 +0000 |
40 | +++ src/app/webbrowser/Browser.qml 2017-03-30 13:48:57 +0000 |
41 | @@ -40,6 +40,8 @@ |
42 | currentWebview: tabsModel && tabsModel.currentTab ? tabsModel.currentTab.webview : null |
43 | |
44 | property bool incognito: false |
45 | + property bool downloadsViewOpened: downloadsViewLoader.status == Loader.Ready |
46 | + property bool discardFinishedDownloads: false |
47 | |
48 | property var tabsModel: TabsModel { |
49 | // These methods are required by the TabsBar component |
50 | @@ -523,6 +525,7 @@ |
51 | objectName: "chrome" |
52 | |
53 | tab: internal.nextTab || tabsModel.currentTab |
54 | + downloadManager: downloadHandlerLoader.item |
55 | tabsModel: browser.tabsModel |
56 | searchUrl: currentSearchEngine.urlTemplate |
57 | |
58 | @@ -627,6 +630,10 @@ |
59 | iconName: "save" |
60 | enabled: downloadHandlerLoader.status == Loader.Ready && contentHandlerLoader.status == Loader.Ready |
61 | onTriggered: downloadsViewLoader.active = true |
62 | + property var downloadsInProgress: downloadHandlerLoader.item ? downloadHandlerLoader.item.downloadsInProgress : [] |
63 | + property var downloadsFinished: downloadHandlerLoader.item ? downloadHandlerLoader.item.downloadsFinished : [] |
64 | + property int count: downloadsInProgress.length + downloadsFinished.length |
65 | + property bool pulsating: downloadsInProgress.length > 0 |
66 | }, |
67 | Action { |
68 | objectName: "settings" |
69 | @@ -991,8 +998,10 @@ |
70 | |
71 | Loader { |
72 | id: downloadHandlerLoader |
73 | - source: "DownloadHandler.qml" |
74 | asynchronous: true |
75 | + Component.onCompleted: setSource("DownloadHandler.qml", |
76 | + {"incognito": Qt.binding(function () {return browser.incognito}), |
77 | + "discardFinishedDownloads": Qt.binding(function () {return browser.discardFinishedDownloads})}) |
78 | } |
79 | |
80 | property Component tabComponent |
81 | |
82 | === modified file 'src/app/webbrowser/Chrome.qml' |
83 | --- src/app/webbrowser/Chrome.qml 2017-02-14 10:12:50 +0000 |
84 | +++ src/app/webbrowser/Chrome.qml 2017-03-30 13:48:57 +0000 |
85 | @@ -25,6 +25,7 @@ |
86 | |
87 | property var tabsModel |
88 | property alias tab: navigationBar.tab |
89 | + property alias downloadManager: navigationBar.downloadManager |
90 | readonly property var webview: tab ? tab.webview : null |
91 | property alias searchUrl: navigationBar.searchUrl |
92 | property alias text: navigationBar.text |
93 | |
94 | === added file 'src/app/webbrowser/CountEmblem.qml' |
95 | --- src/app/webbrowser/CountEmblem.qml 1970-01-01 00:00:00 +0000 |
96 | +++ src/app/webbrowser/CountEmblem.qml 2017-03-30 13:48:57 +0000 |
97 | @@ -0,0 +1,66 @@ |
98 | +/* |
99 | + * Copyright 2017 Canonical Ltd. |
100 | + * |
101 | + * This file is part of webbrowser-app. |
102 | + * |
103 | + * webbrowser-app is free software; you can redistribute it and/or modify |
104 | + * it under the terms of the GNU General Public License as published by |
105 | + * the Free Software Foundation; version 3. |
106 | + * |
107 | + * webbrowser-app is distributed in the hope that it will be useful, |
108 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
109 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
110 | + * GNU General Public License for more details. |
111 | + * |
112 | + * You should have received a copy of the GNU General Public License |
113 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
114 | + */ |
115 | + |
116 | +import QtQuick 2.4 |
117 | +import Ubuntu.Components 1.3 |
118 | + |
119 | +Item { |
120 | + id: countEmblem |
121 | + |
122 | + property int count: 0 |
123 | + property bool pulsating: false |
124 | + readonly property real maxWidth: parent.width |
125 | + |
126 | + implicitWidth: Math.min(maxWidth, Math.max(units.gu(2), countLabel.implicitWidth + units.gu(1))) |
127 | + implicitHeight: units.gu(2) |
128 | + visible: countEmblem.count > 0 |
129 | + |
130 | + UbuntuShape { |
131 | + anchors.fill: parent |
132 | + anchors.margins: -units.dp(1) |
133 | + backgroundColor: Qt.darker(backgroundShape.backgroundColor, 1.3) |
134 | + aspect: UbuntuShape.Flat |
135 | + |
136 | + opacity: 0 |
137 | + SequentialAnimation on opacity { |
138 | + running: countEmblem.pulsating |
139 | + alwaysRunToEnd: true |
140 | + loops: Animation.Infinite |
141 | + NumberAnimation { to: 1; duration: UbuntuAnimation.SlowDuration; easing: UbuntuAnimation.StandardEasingReverse } |
142 | + NumberAnimation { to: 0; duration: UbuntuAnimation.SlowDuration; easing: UbuntuAnimation.StandardEasing } |
143 | + } |
144 | + } |
145 | + |
146 | + UbuntuShape { |
147 | + id: backgroundShape |
148 | + anchors.fill: parent |
149 | + backgroundColor: pulsating ? theme.palette.normal.activity : theme.palette.normal.positive |
150 | + aspect: UbuntuShape.Flat |
151 | + } |
152 | + |
153 | + Label { |
154 | + id: countLabel |
155 | + text: countEmblem.count |
156 | + anchors.centerIn: parent |
157 | + width: countEmblem.maxWidth - units.gu(1) |
158 | + horizontalAlignment: Text.AlignHCenter |
159 | + elide: Text.ElideRight |
160 | + color: pulsating ? theme.palette.normal.activityText : theme.palette.normal.positiveText |
161 | + textSize: Label.Small |
162 | + } |
163 | +} |
164 | |
165 | === modified file 'src/app/webbrowser/DownloadHandler.qml' |
166 | --- src/app/webbrowser/DownloadHandler.qml 2016-01-12 11:06:49 +0000 |
167 | +++ src/app/webbrowser/DownloadHandler.qml 2017-03-30 13:48:57 +0000 |
168 | @@ -21,6 +21,67 @@ |
169 | import webbrowserapp.private 0.1 |
170 | |
171 | DownloadManager { |
172 | + id: downloadManager |
173 | + |
174 | + property var downloadsInProgress: [] |
175 | + property var downloadsFinished: [] |
176 | + property bool incognito: false |
177 | + property bool discardFinishedDownloads: false |
178 | + onDiscardFinishedDownloadsChanged: if (discardFinishedDownloads) downloadsFinished = [] |
179 | + |
180 | + function exists(downloadId) { |
181 | + for(var i = 0; i < downloadManager.downloads.length; i++) { |
182 | + var download = downloadManager.downloads[i]; |
183 | + if (download.downloadId == downloadId) { |
184 | + return true; |
185 | + } |
186 | + } |
187 | + return false; |
188 | + } |
189 | + |
190 | + function listDownloadsInProgress() { |
191 | + var downloads = []; |
192 | + for(var i = 0; i < DownloadsModel.count; i++) { |
193 | + var download = DownloadsModel.get(i); |
194 | + // There can be downloads in DownloadsModel which are not 'complete' |
195 | + // but not in progress any more (typical reason is because they failed). |
196 | + // In order to filter them out, we check that they do not exist in |
197 | + // in the DownloadManager. |
198 | + if (!downloadManager.exists(download.downloadId)) { |
199 | + continue; |
200 | + } |
201 | + |
202 | + if (!download.complete && |
203 | + (download.incognito == downloadManager.incognito)) { |
204 | + downloads.push(download.downloadId); |
205 | + } |
206 | + } |
207 | + return downloads; |
208 | + } |
209 | + |
210 | + function listDifference(list, minusList) { |
211 | + return list.filter(function(i) {return minusList.indexOf(i) == -1;}); |
212 | + } |
213 | + |
214 | + function updateDownloads() { |
215 | + var downloadsInProgressBefore = downloadsInProgress; |
216 | + downloadsInProgress = listDownloadsInProgress(); |
217 | + if (!discardFinishedDownloads) { |
218 | + var newDownloadsFinished = listDifference(downloadsInProgressBefore, downloadsInProgress); |
219 | + downloadsFinished = downloadsFinished.concat(newDownloadsFinished); |
220 | + } |
221 | + } |
222 | + |
223 | + onDownloadsChanged: updateDownloads() |
224 | + Component.onCompleted: updateDownloads() |
225 | + |
226 | + property var downloadsModelConnections: Connections { |
227 | + target: DownloadsModel |
228 | + onDataChanged: downloadManager.updateDownloads() |
229 | + onRowCountChanged: downloadManager.updateDownloads() |
230 | + onModelReset: downloadManager.updateDownloads() |
231 | + } |
232 | + |
233 | onDownloadFinished: { |
234 | if (DownloadsModel.contains(download.downloadId)) { |
235 | DownloadsModel.moveToDownloads(download.downloadId, path) |
236 | |
237 | === modified file 'src/app/webbrowser/NavigationBar.qml' |
238 | --- src/app/webbrowser/NavigationBar.qml 2017-02-03 15:11:00 +0000 |
239 | +++ src/app/webbrowser/NavigationBar.qml 2017-03-30 13:48:57 +0000 |
240 | @@ -41,6 +41,7 @@ |
241 | property color fgColor: Theme.palette.normal.baseText |
242 | property color iconColor: UbuntuColors.darkGrey |
243 | property real availableHeight |
244 | + property var downloadManager |
245 | |
246 | onFindInPageModeChanged: if (findInPageMode) addressbar.text = "" |
247 | onIncognitoChanged: findInPageMode = false |
248 | @@ -206,6 +207,19 @@ |
249 | internal.openDrawer.opened = true |
250 | } |
251 | } |
252 | + |
253 | + CountEmblem { |
254 | + anchors { |
255 | + right: parent.right |
256 | + top: parent.top |
257 | + topMargin: units.gu(0.5) |
258 | + } |
259 | + objectName: "countEmblem" |
260 | + readonly property var downloadsInProgress: root.downloadManager ? root.downloadManager.downloadsInProgress : [] |
261 | + readonly property var downloadsFinished: root.downloadManager ? root.downloadManager.downloadsFinished : [] |
262 | + count: downloadsInProgress.length + downloadsFinished.length |
263 | + pulsating: downloadsInProgress.length > 0 |
264 | + } |
265 | } |
266 | } |
267 | } |
268 | @@ -346,7 +360,7 @@ |
269 | left: actionIcon.right |
270 | leftMargin: units.gu(2) |
271 | verticalCenter: parent.verticalCenter |
272 | - right: parent.right |
273 | + right: countEmblem.left |
274 | rightMargin: units.gu(1) |
275 | } |
276 | text: model.text |
277 | @@ -354,6 +368,19 @@ |
278 | color: root.fgColor |
279 | elide: Text.ElideRight |
280 | } |
281 | + |
282 | + CountEmblem { |
283 | + id: countEmblem |
284 | + anchors { |
285 | + top: undefined |
286 | + verticalCenter: parent.verticalCenter |
287 | + right: parent.right |
288 | + rightMargin: units.gu(1) |
289 | + } |
290 | + width: visible ? implicitWidth : 0 |
291 | + count: modelData.count !== undefined ? modelData.count : 0 |
292 | + pulsating: modelData.pulsating !== undefined && modelData.pulsating |
293 | + } |
294 | } |
295 | } |
296 | } |
297 | |
298 | === modified file 'src/app/webbrowser/TabComponent.qml' |
299 | --- src/app/webbrowser/TabComponent.qml 2017-02-15 11:22:05 +0000 |
300 | +++ src/app/webbrowser/TabComponent.qml 2017-03-30 13:48:57 +0000 |
301 | @@ -449,7 +449,6 @@ |
302 | function startDownload(downloadId, download, mimeType) { |
303 | DownloadsModel.add(downloadId, download.url, mimeType, incognito) |
304 | download.start() |
305 | - downloadsViewLoader.active = true |
306 | } |
307 | |
308 | } |
309 | |
310 | === modified file 'src/app/webbrowser/downloads-model.cpp' |
311 | --- src/app/webbrowser/downloads-model.cpp 2016-09-22 09:11:35 +0000 |
312 | +++ src/app/webbrowser/downloads-model.cpp 2017-03-30 13:48:57 +0000 |
313 | @@ -78,6 +78,7 @@ |
314 | createOrAlterDatabaseSchema(); |
315 | endResetModel(); |
316 | Q_EMIT rowCountChanged(); |
317 | + fetchMore(); |
318 | } |
319 | |
320 | void DownloadsModel::createOrAlterDatabaseSchema() |
321 | @@ -451,6 +452,26 @@ |
322 | } |
323 | } |
324 | |
325 | +QVariantMap DownloadsModel::get(int row) |
326 | +{ |
327 | + if (row < 0 || row >= rowCount()) { |
328 | + return QVariantMap(); |
329 | + } |
330 | + |
331 | + QVariantMap res; |
332 | + QHash<int,QByteArray> names = roleNames(); |
333 | + QHashIterator<int, QByteArray> i(names); |
334 | + |
335 | + while (i.hasNext()) { |
336 | + i.next(); |
337 | + QModelIndex idx = index(row, 0); |
338 | + QVariant data = idx.data(i.key()); |
339 | + res[i.value()] = data; |
340 | + } |
341 | + |
342 | + return res; |
343 | +} |
344 | + |
345 | void DownloadsModel::removeExistingEntryFromDatabase(const QString& path) |
346 | { |
347 | QSqlQuery query(m_database); |
348 | |
349 | === modified file 'src/app/webbrowser/downloads-model.h' |
350 | --- src/app/webbrowser/downloads-model.h 2016-09-22 09:11:35 +0000 |
351 | +++ src/app/webbrowser/downloads-model.h 2017-03-30 13:48:57 +0000 |
352 | @@ -73,6 +73,7 @@ |
353 | Q_INVOKABLE void pauseDownload(const QString& downloadId); |
354 | Q_INVOKABLE void resumeDownload(const QString& downloadId); |
355 | Q_INVOKABLE void pruneIncognitoDownloads(); |
356 | + Q_INVOKABLE QVariantMap get(int row); |
357 | |
358 | Q_SIGNALS: |
359 | void databasePathChanged() const; |
360 | |
361 | === modified file 'src/app/webbrowser/webbrowser-app.cpp' |
362 | --- src/app/webbrowser/webbrowser-app.cpp 2017-02-14 10:12:50 +0000 |
363 | +++ src/app/webbrowser/webbrowser-app.cpp 2017-03-30 13:48:57 +0000 |
364 | @@ -83,7 +83,7 @@ |
365 | if (BrowserApplication::initialize("webbrowser/webbrowser-app.qml", QStringLiteral("webbrowser-app"))) { |
366 | QStringList searchEnginesSearchPaths; |
367 | searchEnginesSearchPaths << QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/searchengines"; |
368 | - searchEnginesSearchPaths << UbuntuBrowserDirectory() + "/webbrowser/searchengines"; |
369 | + searchEnginesSearchPaths << UbuntuBrowserDirectory() + "webbrowser/searchengines"; |
370 | m_engine->rootContext()->setContextProperty("searchEnginesSearchPaths", searchEnginesSearchPaths); |
371 | |
372 | m_engine->rootContext()->setContextProperty("__platformName", platformName()); |
373 | |
374 | === modified file 'src/app/webbrowser/webbrowser-app.qml' |
375 | --- src/app/webbrowser/webbrowser-app.qml 2017-03-30 13:48:56 +0000 |
376 | +++ src/app/webbrowser/webbrowser-app.qml 2017-03-30 13:48:57 +0000 |
377 | @@ -87,6 +87,19 @@ |
378 | window.requestActivate() |
379 | } |
380 | |
381 | + function updateDiscardFinishedDownloads() { |
382 | + for (var i = allWindows.length - 1; i >= 0; --i) { |
383 | + var window = allWindows[i] |
384 | + if (window.downloadsViewOpened) { |
385 | + discardFinishedDownloads = true; |
386 | + return; |
387 | + } |
388 | + } |
389 | + discardFinishedDownloads = false; |
390 | + } |
391 | + |
392 | + property bool discardFinishedDownloads: false |
393 | + |
394 | property var windowFactory: Component { |
395 | BrowserWindow { |
396 | id: window |
397 | @@ -95,6 +108,8 @@ |
398 | height: (initialWindowSize.height > 0) ? initialWindowSize.height : defaultHeight |
399 | |
400 | property alias incognito: browser.incognito |
401 | + property alias downloadsViewOpened: browser.downloadsViewOpened |
402 | + onDownloadsViewOpenedChanged: webbrowserapp.updateDiscardFinishedDownloads() |
403 | readonly property alias model: browser.tabsModel |
404 | readonly property var tabsModel: browser.tabsModel |
405 | readonly property bool wide: browser.wide |
406 | @@ -191,6 +206,7 @@ |
407 | thisWindow: window |
408 | settings: webbrowserapp.settings |
409 | windowFactory: webbrowserapp.windowFactory |
410 | + discardFinishedDownloads: webbrowserapp.discardFinishedDownloads |
411 | onNewWindowRequested: { |
412 | var window = windowFactory.createObject( |
413 | null, |
414 | |
415 | === modified file 'tests/qmltests/webbrowser-app/SingleWindowTestCase.qml' |
416 | --- tests/qmltests/webbrowser-app/SingleWindowTestCase.qml 2017-03-30 13:48:56 +0000 |
417 | +++ tests/qmltests/webbrowser-app/SingleWindowTestCase.qml 2017-03-30 13:48:57 +0000 |
418 | @@ -88,10 +88,10 @@ |
419 | } |
420 | |
421 | function open_drawer(action) { |
422 | - var chrome = findChild(window.contentItem, "chrome"); |
423 | - var drawerButton = findChild(chrome, "drawerButton"); |
424 | + var chrome = waitForChild(window.contentItem, "chrome"); |
425 | + var drawerButton = waitForChild(chrome, "drawerButton"); |
426 | clickItem(drawerButton); |
427 | - var drawer = findChild(chrome, "drawer"); |
428 | + var drawer = waitForChild(chrome, "drawer"); |
429 | tryCompare(drawer, "clip", false); |
430 | if (action) { |
431 | clickItem(findChild(drawer, action)); |
432 | |
433 | === modified file 'tests/qmltests/webbrowser-app/WebbrowserAppTestCase.qml' |
434 | --- tests/qmltests/webbrowser-app/WebbrowserAppTestCase.qml 2017-03-30 13:48:56 +0000 |
435 | +++ tests/qmltests/webbrowser-app/WebbrowserAppTestCase.qml 2017-03-30 13:48:57 +0000 |
436 | @@ -44,7 +44,7 @@ |
437 | Loader { |
438 | id: loader |
439 | active: false |
440 | - source: "../../../src/app/webbrowser/webbrowser-app.qml" |
441 | + source: Qt.resolvedUrl("../../../src/app/webbrowser/webbrowser-app.qml") |
442 | } |
443 | |
444 | SignalSpy { |
445 | |
446 | === modified file 'tests/qmltests/webbrowser-app/tst_Downloads.qml' |
447 | --- tests/qmltests/webbrowser-app/tst_Downloads.qml 2017-03-30 13:48:56 +0000 |
448 | +++ tests/qmltests/webbrowser-app/tst_Downloads.qml 2017-03-30 13:48:57 +0000 |
449 | @@ -28,18 +28,34 @@ |
450 | property var optionsDialog: null |
451 | |
452 | function open_downloads() { |
453 | + waitForRendering(window.contentItem); |
454 | open_drawer("downloads"); |
455 | downloadsPage = waitForChild(window.contentItem, "downloadsPage"); |
456 | verify(downloadsPage != null); |
457 | waitForRendering(downloadsPage); |
458 | } |
459 | |
460 | - function test_open_close_downloads_page() { |
461 | - open_downloads(); |
462 | + function close_downloads() { |
463 | var pageHeader = findChild(downloadsPage, "pageHeader"); |
464 | var backButton = waitForChild(pageHeader, "back_button"); |
465 | tryCompare(backButton, "visible", true); |
466 | clickItem(backButton); |
467 | + } |
468 | + |
469 | + function start_download(path) { |
470 | + browse_to(path, false); |
471 | + optionsDialog = |
472 | + waitForChild(window.contentItem, "downloadOptionsDialog"); |
473 | + tryCompare(optionsDialog, "visible", true); |
474 | + var button = findChild(optionsDialog, "downloadFileButton"); |
475 | + clickItem(button); |
476 | + waitForRendering(window.contentItem); |
477 | + } |
478 | + |
479 | + function test_open_close_downloads_page() { |
480 | + open_downloads(); |
481 | + verify(downloadsPage != null); |
482 | + close_downloads(); |
483 | tryCompare(this, "downloadsPage", null); |
484 | } |
485 | |
486 | @@ -91,15 +107,85 @@ |
487 | } |
488 | |
489 | function test_download() { |
490 | - browse_to("test.pdf", false); |
491 | - optionsDialog = |
492 | - waitForChild(window.contentItem, "downloadOptionsDialog"); |
493 | - tryCompare(optionsDialog, "visible", true); |
494 | - var button = findChild(optionsDialog, "downloadFileButton"); |
495 | - clickItem(button); |
496 | - downloadsPage = waitForChild(window.contentItem, "downloadsPage"); |
497 | - verify(downloadsPage != null); |
498 | - tryCompare(downloadsPage, "visible", true); |
499 | + start_download("test.pdf"); |
500 | + var countEmblem = waitForChild(window.contentItem, "countEmblem"); |
501 | + verify(countEmblem != null); |
502 | + tryCompare(countEmblem, "count", 1); |
503 | + tryCompare(countEmblem, "visible", true); |
504 | + open_downloads(); |
505 | + close_downloads(); |
506 | + tryCompare(countEmblem, "visible", false); |
507 | + } |
508 | + |
509 | + function test_multiple_downloads() { |
510 | + var countEmblem = waitForChild(window.contentItem, "countEmblem"); |
511 | + verify(countEmblem != null); |
512 | + tryCompare(countEmblem, "count", 0); |
513 | + tryCompare(countEmblem, "visible", false); |
514 | + |
515 | + // first download |
516 | + start_download("test.pdf"); |
517 | + tryCompare(countEmblem, "count", 1); |
518 | + tryCompare(countEmblem, "visible", true); |
519 | + |
520 | + // second download |
521 | + start_download("test.pdf"); |
522 | + tryCompare(countEmblem, "count", 2); |
523 | + tryCompare(countEmblem, "visible", true); |
524 | + |
525 | + // third download |
526 | + start_download("test.pdf"); |
527 | + tryCompare(countEmblem, "count", 3); |
528 | + tryCompare(countEmblem, "visible", true); |
529 | + |
530 | + open_downloads(); |
531 | + close_downloads(); |
532 | + tryCompare(countEmblem, "count", 0); |
533 | + tryCompare(countEmblem, "visible", false); |
534 | + } |
535 | + |
536 | + function test_download_multiple_windows() { |
537 | + var firstWindow = app.allWindows[0]; |
538 | + open_drawer("newwindow"); |
539 | + tryCompare(app.allWindows, "length", 2); |
540 | + var secondWindow = app.allWindows[1]; |
541 | + |
542 | + var firstCountEmblem = waitForChild(firstWindow.contentItem, "countEmblem"); |
543 | + verify(firstCountEmblem != null); |
544 | + tryCompare(firstCountEmblem, "count", 0); |
545 | + tryCompare(firstCountEmblem, "visible", false); |
546 | + |
547 | + var secondCountEmblem = waitForChild(secondWindow.contentItem, "countEmblem"); |
548 | + verify(secondCountEmblem != null); |
549 | + tryCompare(secondCountEmblem, "count", 0); |
550 | + tryCompare(secondCountEmblem, "visible", false); |
551 | + |
552 | + tryCompare(secondWindow, "active", true); |
553 | + window = secondWindow; |
554 | + start_download("test.pdf"); |
555 | + |
556 | + tryCompare(firstCountEmblem, "count", 1); |
557 | + tryCompare(firstCountEmblem, "visible", true); |
558 | + |
559 | + tryCompare(secondCountEmblem, "count", 1); |
560 | + tryCompare(secondCountEmblem, "visible", true); |
561 | + |
562 | + // Open downloads page in first window, and check that the emblem |
563 | + // is gone in both windows |
564 | + firstWindow.requestActivate(); |
565 | + tryCompare(firstWindow, "active", true); |
566 | + window = firstWindow; |
567 | + |
568 | + open_downloads(); |
569 | + close_downloads(); |
570 | + |
571 | + tryCompare(firstCountEmblem, "count", 0); |
572 | + tryCompare(firstCountEmblem, "visible", false); |
573 | + tryCompare(secondCountEmblem, "count", 0); |
574 | + tryCompare(secondCountEmblem, "visible", false); |
575 | + |
576 | + // Clean up |
577 | + secondWindow.close(); |
578 | } |
579 | |
580 | function test_private_download() { |
581 | @@ -111,6 +197,16 @@ |
582 | verify(privateWindow.incognito); |
583 | tryCompare(privateWindow, "active", true); |
584 | |
585 | + var publicCountEmblem = waitForChild(publicWindow.contentItem, "countEmblem"); |
586 | + verify(publicCountEmblem != null); |
587 | + tryCompare(publicCountEmblem, "count", 0); |
588 | + tryCompare(publicCountEmblem, "visible", false); |
589 | + |
590 | + var privateCountEmblem = waitForChild(privateWindow.contentItem, "countEmblem"); |
591 | + verify(privateCountEmblem != null); |
592 | + tryCompare(privateCountEmblem, "count", 0); |
593 | + tryCompare(privateCountEmblem, "visible", false); |
594 | + |
595 | // Download pdf in private window |
596 | window = privateWindow; |
597 | browse_to("test.pdf", false); |
598 | @@ -119,6 +215,13 @@ |
599 | tryCompare(optionsDialog, "visible", true); |
600 | var button = findChild(optionsDialog, "downloadFileButton"); |
601 | clickItem(button); |
602 | + |
603 | + tryCompare(publicCountEmblem, "count", 0); |
604 | + tryCompare(publicCountEmblem, "visible", false); |
605 | + tryCompare(privateCountEmblem, "count", 1); |
606 | + tryCompare(privateCountEmblem, "visible", true); |
607 | + |
608 | + open_downloads(); |
609 | downloadsPage = waitForChild(window.contentItem, "downloadsPage"); |
610 | verify(downloadsPage != null); |
611 | tryCompare(downloadsPage, "visible", true); |
612 | @@ -128,6 +231,9 @@ |
613 | compare(delegate.url, baseUrl + "test.pdf"); |
614 | verify(delegate.incognito); |
615 | |
616 | + tryCompare(privateCountEmblem, "count", 0); |
617 | + tryCompare(privateCountEmblem, "visible", false); |
618 | + |
619 | // Open downloads page in public window, and check that the private |
620 | // download is not there |
621 | window = publicWindow; |
622 | |
623 | === modified file 'tests/qmltests/webbrowser-app/webbrowser-app-qmltests-launcher.cpp' |
624 | --- tests/qmltests/webbrowser-app/webbrowser-app-qmltests-launcher.cpp 2017-03-30 13:48:56 +0000 |
625 | +++ tests/qmltests/webbrowser-app/webbrowser-app-qmltests-launcher.cpp 2017-03-30 13:48:57 +0000 |
626 | @@ -315,7 +315,8 @@ |
627 | } |
628 | |
629 | QCoreApplication::setOrganizationDomain(QStringLiteral("webbrowser-app-qmltests")); |
630 | - int result = quick_test_main(testArgc, testArgv.data(), "webbrowser-app-qmltests", nullptr); |
631 | + int result = quick_test_main(testArgc, testArgv.data(), "webbrowser-app-qmltests", |
632 | + TestDirectory().absolutePath().toLocal8Bit().constData()); |
633 | httpServer.terminate(); |
634 | httpServer.waitForFinished(); |
635 | return result; |
636 | |
637 | === modified file 'tests/unittests/downloads-model/tst_DownloadsModelTests.cpp' |
638 | --- tests/unittests/downloads-model/tst_DownloadsModelTests.cpp 2016-09-22 11:45:54 +0000 |
639 | +++ tests/unittests/downloads-model/tst_DownloadsModelTests.cpp 2017-03-30 13:48:57 +0000 |
640 | @@ -234,6 +234,19 @@ |
641 | QVERIFY(!model->data(model->index(0, 0), -1).isValid()); |
642 | } |
643 | |
644 | + void shouldReturnDataAsAMap() |
645 | + { |
646 | + model->add(QStringLiteral("testid"), QUrl(QStringLiteral("http://example.org/")), QStringLiteral("text/plain"), false); |
647 | + QVERIFY(model->get(-1).isEmpty()); |
648 | + QVERIFY(!model->get(3)["downloadId"].isValid()); |
649 | + QCOMPARE(model->get(0)["downloadId"].toString(), QStringLiteral("testid")); |
650 | + QCOMPARE(model->get(0)["url"].toUrl(), QUrl(QStringLiteral("http://example.org/"))); |
651 | + QCOMPARE(model->get(0)["mimetype"].toString(), QStringLiteral("text/plain")); |
652 | + QVERIFY(model->get(0)["created"].toDateTime() <= QDateTime::currentDateTime()); |
653 | + QVERIFY(!model->get(0)["complete"].toBool()); |
654 | + QVERIFY(!model->get(0)["incognito"].toBool()); |
655 | + } |
656 | + |
657 | void shouldReturnDatabasePath() |
658 | { |
659 | QCOMPARE(model->databasePath(), QStringLiteral(":memory:")); |
If I initiate a download, I get the animated blue emblem. If I then open the downloads page before the download has completed and keep it open until after the download has completed, I would expect that when closing it, the download emblem is gone, because I obviously know that the download is complete. But it’s still there (turned to green).