Merge lp:webbrowser-app/staging into lp:webbrowser-app

Proposed by Olivier Tilloy
Status: Merged
Merged at revision: 1560
Proposed branch: lp:webbrowser-app/staging
Merge into: lp:webbrowser-app
Diff against target: 2840 lines (+1499/-148)
63 files modified
.bzrignore (+0/-2)
debian/control (+7/-2)
debian/rules (+1/-1)
snapcraft.yaml (+8/-16)
src/Ubuntu/Web/ua-overrides-desktop.js.in (+9/-0)
src/Ubuntu/Web/ua-overrides-mobile.js.in (+3/-0)
src/app/ChromeBase.qml (+1/-0)
src/app/webbrowser/Browser.qml (+158/-29)
src/app/webbrowser/BrowserTab.qml (+19/-2)
src/app/webbrowser/CMakeLists.txt (+2/-0)
src/app/webbrowser/Chrome.qml (+12/-2)
src/app/webbrowser/ContextMenuMobile.qml (+10/-2)
src/app/webbrowser/Suggestions.qml (+1/-1)
src/app/webbrowser/TabComponent.qml (+33/-15)
src/app/webbrowser/TabItem.qml (+2/-2)
src/app/webbrowser/TabsBar.qml (+112/-15)
src/app/webbrowser/TabsList.qml (+2/-2)
src/app/webbrowser/drag-helper.cpp (+203/-0)
src/app/webbrowser/drag-helper.h (+91/-0)
src/app/webbrowser/reparenter.cpp (+124/-0)
src/app/webbrowser/reparenter.h (+46/-0)
src/app/webbrowser/webbrowser-app.cpp (+6/-0)
src/app/webbrowser/webbrowser-app.qml (+33/-3)
src/app/webcontainer/ContextMenuMobile.qml (+10/-2)
src/app/webcontainer/WebappWebview.qml (+5/-4)
tests/autopilot/webbrowser_app/emulators/browser.py (+7/-1)
tests/autopilot/webbrowser_app/tests/__init__.py (+40/-7)
tests/autopilot/webbrowser_app/tests/test_downloads.py (+62/-10)
tests/autopilot/webbrowser_app/tests/test_history.py (+30/-4)
tests/autopilot/webbrowser_app/tests/test_multiple_windows.py (+222/-0)
tests/autopilot/webbrowser_app/tests/test_new_tab_view.py (+10/-0)
tests/unittests/bookmarks-folder-model/CMakeLists.txt (+1/-1)
tests/unittests/bookmarks-folderlist-model/CMakeLists.txt (+1/-1)
tests/unittests/bookmarks-model/CMakeLists.txt (+1/-1)
tests/unittests/container-url-patterns/CMakeLists.txt (+1/-1)
tests/unittests/cookie-store/CMakeLists.txt (+1/-1)
tests/unittests/domain-utils/CMakeLists.txt (+1/-1)
tests/unittests/downloads-model/CMakeLists.txt (+1/-1)
tests/unittests/favicon-fetcher/CMakeLists.txt (+1/-1)
tests/unittests/history-domain-model/CMakeLists.txt (+1/-1)
tests/unittests/history-domainlist-model/CMakeLists.txt (+1/-1)
tests/unittests/history-lastvisitdatelist-model/CMakeLists.txt (+1/-1)
tests/unittests/history-model/CMakeLists.txt (+1/-1)
tests/unittests/intent-filter/CMakeLists.txt (+1/-1)
tests/unittests/limit-proxy-model/CMakeLists.txt (+1/-1)
tests/unittests/meminfo/CMakeLists.txt (+1/-1)
tests/unittests/oxide-cookie-helper/CMakeLists.txt (+1/-1)
tests/unittests/qml/CMakeLists.txt (+2/-0)
tests/unittests/qml/ReparenterFakeContainer.qml (+40/-0)
tests/unittests/qml/ReparenterFakeTab.qml (+37/-0)
tests/unittests/qml/tst_BrowserTab.qml (+3/-2)
tests/unittests/qml/tst_QmlTests.cpp (+7/-0)
tests/unittests/qml/tst_Reparenter.qml (+114/-0)
tests/unittests/qml/tst_TabsBar.qml (+2/-0)
tests/unittests/qml/tst_UbuntuWebView02.qml (+1/-0)
tests/unittests/search-engine/CMakeLists.txt (+1/-1)
tests/unittests/session-storage/CMakeLists.txt (+1/-1)
tests/unittests/session-utils/CMakeLists.txt (+1/-1)
tests/unittests/single-instance-manager/CMakeLists.txt (+1/-1)
tests/unittests/tabs-model/CMakeLists.txt (+1/-1)
tests/unittests/text-search-filter-model/CMakeLists.txt (+1/-1)
tests/unittests/webapp-container-color-helper/CMakeLists.txt (+1/-1)
tests/unittests/webapp-container-hook/CMakeLists.txt (+1/-1)
To merge this branch: bzr merge lp:webbrowser-app/staging
Reviewer Review Type Date Requested Status
system-apps-ci-bot continuous-integration Needs Fixing
Ubuntu Phablet Team Pending
Review via email: mp+309984@code.launchpad.net

Commit message

TEST - DO NOT MERGE!

To post a comment you must log in.
Revision history for this message
system-apps-ci-bot (system-apps-ci-bot) wrote :

FAILED: Continuous integration, rev:1574
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/722/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/system-apps/job/build/1931/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-0-fetch/1932
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1771
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1771/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1771/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=zesty/1771
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=zesty/1771/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1771
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1771/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1771/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=zesty/1771
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=zesty/1771/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/1771
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/1771/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=xenial+overlay/1771/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=zesty/1771
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=zesty/1771/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/722/rebuild

review: Needs Fixing (continuous-integration)
lp:webbrowser-app/staging updated
1575. By Andrew Hayzen

* Add qtdeclarative5-ubuntu-content1 and qtdeclarative5-ubuntu-download-manager0.1 as depends as they are in main and then fixes issues with saving images
* Enable autopilot TestDownloads on desktop as depends are now met

Revision history for this message
system-apps-ci-bot (system-apps-ci-bot) wrote :

FAILED: Continuous integration, rev:1575
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/723/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/system-apps/job/build/1932/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-0-fetch/1933
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1772
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1772/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1772/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=zesty/1772
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=zesty/1772/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1772
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1772/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1772/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=zesty/1772
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=zesty/1772/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/1772
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/1772/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=xenial+overlay/1772/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=zesty/1772
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=zesty/1772/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/723/rebuild

review: Needs Fixing (continuous-integration)
lp:webbrowser-app/staging updated
1576. By Olivier Tilloy

Use the ubuntu-app-platform content interface.

1577. By Olivier Tilloy

Update version number in snapcraft.yaml.

Revision history for this message
system-apps-ci-bot (system-apps-ci-bot) wrote :

FAILED: Continuous integration, rev:1576
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/724/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/system-apps/job/build/1994/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-0-fetch/1997
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1827
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1827/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1827
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1827/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=zesty/1827
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=zesty/1827/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1827
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1827/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1827
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1827/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=zesty/1827/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/1827
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/1827/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=xenial+overlay/1827/console
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=zesty/1827/console

Click here to trigger a rebuild:
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/724/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
system-apps-ci-bot (system-apps-ci-bot) wrote :

FAILED: Continuous integration, rev:1577
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/725/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/system-apps/job/build/1995/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-0-fetch/1998
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1828
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1828/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1828
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1828/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=zesty/1828
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=zesty/1828/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1828
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1828/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1828/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=zesty/1828
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=zesty/1828/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/1828
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/1828/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=xenial+overlay/1828/console
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=zesty/1828/console

Click here to trigger a rebuild:
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/725/rebuild

review: Needs Fixing (continuous-integration)
lp:webbrowser-app/staging updated
1578. By Olivier Tilloy

Desktop UA override for google docs.

Revision history for this message
system-apps-ci-bot (system-apps-ci-bot) wrote :

FAILED: Continuous integration, rev:1578
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/726/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/system-apps/job/build/2035/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-0-fetch/2038
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1868
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1868/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1868/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=zesty/1868
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=zesty/1868/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1868
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1868/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1868
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1868/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=zesty/1868
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=zesty/1868/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/1868
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/1868/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=xenial+overlay/1868
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=xenial+overlay/1868/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=zesty/1868/console

Click here to trigger a rebuild:
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/726/rebuild

review: Needs Fixing (continuous-integration)
lp:webbrowser-app/staging updated
1579. By Andrew Hayzen

Add Drag and drop support of tabs between windows on non-mir clients.

1580. By Olivier Tilloy

Merge the latest changes from trunk.

Revision history for this message
system-apps-ci-bot (system-apps-ci-bot) wrote :

FAILED: Continuous integration, rev:1580
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/727/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/system-apps/job/build/2073/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-0-fetch/2076
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1906
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1906/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1906/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=zesty/1906
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=zesty/1906/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1906
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1906/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1906
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1906/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=zesty/1906
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=zesty/1906/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/1906
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/1906/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=xenial+overlay/1906/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=zesty/1906
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=zesty/1906/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/727/rebuild

review: Needs Fixing (continuous-integration)
lp:webbrowser-app/staging updated
1581. By Andrew Hayzen

* Improve styling for drag handle to match design
* Add extra properties to DragHelper to allow for changing border size and handle size etc

1582. By Andrew Hayzen

Ensure X position is set correctly when dragging is stopped.

Revision history for this message
system-apps-ci-bot (system-apps-ci-bot) wrote :

FAILED: Continuous integration, rev:1582
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/728/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/system-apps/job/build/2082/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-0-fetch/2085
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1915
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1915/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1915
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1915/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=zesty/1915
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=zesty/1915/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1915
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1915/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1915
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1915/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=zesty/1915/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/1915
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/1915/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=xenial+overlay/1915/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=zesty/1915
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=zesty/1915/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/728/rebuild

review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2016-10-06 10:16:41 +0000
3+++ .bzrignore 2016-11-30 14:23:08 +0000
4@@ -56,5 +56,3 @@
5 coverage-xml.cmake
6 coverage.*
7 coveragereport/
8-tst_*Tests.xml
9-tst_*Test.xml
10
11=== modified file 'debian/control'
12--- debian/control 2016-08-29 16:34:14 +0000
13+++ debian/control 2016-11-30 14:23:08 +0000
14@@ -45,7 +45,7 @@
15 Depends: ${misc:Depends},
16 ${shlibs:Depends},
17 fonts-liberation,
18- liboxideqt-qmlplugin (>= 1.15),
19+ liboxideqt-qmlplugin (>= 1.17),
20 libqt5sql5-sqlite,
21 qml-module-qt-labs-folderlistmodel,
22 qml-module-qt-labs-settings,
23@@ -53,6 +53,8 @@
24 qml-module-qtquick-layouts,
25 qml-module-qtquick-window2 (>= 5.3),
26 qml-module-ubuntu-web (= ${binary:Version}),
27+ qtdeclarative5-ubuntu-content1,
28+ qtdeclarative5-ubuntu-download-manager0.1,
29 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3),
30 qtdeclarative5-unity-action-plugin,
31 Replaces: webbrowser-app-assets,
32@@ -70,12 +72,14 @@
33 Depends: ${misc:Depends},
34 ${shlibs:Depends},
35 fonts-liberation,
36- liboxideqt-qmlplugin (>= 1.8),
37+ liboxideqt-qmlplugin (>= 1.17),
38 libqt5sql5-sqlite,
39 qml-module-qtquick2 (>= 5.4),
40 qml-module-qtquick-window2 (>= 5.3),
41 qml-module-ubuntu-onlineaccounts,
42 qml-module-ubuntu-web (= ${binary:Version}),
43+ qtdeclarative5-ubuntu-content1,
44+ qtdeclarative5-ubuntu-download-manager0.1,
45 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3),
46 qtdeclarative5-unity-action-plugin,
47 unity-webapps-qml,
48@@ -164,6 +168,7 @@
49 Multi-Arch: foreign
50 Depends: ${misc:Depends},
51 autopilot-qt5,
52+ content-hub-testability,
53 python3-autopilot,
54 python3-fixtures,
55 python3-psutil,
56
57=== modified file 'debian/rules'
58--- debian/rules 2016-10-13 20:07:10 +0000
59+++ debian/rules 2016-11-30 14:23:08 +0000
60@@ -44,5 +44,5 @@
61
62 override_dh_auto_test:
63 mkdir -p $(BUILDHOME)
64- HOME=$(BUILDHOME) dh_auto_test
65+ HOME=$(BUILDHOME) dh_auto_test -- ARGS+=-VV
66
67
68=== added directory 'snap/ubuntu-app-platform'
69=== modified file 'snapcraft.yaml'
70--- snapcraft.yaml 2016-10-07 14:42:55 +0000
71+++ snapcraft.yaml 2016-11-30 14:23:08 +0000
72@@ -1,5 +1,5 @@
73 name: webbrowser-app
74-version: 0.23+16.10.20160928-0ubuntu1
75+version: 20161117-staging
76 summary: Ubuntu web browser
77 description: A lightweight web browser tailored for Ubuntu, based on the Oxide browser engine and using the Ubuntu UI components.
78 confinement: strict
79@@ -13,6 +13,7 @@
80 - network
81 - network-bind
82 - opengl
83+ - platform
84 - pulseaudio
85 - screen-inhibit-control
86 - unity7
87@@ -21,6 +22,11 @@
88 browser-sandbox:
89 interface: browser-support
90 allow-sandbox: true
91+ platform:
92+ content: ubuntu-app-platform1
93+ default-provider: ubuntu-app-platform
94+ interface: content
95+ target: ubuntu-app-platform
96
97 parts:
98 webbrowser-app:
99@@ -43,21 +49,7 @@
100 - xvfb
101 stage-packages:
102 - fonts-liberation
103- - liboxideqt-qmlplugin
104- - libqt5sql5-sqlite
105- - mir-graphics-drivers-desktop
106- - qml-module-qt-labs-folderlistmodel
107- - qml-module-qt-labs-settings
108- - qml-module-qtquick2
109- - qml-module-qtquick-layouts
110- - qml-module-qtquick-window2
111- - qml-module-ubuntu-components
112- - qml-module-ubuntu-thumbnailer0.1
113- - qtdeclarative5-ubuntu-content1
114- - qtdeclarative5-ubuntu-download-manager0.1
115- - qtdeclarative5-unity-action-plugin
116- - qtubuntu-desktop
117- after: [desktop-qt5]
118+ after: [desktop-ubuntu-app-platform]
119
120 launcher:
121 plugin: dump
122
123=== modified file 'src/Ubuntu/Web/ua-overrides-desktop.js.in'
124--- src/Ubuntu/Web/ua-overrides-desktop.js.in 2016-10-14 14:37:23 +0000
125+++ src/Ubuntu/Web/ua-overrides-desktop.js.in 2016-11-30 14:23:08 +0000
126@@ -33,4 +33,13 @@
127
128 // Google recaptcha (https://launchpad.net/bugs/1599146)
129 ["^https:\/\/www\.google\.com\/recaptcha\/", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/${CHROMIUM_VERSION} Safari/537.36"],
130+
131+ // ESPN websites (https://launchpad.net/bugs/1637285)
132+ ["^https?:\/\/(.+\.)?espn(fc)?\.co(m|\.uk)\/", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/${CHROMIUM_VERSION} Safari/537.36"],
133+
134+ // meet.jit.si (https://launchpad.net/bugs/1635971)
135+ ["^https:\/\/meet\.jit\.si\/", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/${CHROMIUM_VERSION} Safari/537.36"],
136+
137+ // Google docs (https://launchpad.net/bugs/1643386)
138+ ["^https:\/\/(docs|drive)\.google\.com\/", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/${CHROMIUM_VERSION} Safari/537.36"],
139 ];
140
141=== modified file 'src/Ubuntu/Web/ua-overrides-mobile.js.in'
142--- src/Ubuntu/Web/ua-overrides-mobile.js.in 2016-10-14 14:37:23 +0000
143+++ src/Ubuntu/Web/ua-overrides-mobile.js.in 2016-11-30 14:23:08 +0000
144@@ -35,4 +35,7 @@
145
146 // Google recaptcha (https://launchpad.net/bugs/1599146)
147 ["^https:\/\/www\.google\.com\/recaptcha\/", "Mozilla/5.0 (Linux; Ubuntu @UBUNTU_VERSION@ like Android 4.4;) AppleWebKit/537.36 Chrome/${CHROMIUM_VERSION} Safari/537.36"],
148+
149+ // meet.jit.si (https://launchpad.net/bugs/1635971)
150+ ["^https:\/\/meet\.jit\.si\/", "Mozilla/5.0 (Linux; Ubuntu @UBUNTU_VERSION@ like Android 5.0;) AppleWebKit/537.36 Chrome/${CHROMIUM_VERSION} Safari/537.36"],
151 ];
152
153=== modified file 'src/app/ChromeBase.qml'
154--- src/app/ChromeBase.qml 2016-09-28 07:51:22 +0000
155+++ src/app/ChromeBase.qml 2016-11-30 14:23:08 +0000
156@@ -62,6 +62,7 @@
157 right: parent.right
158 bottom: parent.bottom
159 }
160+ objectName: "chromeProgressBar"
161
162 z: 2
163 }
164
165=== modified file 'src/app/webbrowser/Browser.qml'
166--- src/app/webbrowser/Browser.qml 2016-10-11 16:16:40 +0000
167+++ src/app/webbrowser/Browser.qml 2016-11-30 14:23:08 +0000
168@@ -19,10 +19,10 @@
169 import QtQuick 2.4
170 import QtQuick.Window 2.2
171 import Qt.labs.settings 1.0
172-import Ubuntu.Web 0.2
173 import com.canonical.Oxide 1.15 as Oxide
174 import Ubuntu.Components 1.3
175 import Ubuntu.Components.Popups 1.3
176+import Ubuntu.Web 0.2
177 import Unity.InputInfo 0.1
178 import webbrowserapp.private 0.1
179 import webbrowsercommon.private 0.1
180@@ -46,6 +46,8 @@
181
182 property var tabsModel: TabsModel {}
183
184+ property BrowserWindow thisWindow
185+
186 function serializeTabState(tab) {
187 var state = {}
188 state.uniqueId = tab.uniqueId
189@@ -66,10 +68,25 @@
190 }
191
192 function createTab(properties) {
193- return tabComponent.createObject(tabContainer, properties)
194+ return internal.createTabHelper(properties)
195+ }
196+
197+ function bindExistingTab(tab) {
198+ Reparenter.reparent(tab, tabContainer);
199+
200+ var properties = internal.buildContextProperties();
201+
202+ for (var prop in properties) {
203+ tab[prop] = properties[prop];
204+ }
205+
206+ // Ensure that we have switched to the tab
207+ // otherwise chrome position can break
208+ internal.switchToTab(tabsModel.count - 1, true);
209 }
210
211 signal newWindowRequested(bool incognito)
212+ signal newWindowFromTab(var tab, var callback)
213 signal openLinkInWindowRequested(url url, bool incognito)
214
215 Connections {
216@@ -167,6 +184,10 @@
217 top: parent.top
218 }
219 height: parent.height - osk.height - bottomEdgeBar.height
220+ // disable when newTabView is shown otherwise webview can capture drag events
221+ // do not use visible otherwise when a new tab is opened the locationBarController.offset
222+ // doesn't get updated, causing the Chrome to disappear
223+ enabled: !newTabViewLoader.active
224
225 focus: !errorSheetLoader.focus &&
226 !invalidCertificateErrorSheetLoader.focus &&
227@@ -465,6 +486,8 @@
228 showTabsBar: browser.wide
229 showFaviconInAddressBar: !browser.wide
230
231+ thisWindow: browser.thisWindow
232+
233 availableHeight: tabContainer.height - height - y
234
235 touchEnabled: internal.hasTouchScreen
236@@ -498,7 +521,8 @@
237
238 onSwitchToTab: internal.switchToTab(index, true)
239 onRequestNewTab: internal.openUrlInNewTab("", makeCurrent, true, index)
240- onTabClosed: internal.closeTab(index)
241+ onRequestNewWindowFromTab: browser.newWindowFromTab(tab, callback)
242+ onTabClosed: internal.closeTab(index, moving)
243
244 onFindInPageModeChanged: {
245 if (!chrome.findInPageMode) internal.resetFocus()
246@@ -570,7 +594,7 @@
247
248 Keys.onDownPressed: {
249 if (suggestionsList.count) suggestionsList.focus = true
250- else if (newTabViewLoader.status == Loader.Ready) {
251+ else if (!incognito && (newTabViewLoader.status == Loader.Ready)) {
252 newTabViewLoader.forceActiveFocus()
253 }
254 }
255@@ -977,7 +1001,7 @@
256
257 function openUrlInNewTab(url, setCurrent, load, index) {
258 load = typeof load !== 'undefined' ? load : true
259- var tab = tabComponent.createObject(tabContainer, {"initialUrl": url})
260+ var tab = internal.createTabHelper({"initialUrl": url})
261 addTab(tab, setCurrent, index)
262 if (load) {
263 tab.load()
264@@ -996,8 +1020,36 @@
265 }
266 }
267
268- function closeTab(index) {
269+ function buildContextProperties(properties) {
270+ if (properties === undefined) {
271+ properties = {};
272+ }
273+
274+ properties["bottomEdgeHandle"] = bottomEdgeHandle;
275+ properties["browser"] = browser;
276+ properties["chrome"] = chrome;
277+ properties["chromeController"] = chromeController;
278+ properties["contentHandlerLoader"] = contentHandlerLoader;
279+ properties["downloadDialogLoader"] = downloadDialogLoader;
280+ properties["downloadsViewLoader"] = downloadsViewLoader;
281+ properties["filePickerLoader"] = filePickerLoader;
282+ properties["internal"] = internal;
283+ properties["recentView"] = recentView;
284+ properties["tabsModel"] = tabsModel;
285+
286+ return properties;
287+ }
288+
289+ function createTabHelper(properties) {
290+ return Reparenter.createObject(tabComponent, tabContainer, internal.buildContextProperties(properties));
291+ }
292+
293+ function closeTab(index, moving) {
294+ moving = moving === undefined ? false : moving;
295+
296 var tab = tabsModel.get(index)
297+ tabsModel.remove(index)
298+
299 if (tab) {
300 if (!incognito && tab.url.toString().length > 0) {
301 closedTabHistory.push({
302@@ -1005,9 +1057,12 @@
303 index: index
304 })
305 }
306- tab.close()
307+
308+ // When moving a tab between windows don't close the tab as it has been moved
309+ if (!moving) {
310+ tab.close()
311+ }
312 }
313- tabsModel.remove(index)
314 if (tabsModel.currentTab) {
315 tabsModel.currentTab.load()
316 }
317@@ -1163,60 +1218,60 @@
318 // Ctrl+Tab or Ctrl+PageDown: cycle through open tabs
319 Shortcut {
320 sequence: StandardKey.NextChild
321- enabled: tabContainer.visible || recentView.visible
322+ enabled: contentsContainer.visible || recentView.visible
323 onActivated: internal.switchToNextTab()
324 }
325 Shortcut {
326 sequence: "Ctrl+PgDown"
327- enabled: tabContainer.visible || recentView.visible
328+ enabled: contentsContainer.visible || recentView.visible
329 onActivated: internal.switchToNextTab()
330 }
331
332 // Ctrl+Shift+Tab or Ctrl+PageUp: cycle through open tabs in reverse order
333 Shortcut {
334 sequence: StandardKey.PreviousChild
335- enabled: tabContainer.visible || recentView.visible
336+ enabled: contentsContainer.visible || recentView.visible
337 onActivated: internal.switchToPreviousTab()
338 }
339 Shortcut {
340 sequence: "Ctrl+Shift+Tab"
341- enabled: tabContainer.visible || recentView.visible
342+ enabled: contentsContainer.visible || recentView.visible
343 onActivated: internal.switchToPreviousTab()
344 }
345 Shortcut {
346 sequence: "Ctrl+PgUp"
347- enabled: tabContainer.visible || recentView.visible
348+ enabled: contentsContainer.visible || recentView.visible
349 onActivated: internal.switchToPreviousTab()
350 }
351
352 // Ctrl+W or Ctrl+F4: Close the current tab
353 Shortcut {
354 sequence: StandardKey.Close
355- enabled: tabContainer.visible || recentView.visible
356+ enabled: contentsContainer.visible || recentView.visible
357 onActivated: internal.closeCurrentTab()
358 }
359 Shortcut {
360 sequence: "Ctrl+F4"
361- enabled: tabContainer.visible || recentView.visible
362+ enabled: contentsContainer.visible || recentView.visible
363 onActivated: internal.closeCurrentTab()
364 }
365
366 // Ctrl+Shift+W or Ctrl+Shift+T: Undo close tab
367 Shortcut {
368 sequence: "Ctrl+Shift+W"
369- enabled: tabContainer.visible || recentView.visible
370+ enabled: contentsContainer.visible || recentView.visible
371 onActivated: internal.undoCloseTab()
372 }
373 Shortcut {
374 sequence: "Ctrl+Shift+T"
375- enabled: tabContainer.visible || recentView.visible
376+ enabled: contentsContainer.visible || recentView.visible
377 onActivated: internal.undoCloseTab()
378 }
379
380 // Ctrl+T: Open a new Tab
381 Shortcut {
382 sequence: StandardKey.AddTab
383- enabled: tabContainer.visible || recentView.visible ||
384+ enabled: contentsContainer.visible || recentView.visible ||
385 bookmarksViewLoader.active || historyViewLoader.active
386 onActivated: {
387 internal.openUrlInNewTab("", true)
388@@ -1229,24 +1284,24 @@
389 // F6 or Ctrl+L or Alt+D: Select the content in the address bar
390 Shortcut {
391 sequence: "F6"
392- enabled: tabContainer.visible
393+ enabled: contentsContainer.visible
394 onActivated: internal.focusAddressBar(true)
395 }
396 Shortcut {
397 sequence: "Ctrl+L"
398- enabled: tabContainer.visible
399+ enabled: contentsContainer.visible
400 onActivated: internal.focusAddressBar(true)
401 }
402 Shortcut {
403 sequence: "Alt+D"
404- enabled: tabContainer.visible
405+ enabled: contentsContainer.visible
406 onActivated: internal.focusAddressBar(true)
407 }
408
409 // Ctrl+D: Toggle bookmarked state on current Tab
410 Shortcut {
411 sequence: "Ctrl+D"
412- enabled: tabContainer.visible
413+ enabled: contentsContainer.visible
414 onActivated: {
415 if (internal.currentBookmarkOptionsDialog) {
416 internal.currentBookmarkOptionsDialog.hide()
417@@ -1263,47 +1318,47 @@
418 // Ctrl+H: Show History
419 Shortcut {
420 sequence: "Ctrl+H"
421- enabled: tabContainer.visible
422+ enabled: contentsContainer.visible
423 onActivated: historyViewLoader.active = true
424 }
425
426 // Ctrl+Shift+O: Show Bookmarks
427 Shortcut {
428 sequence: "Ctrl+Shift+O"
429- enabled: tabContainer.visible
430+ enabled: contentsContainer.visible
431 onActivated: bookmarksViewLoader.active = true
432 }
433
434 // Alt+← or Backspace: Goes to the previous page in history
435 Shortcut {
436 sequence: StandardKey.Back
437- enabled: tabContainer.visible
438+ enabled: contentsContainer.visible
439 onActivated: internal.historyGoBack()
440 }
441
442 // Alt+→ or Shift+Backspace: Goes to the next page in history
443 Shortcut {
444 sequence: StandardKey.Forward
445- enabled: tabContainer.visible
446+ enabled: contentsContainer.visible
447 onActivated: internal.historyGoForward()
448 }
449
450 // F5 or Ctrl+R: Reload current Tab
451 Shortcut {
452 sequence: StandardKey.Refresh
453- enabled: tabContainer.visible
454+ enabled: contentsContainer.visible
455 onActivated: if (currentWebview) currentWebview.reload()
456 }
457 Shortcut {
458 sequence: "F5"
459- enabled: tabContainer.visible
460+ enabled: contentsContainer.visible
461 onActivated: if (currentWebview) currentWebview.reload()
462 }
463
464 // Ctrl+F: Find in Page
465 Shortcut {
466 sequence: StandardKey.Find
467- enabled: tabContainer.visible && !newTabViewLoader.active
468+ enabled: contentsContainer.visible && !newTabViewLoader.active
469 onActivated: chrome.findInPageMode = true
470 }
471
472@@ -1400,4 +1455,78 @@
473 source: "ContentPickerDialog.qml"
474 asynchronous: true
475 }
476+
477+ DropArea {
478+ id: dropArea
479+ anchors {
480+ fill: parent
481+ }
482+ keys: ["webbrowser/tab-" + (incognito ? "incognito" : "public")]
483+
484+ readonly property real heightThreshold: chrome.tabsBarHeight
485+
486+ onDropped: {
487+ // IgnoreAction - no DropArea accepted so New Window
488+ // MoveAction - DropArea accept but different window
489+ // CopyAction - DropArea accept but same window
490+
491+ if (drag.y > heightThreshold) {
492+ // Dropped in bottom area, creating new window
493+ drop.accept(Qt.IgnoreAction);
494+ } else if (drag.source.tabWindow === thisWindow) {
495+ // Dropped in same window
496+ drop.accept(Qt.CopyAction);
497+ } else {
498+ // Dropped in new window, moving tab
499+
500+ thisWindow.addExistingTab(drag.source.tab);
501+ thisWindow.tabsModel.currentIndex = window.tabsModel.count - 1;
502+ thisWindow.show();
503+ thisWindow.requestActivate();
504+
505+ thisWindow.tabsModel.currentTab.load();
506+
507+ drop.accept(Qt.MoveAction);
508+ }
509+ }
510+ onEntered: {
511+ thisWindow.raise()
512+ thisWindow.requestActivate();
513+ }
514+ onPositionChanged: {
515+ if (drag.source.tabWindow === thisWindow && drag.y < heightThreshold) {
516+ // tab drag is within same window and in chrome
517+ // so reorder tabs by setting tabDelegate x position
518+ drag.source.x = drag.x - (drag.source.width / 2);
519+ }
520+ }
521+
522+ Rectangle {
523+ anchors {
524+ left: parent.left
525+ right: parent.right
526+ top: parent.top
527+ }
528+ color: "#FFF"
529+ height: dropArea.heightThreshold
530+ opacity: {
531+ // Only hide the white shade when this is the active window
532+ // and there is no drag being performed or the drag event is
533+ // over the tabs bar
534+ if (thisWindow.active && !DragHelper.dragging) {
535+ 0
536+ } else if (dropArea.containsDrag && dropArea.drag.y <= dropArea.heightThreshold) {
537+ 0
538+ } else {
539+ 0.6
540+ }
541+ }
542+
543+ Behavior on opacity {
544+ NumberAnimation {
545+
546+ }
547+ }
548+ }
549+ }
550 }
551
552=== modified file 'src/app/webbrowser/BrowserTab.qml'
553--- src/app/webbrowser/BrowserTab.qml 2016-10-07 11:47:05 +0000
554+++ src/app/webbrowser/BrowserTab.qml 2016-11-30 14:23:08 +0000
555@@ -98,6 +98,17 @@
556 }
557 }
558
559+ function loadExisting(existingTab) {
560+ if (!webview && !internal.incubator) {
561+ // Reparent the webview and any other vars
562+ existingTab.webview.parent = webviewContainer;
563+ existingTab.webview.tab = tab;
564+
565+ // Set the webview into this window
566+ webviewContainer.webview = existingTab.webview;
567+ }
568+ }
569+
570 function unload() {
571 if (webview) {
572 initialUrl = webview.url
573@@ -118,11 +129,17 @@
574 }
575 }
576
577- function close() {
578+ function close(reparentDestroy) {
579 var _url = url
580 unload()
581 if (_url.toString()) PreviewManager.checkDelete(_url)
582- destroy()
583+
584+ if (reparentDestroy || reparentDestroy === undefined) {
585+ // Destroys context and object
586+ Reparenter.destroyContextAndObject(tab);
587+ } else {
588+ destroy();
589+ }
590 }
591
592 QtObject {
593
594=== modified file 'src/app/webbrowser/CMakeLists.txt'
595--- src/app/webbrowser/CMakeLists.txt 2015-12-10 09:06:06 +0000
596+++ src/app/webbrowser/CMakeLists.txt 2016-11-30 14:23:08 +0000
597@@ -33,7 +33,9 @@
598
599 set(WEBBROWSER_APP_SRC
600 cache-deleter.cpp
601+ drag-helper.cpp
602 file-operations.cpp
603+ reparenter.cpp
604 searchengine.cpp
605 webbrowser-app.cpp
606 )
607
608=== modified file 'src/app/webbrowser/Chrome.qml'
609--- src/app/webbrowser/Chrome.qml 2016-10-10 17:00:52 +0000
610+++ src/app/webbrowser/Chrome.qml 2016-11-30 14:23:08 +0000
611@@ -42,10 +42,13 @@
612 property alias availableHeight: navigationBar.availableHeight
613 readonly property alias bookmarkTogglePlaceHolder: navigationBar.bookmarkTogglePlaceHolder
614 property bool touchEnabled: true
615+ readonly property real tabsBarHeight: tabsBar.height + content.anchors.topMargin
616+ property BrowserWindow thisWindow
617
618 signal switchToTab(int index)
619 signal requestNewTab(int index, bool makeCurrent)
620- signal tabClosed(int index)
621+ signal requestNewWindowFromTab(var tab, var callback)
622+ signal tabClosed(int index, bool moving)
623
624 backgroundColor: incognito ? UbuntuColors.darkGrey : "#ffffff"
625
626@@ -75,6 +78,7 @@
627 "model": Qt.binding(function () {return chrome.tabsModel}),
628 "incognito": Qt.binding(function () {return chrome.incognito}),
629 "fgColor": Qt.binding(function () {return navigationBar.fgColor}),
630+ "thisWindow": Qt.binding(function () {return chrome.thisWindow}),
631 "touchEnabled": Qt.binding(function () {return chrome.touchEnabled})
632 })
633 }
634@@ -84,7 +88,8 @@
635
636 onSwitchToTab: chrome.switchToTab(index)
637 onRequestNewTab: chrome.requestNewTab(index, makeCurrent)
638- onTabClosed: chrome.tabClosed(index)
639+ onRequestNewWindowFromTab: chrome.requestNewWindowFromTab(tab, callback)
640+ onTabClosed: chrome.tabClosed(index, moving)
641 }
642 asynchronous: true
643
644@@ -130,4 +135,9 @@
645 }
646
647 loadProgress: (loading && webview) ? webview.loadProgress : 0
648+
649+ // If the webview changes the use the loading state of the new webview
650+ // otherwise opening a new tab/window while another webview was loading
651+ // can cause a progress bar to be left behind at zero percent pad.lv/1638337
652+ onWebviewChanged: loading = webview ? webview.loading : false
653 }
654
655=== modified file 'src/app/webbrowser/ContextMenuMobile.qml'
656--- src/app/webbrowser/ContextMenuMobile.qml 2016-09-19 12:08:03 +0000
657+++ src/app/webbrowser/ContextMenuMobile.qml 2016-11-30 14:23:08 +0000
658@@ -23,6 +23,8 @@
659 import com.canonical.Oxide 1.8 as Oxide
660
661 Popups.Dialog {
662+ id: contextMenu
663+
664 property QtObject contextModel: model
665 property ActionList actions: null
666
667@@ -119,7 +121,7 @@
668 }
669 }
670
671- onTriggered: contextModel.close()
672+ onTriggered: contextMenu.hide()
673 }
674 }
675
676@@ -138,7 +140,13 @@
677 fontSize: "x-small"
678 text: i18n.tr("Cancel")
679 }
680- onTriggered: contextModel.close()
681+ onTriggered: contextMenu.hide()
682+ }
683+
684+ onVisibleChanged: {
685+ if (!visible) {
686+ contextModel.close()
687+ }
688 }
689
690 // adjust default dialog visuals to custom requirements for the context menu
691
692=== modified file 'src/app/webbrowser/Suggestions.qml'
693--- src/app/webbrowser/Suggestions.qml 2015-08-24 16:51:47 +0000
694+++ src/app/webbrowser/Suggestions.qml 2016-11-30 14:23:08 +0000
695@@ -75,7 +75,7 @@
696 title: selected ? modelData.title : Highlight.highlightTerms(modelData.title, searchTerms)
697 subtitle: modelData.displayUrl ? (selected ? modelData.url :
698 Highlight.highlightTerms(modelData.url, searchTerms)) : ""
699- icon: modelData.icon
700+ icon: modelData.icon || ""
701 selected: suggestionsList.activeFocus && ListView.isCurrentItem
702
703 onActivated: suggestions.activated(modelData.url)
704
705=== modified file 'src/app/webbrowser/TabComponent.qml'
706--- src/app/webbrowser/TabComponent.qml 2016-10-11 16:17:11 +0000
707+++ src/app/webbrowser/TabComponent.qml 2016-11-30 14:23:08 +0000
708@@ -34,10 +34,22 @@
709
710 BrowserTab {
711 anchors.fill: parent
712- incognito: browser.incognito
713- current: tabsModel && tabsModel.currentTab === this
714+ incognito: browser ? browser.incognito : false
715+ current: browser ? browser.tabsModel && browser.tabsModel.currentTab === this : false
716 focus: current
717
718+ property var bottomEdgeHandle
719+ property var browser
720+ property var chrome
721+ property var chromeController
722+ property var contentHandlerLoader
723+ property var downloadDialogLoader
724+ property var downloadsViewLoader
725+ property var filePickerLoader
726+ property var internal
727+ property var recentView
728+ property var tabsModel
729+
730 Item {
731 id: contextualMenuTarget
732 visible: false
733@@ -49,18 +61,18 @@
734 property BrowserTab tab
735 readonly property bool current: tab.current
736
737- currentWebview: browser.currentWebview
738- filePicker: filePickerLoader.item
739+ currentWebview: browser ? browser.currentWebview : null
740+ filePicker: filePickerLoader ? filePickerLoader.item : null
741
742 anchors.fill: parent
743
744 focus: true
745
746- enabled: current && !bottomEdgeHandle.dragging && !recentView.visible && tabContainer.focus
747+ enabled: current && !bottomEdgeHandle.dragging && !recentView.visible && parent.focus
748
749 locationBarController {
750- height: chrome.height
751- mode: chromeController.defaultMode
752+ height: chrome ? chrome.height : 0
753+ mode: chromeController ? chromeController.defaultMode : null
754 }
755
756 //experimental.preferences.developerExtrasEnabled: developerExtrasEnabled
757@@ -115,7 +127,7 @@
758 }
759 Actions.Share {
760 objectName: "ShareContextualAction"
761- enabled: (contentHandlerLoader.status == Loader.Ready) && contextModel &&
762+ enabled: (contentHandlerLoader && contentHandlerLoader.status == Loader.Ready) && contextModel &&
763 (contextModel.linkUrl.toString() || contextModel.selectionText)
764 onTriggered: {
765 if (contextModel.linkUrl.toString()) {
766@@ -135,9 +147,10 @@
767 Actions.CopyImage {
768 objectName: "CopyImageContextualAction"
769 enabled: contextModel &&
770- (contextModel.mediaType === Oxide.WebView.MediaTypeImage) &&
771- contextModel.srcUrl.toString()
772- onTriggered: Clipboard.push(["text/plain", contextModel.srcUrl.toString()])
773+ ((contextModel.mediaType === Oxide.WebView.MediaTypeImage) ||
774+ (contextModel.mediaType === Oxide.WebView.MediaTypeCanvas)) &&
775+ contextModel.hasImageContents
776+ onTriggered: contextModel.copyImage()
777 }
778 Actions.SaveImage {
779 objectName: "SaveImageContextualAction"
780@@ -237,10 +250,10 @@
781 Component.onCompleted: webviewimpl.contextMenuOnCompleted(this)
782 }
783 }
784- contextMenu: browser.wide ? contextMenuWideComponent : contextMenuNarrowComponent
785+ contextMenu: browser && browser.wide ? contextMenuWideComponent : contextMenuNarrowComponent
786
787 onNewViewRequested: {
788- var tab = tabComponent.createObject(tabContainer, {"request": request})
789+ var tab = browser.createTab({"request": request})
790 var setCurrent = (request.disposition == Oxide.NewViewRequest.DispositionNewForegroundTab)
791 internal.addTab(tab, setCurrent)
792 if (setCurrent) tabContainer.forceActiveFocus()
793@@ -256,9 +269,14 @@
794 break
795 }
796 }
797+
798+ // tab.close() destroys the context so add new tab before destroy if required
799+ if (tabsModel.count === 0) {
800+ internal.openUrlInNewTab("", true, true)
801+ }
802+
803 tab.close()
804- }
805- if (tabsModel.count === 0) {
806+ } else if (tabsModel.count === 0) {
807 internal.openUrlInNewTab("", true, true)
808 }
809 }
810
811=== modified file 'src/app/webbrowser/TabItem.qml'
812--- src/app/webbrowser/TabItem.qml 2016-10-10 09:13:53 +0000
813+++ src/app/webbrowser/TabItem.qml 2016-11-30 14:23:08 +0000
814@@ -39,7 +39,7 @@
815 property color fgColor: Theme.palette.normal.baseText
816
817 property bool touchEnabled: true
818-
819+
820 readonly property bool showCloseIcon: closeIcon.x > units.gu(1) + tabItem.width / 2
821
822 signal selected()
823@@ -64,7 +64,7 @@
824 verticalCenter: parent.verticalCenter
825 }
826 shouldCache: !incognito
827-
828+
829 // Scale width and height of favicon when tabWidth becomes small
830 height: width
831 width: Math.min(units.dp(16), Math.min(tabItem.width - anchors.leftMargin * 2, tabItem.height))
832
833=== modified file 'src/app/webbrowser/TabsBar.qml'
834--- src/app/webbrowser/TabsBar.qml 2016-10-05 11:03:05 +0000
835+++ src/app/webbrowser/TabsBar.qml 2016-11-30 14:23:08 +0000
836@@ -19,6 +19,10 @@
837 import QtQuick 2.4
838 import Ubuntu.Components 1.3
839 import Ubuntu.Components.Popups 1.3
840+
841+import webbrowserapp.private 0.1
842+
843+import "."
844 import ".."
845
846 Item {
847@@ -26,19 +30,21 @@
848
849 property alias model: repeater.model
850
851+ property BrowserWindow thisWindow
852+
853 property real minTabWidth: 0 //units.gu(6)
854 property real maxTabWidth: units.gu(20)
855 property real tabWidth: model ? Math.max(Math.min(tabsContainer.maxWidth / model.count, maxTabWidth), minTabWidth) : 0
856
857 // Minimum size of the larger tab
858 readonly property real minActiveTabWidth: units.gu(10)
859-
860+
861 // When there is a larger tab, calc the smaller tab size
862 readonly property real nonActiveTabWidth: (tabsContainer.maxWidth - minActiveTabWidth) / Math.max(model.count - 1, 1)
863
864 // The size of the right margin of the tab
865 readonly property real rightMargin: units.dp(1)
866-
867+
868 // Whether there will be one larger tab or not
869 readonly property bool unevenTabWidth: tabWidth + rightMargin < minActiveTabWidth
870
871@@ -50,7 +56,8 @@
872
873 signal switchToTab(int index)
874 signal requestNewTab(int index, bool makeCurrent)
875- signal tabClosed(int index)
876+ signal requestNewWindowFromTab(var tab, var callback)
877+ signal tabClosed(int index, bool moving)
878
879 MouseArea {
880 anchors.fill: parent
881@@ -110,9 +117,18 @@
882 onTriggered: menu.tab.reload()
883 }
884 Action {
885+ objectName: "tab_action_move_to_new_window"
886+ text: i18n.tr("Move to New Window")
887+ onTriggered: {
888+ // callback function only removes from model
889+ // and not destroy as webview is in new window
890+ root.requestNewWindowFromTab(menu.tab, function() { root.tabClosed(menu.targetIndex, true); });
891+ }
892+ }
893+ Action {
894 objectName: "tab_action_close_tab"
895 text: i18n.tr("Close Tab")
896- onTriggered: root.tabClosed(menu.targetIndex)
897+ onTriggered: root.tabClosed(menu.targetIndex, false)
898 }
899 }
900 }
901@@ -130,6 +146,10 @@
902 width: tabWidth * root.model.count
903 readonly property real maxWidth: root.width - newTabButton.width - units.gu(2)
904
905+ readonly property int maxYDiff: height / 4
906+
907+ function sign(number) { return number / Math.abs(number); }
908+
909 Repeater {
910 id: repeater
911
912@@ -140,26 +160,32 @@
913 objectName: "tabDelegate"
914
915 readonly property int tabIndex: index
916+ readonly property var tab: root.model.get(index)
917+ readonly property BrowserWindow tabWindow: root.thisWindow
918
919- anchors.top: tabsContainer.top
920-
921+ property real rightMargin: units.dp(1)
922 width: getSize(index)
923 height: tabsContainer.height
924+ y: tabsContainer.y // don't use anchor otherwise drag doesn't work
925
926 acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
927 readonly property bool dragging: drag.active
928 drag {
929 target: (pressedButtons === Qt.LeftButton) ? tabDelegate : null
930- axis: Drag.XAxis
931+ // FIXME: disable drag and drop on mir pad.lv/1627013
932+ axis: __platformName != "ubuntumirclient" ? Drag.XAndYAxis : Drag.XAxis
933 minimumX: 0
934 maximumX: root.width - tabDelegate.width
935 filterChildren: true
936 }
937
938 TabItem {
939- anchors.fill: parent
940-
941 active: tabIndex === root.model.currentIndex
942+ anchors {
943+ left: parent.left
944+ right: parent.right
945+ }
946+ height: tabsContainer.height
947 hoverable: true
948 incognito: root.incognito
949 title: model.title ? model.title : (model.url.toString() ? model.url : i18n.tr("New tab"))
950@@ -170,7 +196,11 @@
951
952 rightMargin: root.rightMargin
953
954- onClosed: root.tabClosed(index)
955+ // Keep the visual tabitem within maxYDiff of starting point when
956+ // dragging vertically so that it doesn't cover other elements
957+ y: Math.abs(parent.y) > tabsContainer.maxYDiff ? (tabsContainer.sign(parent.y) * tabsContainer.maxYDiff) - parent.y : 0
958+
959+ onClosed: root.tabClosed(index, false)
960 onSelected: root.switchToTab(index)
961 onContextMenu: PopupUtils.open(contextualOptionsComponent, tabDelegate, {"targetIndex": index})
962 }
963@@ -180,15 +210,82 @@
964 property: "reordering"
965 value: dragging
966 }
967-
968+
969 Behavior on width { NumberAnimation { duration: 250 } }
970
971 Binding on x {
972- when: !dragging
973+ when: !dragging && !DragHelper.dragging
974 value: getLeftX(index)
975 }
976
977- Behavior on x { NumberAnimation { duration: 250 } }
978+ Behavior on x {
979+ NumberAnimation {
980+ duration: 250
981+ }
982+ }
983+
984+ NumberAnimation {
985+ id: resetVerticalAnimation
986+ target: tabDelegate
987+ duration: 250
988+ property: "y"
989+ to: 0
990+ }
991+
992+ onPositionChanged: {
993+ // FIXME: disable drag and drop on mir pad.lv/1627013
994+ if (Math.abs(y) > height && __platformName != "ubuntumirclient") {
995+ // Reset visual position of tab delegate
996+ resetVerticalAnimation.start();
997+
998+ if (mouse.buttons === Qt.LeftButton) {
999+ // Generate tab preview for drag handle
1000+ DragHelper.expectedAction = Qt.IgnoreAction | Qt.CopyAction | Qt.MoveAction
1001+ DragHelper.mimeType = "webbrowser/tab-" + (root.incognito ? "incognito" : "public")
1002+ DragHelper.previewBorderWidth = units.gu(1)
1003+ DragHelper.previewSize = Qt.size(units.gu(35), units.gu(22.5))
1004+ DragHelper.previewTopCrop = chrome.height
1005+ DragHelper.previewUrl = PreviewManager.previewPathFromUrl(tab.url)
1006+ DragHelper.source = tabDelegate
1007+
1008+ var dropAction = DragHelper.execDrag(tab.url);
1009+
1010+ // IgnoreAction - no DropArea accepted so New Window
1011+ // MoveAction - DropArea accept but different window
1012+ // CopyAction - DropArea accept but same window
1013+
1014+ if (dropAction === Qt.MoveAction) {
1015+ // Moved into another window
1016+
1017+ // drag.active does not become false when
1018+ // closing the tab so set reordering back
1019+ repeater.reordering = false;
1020+
1021+ // Just remove from model and do not destory
1022+ // as webview is used in other window
1023+ root.tabClosed(index, true);
1024+ } else if (dropAction === Qt.CopyAction) {
1025+ // Moved into the same window
1026+
1027+ // So no action
1028+ } else if (dropAction === Qt.IgnoreAction) {
1029+ // Moved outside of any window
1030+
1031+ // drag.active does not become false when
1032+ // closing the tab so set reordering back
1033+ repeater.reordering = false;
1034+
1035+ // callback function only removes from model
1036+ // and not destroy as webview is in new window
1037+ root.requestNewWindowFromTab(tab, function() { root.tabClosed(index, true); })
1038+ } else {
1039+ // Unknown state
1040+ console.debug("Unknown drop action:", dropAction);
1041+ }
1042+ }
1043+ }
1044+ }
1045+ onReleased: resetVerticalAnimation.start();
1046
1047 function getLeftX(index) {
1048 if (unevenTabWidth) {
1049@@ -204,7 +301,7 @@
1050 return index * (tabWidth + rightMargin)
1051 }
1052 }
1053-
1054+
1055 function getSize(index) {
1056 if (unevenTabWidth) {
1057 // Uneven tabs so use large or small depending which index
1058@@ -217,7 +314,7 @@
1059 return tabWidth + rightMargin
1060 }
1061 }
1062-
1063+
1064 onXChanged: {
1065 if (!dragging) return
1066
1067
1068=== modified file 'src/app/webbrowser/TabsList.qml'
1069--- src/app/webbrowser/TabsList.qml 2016-02-25 14:54:54 +0000
1070+++ src/app/webbrowser/TabsList.qml 2016-11-30 14:23:08 +0000
1071@@ -109,14 +109,14 @@
1072 incognito: tabslist.incognito
1073 tab: model.tab
1074 showContent: ((index > 0) && (delegate.y > flickable.contentY)) ||
1075- !(tab.webview && tab.webview.visible)
1076+ !(tab && tab.webview && tab.webview.visible)
1077
1078 Binding {
1079 // Change the height of the location bar controller
1080 // for the first webview only, and only while the tabs
1081 // list view is visible.
1082 when: tabslist.visible && (index == 0)
1083- target: tab.webview ? tab.webview.locationBarController : null
1084+ target: tab && tab.webview ? tab.webview.locationBarController : null
1085 property: "height"
1086 value: invisibleTabChrome.height
1087 }
1088
1089=== added file 'src/app/webbrowser/drag-helper.cpp'
1090--- src/app/webbrowser/drag-helper.cpp 1970-01-01 00:00:00 +0000
1091+++ src/app/webbrowser/drag-helper.cpp 2016-11-30 14:23:08 +0000
1092@@ -0,0 +1,203 @@
1093+/*
1094+ * Copyright 2016 Canonical Ltd.
1095+ *
1096+ * This file is part of webbrowser-app.
1097+ *
1098+ * webbrowser-app is free software; you can redistribute it and/or modify
1099+ * it under the terms of the GNU General Public License as published by
1100+ * the Free Software Foundation; version 3.
1101+ *
1102+ * webbrowser-app is distributed in the hope that it will be useful,
1103+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1104+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1105+ * GNU General Public License for more details.
1106+ *
1107+ * You should have received a copy of the GNU General Public License
1108+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1109+ */
1110+
1111+#include "drag-helper.h"
1112+
1113+#include <QtCore/QMimeData>
1114+#include <QtCore/QPoint>
1115+#include <QtCore/QSize>
1116+#include <QtCore/QString>
1117+#include <QtGui/QDrag>
1118+#include <QtGui/QDropEvent>
1119+#include <QtGui/QPainter>
1120+#include <QtGui/QPen>
1121+#include <QtGui/QPixmap>
1122+#include <QtQuick/QQuickItem>
1123+
1124+DragHelper::DragHelper()
1125+ : QObject(),
1126+ m_active(false),
1127+ m_dragging(false),
1128+ m_expected_action(Qt::IgnoreAction),
1129+ m_mime_type(QStringLiteral("webbrowser/tab")),
1130+ m_preview_border_width(8),
1131+ m_preview_size(QSizeF(200, 150)),
1132+ m_preview_top_crop(0),
1133+ m_preview_url(""),
1134+ m_source(Q_NULLPTR)
1135+{
1136+
1137+}
1138+
1139+QPixmap DragHelper::drawPixmapWithBorder(QPixmap pixmap, int borderWidth, QColor color)
1140+{
1141+ // Create a transparent pixmap to draw to
1142+ QPixmap output(pixmap.width() + borderWidth * 2, pixmap.height() + borderWidth * 2);
1143+ output.fill(QColor(0, 0, 0, 0));
1144+
1145+ // Draw the pixmap with space around the edge for a border
1146+ QPainter borderPainter(&output);
1147+ borderPainter.setRenderHint(QPainter::Antialiasing);
1148+ borderPainter.drawPixmap(borderWidth, borderWidth, pixmap);
1149+
1150+ // Define a pen to use for the border
1151+ QPen borderPen;
1152+ borderPen.setColor(color);
1153+ borderPen.setJoinStyle(Qt::MiterJoin);
1154+ borderPen.setStyle(Qt::SolidLine);
1155+ borderPen.setWidth(borderWidth);
1156+
1157+ // Set the pen and draw the border
1158+ borderPainter.setPen(borderPen);
1159+ borderPainter.drawRect(borderWidth / 2, borderWidth / 2,
1160+ output.width() - borderWidth, output.height() - borderWidth);
1161+
1162+ return output;
1163+}
1164+
1165+Qt::DropAction DragHelper::execDrag(QString tabId)
1166+{
1167+ QDrag *drag = new QDrag(m_source);
1168+
1169+ // Create a mimedata object to use for the drag
1170+ QMimeData *mimeData = new QMimeData;
1171+ mimeData->setData(mimeType(), tabId.toLatin1());
1172+
1173+ // Get a bordered pixmap of the previewUrl
1174+ QSize size = previewSize().toSize();
1175+
1176+ QPixmap pixmap = drawPixmapWithBorder(getPreviewUrlAsPixmap(size.width(), size.height()),
1177+ previewBorderWidth(), QColor(205, 205, 205, 255 * 0.6)); // #cdcdcd
1178+
1179+ // Setup the drag and then execute it
1180+ drag->setHotSpot(QPoint(size.width() * 0.1, size.height() * 0.1));
1181+ drag->setMimeData(mimeData);
1182+ drag->setPixmap(pixmap);
1183+
1184+ setDragging(true);
1185+
1186+ Qt::DropAction action = drag->exec(expectedAction());
1187+
1188+ setDragging(false);
1189+
1190+ return action;
1191+}
1192+
1193+QPixmap DragHelper::getPreviewUrlAsPixmap(int width, int height)
1194+{
1195+ QSize pixmapSize(width, height);
1196+ QPixmap pixmap(previewUrl());
1197+
1198+ if (pixmap.isNull()) {
1199+ // If loading pixmap failed, draw a white rectangle
1200+ pixmap = QPixmap(pixmapSize);
1201+ QPainter painter(&pixmap);
1202+ painter.eraseRect(0, 0, pixmapSize.width(), pixmapSize.height());
1203+ painter.fillRect(0, 0, pixmapSize.width(), pixmapSize.height(), QColor(255, 255, 255, 255));
1204+ } else {
1205+ // Crop transparent part off the top of the image
1206+ pixmap = pixmap.copy(0, previewTopCrop(), pixmap.width(), pixmap.height() - previewTopCrop());
1207+
1208+ // Scale image to fit the expected size
1209+ pixmap = pixmap.scaled(pixmapSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
1210+ }
1211+
1212+ return pixmap;
1213+}
1214+
1215+void DragHelper::setActive(bool active)
1216+{
1217+ if (m_active != active) {
1218+ m_active = active;
1219+
1220+ Q_EMIT activeChanged();
1221+ }
1222+}
1223+
1224+void DragHelper::setDragging(bool dragging)
1225+{
1226+ if (m_dragging != dragging) {
1227+ m_dragging = dragging;
1228+
1229+ Q_EMIT draggingChanged();
1230+ }
1231+}
1232+
1233+void DragHelper::setExpectedAction(Qt::DropAction expectedAction)
1234+{
1235+ if (m_expected_action != expectedAction) {
1236+ m_expected_action = expectedAction;
1237+
1238+ Q_EMIT expectedActionChanged();
1239+ }
1240+}
1241+
1242+void DragHelper::setMimeType(QString mimeType)
1243+{
1244+ if (m_mime_type != mimeType) {
1245+ m_mime_type = mimeType;
1246+
1247+ Q_EMIT mimeTypeChanged();
1248+ }
1249+}
1250+
1251+void DragHelper::setPreviewBorderWidth(int previewBorderWidth)
1252+{
1253+ if (m_preview_border_width != previewBorderWidth) {
1254+ m_preview_border_width = previewBorderWidth;
1255+
1256+ Q_EMIT previewBorderWidthChanged();
1257+ }
1258+}
1259+
1260+void DragHelper::setPreviewSize(QSizeF previewSize)
1261+{
1262+ if (m_preview_size != previewSize) {
1263+ m_preview_size = previewSize;
1264+
1265+ Q_EMIT previewSizeChanged();
1266+ }
1267+}
1268+
1269+void DragHelper::setPreviewTopCrop(int previewTopCrop)
1270+{
1271+ if (m_preview_top_crop != previewTopCrop) {
1272+ m_preview_top_crop = previewTopCrop;
1273+
1274+ Q_EMIT previewTopCropChanged();
1275+ }
1276+}
1277+
1278+void DragHelper::setPreviewUrl(QString previewUrl)
1279+{
1280+ if (m_preview_url != previewUrl) {
1281+ m_preview_url = previewUrl;
1282+
1283+ Q_EMIT previewUrlChanged();
1284+ }
1285+}
1286+
1287+void DragHelper::setSource(QQuickItem *source)
1288+{
1289+ if (m_source != source) {
1290+ m_source = source;
1291+
1292+ Q_EMIT sourceChanged();
1293+ }
1294+}
1295+
1296
1297=== added file 'src/app/webbrowser/drag-helper.h'
1298--- src/app/webbrowser/drag-helper.h 1970-01-01 00:00:00 +0000
1299+++ src/app/webbrowser/drag-helper.h 2016-11-30 14:23:08 +0000
1300@@ -0,0 +1,91 @@
1301+/*
1302+ * Copyright 2016 Canonical Ltd.
1303+ *
1304+ * This file is part of webbrowser-app.
1305+ *
1306+ * webbrowser-app is free software; you can redistribute it and/or modify
1307+ * it under the terms of the GNU General Public License as published by
1308+ * the Free Software Foundation; version 3.
1309+ *
1310+ * webbrowser-app is distributed in the hope that it will be useful,
1311+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1312+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1313+ * GNU General Public License for more details.
1314+ *
1315+ * You should have received a copy of the GNU General Public License
1316+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1317+ */
1318+
1319+#ifndef __DRAGHELPER_H__
1320+#define __DRAGHELPER_H__
1321+
1322+#include <QtCore/QSizeF>
1323+#include <QtCore/QObject>
1324+#include <QtCore/QString>
1325+#include <QtGui/QColor>
1326+#include <QtGui/QMouseEvent>
1327+
1328+class QQuickItem;
1329+
1330+class DragHelper : public QObject
1331+{
1332+ Q_OBJECT
1333+
1334+ Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
1335+ Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
1336+ Q_PROPERTY(Qt::DropAction expectedAction READ expectedAction WRITE setExpectedAction NOTIFY expectedActionChanged)
1337+ Q_PROPERTY(QString mimeType READ mimeType WRITE setMimeType NOTIFY mimeTypeChanged)
1338+ Q_PROPERTY(int previewBorderWidth READ previewBorderWidth WRITE setPreviewBorderWidth NOTIFY previewBorderWidthChanged)
1339+ Q_PROPERTY(QSizeF previewSize READ previewSize WRITE setPreviewSize NOTIFY previewSizeChanged)
1340+ Q_PROPERTY(int previewTopCrop READ previewTopCrop WRITE setPreviewTopCrop NOTIFY previewTopCropChanged)
1341+ Q_PROPERTY(QString previewUrl READ previewUrl WRITE setPreviewUrl NOTIFY previewUrlChanged)
1342+ Q_PROPERTY(QQuickItem* source READ source WRITE setSource NOTIFY sourceChanged)
1343+public:
1344+ DragHelper();
1345+ bool active() { return m_active; }
1346+ bool dragging() { return m_dragging; }
1347+ Qt::DropAction expectedAction() { return m_expected_action; }
1348+ QString mimeType() { return m_mime_type; }
1349+ int previewBorderWidth() { return m_preview_border_width; }
1350+ QSizeF previewSize() { return m_preview_size; }
1351+ int previewTopCrop() { return m_preview_top_crop; }
1352+ QString previewUrl() { return m_preview_url; }
1353+ QQuickItem *source() { return m_source; }
1354+signals:
1355+ void activeChanged();
1356+ void draggingChanged();
1357+ void expectedActionChanged();
1358+ void mimeTypeChanged();
1359+ void previewBorderWidthChanged();
1360+ void previewSizeChanged();
1361+ void previewTopCropChanged();
1362+ void previewUrlChanged();
1363+ void sourceChanged();
1364+public slots:
1365+ Q_INVOKABLE Qt::DropAction execDrag(QString tabId);
1366+ void setActive(bool active);
1367+ void setExpectedAction(Qt::DropAction expectedAction);
1368+ void setMimeType(QString mimeType);
1369+ void setPreviewBorderWidth(int previewBorderWidth);
1370+ void setPreviewSize(QSizeF previewSize);
1371+ void setPreviewTopCrop(int previewTopCrop);
1372+ void setPreviewUrl(QString previewUrl);
1373+ void setSource(QQuickItem *source);
1374+private:
1375+ QPixmap drawPixmapWithBorder(QPixmap pixmap, int borderWidth, QColor color);
1376+ QPixmap getPreviewUrlAsPixmap(int width, int height);
1377+ void setDragging(bool dragging);
1378+
1379+ bool m_active;
1380+ bool m_dragging;
1381+ Qt::DropAction m_expected_action;
1382+ QString m_mime_type;
1383+ int m_preview_border_width;
1384+ QSizeF m_preview_size;
1385+ int m_preview_top_crop;
1386+ QString m_preview_url;
1387+ QQuickItem *m_source;
1388+};
1389+
1390+#endif // __DRAGHELPER_H__
1391+
1392
1393=== added file 'src/app/webbrowser/reparenter.cpp'
1394--- src/app/webbrowser/reparenter.cpp 1970-01-01 00:00:00 +0000
1395+++ src/app/webbrowser/reparenter.cpp 2016-11-30 14:23:08 +0000
1396@@ -0,0 +1,124 @@
1397+/*
1398+ * Copyright 2016 Canonical Ltd.
1399+ *
1400+ * This file is part of webbrowser-app.
1401+ *
1402+ * webbrowser-app is free software; you can redistribute it and/or modify
1403+ * it under the terms of the GNU General Public License as published by
1404+ * the Free Software Foundation; version 3.
1405+ *
1406+ * webbrowser-app is distributed in the hope that it will be useful,
1407+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1408+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1409+ * GNU General Public License for more details.
1410+ *
1411+ * You should have received a copy of the GNU General Public License
1412+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1413+ */
1414+
1415+#include "reparenter.h"
1416+
1417+#include <QtCore/QPointer>
1418+#include <QtCore/QVariantMap>
1419+#include <QtQml>
1420+#include <QtQml/QQmlComponent>
1421+#include <QtQml/QQmlContext>
1422+#include <QtQml/QQmlEngine>
1423+#include <QtQml/QQmlProperty>
1424+#include <QtQuick/QQuickItem>
1425+
1426+Reparenter::Reparenter()
1427+{
1428+}
1429+
1430+// Upon deconstruction ensure that all created contexts are destroyed
1431+Reparenter::~Reparenter()
1432+{
1433+ QMap<QPointer<QQmlContext>, QPointer<QObject>>::iterator i;
1434+
1435+ for (i = m_contexts.begin(); i != m_contexts.end(); ++i) {
1436+ QPointer<QQmlContext> context = i.key();
1437+ QPointer<QObject> obj = i.value();
1438+
1439+ // If there is valid object then delete
1440+ if (obj) {
1441+ delete obj;
1442+ }
1443+
1444+ // If there is a valid context then delete
1445+ if (context) {
1446+ delete context;
1447+ }
1448+ }
1449+
1450+ m_contexts.clear(); // ensure contexts are removed
1451+}
1452+
1453+// Create an object of the given component with the context given
1454+// if no context is given then the context is the instance of this class
1455+// this method is required so that a custom context can be created, so that
1456+// when tabs are moved between Windows and the window is destroyed, its context
1457+// it not also destroyed
1458+QObject *Reparenter::createObject(QQmlComponent *comp, QQuickItem *parent, QVariantMap properties, QQuickItem *contextItem)
1459+{
1460+ // Make context for the object
1461+ QPointer<QQmlContext> context;
1462+
1463+ if (contextItem == Q_NULLPTR) {
1464+ // Build context from parent
1465+ context = new QQmlContext(qmlEngine(parent)->rootContext());
1466+ context->setContextObject(parent);
1467+ } else {
1468+ context = new QQmlContext(QQmlEngine::contextForObject(contextItem));
1469+ context->setContextObject(contextItem);
1470+ }
1471+
1472+ // Make component
1473+ QPointer<QObject> obj = comp->beginCreate(context);
1474+
1475+ // Set visual and actual parent
1476+ reparent(qobject_cast<QQuickItem *>(obj), parent);
1477+
1478+ // Load properties into object
1479+ for (QString key : properties.keys()) {
1480+ QQmlProperty::write(obj, key, properties.value(key));
1481+ }
1482+
1483+ // Add to store
1484+ m_contexts.insert(context, obj);
1485+
1486+ comp->completeCreate();
1487+
1488+ return obj;
1489+}
1490+
1491+// Contexts that have been created by us, must be destroyed by us
1492+// so this helper method destroys the context and object
1493+void Reparenter::destroyContextAndObject(QQuickItem *item)
1494+{
1495+ // Get context for object
1496+ QQmlContext *context = QQmlEngine::contextForObject(item)->parentContext();
1497+
1498+ // Remove from store
1499+ int removed = m_contexts.remove(context);
1500+
1501+ // Disconnect everything
1502+ item->disconnect();
1503+
1504+ // Delete context if it was removed from our store
1505+ if (removed > 0) {
1506+ context->deleteLater();
1507+ }
1508+
1509+ // Delete the object
1510+ item->deleteLater();
1511+}
1512+
1513+// Reparent the actual objects parent and its visual parent
1514+void Reparenter::reparent(QQuickItem *obj, QQuickItem *newParent)
1515+{
1516+ // Set object and visual parent
1517+ obj->setParent(newParent);
1518+ obj->setParentItem(newParent);
1519+}
1520+
1521
1522=== added file 'src/app/webbrowser/reparenter.h'
1523--- src/app/webbrowser/reparenter.h 1970-01-01 00:00:00 +0000
1524+++ src/app/webbrowser/reparenter.h 2016-11-30 14:23:08 +0000
1525@@ -0,0 +1,46 @@
1526+/*
1527+ * Copyright 2016 Canonical Ltd.
1528+ *
1529+ * This file is part of webbrowser-app.
1530+ *
1531+ * webbrowser-app is free software; you can redistribute it and/or modify
1532+ * it under the terms of the GNU General Public License as published by
1533+ * the Free Software Foundation; version 3.
1534+ *
1535+ * webbrowser-app is distributed in the hope that it will be useful,
1536+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1537+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1538+ * GNU General Public License for more details.
1539+ *
1540+ * You should have received a copy of the GNU General Public License
1541+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1542+ */
1543+
1544+#ifndef __REPARENTER_H__
1545+#define __REPARENTER_H__
1546+
1547+#include <QtCore/QMap>
1548+#include <QtCore/QObject>
1549+#include <QtCore/QPointer>
1550+#include <QtCore/QVariantMap>
1551+#include <QtQml/QQmlComponent>
1552+#include <QtQml/QQmlContext>
1553+#include <QtQuick/QQuickItem>
1554+
1555+class Reparenter : public QObject
1556+{
1557+ Q_OBJECT
1558+
1559+public:
1560+ Reparenter();
1561+ ~Reparenter();
1562+
1563+ Q_INVOKABLE QObject *createObject(QQmlComponent *comp, QQuickItem *parent, QVariantMap properties={}, QQuickItem *contextItem=Q_NULLPTR);
1564+ Q_INVOKABLE void destroyContextAndObject(QQuickItem *item);
1565+ Q_INVOKABLE void reparent(QQuickItem *obj, QQuickItem *newParent);
1566+private:
1567+ QMap<QPointer<QQmlContext>, QPointer<QObject>> m_contexts;
1568+};
1569+
1570+#endif // __REPARENTER_H__
1571+
1572
1573=== modified file 'src/app/webbrowser/webbrowser-app.cpp'
1574--- src/app/webbrowser/webbrowser-app.cpp 2016-08-18 16:29:35 +0000
1575+++ src/app/webbrowser/webbrowser-app.cpp 2016-11-30 14:23:08 +0000
1576@@ -21,11 +21,13 @@
1577 #include "cache-deleter.h"
1578 #include "config.h"
1579 #include "downloads-model.h"
1580+#include "drag-helper.h"
1581 #include "file-operations.h"
1582 #include "history-domainlist-model.h"
1583 #include "history-lastvisitdatelist-model.h"
1584 #include "history-model.h"
1585 #include "limit-proxy-model.h"
1586+#include "reparenter.h"
1587 #include "searchengine.h"
1588 #include "text-search-filter-model.h"
1589 #include "tabs-model.h"
1590@@ -60,6 +62,8 @@
1591 MAKE_SINGLETON_FACTORY(BookmarksModel)
1592 MAKE_SINGLETON_FACTORY(HistoryModel)
1593 MAKE_SINGLETON_FACTORY(DownloadsModel)
1594+MAKE_SINGLETON_FACTORY(Reparenter)
1595+MAKE_SINGLETON_FACTORY(DragHelper)
1596
1597 bool WebbrowserApp::initialize()
1598 {
1599@@ -76,6 +80,8 @@
1600 qmlRegisterSingletonType<CacheDeleter>(uri, 0, 1, "CacheDeleter", CacheDeleter_singleton_factory);
1601 qmlRegisterSingletonType<DownloadsModel>(uri, 0, 1, "DownloadsModel", DownloadsModel_singleton_factory);
1602 qmlRegisterType<TextSearchFilterModel>(uri, 0, 1, "TextSearchFilterModel");
1603+ qmlRegisterSingletonType<DragHelper>(uri, 0, 1, "DragHelper", DragHelper_singleton_factory);
1604+ qmlRegisterSingletonType<Reparenter>(uri, 0, 1, "Reparenter", Reparenter_singleton_factory);
1605
1606 if (BrowserApplication::initialize("webbrowser/webbrowser-app.qml", QStringLiteral("webbrowser-app"))) {
1607 QStringList searchEnginesSearchPaths;
1608
1609=== modified file 'src/app/webbrowser/webbrowser-app.qml'
1610--- src/app/webbrowser/webbrowser-app.qml 2016-10-10 17:00:52 +0000
1611+++ src/app/webbrowser/webbrowser-app.qml 2016-11-30 14:23:08 +0000
1612@@ -92,7 +92,7 @@
1613 readonly property var tabsModel: browser.tabsModel
1614
1615 currentWebview: browser.currentWebview
1616-
1617+
1618 title: {
1619 if (browser.title) {
1620 // TRANSLATORS: %1 refers to the current page’s title
1621@@ -119,6 +119,7 @@
1622 session.clear()
1623 }
1624 }
1625+
1626 if (incognito && (allWindows.length > 1)) {
1627 // If the last incognito window is being closed,
1628 // prune incognito entries from the downloads model
1629@@ -133,6 +134,7 @@
1630 DownloadsModel.pruneIncognitoDownloads()
1631 }
1632 }
1633+
1634 destroy()
1635 }
1636
1637@@ -181,7 +183,27 @@
1638 Browser {
1639 id: browser
1640 anchors.fill: parent
1641+ thisWindow: window
1642 settings: webbrowserapp.settings
1643+ onNewWindowFromTab: {
1644+ var window = windowFactory.createObject(
1645+ null,
1646+ {
1647+ "incognito": tab.incognito,
1648+ "height": parent.height,
1649+ "width": parent.width,
1650+ }
1651+ );
1652+
1653+ window.addExistingTab(tab);
1654+ window.tabsModel.currentIndex = window.tabsModel.count - 1;
1655+ window.show();
1656+ window.requestActivate();
1657+
1658+ window.tabsModel.currentTab.load();
1659+
1660+ callback();
1661+ }
1662 onNewWindowRequested: {
1663 var window = windowFactory.createObject(
1664 null,
1665@@ -261,10 +283,18 @@
1666 }
1667
1668 function addTab(url) {
1669- var tab = browser.createTab({"initialUrl": url})
1670+ var tab = browser.createTab({"initialUrl": url || ""})
1671 tabsModel.add(tab)
1672 return tab
1673 }
1674+
1675+ function addExistingTab(tab) {
1676+ tabsModel.add(tab);
1677+
1678+ browser.bindExistingTab(tab);
1679+
1680+ return tab;
1681+ }
1682 }
1683 }
1684
1685@@ -438,7 +468,7 @@
1686 for (var w in allWindows) {
1687 var candidate = getCandidate(allWindows[w].tabsModel)
1688 if (candidate) {
1689- if (browser.incognito) {
1690+ if (allWindows[w].incognito) {
1691 console.warn("Unloading a background incognito tab to free up some memory")
1692 } else {
1693 console.warn("Unloading background tab (%1) to free up some memory".arg(candidate.url))
1694
1695=== modified file 'src/app/webcontainer/ContextMenuMobile.qml'
1696--- src/app/webcontainer/ContextMenuMobile.qml 2016-09-19 12:08:03 +0000
1697+++ src/app/webcontainer/ContextMenuMobile.qml 2016-11-30 14:23:08 +0000
1698@@ -23,6 +23,8 @@
1699 import com.canonical.Oxide 1.8 as Oxide
1700
1701 Popups.Dialog {
1702+ id: contextMenu
1703+
1704 property QtObject contextModel: model
1705 property ActionList actions: null
1706
1707@@ -121,7 +123,7 @@
1708 }
1709 }
1710
1711- onTriggered: contextModel.close()
1712+ onTriggered: contextMenu.hide()
1713 }
1714 }
1715
1716@@ -140,7 +142,13 @@
1717 fontSize: "x-small"
1718 text: i18n.tr("Cancel")
1719 }
1720- onTriggered: contextModel.close()
1721+ onTriggered: contextMenu.hide()
1722+ }
1723+
1724+ onVisibleChanged: {
1725+ if (!visible) {
1726+ contextModel.close()
1727+ }
1728 }
1729
1730 // adjust default dialog visuals to custom requirements for the context menu
1731
1732=== modified file 'src/app/webcontainer/WebappWebview.qml'
1733--- src/app/webcontainer/WebappWebview.qml 2016-03-16 15:17:34 +0000
1734+++ src/app/webcontainer/WebappWebview.qml 2016-11-30 14:23:08 +0000
1735@@ -17,7 +17,7 @@
1736 */
1737
1738 import QtQuick 2.4
1739-import com.canonical.Oxide 1.8 as Oxide
1740+import com.canonical.Oxide 1.15 as Oxide
1741 import Ubuntu.Components 1.3
1742 import Ubuntu.Components.Popups 1.3
1743 import Ubuntu.Web 0.2
1744@@ -64,9 +64,10 @@
1745 }
1746 Actions.CopyImage {
1747 enabled: contextModel &&
1748- (contextModel.mediaType === Oxide.WebView.MediaTypeImage) &&
1749- contextModel.srcUrl.toString()
1750- onTriggered: Clipboard.push(["text/plain", contextModel.srcUrl.toString()])
1751+ ((contextModel.mediaType === Oxide.WebView.MediaTypeImage) ||
1752+ (contextModel.mediaType === Oxide.WebView.MediaTypeCanvas)) &&
1753+ contextModel.hasImageContents
1754+ onTriggered: contextModel.copyImage()
1755 objectName: "CopyImageContextualAction"
1756 }
1757 Actions.SaveImage {
1758
1759=== modified file 'tests/autopilot/webbrowser_app/emulators/browser.py'
1760--- tests/autopilot/webbrowser_app/emulators/browser.py 2016-10-13 14:36:24 +0000
1761+++ tests/autopilot/webbrowser_app/emulators/browser.py 2016-11-30 14:23:08 +0000
1762@@ -316,6 +316,10 @@
1763 return self.select_single("ChromeButton",
1764 objectName="findPreviousButton")
1765
1766+ def get_progress_bar(self):
1767+ return self.select_single("ProgressBar",
1768+ objectName="chromeProgressBar")
1769+
1770
1771 class AddressBar(uitk.UbuntuUIToolkitCustomProxyObjectBase):
1772
1773@@ -522,7 +526,9 @@
1774
1775 class DownloadsPage(BrowserPage):
1776
1777- pass
1778+ def get_download_entries(self):
1779+ return sorted(self.select_many("DownloadDelegate"),
1780+ key=lambda item: item.globalRect.y)
1781
1782
1783 class HistoryView(uitk.UbuntuUIToolkitCustomProxyObjectBase):
1784
1785=== modified file 'tests/autopilot/webbrowser_app/tests/__init__.py'
1786--- tests/autopilot/webbrowser_app/tests/__init__.py 2016-09-20 21:56:25 +0000
1787+++ tests/autopilot/webbrowser_app/tests/__init__.py 2016-11-30 14:23:08 +0000
1788@@ -216,23 +216,29 @@
1789 self.pointing_device.click_object(bookmarks_action)
1790 return self.main_window.get_bookmarks_view()
1791
1792- def open_history(self):
1793- chrome = self.main_window.chrome
1794+ def open_history(self, window=None):
1795+ if window is None:
1796+ window = self.main_window
1797+
1798+ chrome = window.chrome
1799 drawer_button = chrome.get_drawer_button()
1800 self.pointing_device.click_object(drawer_button)
1801 chrome.get_drawer()
1802 history_action = chrome.get_drawer_action("history")
1803 self.pointing_device.click_object(history_action)
1804- return self.main_window.get_history_view()
1805-
1806- def open_downloads(self):
1807- chrome = self.main_window.chrome
1808+ return window.get_history_view()
1809+
1810+ def open_downloads(self, window=None):
1811+ if window is None:
1812+ window = self.main_window
1813+
1814+ chrome = window.chrome
1815 drawer_button = chrome.get_drawer_button()
1816 self.pointing_device.click_object(drawer_button)
1817 chrome.get_drawer()
1818 downloads_action = chrome.get_drawer_action("downloads")
1819 self.pointing_device.click_object(downloads_action)
1820- return self.main_window.get_downloads_page()
1821+ return window.get_downloads_page()
1822
1823 def assert_number_webviews_eventually(self, count):
1824 self.assertThat(lambda: len(self.main_window.get_webviews()),
1825@@ -256,6 +262,33 @@
1826 os.kill(child.pid, signal)
1827 break
1828
1829+ def switch_to_unfocused_window(self, target_window,
1830+ expected_number_unfocused_windows=1):
1831+ try:
1832+ windows = [
1833+ window for window in self.process_manager.get_open_windows()
1834+ if window.application.desktop_file ==
1835+ "webbrowser-app.desktop" and
1836+ not window.is_focused
1837+ ]
1838+
1839+ self.assertThat(len(windows),
1840+ Equals(expected_number_unfocused_windows))
1841+
1842+ # Cycle through possible windows until target gets focus
1843+ for window in windows:
1844+ window.set_focus()
1845+ self.assertThat(lambda: window.is_focused,
1846+ Eventually(Equals(True)))
1847+
1848+ if target_window.activeFocus:
1849+ break
1850+ except (RuntimeError, ImportError):
1851+ # Fallback to clicking on the window
1852+ self.pointing_device.click_object(target_window)
1853+
1854+ self.assertThat(target_window.activeFocus, Eventually(Equals(True)))
1855+
1856
1857 class StartOpenRemotePageTestCaseBase(BrowserTestCaseBase):
1858
1859
1860=== modified file 'tests/autopilot/webbrowser_app/tests/test_downloads.py'
1861--- tests/autopilot/webbrowser_app/tests/test_downloads.py 2015-12-15 16:02:16 +0000
1862+++ tests/autopilot/webbrowser_app/tests/test_downloads.py 2016-11-30 14:23:08 +0000
1863@@ -21,11 +21,12 @@
1864
1865 from testtools.matchers import Equals
1866
1867+import ubuntuuitoolkit as uitk
1868+
1869+import subprocess
1870 import testtools
1871
1872
1873-@testtools.skipIf(model() == "Desktop", "Don't run on desktop, as "
1874- "dependencies aren't guaranteed")
1875 class TestDownloads(StartOpenRemotePageTestCaseBase):
1876
1877 def test_open_close_downloads_page(self):
1878@@ -60,6 +61,65 @@
1879 self.assertThat(options_dialog.visible, Eventually(Equals(True)))
1880 self.main_window.click_cancel_download_button()
1881
1882+ def test_download(self):
1883+ self.main_window.go_to_url(self.base_url + "/downloadpdf")
1884+ options_dialog = self.main_window.get_download_options_dialog()
1885+ self.assertThat(options_dialog.visible, Eventually(Equals(True)))
1886+ self.main_window.click_download_file_button()
1887+ downloads_page = self.main_window.get_downloads_page()
1888+ self.assertThat(downloads_page.visible, Eventually(Equals(True)))
1889+
1890+ @testtools.skipIf(model() != "Desktop",
1891+ "Desktop only due to switch_to_unfocused_window")
1892+ def test_private_download(self):
1893+ self.open_new_private_window()
1894+
1895+ public_window = self.app.get_windows(incognito=False)[0]
1896+ private_window = self.app.get_windows(incognito=True)[0]
1897+ pdf_download_url = self.base_url + "/downloadpdf"
1898+
1899+ # Download pdf in private window
1900+ private_window.go_to_url(pdf_download_url)
1901+ options_dialog = private_window.get_download_options_dialog()
1902+ self.assertThat(options_dialog.visible, Eventually(Equals(True)))
1903+ private_window.click_download_file_button()
1904+
1905+ # Open downloads page in private window
1906+ private_downloads_page = private_window.get_downloads_page()
1907+ private_downloads_page.visible.wait_for(True)
1908+
1909+ # Check that there is one url in the private downloads window
1910+ entries = private_downloads_page.get_download_entries()
1911+ self.assertThat(len(entries), Equals(1))
1912+ self.assertThat(entries[0].url, Equals(pdf_download_url))
1913+ self.assertThat(entries[0].incognito, Equals(True))
1914+
1915+ # Focus public window
1916+ self.switch_to_unfocused_window(public_window)
1917+
1918+ # Open downloads page in public window
1919+ public_downloads_page = self.open_downloads(public_window)
1920+ public_downloads_page.visible.wait_for(True)
1921+
1922+ # Check that there are no entries in the public downloads window
1923+ entries = public_downloads_page.get_download_entries()
1924+ self.assertThat(len(entries), Equals(0))
1925+
1926+
1927+class TestDownloadsWithContentHubTestability(StartOpenRemotePageTestCaseBase):
1928+ def setUp(self):
1929+ # Run content-hub-peer-hook-wrapper which ensures that
1930+ # content-hub-testability has been register for the ContentPeersModel
1931+
1932+ # Find arch path of content-hub-peer-hook-wrapper
1933+ path = ("/usr/lib/%s/content-hub/content-hub-peer-hook-wrapper" %
1934+ uitk.base.get_host_multiarch())
1935+
1936+ return_code = subprocess.check_call([path])
1937+ self.assertThat(return_code, Equals(0))
1938+
1939+ super(TestDownloadsWithContentHubTestability, self).setUp()
1940+
1941 def test_picker(self):
1942 self.main_window.go_to_url(self.base_url + "/downloadpdf")
1943 options_dialog = self.main_window.get_download_options_dialog()
1944@@ -67,11 +127,3 @@
1945 self.main_window.click_choose_app_button()
1946 picker = self.main_window.get_peer_picker()
1947 self.assertThat(picker.visible, Eventually(Equals(True)))
1948-
1949- def test_download(self):
1950- self.main_window.go_to_url(self.base_url + "/downloadpdf")
1951- options_dialog = self.main_window.get_download_options_dialog()
1952- self.assertThat(options_dialog.visible, Eventually(Equals(True)))
1953- self.main_window.click_download_file_button()
1954- downloads_page = self.main_window.get_downloads_page()
1955- self.assertThat(downloads_page.visible, Eventually(Equals(True)))
1956
1957=== modified file 'tests/autopilot/webbrowser_app/tests/test_history.py'
1958--- tests/autopilot/webbrowser_app/tests/test_history.py 2016-10-06 21:07:50 +0000
1959+++ tests/autopilot/webbrowser_app/tests/test_history.py 2016-11-30 14:23:08 +0000
1960@@ -18,15 +18,21 @@
1961
1962 from testtools.matchers import EndsWith, Equals, StartsWith
1963 from autopilot.matchers import Eventually
1964+from autopilot.platform import model
1965
1966 from webbrowser_app.tests import StartOpenRemotePageTestCaseBase
1967
1968+import testtools
1969+
1970
1971 class TestHistory(StartOpenRemotePageTestCaseBase):
1972
1973- def expect_history_entries(self, ordered_urls):
1974- history = self.main_window.get_history_view()
1975- if self.main_window.wide:
1976+ def expect_history_entries(self, ordered_urls, window=None):
1977+ if window is None:
1978+ window = self.main_window
1979+
1980+ history = window.get_history_view()
1981+ if window.wide:
1982 self.assertThat(lambda: len(history.get_entries()),
1983 Eventually(Equals(len(ordered_urls))))
1984 entries = history.get_entries()
1985@@ -34,7 +40,7 @@
1986 self.assertThat(lambda: len(history.get_domain_entries()),
1987 Eventually(Equals(1)))
1988 self.pointing_device.click_object(history.get_domain_entries()[0])
1989- expanded_history = self.main_window.get_expanded_history_view()
1990+ expanded_history = window.get_expanded_history_view()
1991 self.assertThat(lambda: len(expanded_history.get_entries()),
1992 Eventually(Equals(len(ordered_urls))))
1993 entries = expanded_history.get_entries()
1994@@ -125,6 +131,26 @@
1995 self.open_history()
1996 self.expect_history_entries([pushed, url, self.url])
1997
1998+ @testtools.skipIf(model() != "Desktop",
1999+ "Desktop only due to switch_to_unfocused_window")
2000+ def test_private_window_no_history(self):
2001+ self.open_new_private_window()
2002+
2003+ public_window = self.app.get_windows(incognito=False)[0]
2004+ private_window = self.app.get_windows(incognito=True)[0]
2005+
2006+ # Open link in private window
2007+ url = self.base_url + "/test2"
2008+ private_window.go_to_url(url)
2009+ private_window.wait_until_page_loaded(url)
2010+
2011+ # Focus public window
2012+ self.switch_to_unfocused_window(public_window)
2013+
2014+ # Check link is not in history of public window
2015+ self.open_history(window=public_window)
2016+ self.expect_history_entries([self.url], window=public_window)
2017+
2018 def test_title_correct_redirect_header(self):
2019 # Regression test for https://launchpad.net/bugs/1603835
2020 url_redirect = self.base_url + "/redirect-no-title-header"
2021
2022=== modified file 'tests/autopilot/webbrowser_app/tests/test_multiple_windows.py'
2023--- tests/autopilot/webbrowser_app/tests/test_multiple_windows.py 2016-09-20 21:56:25 +0000
2024+++ tests/autopilot/webbrowser_app/tests/test_multiple_windows.py 2016-11-30 14:23:08 +0000
2025@@ -14,7 +14,9 @@
2026 # You should have received a copy of the GNU General Public License
2027 # along with this program. If not, see <http://www.gnu.org/licenses/>.
2028
2029+from autopilot.matchers import Eventually
2030 from testtools.matchers import Equals
2031+from time import sleep
2032
2033 from webbrowser_app.tests import StartOpenRemotePageTestCaseBase
2034
2035@@ -38,3 +40,223 @@
2036 self.assertThat(len(windows), Equals(2))
2037 self.assertThat(len(self.app.get_windows(incognito=False)), Equals(1))
2038 self.assertThat(len(self.app.get_windows(incognito=True)), Equals(1))
2039+
2040+ def test_open_new_window_progress_bar_hidden(self):
2041+ # Regression test for pad.lv/1638337
2042+ url = self.base_url + "/test2"
2043+ self.main_window.go_to_url(url)
2044+ self.main_window.wait_until_page_loaded(url)
2045+
2046+ self.assertThat(self.main_window.chrome.get_progress_bar().visible,
2047+ Eventually(Equals(False)))
2048+
2049+ # Open a new window
2050+ self.open_new_window()
2051+ windows = self.app.get_windows()
2052+ self.assertThat(len(windows), Equals(2))
2053+
2054+ # Check that progress bar is hidden
2055+ for window in windows:
2056+ self.assertThat(window.chrome.get_progress_bar().visible,
2057+ Eventually(Equals(False)))
2058+
2059+
2060+class TestMultipleWindowsDrag(StartOpenRemotePageTestCaseBase):
2061+ def setUp(self):
2062+ super(TestMultipleWindowsDrag, self).setUp()
2063+
2064+ if not self.main_window.wide:
2065+ self.skipTest("Only on wide form factors")
2066+
2067+ def drag_tab(self, tab, x2, y2):
2068+ x1, y1 = self.get_object_center(tab)
2069+
2070+ self.pointing_device.move(x1, y1)
2071+ self.pointing_device.press()
2072+
2073+ # Drag tab downwards first to ensure we activate tab dragging
2074+ for i in range(100):
2075+ self.pointing_device.move(x1, y1 + i)
2076+
2077+ # Move to destination and release
2078+ # pause at each point so we can what is happening
2079+ sleep(0.25)
2080+ self.pointing_device.move(x2, y2)
2081+ sleep(0.25)
2082+ self.pointing_device.release()
2083+ sleep(0.25)
2084+
2085+ def get_object_center(self, obj):
2086+ x1, y1, width, height = obj.globalRect
2087+ x1 += width // 2
2088+ y1 += height // 2
2089+
2090+ return x1, y1
2091+
2092+ def get_tab_delegate(self, window, tabIndex):
2093+ return window.chrome.get_tabs_bar().get_tab(tabIndex)
2094+
2095+ def test_drag_tab_tabbar_nothing(self):
2096+ '''test that dragging a tab out and in of tabbar is same'''
2097+ window = self.app.get_windows()[0]
2098+
2099+ # Drag tab down and then back into tab bar
2100+ tab = self.get_tab_delegate(window, 0)
2101+ x2, y2 = self.get_object_center(tab)
2102+
2103+ self.drag_tab(tab, x2, y2)
2104+
2105+ # Check we still have 1 window and 1 tab
2106+ windows = self.app.get_windows()
2107+ self.assertThat(len(windows), Equals(1))
2108+ self.assertThat(lambda: len(windows[0].get_webviews()),
2109+ Eventually(Equals(1)))
2110+
2111+ def test_drag_tab_bottom_new_window(self):
2112+ '''test with two tabs dragging one to the bottom opens a new window'''
2113+ window = self.app.get_windows()[0]
2114+
2115+ # Open a new tab and check we have two
2116+ self.open_new_tab()
2117+ self.assertThat(lambda: len(window.get_webviews()),
2118+ Eventually(Equals(2)))
2119+
2120+ # Drag new tab to bottom part of window
2121+ tab = self.get_tab_delegate(window, 1)
2122+ x2, y2 = self.get_object_center(window)
2123+
2124+ self.drag_tab(tab, x2, y2)
2125+
2126+ # Check that a new window has been opened
2127+ windows = self.app.get_windows()
2128+ self.assertThat(len(windows), Equals(2))
2129+ self.assertThat(lambda: len(windows[0].get_webviews()),
2130+ Eventually(Equals(1)))
2131+ self.assertThat(lambda: len(windows[1].get_webviews()),
2132+ Eventually(Equals(1)))
2133+
2134+ def test_drag_tab_outside_new_window(self):
2135+ '''test with two tabs dragging one to the bottom opens a new window'''
2136+ window = self.app.get_windows()[0]
2137+
2138+ # Open a new tab and check we have two
2139+ self.open_new_tab()
2140+ self.assertThat(lambda: len(window.get_webviews()),
2141+ Eventually(Equals(2)))
2142+
2143+ # Drag new tab outside of window
2144+ tab = self.get_tab_delegate(window, 1)
2145+ x2, y2, width, height = window.globalRect
2146+
2147+ if x2 > 20:
2148+ x2 -= 20
2149+ else:
2150+ x2 += width + 20
2151+
2152+ self.drag_tab(tab, x2, y2)
2153+
2154+ # Check that a new window has been opened
2155+ windows = self.app.get_windows()
2156+ self.assertThat(len(windows), Equals(2))
2157+ self.assertThat(lambda: len(windows[0].get_webviews()),
2158+ Eventually(Equals(1)))
2159+ self.assertThat(lambda: len(windows[1].get_webviews()),
2160+ Eventually(Equals(1)))
2161+
2162+ def test_drag_tab_between_windows_move(self):
2163+ '''test that dragging a tab from one window to another'''
2164+ # Open a new tab and window
2165+ self.open_new_tab()
2166+ self.open_new_window()
2167+
2168+ windows = self.app.get_windows()
2169+ self.assertThat(len(windows), Equals(2))
2170+ self.assertThat(lambda: len(windows[0].get_webviews()),
2171+ Eventually(Equals(2)))
2172+ self.assertThat(lambda: len(windows[1].get_webviews()),
2173+ Eventually(Equals(1)))
2174+
2175+ # Focus window 0
2176+ self.switch_to_unfocused_window(windows[0])
2177+
2178+ # Move tab into window 1
2179+ tab = self.get_tab_delegate(windows[0], 1)
2180+ x2, y2 = self.get_object_center(windows[1].chrome.get_tabs_bar())
2181+
2182+ self.drag_tab(tab, x2, y2)
2183+
2184+ # Check there are two windows and two tabs open in the second window
2185+ windows = self.app.get_windows()
2186+ self.assertThat(len(windows), Equals(2))
2187+ self.assertThat(lambda: len(windows[0].get_webviews()),
2188+ Eventually(Equals(1)))
2189+ self.assertThat(lambda: len(windows[1].get_webviews()),
2190+ Eventually(Equals(2)))
2191+
2192+ def test_drag_tab_between_windows_move_and_close_window(self):
2193+ '''test that dragging tab from one window to another closes original'''
2194+ self.open_new_window()
2195+ windows = self.app.get_windows()
2196+ self.assertThat(len(windows), Equals(2))
2197+
2198+ # Focus window 0
2199+ self.switch_to_unfocused_window(windows[0])
2200+
2201+ # Move tab into window 1
2202+ tab = self.get_tab_delegate(windows[0], 0)
2203+ x2, y2 = self.get_object_center(windows[1].chrome.get_tabs_bar())
2204+
2205+ self.drag_tab(tab, x2, y2)
2206+
2207+ # Check there are two tabs open in the single remaining window
2208+ windows = self.app.get_windows()
2209+ self.assertThat(len(windows), Equals(1))
2210+ self.assertThat(lambda: len(windows[0].get_webviews()),
2211+ Eventually(Equals(2)))
2212+
2213+ def test_drag_public_tab_into_private_window(self):
2214+ '''test that you cannot drag a public tab into private window'''
2215+ # Open private window, check there are two windows
2216+ self.open_new_private_window()
2217+ windows = self.app.get_windows()
2218+ self.assertThat(len(windows), Equals(2))
2219+
2220+ public_window = self.app.get_windows(incognito=False)[0]
2221+ private_window = self.app.get_windows(incognito=True)[0]
2222+
2223+ # Focus public window
2224+ self.switch_to_unfocused_window(public_window)
2225+
2226+ # Move tab into private window
2227+ tab = self.get_tab_delegate(public_window, 0)
2228+ x2, y2 = self.get_object_center(private_window)
2229+
2230+ self.drag_tab(tab, x2, y2)
2231+
2232+ # Check there are two windows, one of public and one private
2233+ windows = self.app.get_windows()
2234+ self.assertThat(len(windows), Equals(2))
2235+ self.assertThat(len(self.app.get_windows(incognito=False)), Equals(1))
2236+ self.assertThat(len(self.app.get_windows(incognito=True)), Equals(1))
2237+
2238+ def test_drag_private_tab_into_public_window(self):
2239+ '''test that you cannot drag a private tab into public window'''
2240+ # Open private window, check there are two windows
2241+ self.open_new_private_window()
2242+ windows = self.app.get_windows()
2243+ self.assertThat(len(windows), Equals(2))
2244+
2245+ public_window = self.app.get_windows(incognito=False)[0]
2246+ private_window = self.app.get_windows(incognito=True)[0]
2247+
2248+ # Move tab into public window
2249+ tab = self.get_tab_delegate(private_window, 0)
2250+ x2, y2 = self.get_object_center(public_window)
2251+
2252+ self.drag_tab(tab, x2, y2)
2253+
2254+ # Check there are two windows, one of public and one private
2255+ windows = self.app.get_windows()
2256+ self.assertThat(len(windows), Equals(2))
2257+ self.assertThat(len(self.app.get_windows(incognito=False)), Equals(1))
2258+ self.assertThat(len(self.app.get_windows(incognito=True)), Equals(1))
2259
2260=== modified file 'tests/autopilot/webbrowser_app/tests/test_new_tab_view.py'
2261--- tests/autopilot/webbrowser_app/tests/test_new_tab_view.py 2016-10-11 11:25:23 +0000
2262+++ tests/autopilot/webbrowser_app/tests/test_new_tab_view.py 2016-11-30 14:23:08 +0000
2263@@ -466,3 +466,13 @@
2264 self.assertThat(lambda: len(view.get_bookmarks_list()),
2265 Eventually(Equals(2)))
2266 self.assertThat(view.get_bookmarks_list()[0].title, Equals(title))
2267+
2268+
2269+class TestNewTabViewPrivate(StartOpenRemotePageTestCaseBase):
2270+ def test_private_window_uses_private_tab_view(self):
2271+ self.open_new_private_window()
2272+
2273+ private_window = self.app.get_windows(incognito=True)[0]
2274+
2275+ self.assertThat(private_window.get_new_private_tab_view().visible,
2276+ Eventually(Equals(True)))
2277
2278=== modified file 'tests/unittests/bookmarks-folder-model/CMakeLists.txt'
2279--- tests/unittests/bookmarks-folder-model/CMakeLists.txt 2015-07-03 16:18:43 +0000
2280+++ tests/unittests/bookmarks-folder-model/CMakeLists.txt 2016-11-30 14:23:08 +0000
2281@@ -10,4 +10,4 @@
2282 Qt5::Test
2283 webbrowser-app-models
2284 )
2285-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2286+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2287
2288=== modified file 'tests/unittests/bookmarks-folderlist-model/CMakeLists.txt'
2289--- tests/unittests/bookmarks-folderlist-model/CMakeLists.txt 2015-07-03 16:18:43 +0000
2290+++ tests/unittests/bookmarks-folderlist-model/CMakeLists.txt 2016-11-30 14:23:08 +0000
2291@@ -10,4 +10,4 @@
2292 Qt5::Test
2293 webbrowser-app-models
2294 )
2295-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2296+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2297
2298=== modified file 'tests/unittests/bookmarks-model/CMakeLists.txt'
2299--- tests/unittests/bookmarks-model/CMakeLists.txt 2015-06-22 10:29:20 +0000
2300+++ tests/unittests/bookmarks-model/CMakeLists.txt 2016-11-30 14:23:08 +0000
2301@@ -10,4 +10,4 @@
2302 Qt5::Test
2303 webbrowser-app-models
2304 )
2305-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2306+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2307
2308=== modified file 'tests/unittests/container-url-patterns/CMakeLists.txt'
2309--- tests/unittests/container-url-patterns/CMakeLists.txt 2015-06-22 10:29:20 +0000
2310+++ tests/unittests/container-url-patterns/CMakeLists.txt 2016-11-30 14:23:08 +0000
2311@@ -11,4 +11,4 @@
2312 Qt5::Core
2313 Qt5::Test
2314 )
2315-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2316+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2317
2318=== modified file 'tests/unittests/cookie-store/CMakeLists.txt'
2319--- tests/unittests/cookie-store/CMakeLists.txt 2015-06-22 10:29:20 +0000
2320+++ tests/unittests/cookie-store/CMakeLists.txt 2016-11-30 14:23:08 +0000
2321@@ -17,4 +17,4 @@
2322 Qt5::Sql
2323 Qt5::Test
2324 )
2325-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2326+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2327
2328=== modified file 'tests/unittests/domain-utils/CMakeLists.txt'
2329--- tests/unittests/domain-utils/CMakeLists.txt 2015-06-22 10:29:20 +0000
2330+++ tests/unittests/domain-utils/CMakeLists.txt 2016-11-30 14:23:08 +0000
2331@@ -7,4 +7,4 @@
2332 Qt5::Core
2333 Qt5::Test
2334 )
2335-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2336+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2337
2338=== modified file 'tests/unittests/downloads-model/CMakeLists.txt'
2339--- tests/unittests/downloads-model/CMakeLists.txt 2015-12-11 13:38:52 +0000
2340+++ tests/unittests/downloads-model/CMakeLists.txt 2016-11-30 14:23:08 +0000
2341@@ -10,4 +10,4 @@
2342 Qt5::Test
2343 webbrowser-app-models
2344 )
2345-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2346+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2347
2348=== modified file 'tests/unittests/favicon-fetcher/CMakeLists.txt'
2349--- tests/unittests/favicon-fetcher/CMakeLists.txt 2015-06-22 10:29:20 +0000
2350+++ tests/unittests/favicon-fetcher/CMakeLists.txt 2016-11-30 14:23:08 +0000
2351@@ -15,5 +15,5 @@
2352 Qt5::Network
2353 Qt5::Test
2354 )
2355-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2356+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2357 set_tests_properties(${TEST} PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
2358
2359=== modified file 'tests/unittests/history-domain-model/CMakeLists.txt'
2360--- tests/unittests/history-domain-model/CMakeLists.txt 2015-06-22 10:29:20 +0000
2361+++ tests/unittests/history-domain-model/CMakeLists.txt 2016-11-30 14:23:08 +0000
2362@@ -10,4 +10,4 @@
2363 Qt5::Test
2364 webbrowser-app-models
2365 )
2366-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2367+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2368
2369=== modified file 'tests/unittests/history-domainlist-model/CMakeLists.txt'
2370--- tests/unittests/history-domainlist-model/CMakeLists.txt 2015-06-22 10:29:20 +0000
2371+++ tests/unittests/history-domainlist-model/CMakeLists.txt 2016-11-30 14:23:08 +0000
2372@@ -10,4 +10,4 @@
2373 Qt5::Test
2374 webbrowser-app-models
2375 )
2376-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2377+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2378
2379=== modified file 'tests/unittests/history-lastvisitdatelist-model/CMakeLists.txt'
2380--- tests/unittests/history-lastvisitdatelist-model/CMakeLists.txt 2015-07-29 00:25:59 +0000
2381+++ tests/unittests/history-lastvisitdatelist-model/CMakeLists.txt 2016-11-30 14:23:08 +0000
2382@@ -8,4 +8,4 @@
2383 Qt5::Sql
2384 Qt5::Test
2385 )
2386-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2387+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2388
2389=== modified file 'tests/unittests/history-model/CMakeLists.txt'
2390--- tests/unittests/history-model/CMakeLists.txt 2015-06-22 10:29:20 +0000
2391+++ tests/unittests/history-model/CMakeLists.txt 2016-11-30 14:23:08 +0000
2392@@ -10,4 +10,4 @@
2393 Qt5::Test
2394 webbrowser-app-models
2395 )
2396-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2397+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2398
2399=== modified file 'tests/unittests/intent-filter/CMakeLists.txt'
2400--- tests/unittests/intent-filter/CMakeLists.txt 2015-07-20 14:20:37 +0000
2401+++ tests/unittests/intent-filter/CMakeLists.txt 2016-11-30 14:23:08 +0000
2402@@ -14,4 +14,4 @@
2403 Qt5::Qml
2404 Qt5::Test
2405 )
2406-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2407+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2408
2409=== modified file 'tests/unittests/limit-proxy-model/CMakeLists.txt'
2410--- tests/unittests/limit-proxy-model/CMakeLists.txt 2015-06-22 10:29:20 +0000
2411+++ tests/unittests/limit-proxy-model/CMakeLists.txt 2016-11-30 14:23:08 +0000
2412@@ -10,4 +10,4 @@
2413 Qt5::Test
2414 webbrowser-app-models
2415 )
2416-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2417+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2418
2419=== modified file 'tests/unittests/meminfo/CMakeLists.txt'
2420--- tests/unittests/meminfo/CMakeLists.txt 2016-02-09 13:02:16 +0000
2421+++ tests/unittests/meminfo/CMakeLists.txt 2016-11-30 14:23:08 +0000
2422@@ -11,5 +11,5 @@
2423 Qt5::Core
2424 Qt5::Test
2425 )
2426-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2427+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2428 set_tests_properties(${TEST} PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
2429
2430=== modified file 'tests/unittests/oxide-cookie-helper/CMakeLists.txt'
2431--- tests/unittests/oxide-cookie-helper/CMakeLists.txt 2015-06-22 10:29:20 +0000
2432+++ tests/unittests/oxide-cookie-helper/CMakeLists.txt 2016-11-30 14:23:08 +0000
2433@@ -13,4 +13,4 @@
2434 Qt5::Network
2435 Qt5::Test
2436 )
2437-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2438+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2439
2440=== modified file 'tests/unittests/qml/CMakeLists.txt'
2441--- tests/unittests/qml/CMakeLists.txt 2016-08-24 18:17:55 +0000
2442+++ tests/unittests/qml/CMakeLists.txt 2016-11-30 14:23:08 +0000
2443@@ -18,12 +18,14 @@
2444 ${webbrowser-app_SOURCE_DIR}/bookmarks-model.cpp
2445 ${webbrowser-app_SOURCE_DIR}/bookmarks-folder-model.cpp
2446 ${webbrowser-app_SOURCE_DIR}/bookmarks-folderlist-model.cpp
2447+ ${webbrowser-app_SOURCE_DIR}/drag-helper.cpp
2448 ${webbrowser-app_SOURCE_DIR}/file-operations.cpp
2449 ${webbrowser-app_SOURCE_DIR}/history-domain-model.cpp
2450 ${webbrowser-app_SOURCE_DIR}/history-domainlist-model.cpp
2451 ${webbrowser-app_SOURCE_DIR}/history-model.cpp
2452 ${webbrowser-app_SOURCE_DIR}/history-lastvisitdatelist-model.cpp
2453 ${webbrowser-app_SOURCE_DIR}/limit-proxy-model.cpp
2454+ ${webbrowser-app_SOURCE_DIR}/reparenter.cpp
2455 ${webbrowser-app_SOURCE_DIR}/searchengine.cpp
2456 ${webbrowser-app_SOURCE_DIR}/tabs-model.cpp
2457 ${webbrowser-app_SOURCE_DIR}/text-search-filter-model.cpp
2458
2459=== added file 'tests/unittests/qml/ReparenterFakeContainer.qml'
2460--- tests/unittests/qml/ReparenterFakeContainer.qml 1970-01-01 00:00:00 +0000
2461+++ tests/unittests/qml/ReparenterFakeContainer.qml 2016-11-30 14:23:08 +0000
2462@@ -0,0 +1,40 @@
2463+/*
2464+ * Copyright 2016 Canonical Ltd.
2465+ *
2466+ * This file is part of webbrowser-app.
2467+ *
2468+ * webbrowser-app is free software; you can redistribute it and/or modify
2469+ * it under the terms of the GNU General Public License as published by
2470+ * the Free Software Foundation; version 3.
2471+ *
2472+ * webbrowser-app is distributed in the hope that it will be useful,
2473+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2474+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2475+ * GNU General Public License for more details.
2476+ *
2477+ * You should have received a copy of the GNU General Public License
2478+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2479+ */
2480+import QtQuick 2.4
2481+
2482+Item {
2483+ id: containerLeft
2484+ anchors {
2485+ bottom: parent.bottom
2486+ left: parent.left
2487+ right: parent.horizontalCenter
2488+ top: parent.top
2489+ }
2490+
2491+ property var root
2492+
2493+ function makeTab() {
2494+ var component = Qt.createComponent(Qt.resolvedUrl("ReparenterFakeTab.qml"))
2495+ return component.createObject(containerLeft, {})
2496+ }
2497+
2498+ function makeTabHelper() {
2499+ var component = Qt.createComponent(Qt.resolvedUrl("ReparenterFakeTab.qml"))
2500+ return root.builder(component, containerLeft)
2501+ }
2502+}
2503
2504=== added file 'tests/unittests/qml/ReparenterFakeTab.qml'
2505--- tests/unittests/qml/ReparenterFakeTab.qml 1970-01-01 00:00:00 +0000
2506+++ tests/unittests/qml/ReparenterFakeTab.qml 2016-11-30 14:23:08 +0000
2507@@ -0,0 +1,37 @@
2508+/*
2509+ * Copyright 2016 Canonical Ltd.
2510+ *
2511+ * This file is part of webbrowser-app.
2512+ *
2513+ * webbrowser-app is free software; you can redistribute it and/or modify
2514+ * it under the terms of the GNU General Public License as published by
2515+ * the Free Software Foundation; version 3.
2516+ *
2517+ * webbrowser-app is distributed in the hope that it will be useful,
2518+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2519+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2520+ * GNU General Public License for more details.
2521+ *
2522+ * You should have received a copy of the GNU General Public License
2523+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2524+ */
2525+import QtQuick 2.4
2526+
2527+Item {
2528+ anchors {
2529+ fill: parent
2530+ }
2531+
2532+ readonly property MouseArea mouseArea: mouseAreaObj
2533+
2534+ MouseArea {
2535+ id: mouseAreaObj
2536+ anchors {
2537+ fill: parent
2538+ }
2539+
2540+ property int clickCount: 0
2541+
2542+ onClicked: clickCount++
2543+ }
2544+}
2545
2546=== modified file 'tests/unittests/qml/tst_BrowserTab.qml'
2547--- tests/unittests/qml/tst_BrowserTab.qml 2016-08-18 17:10:32 +0000
2548+++ tests/unittests/qml/tst_BrowserTab.qml 2016-11-30 14:23:08 +0000
2549@@ -44,6 +44,8 @@
2550 property int reloaded: 0
2551 property bool loadingState: false
2552 function reload() { reloaded++ }
2553+
2554+ signal loadEvent()
2555 }
2556 readonly property bool webviewPresent: webview
2557 }
2558@@ -163,9 +165,8 @@
2559 tab.current = false
2560 tryCompare(previewSavedSpy, "count", 1)
2561 verify(FileOperations.exists(path))
2562- tab.close()
2563+ tab.close(false)
2564 verify(!FileOperations.exists(path))
2565-
2566 tab.destroy()
2567 }
2568 }
2569
2570=== modified file 'tests/unittests/qml/tst_QmlTests.cpp'
2571--- tests/unittests/qml/tst_QmlTests.cpp 2016-02-11 08:26:47 +0000
2572+++ tests/unittests/qml/tst_QmlTests.cpp 2016-11-30 14:23:08 +0000
2573@@ -21,12 +21,14 @@
2574 #include <QtCore/QObject>
2575 #include <QtCore/QString>
2576 #include <QtCore/QTemporaryDir>
2577+#include <QtQml/QQmlEngine>
2578 #include <QtQml/QtQml>
2579 #include <QtQuickTest/QtQuickTest>
2580
2581 // local
2582 #include "bookmarks-model.h"
2583 #include "bookmarks-folderlist-model.h"
2584+#include "drag-helper.h"
2585 #include "favicon-fetcher.h"
2586 #include "file-operations.h"
2587 #include "history-domain-model.h"
2588@@ -34,6 +36,7 @@
2589 #include "history-model.h"
2590 #include "history-lastvisitdatelist-model.h"
2591 #include "limit-proxy-model.h"
2592+#include "reparenter.h"
2593 #include "searchengine.h"
2594 #include "tabs-model.h"
2595 #include "text-search-filter-model.h"
2596@@ -165,6 +168,8 @@
2597 MAKE_SINGLETON_FACTORY(BookmarksModel)
2598 MAKE_SINGLETON_FACTORY(HistoryModelMock)
2599 MAKE_SINGLETON_FACTORY(TestContext)
2600+MAKE_SINGLETON_FACTORY(Reparenter)
2601+MAKE_SINGLETON_FACTORY(DragHelper)
2602
2603 int main(int argc, char** argv)
2604 {
2605@@ -183,6 +188,8 @@
2606 qmlRegisterType<LimitProxyModel>(browserUri, 0, 1, "LimitProxyModel");
2607 qmlRegisterType<TextSearchFilterModel>(browserUri, 0, 1, "TextSearchFilterModel");
2608 qmlRegisterSingletonType<FileOperations>(browserUri, 0, 1, "FileOperations", FileOperations_singleton_factory);
2609+ qmlRegisterSingletonType<DragHelper>(browserUri, 0, 1, "DragHelper", DragHelper_singleton_factory);
2610+ qmlRegisterSingletonType<Reparenter>(browserUri, 0, 1, "Reparenter", Reparenter_singleton_factory);
2611
2612 const char* testUri = "webbrowsertest.private";
2613 qmlRegisterSingletonType<TestContext>(testUri, 0, 1, "TestContext", TestContext_singleton_factory);
2614
2615=== added file 'tests/unittests/qml/tst_Reparenter.qml'
2616--- tests/unittests/qml/tst_Reparenter.qml 1970-01-01 00:00:00 +0000
2617+++ tests/unittests/qml/tst_Reparenter.qml 2016-11-30 14:23:08 +0000
2618@@ -0,0 +1,114 @@
2619+/*
2620+ * Copyright 2016 Canonical Ltd.
2621+ *
2622+ * This file is part of webbrowser-app.
2623+ *
2624+ * webbrowser-app is free software; you can redistribute it and/or modify
2625+ * it under the terms of the GNU General Public License as published by
2626+ * the Free Software Foundation; version 3.
2627+ *
2628+ * webbrowser-app is distributed in the hope that it will be useful,
2629+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2630+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2631+ * GNU General Public License for more details.
2632+ *
2633+ * You should have received a copy of the GNU General Public License
2634+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2635+ */
2636+import QtQuick 2.4
2637+import QtTest 1.0
2638+import webbrowserapp.private 0.1
2639+
2640+Item {
2641+ id: root
2642+ height: 100
2643+ width: 100
2644+
2645+ property Item containerLeft
2646+
2647+ Item {
2648+ id: containerRight
2649+ anchors {
2650+ bottom: parent.bottom
2651+ left: parent.horizontalCenter
2652+ right: parent.right
2653+ top: parent.top
2654+ }
2655+ }
2656+
2657+ function addExisting(container, tab) {
2658+ tab.parent = container
2659+ }
2660+
2661+ function addExistingHelper(container, tab) {
2662+ Reparenter.reparent(tab, container, {});
2663+ }
2664+
2665+ function builder(component, container) {
2666+ return Reparenter.createObject(component, container)
2667+ }
2668+
2669+ TestCase {
2670+ name: "Reparenter"
2671+ when: windowShown
2672+
2673+ function init() {
2674+ var component = Qt.createComponent(Qt.resolvedUrl("ReparenterFakeContainer.qml"))
2675+ containerLeft = component.createObject(root, {})
2676+ containerLeft.root = root
2677+ }
2678+
2679+ function cleanup() {
2680+ containerRight.children = null
2681+ }
2682+
2683+ function test_reparenter_cpp() {
2684+ var tab = containerLeft.makeTabHelper()
2685+
2686+ // Click on tab ensure it has been clicked
2687+ mouseClick(root, 25, 50, Qt.LeftButton)
2688+ compare(tab.mouseArea.clickCount, 1)
2689+
2690+ // Move tab
2691+ addExistingHelper(containerRight, tab)
2692+
2693+ // Click on tab ensure it has been clicked
2694+ mouseClick(root, 75, 50, Qt.LeftButton)
2695+ compare(tab.mouseArea.clickCount, 2)
2696+
2697+ // Destroy context
2698+ containerLeft.destroy()
2699+
2700+ // Click on tab ensure it has been clicked
2701+ mouseClick(root, 75, 50, Qt.LeftButton)
2702+ compare(tab.mouseArea.clickCount, 3)
2703+
2704+ // Destroy object and check children have gone
2705+ Reparenter.destroyContextAndObject(tab)
2706+ tryCompare(tab, "mouseArea", undefined)
2707+ }
2708+
2709+ function test_reparenter_qml_expect_fail() {
2710+ var tab = containerLeft.makeTab()
2711+
2712+ // Click on tab ensure it has been clicked
2713+ mouseClick(root, 25, 50, Qt.LeftButton)
2714+ compare(tab.mouseArea.clickCount, 1)
2715+
2716+ // Move tab
2717+ addExisting(containerRight, tab)
2718+
2719+ // Click on tab ensure it has been clicked
2720+ mouseClick(root, 75, 50, Qt.LeftButton)
2721+ compare(tab.mouseArea.clickCount, 2)
2722+
2723+ // Destroy context
2724+ containerLeft.destroy()
2725+
2726+ // Attempt to click on tab find that children of tab have been
2727+ // destroyed as the context has gone
2728+ mouseClick(root, 75, 50, Qt.LeftButton)
2729+ tryCompare(tab, "mouseArea", undefined)
2730+ }
2731+ }
2732+}
2733
2734=== modified file 'tests/unittests/qml/tst_TabsBar.qml'
2735--- tests/unittests/qml/tst_TabsBar.qml 2016-10-04 11:33:37 +0000
2736+++ tests/unittests/qml/tst_TabsBar.qml 2016-11-30 14:23:08 +0000
2737@@ -28,6 +28,8 @@
2738 height: 200
2739 signal reload(string url)
2740
2741+ readonly property string __platformName: "MOCKED_PLATFORM_NAME"
2742+
2743 TabsModel {
2744 id: tabsModel
2745 }
2746
2747=== modified file 'tests/unittests/qml/tst_UbuntuWebView02.qml'
2748--- tests/unittests/qml/tst_UbuntuWebView02.qml 2016-09-19 13:17:54 +0000
2749+++ tests/unittests/qml/tst_UbuntuWebView02.qml 2016-11-30 14:23:08 +0000
2750@@ -95,6 +95,7 @@
2751 function test_no_contextual_actions() {
2752 loadHtmlWithHyperlink()
2753 rightClickWebview()
2754+ wait(500)
2755 compare(waitFor(getContextMenu), null)
2756 }
2757
2758
2759=== modified file 'tests/unittests/search-engine/CMakeLists.txt'
2760--- tests/unittests/search-engine/CMakeLists.txt 2015-06-22 10:29:20 +0000
2761+++ tests/unittests/search-engine/CMakeLists.txt 2016-11-30 14:23:08 +0000
2762@@ -11,4 +11,4 @@
2763 Qt5::Core
2764 Qt5::Test
2765 )
2766-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2767+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2768
2769=== modified file 'tests/unittests/session-storage/CMakeLists.txt'
2770--- tests/unittests/session-storage/CMakeLists.txt 2015-06-22 10:29:20 +0000
2771+++ tests/unittests/session-storage/CMakeLists.txt 2016-11-30 14:23:08 +0000
2772@@ -11,4 +11,4 @@
2773 Qt5::Core
2774 Qt5::Test
2775 )
2776-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2777+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2778
2779=== modified file 'tests/unittests/session-utils/CMakeLists.txt'
2780--- tests/unittests/session-utils/CMakeLists.txt 2015-06-22 10:29:20 +0000
2781+++ tests/unittests/session-utils/CMakeLists.txt 2016-11-30 14:23:08 +0000
2782@@ -11,4 +11,4 @@
2783 Qt5::Core
2784 Qt5::Test
2785 )
2786-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2787+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2788
2789=== modified file 'tests/unittests/single-instance-manager/CMakeLists.txt'
2790--- tests/unittests/single-instance-manager/CMakeLists.txt 2016-01-18 14:45:12 +0000
2791+++ tests/unittests/single-instance-manager/CMakeLists.txt 2016-11-30 14:23:08 +0000
2792@@ -13,5 +13,5 @@
2793 Qt5::Network
2794 Qt5::Test
2795 )
2796-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2797+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2798 set_tests_properties(${TEST} PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
2799
2800=== modified file 'tests/unittests/tabs-model/CMakeLists.txt'
2801--- tests/unittests/tabs-model/CMakeLists.txt 2015-06-22 10:29:20 +0000
2802+++ tests/unittests/tabs-model/CMakeLists.txt 2016-11-30 14:23:08 +0000
2803@@ -14,5 +14,5 @@
2804 Qt5::Test
2805 webbrowser-app-models
2806 )
2807-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2808+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2809 set_tests_properties(${TEST} PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
2810
2811=== modified file 'tests/unittests/text-search-filter-model/CMakeLists.txt'
2812--- tests/unittests/text-search-filter-model/CMakeLists.txt 2015-08-19 13:16:06 +0000
2813+++ tests/unittests/text-search-filter-model/CMakeLists.txt 2016-11-30 14:23:08 +0000
2814@@ -10,4 +10,4 @@
2815 Qt5::Test
2816 webbrowser-app-models
2817 )
2818-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2819+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2820
2821=== modified file 'tests/unittests/webapp-container-color-helper/CMakeLists.txt'
2822--- tests/unittests/webapp-container-color-helper/CMakeLists.txt 2016-04-04 17:14:01 +0000
2823+++ tests/unittests/webapp-container-color-helper/CMakeLists.txt 2016-11-30 14:23:08 +0000
2824@@ -13,5 +13,5 @@
2825 Qt5::Gui
2826 Qt5::Test
2827 )
2828-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2829+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})
2830 set_tests_properties(${TEST} PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
2831
2832=== modified file 'tests/unittests/webapp-container-hook/CMakeLists.txt'
2833--- tests/unittests/webapp-container-hook/CMakeLists.txt 2015-06-22 10:29:20 +0000
2834+++ tests/unittests/webapp-container-hook/CMakeLists.txt 2016-11-30 14:23:08 +0000
2835@@ -13,4 +13,4 @@
2836 Qt5::Core
2837 Qt5::Test
2838 )
2839-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
2840+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST})

Subscribers

People subscribed via source and target branches

to all changes:
to status/vote changes: