Merge lp:~fboucault/webbrowser-app/downloads_emblem into lp:webbrowser-app/staging

Proposed by Florian Boucault
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
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.

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.

To post a comment you must log in.
Revision history for this message
Olivier Tilloy (osomon) wrote : Posted in a previous version of this proposal

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).

review: Needs Fixing
Revision history for this message
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.

Revision history for this message
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.

Revision history for this message
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.

review: Needs Fixing
Revision history for this message
Florian Boucault (fboucault) wrote : Posted in a previous version of this proposal

All 3 issues were fixed.

Revision history for this message
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

Merged lp:~fboucault/webbrowser-app/qmltests

1649. By Florian Boucault

Merged lp:~osomon/webbrowser-app/qmltests

1648. By Florian Boucault

Merged lp:~osomon/webbrowser-app/qmltests

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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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:"));

Subscribers

People subscribed via source and target branches