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
=== modified file 'src/app/browserapplication.cpp'
--- src/app/browserapplication.cpp 2016-10-31 10:53:51 +0000
+++ src/app/browserapplication.cpp 2017-03-30 13:48:57 +0000
@@ -183,6 +183,7 @@
183 if (!isRunningInstalled()) {183 if (!isRunningInstalled()) {
184 m_engine->addImportPath(UbuntuBrowserImportsDirectory());184 m_engine->addImportPath(UbuntuBrowserImportsDirectory());
185 }185 }
186 m_engine->setBaseUrl(QUrl::fromLocalFile(UbuntuBrowserDirectory()));
186 qmlEngineCreated(m_engine);187 qmlEngineCreated(m_engine);
187188
188 QQmlContext* context = m_engine->rootContext();189 QQmlContext* context = m_engine->rootContext();
@@ -190,7 +191,7 @@
190 context->setContextProperty("unversionedAppId", unversionedAppId);191 context->setContextProperty("unversionedAppId", unversionedAppId);
191192
192 m_component = new QQmlComponent(m_engine);193 m_component = new QQmlComponent(m_engine);
193 m_component->loadUrl(QUrl::fromLocalFile(UbuntuBrowserDirectory() + "/" + qmlFileSubPath));194 m_component->loadUrl(qmlFileSubPath);
194 if (!m_component->isReady()) {195 if (!m_component->isReady()) {
195 qWarning() << m_component->errorString();196 qWarning() << m_component->errorString();
196 return false;197 return false;
197198
=== modified file 'src/app/config.h.in'
--- src/app/config.h.in 2016-07-12 11:54:37 +0000
+++ src/app/config.h.in 2017-03-30 13:48:57 +0000
@@ -35,9 +35,9 @@
35inline QString UbuntuBrowserDirectory()35inline QString UbuntuBrowserDirectory()
36{36{
37 if (isRunningInstalled()) {37 if (isRunningInstalled()) {
38 return qgetenv("SNAP").append("@CMAKE_INSTALL_FULL_DATADIR@/webbrowser-app");38 return qgetenv("SNAP").append("@CMAKE_INSTALL_FULL_DATADIR@/webbrowser-app/");
39 } else {39 } else {
40 return QStringLiteral("@CMAKE_SOURCE_DIR@/src/app");40 return QStringLiteral("@CMAKE_SOURCE_DIR@/src/app/");
41 }41 }
42}42}
4343
4444
=== modified file 'src/app/webbrowser/Browser.qml'
--- src/app/webbrowser/Browser.qml 2017-03-30 13:48:56 +0000
+++ src/app/webbrowser/Browser.qml 2017-03-30 13:48:57 +0000
@@ -40,6 +40,8 @@
40 currentWebview: tabsModel && tabsModel.currentTab ? tabsModel.currentTab.webview : null40 currentWebview: tabsModel && tabsModel.currentTab ? tabsModel.currentTab.webview : null
4141
42 property bool incognito: false42 property bool incognito: false
43 property bool downloadsViewOpened: downloadsViewLoader.status == Loader.Ready
44 property bool discardFinishedDownloads: false
4345
44 property var tabsModel: TabsModel {46 property var tabsModel: TabsModel {
45 // These methods are required by the TabsBar component47 // These methods are required by the TabsBar component
@@ -523,6 +525,7 @@
523 objectName: "chrome"525 objectName: "chrome"
524526
525 tab: internal.nextTab || tabsModel.currentTab527 tab: internal.nextTab || tabsModel.currentTab
528 downloadManager: downloadHandlerLoader.item
526 tabsModel: browser.tabsModel529 tabsModel: browser.tabsModel
527 searchUrl: currentSearchEngine.urlTemplate530 searchUrl: currentSearchEngine.urlTemplate
528531
@@ -627,6 +630,10 @@
627 iconName: "save"630 iconName: "save"
628 enabled: downloadHandlerLoader.status == Loader.Ready && contentHandlerLoader.status == Loader.Ready631 enabled: downloadHandlerLoader.status == Loader.Ready && contentHandlerLoader.status == Loader.Ready
629 onTriggered: downloadsViewLoader.active = true632 onTriggered: downloadsViewLoader.active = true
633 property var downloadsInProgress: downloadHandlerLoader.item ? downloadHandlerLoader.item.downloadsInProgress : []
634 property var downloadsFinished: downloadHandlerLoader.item ? downloadHandlerLoader.item.downloadsFinished : []
635 property int count: downloadsInProgress.length + downloadsFinished.length
636 property bool pulsating: downloadsInProgress.length > 0
630 },637 },
631 Action {638 Action {
632 objectName: "settings"639 objectName: "settings"
@@ -991,8 +998,10 @@
991998
992 Loader {999 Loader {
993 id: downloadHandlerLoader1000 id: downloadHandlerLoader
994 source: "DownloadHandler.qml"
995 asynchronous: true1001 asynchronous: true
1002 Component.onCompleted: setSource("DownloadHandler.qml",
1003 {"incognito": Qt.binding(function () {return browser.incognito}),
1004 "discardFinishedDownloads": Qt.binding(function () {return browser.discardFinishedDownloads})})
996 }1005 }
9971006
998 property Component tabComponent1007 property Component tabComponent
9991008
=== modified file 'src/app/webbrowser/Chrome.qml'
--- src/app/webbrowser/Chrome.qml 2017-02-14 10:12:50 +0000
+++ src/app/webbrowser/Chrome.qml 2017-03-30 13:48:57 +0000
@@ -25,6 +25,7 @@
2525
26 property var tabsModel26 property var tabsModel
27 property alias tab: navigationBar.tab27 property alias tab: navigationBar.tab
28 property alias downloadManager: navigationBar.downloadManager
28 readonly property var webview: tab ? tab.webview : null29 readonly property var webview: tab ? tab.webview : null
29 property alias searchUrl: navigationBar.searchUrl30 property alias searchUrl: navigationBar.searchUrl
30 property alias text: navigationBar.text31 property alias text: navigationBar.text
3132
=== added file 'src/app/webbrowser/CountEmblem.qml'
--- src/app/webbrowser/CountEmblem.qml 1970-01-01 00:00:00 +0000
+++ src/app/webbrowser/CountEmblem.qml 2017-03-30 13:48:57 +0000
@@ -0,0 +1,66 @@
1/*
2 * Copyright 2017 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.4
20import Ubuntu.Components 1.3
21
22Item {
23 id: countEmblem
24
25 property int count: 0
26 property bool pulsating: false
27 readonly property real maxWidth: parent.width
28
29 implicitWidth: Math.min(maxWidth, Math.max(units.gu(2), countLabel.implicitWidth + units.gu(1)))
30 implicitHeight: units.gu(2)
31 visible: countEmblem.count > 0
32
33 UbuntuShape {
34 anchors.fill: parent
35 anchors.margins: -units.dp(1)
36 backgroundColor: Qt.darker(backgroundShape.backgroundColor, 1.3)
37 aspect: UbuntuShape.Flat
38
39 opacity: 0
40 SequentialAnimation on opacity {
41 running: countEmblem.pulsating
42 alwaysRunToEnd: true
43 loops: Animation.Infinite
44 NumberAnimation { to: 1; duration: UbuntuAnimation.SlowDuration; easing: UbuntuAnimation.StandardEasingReverse }
45 NumberAnimation { to: 0; duration: UbuntuAnimation.SlowDuration; easing: UbuntuAnimation.StandardEasing }
46 }
47 }
48
49 UbuntuShape {
50 id: backgroundShape
51 anchors.fill: parent
52 backgroundColor: pulsating ? theme.palette.normal.activity : theme.palette.normal.positive
53 aspect: UbuntuShape.Flat
54 }
55
56 Label {
57 id: countLabel
58 text: countEmblem.count
59 anchors.centerIn: parent
60 width: countEmblem.maxWidth - units.gu(1)
61 horizontalAlignment: Text.AlignHCenter
62 elide: Text.ElideRight
63 color: pulsating ? theme.palette.normal.activityText : theme.palette.normal.positiveText
64 textSize: Label.Small
65 }
66}
067
=== modified file 'src/app/webbrowser/DownloadHandler.qml'
--- src/app/webbrowser/DownloadHandler.qml 2016-01-12 11:06:49 +0000
+++ src/app/webbrowser/DownloadHandler.qml 2017-03-30 13:48:57 +0000
@@ -21,6 +21,67 @@
21import webbrowserapp.private 0.121import webbrowserapp.private 0.1
2222
23DownloadManager {23DownloadManager {
24 id: downloadManager
25
26 property var downloadsInProgress: []
27 property var downloadsFinished: []
28 property bool incognito: false
29 property bool discardFinishedDownloads: false
30 onDiscardFinishedDownloadsChanged: if (discardFinishedDownloads) downloadsFinished = []
31
32 function exists(downloadId) {
33 for(var i = 0; i < downloadManager.downloads.length; i++) {
34 var download = downloadManager.downloads[i];
35 if (download.downloadId == downloadId) {
36 return true;
37 }
38 }
39 return false;
40 }
41
42 function listDownloadsInProgress() {
43 var downloads = [];
44 for(var i = 0; i < DownloadsModel.count; i++) {
45 var download = DownloadsModel.get(i);
46 // There can be downloads in DownloadsModel which are not 'complete'
47 // but not in progress any more (typical reason is because they failed).
48 // In order to filter them out, we check that they do not exist in
49 // in the DownloadManager.
50 if (!downloadManager.exists(download.downloadId)) {
51 continue;
52 }
53
54 if (!download.complete &&
55 (download.incognito == downloadManager.incognito)) {
56 downloads.push(download.downloadId);
57 }
58 }
59 return downloads;
60 }
61
62 function listDifference(list, minusList) {
63 return list.filter(function(i) {return minusList.indexOf(i) == -1;});
64 }
65
66 function updateDownloads() {
67 var downloadsInProgressBefore = downloadsInProgress;
68 downloadsInProgress = listDownloadsInProgress();
69 if (!discardFinishedDownloads) {
70 var newDownloadsFinished = listDifference(downloadsInProgressBefore, downloadsInProgress);
71 downloadsFinished = downloadsFinished.concat(newDownloadsFinished);
72 }
73 }
74
75 onDownloadsChanged: updateDownloads()
76 Component.onCompleted: updateDownloads()
77
78 property var downloadsModelConnections: Connections {
79 target: DownloadsModel
80 onDataChanged: downloadManager.updateDownloads()
81 onRowCountChanged: downloadManager.updateDownloads()
82 onModelReset: downloadManager.updateDownloads()
83 }
84
24 onDownloadFinished: {85 onDownloadFinished: {
25 if (DownloadsModel.contains(download.downloadId)) {86 if (DownloadsModel.contains(download.downloadId)) {
26 DownloadsModel.moveToDownloads(download.downloadId, path)87 DownloadsModel.moveToDownloads(download.downloadId, path)
2788
=== modified file 'src/app/webbrowser/NavigationBar.qml'
--- src/app/webbrowser/NavigationBar.qml 2017-02-03 15:11:00 +0000
+++ src/app/webbrowser/NavigationBar.qml 2017-03-30 13:48:57 +0000
@@ -41,6 +41,7 @@
41 property color fgColor: Theme.palette.normal.baseText41 property color fgColor: Theme.palette.normal.baseText
42 property color iconColor: UbuntuColors.darkGrey42 property color iconColor: UbuntuColors.darkGrey
43 property real availableHeight43 property real availableHeight
44 property var downloadManager
4445
45 onFindInPageModeChanged: if (findInPageMode) addressbar.text = ""46 onFindInPageModeChanged: if (findInPageMode) addressbar.text = ""
46 onIncognitoChanged: findInPageMode = false47 onIncognitoChanged: findInPageMode = false
@@ -206,6 +207,19 @@
206 internal.openDrawer.opened = true207 internal.openDrawer.opened = true
207 }208 }
208 }209 }
210
211 CountEmblem {
212 anchors {
213 right: parent.right
214 top: parent.top
215 topMargin: units.gu(0.5)
216 }
217 objectName: "countEmblem"
218 readonly property var downloadsInProgress: root.downloadManager ? root.downloadManager.downloadsInProgress : []
219 readonly property var downloadsFinished: root.downloadManager ? root.downloadManager.downloadsFinished : []
220 count: downloadsInProgress.length + downloadsFinished.length
221 pulsating: downloadsInProgress.length > 0
222 }
209 }223 }
210 }224 }
211 }225 }
@@ -346,7 +360,7 @@
346 left: actionIcon.right360 left: actionIcon.right
347 leftMargin: units.gu(2)361 leftMargin: units.gu(2)
348 verticalCenter: parent.verticalCenter362 verticalCenter: parent.verticalCenter
349 right: parent.right363 right: countEmblem.left
350 rightMargin: units.gu(1)364 rightMargin: units.gu(1)
351 }365 }
352 text: model.text366 text: model.text
@@ -354,6 +368,19 @@
354 color: root.fgColor368 color: root.fgColor
355 elide: Text.ElideRight369 elide: Text.ElideRight
356 }370 }
371
372 CountEmblem {
373 id: countEmblem
374 anchors {
375 top: undefined
376 verticalCenter: parent.verticalCenter
377 right: parent.right
378 rightMargin: units.gu(1)
379 }
380 width: visible ? implicitWidth : 0
381 count: modelData.count !== undefined ? modelData.count : 0
382 pulsating: modelData.pulsating !== undefined && modelData.pulsating
383 }
357 }384 }
358 }385 }
359 }386 }
360387
=== modified file 'src/app/webbrowser/TabComponent.qml'
--- src/app/webbrowser/TabComponent.qml 2017-02-15 11:22:05 +0000
+++ src/app/webbrowser/TabComponent.qml 2017-03-30 13:48:57 +0000
@@ -449,7 +449,6 @@
449 function startDownload(downloadId, download, mimeType) {449 function startDownload(downloadId, download, mimeType) {
450 DownloadsModel.add(downloadId, download.url, mimeType, incognito)450 DownloadsModel.add(downloadId, download.url, mimeType, incognito)
451 download.start()451 download.start()
452 downloadsViewLoader.active = true
453 }452 }
454453
455 }454 }
456455
=== modified file 'src/app/webbrowser/downloads-model.cpp'
--- src/app/webbrowser/downloads-model.cpp 2016-09-22 09:11:35 +0000
+++ src/app/webbrowser/downloads-model.cpp 2017-03-30 13:48:57 +0000
@@ -78,6 +78,7 @@
78 createOrAlterDatabaseSchema();78 createOrAlterDatabaseSchema();
79 endResetModel();79 endResetModel();
80 Q_EMIT rowCountChanged();80 Q_EMIT rowCountChanged();
81 fetchMore();
81}82}
8283
83void DownloadsModel::createOrAlterDatabaseSchema()84void DownloadsModel::createOrAlterDatabaseSchema()
@@ -451,6 +452,26 @@
451 }452 }
452}453}
453454
455QVariantMap DownloadsModel::get(int row)
456{
457 if (row < 0 || row >= rowCount()) {
458 return QVariantMap();
459 }
460
461 QVariantMap res;
462 QHash<int,QByteArray> names = roleNames();
463 QHashIterator<int, QByteArray> i(names);
464
465 while (i.hasNext()) {
466 i.next();
467 QModelIndex idx = index(row, 0);
468 QVariant data = idx.data(i.key());
469 res[i.value()] = data;
470 }
471
472 return res;
473}
474
454void DownloadsModel::removeExistingEntryFromDatabase(const QString& path)475void DownloadsModel::removeExistingEntryFromDatabase(const QString& path)
455{476{
456 QSqlQuery query(m_database);477 QSqlQuery query(m_database);
457478
=== modified file 'src/app/webbrowser/downloads-model.h'
--- src/app/webbrowser/downloads-model.h 2016-09-22 09:11:35 +0000
+++ src/app/webbrowser/downloads-model.h 2017-03-30 13:48:57 +0000
@@ -73,6 +73,7 @@
73 Q_INVOKABLE void pauseDownload(const QString& downloadId);73 Q_INVOKABLE void pauseDownload(const QString& downloadId);
74 Q_INVOKABLE void resumeDownload(const QString& downloadId);74 Q_INVOKABLE void resumeDownload(const QString& downloadId);
75 Q_INVOKABLE void pruneIncognitoDownloads();75 Q_INVOKABLE void pruneIncognitoDownloads();
76 Q_INVOKABLE QVariantMap get(int row);
7677
77Q_SIGNALS:78Q_SIGNALS:
78 void databasePathChanged() const;79 void databasePathChanged() const;
7980
=== modified file 'src/app/webbrowser/webbrowser-app.cpp'
--- src/app/webbrowser/webbrowser-app.cpp 2017-02-14 10:12:50 +0000
+++ src/app/webbrowser/webbrowser-app.cpp 2017-03-30 13:48:57 +0000
@@ -83,7 +83,7 @@
83 if (BrowserApplication::initialize("webbrowser/webbrowser-app.qml", QStringLiteral("webbrowser-app"))) {83 if (BrowserApplication::initialize("webbrowser/webbrowser-app.qml", QStringLiteral("webbrowser-app"))) {
84 QStringList searchEnginesSearchPaths;84 QStringList searchEnginesSearchPaths;
85 searchEnginesSearchPaths << QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/searchengines";85 searchEnginesSearchPaths << QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/searchengines";
86 searchEnginesSearchPaths << UbuntuBrowserDirectory() + "/webbrowser/searchengines";86 searchEnginesSearchPaths << UbuntuBrowserDirectory() + "webbrowser/searchengines";
87 m_engine->rootContext()->setContextProperty("searchEnginesSearchPaths", searchEnginesSearchPaths);87 m_engine->rootContext()->setContextProperty("searchEnginesSearchPaths", searchEnginesSearchPaths);
8888
89 m_engine->rootContext()->setContextProperty("__platformName", platformName());89 m_engine->rootContext()->setContextProperty("__platformName", platformName());
9090
=== modified file 'src/app/webbrowser/webbrowser-app.qml'
--- src/app/webbrowser/webbrowser-app.qml 2017-03-30 13:48:56 +0000
+++ src/app/webbrowser/webbrowser-app.qml 2017-03-30 13:48:57 +0000
@@ -87,6 +87,19 @@
87 window.requestActivate()87 window.requestActivate()
88 }88 }
8989
90 function updateDiscardFinishedDownloads() {
91 for (var i = allWindows.length - 1; i >= 0; --i) {
92 var window = allWindows[i]
93 if (window.downloadsViewOpened) {
94 discardFinishedDownloads = true;
95 return;
96 }
97 }
98 discardFinishedDownloads = false;
99 }
100
101 property bool discardFinishedDownloads: false
102
90 property var windowFactory: Component {103 property var windowFactory: Component {
91 BrowserWindow {104 BrowserWindow {
92 id: window105 id: window
@@ -95,6 +108,8 @@
95 height: (initialWindowSize.height > 0) ? initialWindowSize.height : defaultHeight108 height: (initialWindowSize.height > 0) ? initialWindowSize.height : defaultHeight
96109
97 property alias incognito: browser.incognito110 property alias incognito: browser.incognito
111 property alias downloadsViewOpened: browser.downloadsViewOpened
112 onDownloadsViewOpenedChanged: webbrowserapp.updateDiscardFinishedDownloads()
98 readonly property alias model: browser.tabsModel113 readonly property alias model: browser.tabsModel
99 readonly property var tabsModel: browser.tabsModel114 readonly property var tabsModel: browser.tabsModel
100 readonly property bool wide: browser.wide115 readonly property bool wide: browser.wide
@@ -191,6 +206,7 @@
191 thisWindow: window206 thisWindow: window
192 settings: webbrowserapp.settings207 settings: webbrowserapp.settings
193 windowFactory: webbrowserapp.windowFactory208 windowFactory: webbrowserapp.windowFactory
209 discardFinishedDownloads: webbrowserapp.discardFinishedDownloads
194 onNewWindowRequested: {210 onNewWindowRequested: {
195 var window = windowFactory.createObject(211 var window = windowFactory.createObject(
196 null,212 null,
197213
=== modified file 'tests/qmltests/webbrowser-app/SingleWindowTestCase.qml'
--- tests/qmltests/webbrowser-app/SingleWindowTestCase.qml 2017-03-30 13:48:56 +0000
+++ tests/qmltests/webbrowser-app/SingleWindowTestCase.qml 2017-03-30 13:48:57 +0000
@@ -88,10 +88,10 @@
88 }88 }
8989
90 function open_drawer(action) {90 function open_drawer(action) {
91 var chrome = findChild(window.contentItem, "chrome");91 var chrome = waitForChild(window.contentItem, "chrome");
92 var drawerButton = findChild(chrome, "drawerButton");92 var drawerButton = waitForChild(chrome, "drawerButton");
93 clickItem(drawerButton);93 clickItem(drawerButton);
94 var drawer = findChild(chrome, "drawer");94 var drawer = waitForChild(chrome, "drawer");
95 tryCompare(drawer, "clip", false);95 tryCompare(drawer, "clip", false);
96 if (action) {96 if (action) {
97 clickItem(findChild(drawer, action));97 clickItem(findChild(drawer, action));
9898
=== modified file 'tests/qmltests/webbrowser-app/WebbrowserAppTestCase.qml'
--- tests/qmltests/webbrowser-app/WebbrowserAppTestCase.qml 2017-03-30 13:48:56 +0000
+++ tests/qmltests/webbrowser-app/WebbrowserAppTestCase.qml 2017-03-30 13:48:57 +0000
@@ -44,7 +44,7 @@
44 Loader {44 Loader {
45 id: loader45 id: loader
46 active: false46 active: false
47 source: "../../../src/app/webbrowser/webbrowser-app.qml"47 source: Qt.resolvedUrl("../../../src/app/webbrowser/webbrowser-app.qml")
48 }48 }
4949
50 SignalSpy {50 SignalSpy {
5151
=== modified file 'tests/qmltests/webbrowser-app/tst_Downloads.qml'
--- tests/qmltests/webbrowser-app/tst_Downloads.qml 2017-03-30 13:48:56 +0000
+++ tests/qmltests/webbrowser-app/tst_Downloads.qml 2017-03-30 13:48:57 +0000
@@ -28,18 +28,34 @@
28 property var optionsDialog: null28 property var optionsDialog: null
2929
30 function open_downloads() {30 function open_downloads() {
31 waitForRendering(window.contentItem);
31 open_drawer("downloads");32 open_drawer("downloads");
32 downloadsPage = waitForChild(window.contentItem, "downloadsPage");33 downloadsPage = waitForChild(window.contentItem, "downloadsPage");
33 verify(downloadsPage != null);34 verify(downloadsPage != null);
34 waitForRendering(downloadsPage);35 waitForRendering(downloadsPage);
35 }36 }
3637
37 function test_open_close_downloads_page() {38 function close_downloads() {
38 open_downloads();
39 var pageHeader = findChild(downloadsPage, "pageHeader");39 var pageHeader = findChild(downloadsPage, "pageHeader");
40 var backButton = waitForChild(pageHeader, "back_button");40 var backButton = waitForChild(pageHeader, "back_button");
41 tryCompare(backButton, "visible", true);41 tryCompare(backButton, "visible", true);
42 clickItem(backButton);42 clickItem(backButton);
43 }
44
45 function start_download(path) {
46 browse_to(path, false);
47 optionsDialog =
48 waitForChild(window.contentItem, "downloadOptionsDialog");
49 tryCompare(optionsDialog, "visible", true);
50 var button = findChild(optionsDialog, "downloadFileButton");
51 clickItem(button);
52 waitForRendering(window.contentItem);
53 }
54
55 function test_open_close_downloads_page() {
56 open_downloads();
57 verify(downloadsPage != null);
58 close_downloads();
43 tryCompare(this, "downloadsPage", null);59 tryCompare(this, "downloadsPage", null);
44 }60 }
4561
@@ -91,15 +107,85 @@
91 }107 }
92108
93 function test_download() {109 function test_download() {
94 browse_to("test.pdf", false);110 start_download("test.pdf");
95 optionsDialog =111 var countEmblem = waitForChild(window.contentItem, "countEmblem");
96 waitForChild(window.contentItem, "downloadOptionsDialog");112 verify(countEmblem != null);
97 tryCompare(optionsDialog, "visible", true);113 tryCompare(countEmblem, "count", 1);
98 var button = findChild(optionsDialog, "downloadFileButton");114 tryCompare(countEmblem, "visible", true);
99 clickItem(button);115 open_downloads();
100 downloadsPage = waitForChild(window.contentItem, "downloadsPage");116 close_downloads();
101 verify(downloadsPage != null);117 tryCompare(countEmblem, "visible", false);
102 tryCompare(downloadsPage, "visible", true);118 }
119
120 function test_multiple_downloads() {
121 var countEmblem = waitForChild(window.contentItem, "countEmblem");
122 verify(countEmblem != null);
123 tryCompare(countEmblem, "count", 0);
124 tryCompare(countEmblem, "visible", false);
125
126 // first download
127 start_download("test.pdf");
128 tryCompare(countEmblem, "count", 1);
129 tryCompare(countEmblem, "visible", true);
130
131 // second download
132 start_download("test.pdf");
133 tryCompare(countEmblem, "count", 2);
134 tryCompare(countEmblem, "visible", true);
135
136 // third download
137 start_download("test.pdf");
138 tryCompare(countEmblem, "count", 3);
139 tryCompare(countEmblem, "visible", true);
140
141 open_downloads();
142 close_downloads();
143 tryCompare(countEmblem, "count", 0);
144 tryCompare(countEmblem, "visible", false);
145 }
146
147 function test_download_multiple_windows() {
148 var firstWindow = app.allWindows[0];
149 open_drawer("newwindow");
150 tryCompare(app.allWindows, "length", 2);
151 var secondWindow = app.allWindows[1];
152
153 var firstCountEmblem = waitForChild(firstWindow.contentItem, "countEmblem");
154 verify(firstCountEmblem != null);
155 tryCompare(firstCountEmblem, "count", 0);
156 tryCompare(firstCountEmblem, "visible", false);
157
158 var secondCountEmblem = waitForChild(secondWindow.contentItem, "countEmblem");
159 verify(secondCountEmblem != null);
160 tryCompare(secondCountEmblem, "count", 0);
161 tryCompare(secondCountEmblem, "visible", false);
162
163 tryCompare(secondWindow, "active", true);
164 window = secondWindow;
165 start_download("test.pdf");
166
167 tryCompare(firstCountEmblem, "count", 1);
168 tryCompare(firstCountEmblem, "visible", true);
169
170 tryCompare(secondCountEmblem, "count", 1);
171 tryCompare(secondCountEmblem, "visible", true);
172
173 // Open downloads page in first window, and check that the emblem
174 // is gone in both windows
175 firstWindow.requestActivate();
176 tryCompare(firstWindow, "active", true);
177 window = firstWindow;
178
179 open_downloads();
180 close_downloads();
181
182 tryCompare(firstCountEmblem, "count", 0);
183 tryCompare(firstCountEmblem, "visible", false);
184 tryCompare(secondCountEmblem, "count", 0);
185 tryCompare(secondCountEmblem, "visible", false);
186
187 // Clean up
188 secondWindow.close();
103 }189 }
104190
105 function test_private_download() {191 function test_private_download() {
@@ -111,6 +197,16 @@
111 verify(privateWindow.incognito);197 verify(privateWindow.incognito);
112 tryCompare(privateWindow, "active", true);198 tryCompare(privateWindow, "active", true);
113199
200 var publicCountEmblem = waitForChild(publicWindow.contentItem, "countEmblem");
201 verify(publicCountEmblem != null);
202 tryCompare(publicCountEmblem, "count", 0);
203 tryCompare(publicCountEmblem, "visible", false);
204
205 var privateCountEmblem = waitForChild(privateWindow.contentItem, "countEmblem");
206 verify(privateCountEmblem != null);
207 tryCompare(privateCountEmblem, "count", 0);
208 tryCompare(privateCountEmblem, "visible", false);
209
114 // Download pdf in private window210 // Download pdf in private window
115 window = privateWindow;211 window = privateWindow;
116 browse_to("test.pdf", false);212 browse_to("test.pdf", false);
@@ -119,6 +215,13 @@
119 tryCompare(optionsDialog, "visible", true);215 tryCompare(optionsDialog, "visible", true);
120 var button = findChild(optionsDialog, "downloadFileButton");216 var button = findChild(optionsDialog, "downloadFileButton");
121 clickItem(button);217 clickItem(button);
218
219 tryCompare(publicCountEmblem, "count", 0);
220 tryCompare(publicCountEmblem, "visible", false);
221 tryCompare(privateCountEmblem, "count", 1);
222 tryCompare(privateCountEmblem, "visible", true);
223
224 open_downloads();
122 downloadsPage = waitForChild(window.contentItem, "downloadsPage");225 downloadsPage = waitForChild(window.contentItem, "downloadsPage");
123 verify(downloadsPage != null);226 verify(downloadsPage != null);
124 tryCompare(downloadsPage, "visible", true);227 tryCompare(downloadsPage, "visible", true);
@@ -128,6 +231,9 @@
128 compare(delegate.url, baseUrl + "test.pdf");231 compare(delegate.url, baseUrl + "test.pdf");
129 verify(delegate.incognito);232 verify(delegate.incognito);
130233
234 tryCompare(privateCountEmblem, "count", 0);
235 tryCompare(privateCountEmblem, "visible", false);
236
131 // Open downloads page in public window, and check that the private237 // Open downloads page in public window, and check that the private
132 // download is not there238 // download is not there
133 window = publicWindow;239 window = publicWindow;
134240
=== modified file 'tests/qmltests/webbrowser-app/webbrowser-app-qmltests-launcher.cpp'
--- tests/qmltests/webbrowser-app/webbrowser-app-qmltests-launcher.cpp 2017-03-30 13:48:56 +0000
+++ tests/qmltests/webbrowser-app/webbrowser-app-qmltests-launcher.cpp 2017-03-30 13:48:57 +0000
@@ -315,7 +315,8 @@
315 }315 }
316316
317 QCoreApplication::setOrganizationDomain(QStringLiteral("webbrowser-app-qmltests"));317 QCoreApplication::setOrganizationDomain(QStringLiteral("webbrowser-app-qmltests"));
318 int result = quick_test_main(testArgc, testArgv.data(), "webbrowser-app-qmltests", nullptr);318 int result = quick_test_main(testArgc, testArgv.data(), "webbrowser-app-qmltests",
319 TestDirectory().absolutePath().toLocal8Bit().constData());
319 httpServer.terminate();320 httpServer.terminate();
320 httpServer.waitForFinished();321 httpServer.waitForFinished();
321 return result;322 return result;
322323
=== modified file 'tests/unittests/downloads-model/tst_DownloadsModelTests.cpp'
--- tests/unittests/downloads-model/tst_DownloadsModelTests.cpp 2016-09-22 11:45:54 +0000
+++ tests/unittests/downloads-model/tst_DownloadsModelTests.cpp 2017-03-30 13:48:57 +0000
@@ -234,6 +234,19 @@
234 QVERIFY(!model->data(model->index(0, 0), -1).isValid());234 QVERIFY(!model->data(model->index(0, 0), -1).isValid());
235 }235 }
236236
237 void shouldReturnDataAsAMap()
238 {
239 model->add(QStringLiteral("testid"), QUrl(QStringLiteral("http://example.org/")), QStringLiteral("text/plain"), false);
240 QVERIFY(model->get(-1).isEmpty());
241 QVERIFY(!model->get(3)["downloadId"].isValid());
242 QCOMPARE(model->get(0)["downloadId"].toString(), QStringLiteral("testid"));
243 QCOMPARE(model->get(0)["url"].toUrl(), QUrl(QStringLiteral("http://example.org/")));
244 QCOMPARE(model->get(0)["mimetype"].toString(), QStringLiteral("text/plain"));
245 QVERIFY(model->get(0)["created"].toDateTime() <= QDateTime::currentDateTime());
246 QVERIFY(!model->get(0)["complete"].toBool());
247 QVERIFY(!model->get(0)["incognito"].toBool());
248 }
249
237 void shouldReturnDatabasePath()250 void shouldReturnDatabasePath()
238 {251 {
239 QCOMPARE(model->databasePath(), QStringLiteral(":memory:"));252 QCOMPARE(model->databasePath(), QStringLiteral(":memory:"));

Subscribers

People subscribed via source and target branches