Merge lp:~jonas-drange/ubuntu-system-settings/updates-rewrite into lp:ubuntu-system-settings
- updates-rewrite
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Ken VanDine |
Approved revision: | 1876 |
Merged at revision: | 1696 |
Proposed branch: | lp:~jonas-drange/ubuntu-system-settings/updates-rewrite |
Merge into: | lp:ubuntu-system-settings |
Prerequisite: | lp:~jonas-drange/ubuntu-system-settings/makeqmltest |
Diff against target: |
19868 lines (+13831/-3824) 170 files modified
debian/control (+4/-2) plugins/about/CMakeLists.txt (+2/-1) plugins/about/PageComponent.qml (+10/-8) plugins/about/Version.qml (+6/-7) plugins/about/plugin.cpp (+10/-0) plugins/cellular/Components/MultiSim.qml (+0/-5) plugins/system-update/CMakeLists.txt (+67/-22) plugins/system-update/ChangelogExpander.qml (+77/-0) plugins/system-update/ClickUpdateDelegate.qml (+26/-0) plugins/system-update/Configuration.qml (+3/-3) plugins/system-update/DownloadHandler.qml (+204/-0) plugins/system-update/EntryComponent.qml (+24/-19) plugins/system-update/Global.qml (+142/-0) plugins/system-update/ImageUpdatePrompt.qml (+52/-0) plugins/system-update/InstallationFailed.qml (+34/-0) plugins/system-update/NotAuthenticatedNotification.qml (+62/-0) plugins/system-update/PageComponent.qml (+400/-679) plugins/system-update/UpdateDelegate.qml (+412/-0) plugins/system-update/click/apiclient.h (+67/-0) plugins/system-update/click/apiclient_impl.cpp (+215/-0) plugins/system-update/click/apiclient_impl.h (+56/-0) plugins/system-update/click/manager.h (+67/-0) plugins/system-update/click/manager_impl.cpp (+562/-0) plugins/system-update/click/manager_impl.h (+122/-0) plugins/system-update/click/manifest.h (+47/-0) plugins/system-update/click/manifest_impl.cpp (+97/-0) plugins/system-update/click/manifest_impl.h (+47/-0) plugins/system-update/click/sessiontoken.h (+42/-0) plugins/system-update/click/sessiontoken_impl.cpp (+48/-0) plugins/system-update/click/sessiontoken_impl.h (+48/-0) plugins/system-update/click/sso.h (+56/-0) plugins/system-update/click/sso_impl.cpp (+55/-0) plugins/system-update/click/sso_impl.h (+54/-0) plugins/system-update/click/tokendownloader.h (+74/-0) plugins/system-update/click/tokendownloader_factory.h (+44/-0) plugins/system-update/click/tokendownloader_factory_impl.cpp (+36/-0) plugins/system-update/click/tokendownloader_factory_impl.h (+37/-0) plugins/system-update/click/tokendownloader_impl.cpp (+81/-0) plugins/system-update/click/tokendownloader_impl.h (+47/-0) plugins/system-update/download_tracker.cpp (+0/-204) plugins/system-update/download_tracker.h (+0/-106) plugins/system-update/helpers.cpp (+108/-0) plugins/system-update/helpers.h (+47/-0) plugins/system-update/image/imagemanager.h (+46/-0) plugins/system-update/image/imagemanager_impl.cpp (+188/-0) plugins/system-update/image/imagemanager_impl.h (+67/-0) plugins/system-update/network.cpp (+0/-314) plugins/system-update/network.h (+0/-85) plugins/system-update/network/accessmanager.h (+46/-0) plugins/system-update/network/accessmanager_impl.cpp (+47/-0) plugins/system-update/network/accessmanager_impl.h (+41/-0) plugins/system-update/plugin.cpp (+31/-17) plugins/system-update/plugin.h (+0/-1) plugins/system-update/plugin/CMakeLists.txt (+0/-14) plugins/system-update/plugin/update-plugin.cpp (+0/-98) plugins/system-update/plugin/update-plugin.h (+0/-39) plugins/system-update/qmldir (+0/-2) plugins/system-update/qmldir.in (+2/-0) plugins/system-update/system_update.cpp (+0/-281) plugins/system-update/system_update.h (+0/-106) plugins/system-update/update-notification.settings (+1/-2) plugins/system-update/update.cpp (+0/-179) plugins/system-update/update.h (+0/-161) plugins/system-update/update_manager.cpp (+0/-398) plugins/system-update/update_manager.h (+0/-181) plugins/system-update/updatedb.cpp (+418/-0) plugins/system-update/updatedb.h (+77/-0) plugins/system-update/updatemanager.cpp (+217/-0) plugins/system-update/updatemanager.h (+120/-0) plugins/system-update/updatemodel.cpp (+597/-0) plugins/system-update/updatemodel.h (+177/-0) src/CMakeLists.txt (+12/-4) src/systemimage.cpp (+487/-0) src/systemimage.h (+196/-0) tests/CMakeLists.txt (+21/-2) tests/autopilot/ubuntu_system_settings/__init__.py (+4/-0) tests/autopilot/ubuntu_system_settings/tests/__init__.py (+29/-1) tests/autopilot/ubuntu_system_settings/tests/systemimage.py (+71/-37) tests/autopilot/ubuntu_system_settings/tests/test_system_updates.py (+3/-100) tests/autopilot/ubuntu_system_settings/utils/mock_update_click_server.py (+74/-28) tests/mocks/CMakeLists.txt (+1/-0) tests/mocks/QMenuModel/CMakeLists.txt (+25/-0) tests/mocks/QMenuModel/QDBusActionGroup.qml (+52/-0) tests/mocks/QMenuModel/actiondata.h (+54/-0) tests/mocks/QMenuModel/actionstateparser.cpp (+19/-0) tests/mocks/QMenuModel/actionstateparser.h (+35/-0) tests/mocks/QMenuModel/dbus-enums.h (+52/-0) tests/mocks/QMenuModel/plugin.cpp (+40/-0) tests/mocks/QMenuModel/plugin.h (+34/-0) tests/mocks/QMenuModel/qmldir (+4/-0) tests/mocks/Ubuntu/CMakeLists.txt (+3/-0) tests/mocks/Ubuntu/Connectivity/CMakeLists.txt (+15/-0) tests/mocks/Ubuntu/Connectivity/MockNetworkingStatus.cpp (+83/-0) tests/mocks/Ubuntu/Connectivity/MockNetworkingStatus.h (+78/-0) tests/mocks/Ubuntu/Connectivity/plugin.cpp (+40/-0) tests/mocks/Ubuntu/Connectivity/plugin.h (+36/-0) tests/mocks/Ubuntu/Connectivity/qmldir (+2/-0) tests/mocks/Ubuntu/DownloadManager/CMakeLists.txt (+17/-0) tests/mocks/Ubuntu/DownloadManager/MockDownloadManager.cpp (+90/-0) tests/mocks/Ubuntu/DownloadManager/MockDownloadManager.h (+68/-0) tests/mocks/Ubuntu/DownloadManager/MockMetadata.cpp (+73/-0) tests/mocks/Ubuntu/DownloadManager/MockMetadata.h (+64/-0) tests/mocks/Ubuntu/DownloadManager/MockSingleDownload.cpp (+206/-0) tests/mocks/Ubuntu/DownloadManager/MockSingleDownload.h (+113/-0) tests/mocks/Ubuntu/DownloadManager/plugin.cpp (+31/-0) tests/mocks/Ubuntu/DownloadManager/plugin.h (+31/-0) tests/mocks/Ubuntu/DownloadManager/qmldir (+2/-0) tests/mocks/Ubuntu/OnlineAccounts/CMakeLists.txt (+1/-0) tests/mocks/Ubuntu/OnlineAccounts/Client/CMakeLists.txt (+19/-0) tests/mocks/Ubuntu/OnlineAccounts/Client/MockSetup.cpp (+59/-0) tests/mocks/Ubuntu/OnlineAccounts/Client/MockSetup.h (+59/-0) tests/mocks/Ubuntu/OnlineAccounts/Client/plugin.cpp (+29/-0) tests/mocks/Ubuntu/OnlineAccounts/Client/plugin.h (+33/-0) tests/mocks/Ubuntu/OnlineAccounts/Client/qmldir (+2/-0) tests/mocks/Ubuntu/SystemSettings/CMakeLists.txt (+1/-0) tests/mocks/Ubuntu/SystemSettings/Update/CMakeLists.txt (+31/-0) tests/mocks/Ubuntu/SystemSettings/Update/MockSystemImage.cpp (+120/-0) tests/mocks/Ubuntu/SystemSettings/Update/MockSystemImage.h (+91/-0) tests/mocks/Ubuntu/SystemSettings/Update/MockUpdateManager.cpp (+48/-0) tests/mocks/Ubuntu/SystemSettings/Update/MockUpdateManager.h (+39/-0) tests/mocks/Ubuntu/SystemSettings/Update/MockUpdateModel.cpp (+44/-0) tests/mocks/Ubuntu/SystemSettings/Update/MockUpdateModel.h (+48/-0) tests/mocks/Ubuntu/SystemSettings/Update/plugin.cpp (+62/-0) tests/mocks/Ubuntu/SystemSettings/Update/plugin.h (+33/-0) tests/mocks/Ubuntu/SystemSettings/Update/qmldir (+2/-0) tests/mocks/plugins/system-update/fakeapiclient.h (+78/-0) tests/mocks/plugins/system-update/fakeclickmanager.h (+96/-0) tests/mocks/plugins/system-update/fakeimagemanager.h (+59/-0) tests/mocks/plugins/system-update/fakemanifest.h (+52/-0) tests/mocks/plugins/system-update/fakesessiontoken.h (+53/-0) tests/mocks/plugins/system-update/fakesso.h (+62/-0) tests/mocks/plugins/system-update/faketokendownloader.h (+69/-0) tests/mocks/plugins/system-update/faketokendownloader_factory.h (+52/-0) tests/mocks/system-image-dbus/fakesystemimagedbus.cpp (+45/-0) tests/mocks/system-image-dbus/fakesystemimagedbus.h (+64/-0) tests/plugins/CMakeLists.txt (+35/-6) tests/plugins/security-privacy/CMakeLists.txt (+1/-1) tests/plugins/system-update/CMakeLists.txt (+81/-54) tests/plugins/system-update/Source/qmldir (+9/-0) tests/plugins/system-update/click.result (+12/-3) tests/plugins/system-update/fakenetwork.cpp (+0/-50) tests/plugins/system-update/fakenetwork.h (+0/-60) tests/plugins/system-update/fakeprocess.cpp (+0/-63) tests/plugins/system-update/fakeprocess.h (+0/-48) tests/plugins/system-update/fakessoservice.cpp (+0/-27) tests/plugins/system-update/fakessoservice.h (+0/-35) tests/plugins/system-update/fakesystemupdate.cpp (+0/-28) tests/plugins/system-update/fakesystemupdate.h (+0/-68) tests/plugins/system-update/mockclickcommand (+15/-0) tests/plugins/system-update/mockclickserver.h (+57/-0) tests/plugins/system-update/mockclickserver.py (+220/-0) tests/plugins/system-update/tst_clickclient.cpp (+165/-0) tests/plugins/system-update/tst_clickmanager.cpp (+548/-0) tests/plugins/system-update/tst_clickmanifest.cpp (+100/-0) tests/plugins/system-update/tst_helpers.cpp (+71/-0) tests/plugins/system-update/tst_imagemanager.cpp (+269/-0) tests/plugins/system-update/tst_network.cpp (+0/-58) tests/plugins/system-update/tst_systemupdate_download_handler.qml (+230/-0) tests/plugins/system-update/tst_systemupdate_entrycomponent.qml (+108/-0) tests/plugins/system-update/tst_systemupdate_global.qml (+297/-0) tests/plugins/system-update/tst_systemupdate_noauthentication.qml (+71/-0) tests/plugins/system-update/tst_systemupdate_pagecomponent.qml (+388/-0) tests/plugins/system-update/tst_systemupdate_update.qml (+374/-0) tests/plugins/system-update/tst_systemupdate_update_visuals.qml (+219/-0) tests/plugins/system-update/tst_tokendownloader.cpp (+107/-0) tests/plugins/system-update/tst_update.cpp (+0/-55) tests/plugins/system-update/tst_updatedb.cpp (+303/-0) tests/plugins/system-update/tst_updatemanager.cpp (+0/-162) tests/plugins/system-update/tst_updatemodel.cpp (+681/-0) tests/tst_systemimage.cpp (+287/-0) |
To merge this branch: | bzr merge lp:~jonas-drange/ubuntu-system-settings/updates-rewrite |
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
system-apps-ci-bot | continuous-integration | Needs Fixing | |
Ken VanDine | Needs Fixing | ||
Matthew Paul Thomas | design | Pending | |
PS Jenkins bot | continuous-integration | Pending | |
Review via email: mp+301565@code.launchpad.net |
Commit message
rewrite the system update panel
Description of the change
Overview
=======
* Ubuntu.
* Stores updates persistently to provide a better experience.
* Higher test coverage of both C++ and QML systems.
* Implements newer visual designs and specs
* Shows installed updates.
Bugs fixed
=======
* Bug 1387200: We now use mvc magic to make sure repaints does not obliterate any progress/statuses etc.
* Bug 1282499: We now present it attractively (per visual design).
* Bug 1419803: System Image download stalls
* Bug 1567877: Unreliable app installations (we no longer implement our own bindings)
* Bug 1260768: Use ApplyUpdate correctly (we now do)
* Bug 1416518: System Image download stalls. Should be fixed by calling DownloadUpdate if a user has previously started one. The old system-update code could not know this, but we can (via the database).
* Bug 1489389: Reads the boolean return value of the Rebooting() signal and allows the user to retry if it failed.
* Bug 1522248: Fixed, but the string is hidden due to string freeze.
* Bug 1562987: We now have some animation, it might still need more work, though.
* Bug 1572143: Don't hide SI downloads when on cellular data. Always show them.
* Bug 1272313: Add a Stop button (named Cancel due to string freeze) that stops all checks.
* Bug 1353125: Using a database allows us to make better assertions as to the state of updates after they have started.
* Bug 1409069: Partial fix, as we now show the amount of both SI updates and click updates if we know it.
* Bug 1494699: We now show changelogs.
Checklist
=======
* Is your branch in sync with latest trunk (e.g. bzr pull lp:trunk -> no changes)
Yes
* Did you build your software in a clean sbuild/pbuilder chroot or ppa?
Yes
* Did you build your software in a clean sbuild/pbuilder armhf chroot or ppa?
Yes
* Has your component "TestPlan” been executed successfully on emulator, N4?
Not yet
* Has a 5 minute exploratory testing run been executed on N4?
N/A
* If you changed the packaging (debian), did you subscribe a core-dev to this MP?
Ken will look at it. I've added libubuntu-
* If you changed the UI, did you subscribe the design-reviewers to this MP?
Yes
* What components might get impacted by your changes?
- The About panel as it no longer uses the System Update plugin to read System Image properties (like version, update date etc).
- The System Update panel has been almost entirely re-written.
* Have you requested review by the teams of these owning components?
N/A
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1797
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1798
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1799
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1802
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1811
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1812
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1813
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1814
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1815
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1820
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1823
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1824
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1827
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1831
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1832
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1833
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1835
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1837
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1840
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1841
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1843
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1845
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1847
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1849
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1851
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1856
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1859
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
- 1860. By Jonas G. Drange
-
fix typo, change visuals test a bit
- 1861. By Jonas G. Drange
-
fix typo
- 1862. By Jonas G. Drange
-
use explicitly set width on the mainSlots topmost item
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1860
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
- 1863. By Jonas G. Drange
-
we can't make any assumptions as to what state the system updates page will be in, so drop the assertion
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1862
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1863
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
- 1864. By Jonas G. Drange
-
stop using minimal qpa plugin, instead use guiless main
- 1865. By Jonas G. Drange
-
use guiless main for all non-graphical tests
- 1866. By Jonas G. Drange
-
guiless, not appless
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1866
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Ken VanDine (ken-vandine) wrote : | # |
I'd rather rename SystemUpdate to UpdateManager, I think it follows the theme better.
We should add a schema version for the DB. When there's a schema change needed, I think it'll be fine to just blow away the data and re-initialize the DB.
- 1867. By Jonas G. Drange
-
let otas be branded as such
- 1868. By Jonas G. Drange
-
echo qprocess output
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1868
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 1869. By Jonas G. Drange
-
try starting a server using various ports.
- 1870. By Jonas G. Drange
-
rename SystemUpdate -> UpdateManager as requested by Ken, delete unused downloadmanager mock
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1869
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1870
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Ken VanDine (ken-vandine) wrote : | # |
Please add a runtime depends for ubuntu-
- 1871. By Jonas G. Drange
-
add functionality for reverted updates, finish renaming, and add schema versioning
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1871
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
- 1872. By Jonas G. Drange
-
enable pagecomponent tests, fix broken checking logic
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1872
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
- 1873. By Jonas G. Drange
-
don't nuke tokens etc when marking as uninstalled
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1873
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
- 1874. By Jonas G. Drange
-
log a bit, and unset download id if uninstalled
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1874
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
- 1875. By Jonas G. Drange
-
when restoring UDM download, listen to process. Remove fixmes
- 1876. By Jonas G. Drange
-
link uss
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1876
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Preview Diff
1 | === modified file 'debian/control' |
2 | --- debian/control 2016-08-16 11:46:38 +0000 |
3 | +++ debian/control 2016-08-16 11:46:43 +0000 |
4 | @@ -21,6 +21,7 @@ |
5 | libpolkit-agent-1-dev, |
6 | libqmenumodel-dev, |
7 | libtrust-store-dev, |
8 | + libubuntu-app-launch2-dev, |
9 | libudev-dev, |
10 | libunity-api-dev, |
11 | libupower-glib-dev, |
12 | @@ -33,18 +34,19 @@ |
13 | qtbase5-private-dev, |
14 | qtdeclarative5-dev, |
15 | qtdeclarative5-dev-tools, |
16 | + qtdeclarative5-quicklayouts-plugin, |
17 | qtdeclarative5-ubuntu-history0.1, |
18 | qtdeclarative5-ubuntu-keyboard-extensions0.1 [armhf amd64 i386], |
19 | + qtdeclarative5-ubuntu-download-manager0.1 (>= 1.3~), |
20 | libapt-pkg-dev, |
21 | libgnome-desktop-3-dev, |
22 | libgsettings-qt-dev, |
23 | # test-deps |
24 | + dpkg-dev, |
25 | qml-module-qttest, |
26 | qml-module-qtquick2, |
27 | qtdeclarative5-ubuntu-ui-toolkit-plugin | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles, |
28 | libubuntuoneauth-2.0-dev, |
29 | - libubuntu-download-manager-client-dev, |
30 | - libubuntu-download-manager-common-dev, |
31 | libqtdbusmock1-dev (>= 0.2+14.04.20140724), |
32 | libqtdbustest1-dev, |
33 | xvfb, |
34 | |
35 | === modified file 'plugins/about/CMakeLists.txt' |
36 | --- plugins/about/CMakeLists.txt 2016-01-22 19:57:26 +0000 |
37 | +++ plugins/about/CMakeLists.txt 2016-08-16 11:46:43 +0000 |
38 | @@ -2,6 +2,7 @@ |
39 | include_directories(${GLIB_INCLUDE_DIRS}) |
40 | include_directories(${GIO_INCLUDE_DIRS}) |
41 | include_directories(${CLICK_INCLUDE_DIRS}) |
42 | +include_directories(${CLICK_INCLUDE_DIRS}) |
43 | add_definitions(-DQT_NO_KEYWORDS) |
44 | |
45 | |
46 | @@ -31,7 +32,7 @@ |
47 | |
48 | qt5_use_modules(UbuntuStorageAboutPanel Qml Quick DBus) |
49 | target_link_libraries(UbuntuStorageAboutPanel |
50 | -${ANDR_PROP_LDFLAGS} ${GLIB_LDFLAGS} ${GIO_LDFLAGS} ${CLICK_LDFLAGS}) |
51 | +${ANDR_PROP_LDFLAGS} ${GLIB_LDFLAGS} ${GIO_LDFLAGS} ${CLICK_LDFLAGS} uss-systemimage) |
52 | |
53 | |
54 | set(PLUG_DIR ${PLUGIN_PRIVATE_MODULE_DIR}/Ubuntu/SystemSettings/StorageAbout) |
55 | |
56 | === modified file 'plugins/about/PageComponent.qml' |
57 | --- plugins/about/PageComponent.qml 2016-07-14 13:51:56 +0000 |
58 | +++ plugins/about/PageComponent.qml 2016-08-16 11:46:43 +0000 |
59 | @@ -25,7 +25,6 @@ |
60 | import Ubuntu.Components 1.3 |
61 | import Ubuntu.Components.ListItems 1.3 as ListItems |
62 | import Ubuntu.SystemSettings.StorageAbout 1.0 |
63 | -import Ubuntu.SystemSettings.Update 1.0 |
64 | import Ubuntu.SystemSettings.Bluetooth 1.0 |
65 | import MeeGo.QOfono 0.2 |
66 | |
67 | @@ -161,8 +160,8 @@ |
68 | |
69 | SettingsListItems.SingleValueProgression { |
70 | property string versionIdentifier: { |
71 | - var num = UpdateManager.currentBuildNumber; |
72 | - var ota = UpdateManager.detailedVersionDetails['tag']; |
73 | + var num = SystemImage.currentBuildNumber; |
74 | + var ota = SystemImage.versionTag; |
75 | num = num ? "r%1".arg(num.toString()) : ""; |
76 | return ota ? ota : num; |
77 | } |
78 | @@ -179,8 +178,8 @@ |
79 | SettingsListItems.SingleValue { |
80 | objectName: "lastUpdatedItem" |
81 | text: i18n.tr("Last updated") |
82 | - value: UpdateManager.lastUpdateDate && !isNaN(UpdateManager.lastUpdateDate) ? |
83 | - Qt.formatDate(UpdateManager.lastUpdateDate) : i18n.tr("Never") |
84 | + value: SystemImage.lastUpdateDate && !isNaN(SystemImage.lastUpdateDate) ? |
85 | + Qt.formatDate(SystemImage.lastUpdateDate) : i18n.tr("Never") |
86 | } |
87 | |
88 | SettingsListItems.SingleControl { |
89 | @@ -193,10 +192,13 @@ |
90 | var upPlugin = pluginManager.getByName("system-update") |
91 | if (upPlugin) { |
92 | var updatePage = upPlugin.pageComponent |
93 | - if (updatePage) |
94 | - pageStack.push(updatePage) |
95 | - else |
96 | + var updatePageItem; |
97 | + if (updatePage) { |
98 | + updatePageItem = pageStack.push(updatePage); |
99 | + updatePageItem.check(true); // Force a check. |
100 | + } else { |
101 | console.warn("Failed to get system-update pageComponent") |
102 | + } |
103 | } else { |
104 | console.warn("Failed to get system-update plugin instance") |
105 | } |
106 | |
107 | === modified file 'plugins/about/Version.qml' |
108 | --- plugins/about/Version.qml 2015-10-29 15:48:06 +0000 |
109 | +++ plugins/about/Version.qml 2016-08-16 11:46:43 +0000 |
110 | @@ -28,7 +28,6 @@ |
111 | import Ubuntu.Components 1.3 |
112 | import Ubuntu.Components.ListItems 1.3 as ListItem |
113 | import Ubuntu.SystemSettings.StorageAbout 1.0 |
114 | -import Ubuntu.SystemSettings.Update 1.0 |
115 | |
116 | ItemPage { |
117 | id: versionPage |
118 | @@ -67,8 +66,8 @@ |
119 | SingleValueStacked { |
120 | objectName: "ubuntuVersionBuildNumberItem" |
121 | text: i18n.tr("Ubuntu Image part") |
122 | - value: UpdateManager.currentUbuntuBuildNumber |
123 | - visible: UpdateManager.currentUbuntuBuildNumber |
124 | + value: SystemImage.currentUbuntuBuildNumber |
125 | + visible: SystemImage.currentUbuntuBuildNumber |
126 | } |
127 | |
128 | SingleValueStacked { |
129 | @@ -81,8 +80,8 @@ |
130 | SingleValueStacked { |
131 | objectName: "deviceVersionBuildNumberItem" |
132 | text: i18n.tr("Device Image part") |
133 | - value: UpdateManager.currentDeviceBuildNumber |
134 | - visible: UpdateManager.currentDeviceBuildNumber |
135 | + value: SystemImage.currentDeviceBuildNumber |
136 | + visible: SystemImage.currentDeviceBuildNumber |
137 | } |
138 | |
139 | SingleValueStacked { |
140 | @@ -95,8 +94,8 @@ |
141 | SingleValueStacked { |
142 | objectName: "customizationBuildNumberItem" |
143 | text: i18n.tr("Customization Image part") |
144 | - value: UpdateManager.currentCustomBuildNumber |
145 | - visible: UpdateManager.currentCustomBuildNumber |
146 | + value: SystemImage.currentCustomBuildNumber |
147 | + visible: SystemImage.currentCustomBuildNumber |
148 | } |
149 | } |
150 | } |
151 | |
152 | === modified file 'plugins/about/plugin.cpp' |
153 | --- plugins/about/plugin.cpp 2016-01-22 19:57:26 +0000 |
154 | +++ plugins/about/plugin.cpp 2016-08-16 11:46:43 +0000 |
155 | @@ -23,7 +23,14 @@ |
156 | #include <QtQml/QQmlContext> |
157 | #include "click.h" |
158 | #include "storageabout.h" |
159 | +#include "systemimage.h" |
160 | |
161 | +static QObject *siSingletonProvider(QQmlEngine *engine, QJSEngine *scriptEngine) |
162 | +{ |
163 | + Q_UNUSED(engine) |
164 | + Q_UNUSED(scriptEngine) |
165 | + return new QSystemImage; |
166 | +} |
167 | |
168 | void BackendPlugin::registerTypes(const char *uri) |
169 | { |
170 | @@ -32,6 +39,9 @@ |
171 | qRegisterMetaType<ClickModel::Roles>(); |
172 | qmlRegisterType<ClickModel>(uri, 1, 0, "ClickRoles"); |
173 | qmlRegisterType<StorageAbout>(uri, 1, 0, "UbuntuStorageAboutPanel"); |
174 | + qmlRegisterSingletonType<QSystemImage>( |
175 | + uri, 1, 0, "SystemImage", siSingletonProvider |
176 | + ); |
177 | } |
178 | |
179 | void BackendPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
180 | |
181 | === modified file 'plugins/cellular/Components/MultiSim.qml' |
182 | --- plugins/cellular/Components/MultiSim.qml 2016-07-14 13:51:56 +0000 |
183 | +++ plugins/cellular/Components/MultiSim.qml 2016-08-16 11:46:43 +0000 |
184 | @@ -25,11 +25,6 @@ |
185 | import Ubuntu.SystemSettings.Cellular 1.0 |
186 | import Ubuntu.Components.ListItems 1.3 as ListItems |
187 | |
188 | -/* This is a temporary solution to the issue of Hotspots failing on mako. If |
189 | -the device is mako, we hide the hotspot entry. Will be removed once lp:1434591 |
190 | -has been resolved. */ |
191 | -import Ubuntu.SystemSettings.Update 1.0 |
192 | - |
193 | Column { |
194 | objectName: "multiSim" |
195 | |
196 | |
197 | === modified file 'plugins/system-update/CMakeLists.txt' |
198 | --- plugins/system-update/CMakeLists.txt 2016-06-29 14:33:15 +0000 |
199 | +++ plugins/system-update/CMakeLists.txt 2016-08-16 11:46:43 +0000 |
200 | @@ -1,32 +1,80 @@ |
201 | -set(QML_SOURCES PageComponent.qml Configuration.qml) |
202 | -SET (CMAKE_AUTOMOC ON) |
203 | - |
204 | -add_library(UbuntuUpdatePanel MODULE plugin.h plugin.cpp |
205 | -${QML_SOURCES}) |
206 | - |
207 | -qt5_use_modules(UbuntuUpdatePanel Qml Quick Network DBus) |
208 | -include_directories(/usr/include/apt-pkg/) |
209 | - |
210 | -pkg_check_modules(UBUNTU_DOWNLOAD_MANAGER_CLIENT REQUIRED ubuntu-download-manager-client) |
211 | -pkg_check_modules(UBUNTU_DOWNLOAD_MANAGER_COMMON REQUIRED ubuntu-download-manager-common) |
212 | +set(CMAKE_AUTOMOC ON) |
213 | +set(QML_SOURCES |
214 | + ClickUpdateDelegate.qml |
215 | + Configuration.qml |
216 | + ChangelogExpander.qml |
217 | + DownloadHandler.qml |
218 | + Global.qml |
219 | + ImageUpdatePrompt.qml |
220 | + NotAuthenticatedNotification.qml |
221 | + PageComponent.qml |
222 | + UpdateDelegate.qml |
223 | +) |
224 | + |
225 | +include_directories( |
226 | + ${CMAKE_CURRENT_BINARY_DIR} |
227 | + ${CMAKE_CURRENT_SOURCE_DIR} |
228 | + /usr/include/apt-pkg/ |
229 | +) |
230 | + |
231 | +pkg_check_modules(UAL REQUIRED ubuntu-app-launch-2) |
232 | +add_definitions(${UAL_CFLAGS} ${UAL_CFLAGS_OTHER}) |
233 | pkg_check_modules(UBUNTUONEAUTH REQUIRED ubuntuoneauth-2.0) |
234 | add_definitions(${UBUNTUONEAUTH_CFLAGS} ${UBUNTUONEAUTH_CFLAGS_OTHER}) |
235 | -target_link_libraries(UbuntuUpdatePanel |
236 | + |
237 | +add_library(UpdatePlugin SHARED |
238 | + click/apiclient.h |
239 | + click/manager.h |
240 | + click/manifest.h |
241 | + click/sessiontoken.h |
242 | + click/sso.h |
243 | + click/tokendownloader.h |
244 | + click/tokendownloader_factory.h |
245 | + |
246 | + click/apiclient_impl.cpp |
247 | + click/manifest_impl.cpp |
248 | + click/sessiontoken_impl.cpp |
249 | + click/sso_impl.cpp |
250 | + click/tokendownloader_impl.cpp |
251 | + click/tokendownloader_factory_impl.cpp |
252 | + click/manager_impl.cpp |
253 | + |
254 | + image/imagemanager.h |
255 | + image/imagemanager_impl.cpp |
256 | + |
257 | + network/accessmanager.h |
258 | + network/accessmanager_impl.cpp |
259 | + |
260 | + helpers.cpp |
261 | + update.cpp |
262 | + updatedb.cpp |
263 | + updatemodel.cpp |
264 | + updatemanager.cpp |
265 | + ../../src/i18n.cpp |
266 | +) |
267 | +qt5_use_modules(UpdatePlugin Quick Core Network Sql) |
268 | +target_link_libraries(UpdatePlugin |
269 | apt-pkg |
270 | - update-plugin |
271 | + uss-systemimage |
272 | + ${UAL_LDFLAGS} |
273 | ${UBUNTUONEAUTH_LDFLAGS} |
274 | - ${UBUNTU_DOWNLOAD_MANAGER_CLIENT_LDFLAGS} |
275 | - ${UBUNTU_DOWNLOAD_MANAGER_COMMON_LDFLAGS} |
276 | -) |
277 | +) |
278 | + |
279 | +add_library(UbuntuUpdatePanel MODULE |
280 | + plugin.cpp |
281 | + ${QML_SOURCES} |
282 | +) |
283 | +qt5_use_modules(UbuntuUpdatePanel Qml Quick) |
284 | +target_link_libraries(UbuntuUpdatePanel UpdatePlugin) |
285 | |
286 | set(PLUG_DIR ${PLUGIN_PRIVATE_MODULE_DIR}/Ubuntu/SystemSettings/Update) |
287 | +install(TARGETS UpdatePlugin DESTINATION ${PLUGIN_MODULE_DIR}) |
288 | install(TARGETS UbuntuUpdatePanel DESTINATION ${PLUG_DIR}) |
289 | -install(FILES qmldir DESTINATION ${PLUG_DIR}) |
290 | +install(FILES qmldir.in DESTINATION ${PLUG_DIR} RENAME qmldir) |
291 | install(FILES ${QML_SOURCES} DESTINATION ${PLUGIN_QML_DIR}/system-update) |
292 | |
293 | install(FILES system-update.settings DESTINATION ${PLUGIN_MANIFEST_DIR}) |
294 | -install(FILES images/settings-system-update.svg DESTINATION ${PLUGIN_MANIFEST_DIR}/icons) |
295 | - |
296 | +install(FILES settings-system-update.svg DESTINATION ${PLUGIN_MANIFEST_DIR}/icons) |
297 | |
298 | set(QML_SOURCES_NOTIFICATION EntryComponent.qml) |
299 | |
300 | @@ -36,8 +84,5 @@ |
301 | COMMAND echo This is just a dummy. |
302 | SOURCES ${QML_SOURCES_NOTIFICATION}) |
303 | |
304 | - |
305 | install(FILES update-notification.settings DESTINATION ${PLUGIN_MANIFEST_DIR}) |
306 | install(FILES ${QML_SOURCES_NOTIFICATION} DESTINATION ${PLUGIN_QML_DIR}/update-notification) |
307 | - |
308 | -add_subdirectory(plugin) |
309 | |
310 | === added file 'plugins/system-update/ChangelogExpander.qml' |
311 | --- plugins/system-update/ChangelogExpander.qml 1970-01-01 00:00:00 +0000 |
312 | +++ plugins/system-update/ChangelogExpander.qml 2016-08-16 11:46:43 +0000 |
313 | @@ -0,0 +1,77 @@ |
314 | +/* |
315 | + * This file is part of system-settings |
316 | + * |
317 | + * Copyright (C) 2016 Canonical Ltd. |
318 | + * |
319 | + * This program is free software: you can redistribute it and/or modify it |
320 | + * under the terms of the GNU General Public License version 3, as published |
321 | + * by the Free Software Foundation. |
322 | + * |
323 | + * This program is distributed in the hope that it will be useful, but |
324 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
325 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
326 | + * PURPOSE. See the GNU General Public License for more details. |
327 | + * |
328 | + * You should have received a copy of the GNU General Public License along |
329 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
330 | + * |
331 | + */ |
332 | + |
333 | +import QtQuick 2.4 |
334 | +import QtQuick.Layouts 1.1 |
335 | +import Ubuntu.Components 1.3 |
336 | + |
337 | +Item { |
338 | + property string version |
339 | + property bool expanded: false |
340 | + |
341 | + signal clicked() |
342 | + |
343 | + height: label.implicitHeight |
344 | + |
345 | + Label { |
346 | + id: label |
347 | + objectName: "updateVersionLabel" |
348 | + |
349 | + anchors { |
350 | + left: parent.left |
351 | + top: parent.top |
352 | + } |
353 | + |
354 | + verticalAlignment: Text.AlignVCenter |
355 | + text: i18n.tr("Version %1").arg(version) |
356 | + fontSize: "small" |
357 | + elide: Text.ElideMiddle |
358 | + |
359 | + } |
360 | + |
361 | + Icon { |
362 | + id: icon |
363 | + visible: parent.enabled |
364 | + name: "next" |
365 | + anchors { |
366 | + left: label.right |
367 | + leftMargin: units.gu(0.5) |
368 | + verticalCenter: label.verticalCenter |
369 | + } |
370 | + |
371 | + rotation: parent.expanded ? 90 : 0 |
372 | + width: units.gu(1.5) |
373 | + height: width |
374 | + |
375 | + Behavior on rotation { |
376 | + animation: UbuntuNumberAnimation {} |
377 | + } |
378 | + } |
379 | + |
380 | + MouseArea { |
381 | + anchors { |
382 | + fill: label |
383 | + margins: units.gu(-3) // grow hitbox |
384 | + } |
385 | + onClicked: { |
386 | + if (!label.enabled) return; |
387 | + parent.clicked() |
388 | + } |
389 | + } |
390 | +} |
391 | |
392 | === added file 'plugins/system-update/ClickUpdateDelegate.qml' |
393 | --- plugins/system-update/ClickUpdateDelegate.qml 1970-01-01 00:00:00 +0000 |
394 | +++ plugins/system-update/ClickUpdateDelegate.qml 2016-08-16 11:46:43 +0000 |
395 | @@ -0,0 +1,26 @@ |
396 | +/* |
397 | + * This file is part of system-settings |
398 | + * |
399 | + * Copyright (C) 2016 Canonical Ltd. |
400 | + * |
401 | + * This program is free software: you can redistribute it and/or modify it |
402 | + * under the terms of the GNU General Public License version 3, as published |
403 | + * by the Free Software Foundation. |
404 | + * |
405 | + * This program is distributed in the hope that it will be useful, but |
406 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
407 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
408 | + * PURPOSE. See the GNU General Public License for more details. |
409 | + * |
410 | + * You should have received a copy of the GNU General Public License along |
411 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
412 | + */ |
413 | + |
414 | +import QtQuick 2.4 |
415 | +import Ubuntu.SystemSettings.Update 1.0 |
416 | + |
417 | +UpdateDelegate { |
418 | + id: update |
419 | + |
420 | + property string signedUrl |
421 | +} |
422 | |
423 | === modified file 'plugins/system-update/Configuration.qml' |
424 | --- plugins/system-update/Configuration.qml 2016-06-29 14:33:15 +0000 |
425 | +++ plugins/system-update/Configuration.qml 2016-08-16 11:46:43 +0000 |
426 | @@ -35,9 +35,9 @@ |
427 | text: i18n.tr ("Download future updates automatically:") |
428 | model: downloadSelector |
429 | delegate: selectorDelegate |
430 | - selectedIndex: UpdateManager.downloadMode |
431 | - onSelectedIndexChanged: UpdateManager.downloadMode = selectedIndex |
432 | - Component.onCompleted: selectedIndex = UpdateManager.downloadMode |
433 | + selectedIndex: SystemImage.downloadMode |
434 | + onSelectedIndexChanged: SystemImage.downloadMode = selectedIndex |
435 | + Component.onCompleted: selectedIndex = SystemImage.downloadMode |
436 | } |
437 | Component { |
438 | id: selectorDelegate |
439 | |
440 | === added file 'plugins/system-update/DownloadHandler.qml' |
441 | --- plugins/system-update/DownloadHandler.qml 1970-01-01 00:00:00 +0000 |
442 | +++ plugins/system-update/DownloadHandler.qml 2016-08-16 11:46:43 +0000 |
443 | @@ -0,0 +1,204 @@ |
444 | +/* |
445 | + * This file is part of system-settings |
446 | + * |
447 | + * Copyright (C) 2016 Canonical Ltd. |
448 | + * |
449 | + * This program is free software: you can redistribute it and/or modify it |
450 | + * under the terms of the GNU General Public License version 3, as published |
451 | + * by the Free Software Foundation. |
452 | + * |
453 | + * This program is distributed in the hope that it will be useful, but |
454 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
455 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
456 | + * PURPOSE. See the GNU General Public License for more details. |
457 | + * |
458 | + * You should have received a copy of the GNU General Public License along |
459 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
460 | + * |
461 | + */ |
462 | +import QtQuick 2.4 |
463 | +import Ubuntu.DownloadManager 1.2 |
464 | + |
465 | +Item { |
466 | + id: root |
467 | + property var updateModel |
468 | + property alias downloads: downloadManager.downloads |
469 | + property var udm: DownloadManager { |
470 | + id: downloadManager |
471 | + onDownloadFinished: { |
472 | + updateModel.setInstalled(download.metadata.custom.identifier, |
473 | + download.metadata.custom.revision); |
474 | + } |
475 | + onDownloadPaused: { |
476 | + updateModel.pauseUpdate(download.metadata.custom.identifier, |
477 | + download.metadata.custom.revision) |
478 | + } |
479 | + onDownloadResumed: { |
480 | + updateModel.resumeUpdate(download.metadata.custom.identifier, |
481 | + download.metadata.custom.revision) |
482 | + } |
483 | + onDownloadCanceled: { |
484 | + updateModel.cancelUpdate(download.metadata.custom.identifier, |
485 | + download.metadata.custom.revision) |
486 | + } |
487 | + onErrorFound: { |
488 | + updateModel.setError(download.metadata.custom.identifier, |
489 | + download.metadata.custom.revision, |
490 | + download.errorMessage) |
491 | + } |
492 | + onDownloadsChanged: restoreDownloads() |
493 | + Component.onCompleted: restoreDownloads() |
494 | + } |
495 | + |
496 | + function downloadAll() { |
497 | + |
498 | + } |
499 | + |
500 | + function restoreDownloads() { |
501 | + var dl; |
502 | + for (var i = 0; i<downloads.length; i++) { |
503 | + dl = downloads[i]; |
504 | + if (!dl._bound) { |
505 | + /* We only bind those signals here, that the UDM does not |
506 | + receive, i.e. processing and progressChanged. */ |
507 | + dl.progressChanged.connect(onDownloadProgress.bind(dl)); |
508 | + dl.processing.connect(onDownloadProcessing.bind(dl)); |
509 | + dl._bound = true; |
510 | + } |
511 | + } |
512 | + } |
513 | + |
514 | + function resumeDownload(click) { |
515 | + var download = getDownloadFor(click); |
516 | + if (download && !download.downloading && !download.isCompleted) { |
517 | + download.resume(); |
518 | + } |
519 | + } |
520 | + |
521 | + function pauseDownload(click) { |
522 | + var download = getDownloadFor(click); |
523 | + if (download && download.downloading) { |
524 | + download.pause(); |
525 | + } |
526 | + } |
527 | + |
528 | + // Return download for a click update. |
529 | + function getDownloadFor(click) { |
530 | + var cust; |
531 | + var dl; |
532 | + |
533 | + for (var i = 0; i<downloads.length; i++) { |
534 | + dl = downloads[i]; |
535 | + if (dl.errorMessage || dl.isCompleted) { |
536 | + // Ignore failed and completed downloads. |
537 | + continue; |
538 | + } |
539 | + |
540 | + cust = downloads[i].metadata.custom; |
541 | + if (cust.identifier === click.identifier && cust.revision === click.revision) { |
542 | + return downloads[i]; |
543 | + } |
544 | + } |
545 | + return null; |
546 | + } |
547 | + |
548 | + function hasExistingDownload(click) { |
549 | + var existingDownload = getDownloadFor(click); |
550 | + return (existingDownload !== null && |
551 | + !existingDownload.errorMessage && |
552 | + !existingDownload.isCompleted); |
553 | + } |
554 | + |
555 | + function retryDownload(click) { |
556 | + return createDownload(click, true); |
557 | + } |
558 | + |
559 | + function createDownload(click, useSignedUrl) { |
560 | + if (hasExistingDownload(click)) { |
561 | + return null; |
562 | + } |
563 | + var downloadUrl = click.downloadUrl; |
564 | + var metadata = { |
565 | + "command": click.command, |
566 | + "title": click.title, |
567 | + "showInIndicator": false |
568 | + }; |
569 | + var metadataObj = mdt.createObject(root, metadata); |
570 | + metadataObj.custom = { |
571 | + "identifier": click.identifier, |
572 | + "package-name": click.identifier, |
573 | + "revision": click.revision, |
574 | + }; |
575 | + |
576 | + var hdrs = {} |
577 | + if (useSignedUrl) { |
578 | + if (!click.signedDownloadUrl) { |
579 | + console.warn('The signed download URL was empty.'); |
580 | + } |
581 | + downloadUrl = click.signedDownloadUrl; |
582 | + } else { |
583 | + // If we're using an unsigned URL, we need to provide this header. |
584 | + hdrs["X-Click-Token"] = click.token; |
585 | + } |
586 | + |
587 | + var singleDownloadObj = sdl.createObject(root, { |
588 | + "autoStart": true, |
589 | + "hash": click.downloadHash, |
590 | + "algorithm": "sha512", |
591 | + "headers": hdrs, |
592 | + "metadata": metadataObj, |
593 | + "revision": click.revision, |
594 | + "identifier": click.identifier |
595 | + }); |
596 | + singleDownloadObj.download(downloadUrl); |
597 | + return singleDownloadObj; |
598 | + } |
599 | + |
600 | + function onDownloadProgress(progress) { |
601 | + updateModel.setProgress(this.metadata.custom.identifier, |
602 | + this.metadata.custom.revision, |
603 | + this.progress); |
604 | + } |
605 | + |
606 | + function onDownloadProcessing() { |
607 | + updateModel.processUpdate(this.metadata.custom.identifier, |
608 | + this.metadata.custom.revision); |
609 | + } |
610 | + |
611 | + /* If a update's model has a downloadId, check if UDM knows it. If not, |
612 | + treat this as a failure. Workaround for lp:1603770. */ |
613 | + function assertDownloadExist(click) { |
614 | + if (!getDownloadFor(click)) { |
615 | + updateModel.setError( |
616 | + click.identifier, click.revision, |
617 | + i18n.tr("Installation failed") |
618 | + ); |
619 | + } |
620 | + } |
621 | + |
622 | + Component { |
623 | + id: sdl |
624 | + SingleDownload { |
625 | + id: download |
626 | + objectName: "singleDownload" |
627 | + property bool _bound: true |
628 | + |
629 | + onDownloadIdChanged: { |
630 | + updateModel.queueUpdate(metadata.custom.identifier, |
631 | + metadata.custom.revision, |
632 | + downloadId); |
633 | + } |
634 | + onStarted: { |
635 | + updateModel.startUpdate(metadata.custom.identifier, |
636 | + metadata.custom.revision); |
637 | + } |
638 | + onProgressChanged: onDownloadProgress.call(download) |
639 | + onProcessing: onDownloadProcessing.call(download) |
640 | + } |
641 | + } |
642 | + |
643 | + Component { |
644 | + id: mdt |
645 | + Metadata {} |
646 | + } |
647 | +} |
648 | |
649 | === modified file 'plugins/system-update/EntryComponent.qml' |
650 | --- plugins/system-update/EntryComponent.qml 2016-07-14 13:51:56 +0000 |
651 | +++ plugins/system-update/EntryComponent.qml 2016-08-16 11:46:43 +0000 |
652 | @@ -20,13 +20,18 @@ |
653 | |
654 | import QtQuick 2.4 |
655 | import Ubuntu.Components 1.3 |
656 | +import Ubuntu.DownloadManager 1.2 |
657 | import Ubuntu.SystemSettings.Update 1.0 |
658 | |
659 | ListItem { |
660 | id: root |
661 | objectName: "entryComponent-updates" |
662 | - property int updatesAvailable: 0 |
663 | - height: layout.height |
664 | + property int updatesAvailable: { |
665 | + var imageUpdateCount = SystemImage.checkTarget() ? 1 : 0; |
666 | + return updatesRep.count + imageUpdateCount; |
667 | + } |
668 | + height: updatesAvailable > 0 ? layout.height : 0 |
669 | + onClicked: main.loadPluginByName("system-update"); |
670 | |
671 | ListItemLayout { |
672 | id: layout |
673 | @@ -43,22 +48,22 @@ |
674 | ProgressionSlot {} |
675 | } |
676 | |
677 | - function _updatesRefresh() { |
678 | - var _updatesAvailable = 0; |
679 | - for (var i=0; i < UpdateManager.model.length; i++) { |
680 | - if (UpdateManager.model[i].updateRequired) |
681 | - _updatesAvailable += 1; |
682 | + DownloadManager { |
683 | + onDownloadFinished: { |
684 | + UpdateManager.model.setInstalled( |
685 | + download.metadata.custom.identifier, |
686 | + download.metadata.custom.revision |
687 | + ); |
688 | } |
689 | - updatesAvailable = _updatesAvailable; |
690 | - } |
691 | - |
692 | - Connections { |
693 | - id: updateManager |
694 | - objectName: "updateManager" |
695 | - target: UpdateManager |
696 | - onModelChanged: root._updatesRefresh() |
697 | - onUpdateAvailableFound: root._updatesRefresh() |
698 | - } |
699 | - |
700 | - onClicked: main.loadPluginByName("system-update"); |
701 | + } |
702 | + |
703 | + Repeater { |
704 | + width: 1 |
705 | + height: 1 |
706 | + id: updatesRep |
707 | + model: UpdateManager.clickUpdates |
708 | + Item { width: 1; height: 1 } |
709 | + } |
710 | + |
711 | + Behavior on height { UbuntuNumberAnimation {} } |
712 | } |
713 | |
714 | === added file 'plugins/system-update/Global.qml' |
715 | --- plugins/system-update/Global.qml 1970-01-01 00:00:00 +0000 |
716 | +++ plugins/system-update/Global.qml 2016-08-16 11:46:43 +0000 |
717 | @@ -0,0 +1,142 @@ |
718 | +/* |
719 | + * This file is part of system-settings |
720 | + * |
721 | + * Copyright (C) 2016 Canonical Ltd. |
722 | + * |
723 | + * This program is free software: you can redistribute it and/or modify it |
724 | + * under the terms of the GNU General Public License version 3, as published |
725 | + * by the Free Software Foundation. |
726 | + * |
727 | + * This program is distributed in the hope that it will be useful, but |
728 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
729 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
730 | + * PURPOSE. See the GNU General Public License for more details. |
731 | + * |
732 | + * You should have received a copy of the GNU General Public License along |
733 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
734 | + */ |
735 | + |
736 | +import QtQuick 2.4 |
737 | +import QtQuick.Layouts 1.1 |
738 | +import Ubuntu.Components 1.3 |
739 | +import Ubuntu.Components.ListItems 1.3 as ListItems |
740 | +import Ubuntu.SystemSettings.Update 1.0 |
741 | + |
742 | +Item { |
743 | + id: g |
744 | + |
745 | + property bool batchMode |
746 | + property int status // A UpdateManager::Status |
747 | + property bool requireRestart: false |
748 | + property int updatesCount: 0 |
749 | + property bool online: false |
750 | + |
751 | + property bool hidden: { |
752 | + switch (status) { |
753 | + case UpdateManager.StatusNetworkError: |
754 | + case UpdateManager.StatusServerError: |
755 | + return true; |
756 | + } |
757 | + return !online || |
758 | + (updatesCount <= 1 && status === UpdateManager.StatusIdle) || |
759 | + batchMode |
760 | + } |
761 | + |
762 | + signal stop() |
763 | + signal requestInstall() |
764 | + signal install() |
765 | + |
766 | + Behavior on height { |
767 | + UbuntuNumberAnimation {} |
768 | + } |
769 | + |
770 | + RowLayout { |
771 | + id: checking |
772 | + spacing: units.gu(2) |
773 | + anchors { |
774 | + fill: parent |
775 | + margins: units.gu(2) |
776 | + } |
777 | + |
778 | + Behavior on opacity { |
779 | + UbuntuNumberAnimation {} |
780 | + } |
781 | + |
782 | + opacity: visible ? 1 : 0 |
783 | + visible: { |
784 | + switch (g.status) { |
785 | + case UpdateManager.StatusCheckingClickUpdates: |
786 | + case UpdateManager.StatusCheckingImageUpdates: |
787 | + case UpdateManager.StatusCheckingAllUpdates: |
788 | + return true; |
789 | + } |
790 | + return false; |
791 | + } |
792 | + |
793 | + ActivityIndicator { |
794 | + running: parent.visible |
795 | + } |
796 | + |
797 | + Label { |
798 | + text: i18n.tr("Checking for updates…") |
799 | + } |
800 | + |
801 | + Button { |
802 | + objectName: "updatesGlobalStopButton" |
803 | + text: i18n.tr("Stop") |
804 | + onClicked: g.stop() |
805 | + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter |
806 | + } |
807 | + } |
808 | + |
809 | + RowLayout { |
810 | + id: install |
811 | + anchors { |
812 | + fill: parent |
813 | + margins: units.gu(2) |
814 | + } |
815 | + spacing: units.gu(2) |
816 | + |
817 | + Behavior on opacity { |
818 | + UbuntuNumberAnimation {} |
819 | + } |
820 | + |
821 | + opacity: visible ? 1 : 0 |
822 | + visible: { |
823 | + var canInstall = g.status === UpdateManager.StatusIdle; |
824 | + return canInstall && updatesCount > 1; |
825 | + } |
826 | + |
827 | + Label { |
828 | + objectName: "updatesGlobalInfoLabel" |
829 | + // // TRANSLATORS: %1 is number of software updates available. |
830 | + text: i18n.tr("%1 update available", |
831 | + "%1 updates available", |
832 | + updatesCount).arg(updatesCount) |
833 | + Layout.fillWidth: true |
834 | + } |
835 | + |
836 | + Button { |
837 | + objectName: "updatesGlobalInstallButton" |
838 | + text: { |
839 | + if (g.requireRestart === true) { |
840 | + return i18n.tr("Update all…"); |
841 | + } else { |
842 | + return i18n.tr("Update all"); |
843 | + } |
844 | + } |
845 | + onClicked: g.requestInstall() |
846 | + color: theme.palette.normal.positive |
847 | + strokeColor: "transparent" |
848 | + } |
849 | + } |
850 | + |
851 | + ListItems.ThinDivider { |
852 | + visible: !g.hidden |
853 | + anchors { |
854 | + left: parent.left |
855 | + right: parent.right |
856 | + bottom: parent.bottom |
857 | + } |
858 | + } |
859 | +} |
860 | |
861 | === added file 'plugins/system-update/ImageUpdatePrompt.qml' |
862 | --- plugins/system-update/ImageUpdatePrompt.qml 1970-01-01 00:00:00 +0000 |
863 | +++ plugins/system-update/ImageUpdatePrompt.qml 2016-08-16 11:46:43 +0000 |
864 | @@ -0,0 +1,52 @@ |
865 | +/* |
866 | + * This file is part of system-settings |
867 | + * |
868 | + * Copyright (C) 2016 Canonical Ltd. |
869 | + * |
870 | + * This program is free software: you can redistribute it and/or modify it |
871 | + * under the terms of the GNU General Public License version 3, as published |
872 | + * by the Free Software Foundation. |
873 | + * |
874 | + * This program is distributed in the hope that it will be useful, but |
875 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
876 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
877 | + * PURPOSE. See the GNU General Public License for more details. |
878 | + * |
879 | + * You should have received a copy of the GNU General Public License along |
880 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
881 | + */ |
882 | +import QtQuick 2.4 |
883 | +import Ubuntu.Components 1.3 |
884 | +import Ubuntu.Components.Popups 1.3 |
885 | + |
886 | +Dialog { |
887 | + id: dialogueInstall |
888 | + objectName: "imagePrompt" |
889 | + |
890 | + property alias havePowerForUpdate: installBtn.visible |
891 | + |
892 | + signal requestSystemUpdate() |
893 | + |
894 | + title: i18n.tr("Update System") |
895 | + text: havePowerForUpdate |
896 | + ? i18n.tr("The device needs to restart to install the system update.") |
897 | + : i18n.tr("Connect the device to power before installing the system update.") |
898 | + |
899 | + Button { |
900 | + id: installBtn |
901 | + objectName: "imagePromptInstall" |
902 | + text: i18n.tr("Restart & Install") |
903 | + color: UbuntuColors.orange |
904 | + onClicked: { |
905 | + dialogueInstall.requestSystemUpdate(); |
906 | + PopupUtils.close(dialogueInstall); |
907 | + } |
908 | + } |
909 | + |
910 | + Button { |
911 | + objectName: "imagePromptCancel" |
912 | + text: i18n.tr("Cancel") |
913 | + color: UbuntuColors.warmGrey |
914 | + onClicked: PopupUtils.close(dialogueInstall) |
915 | + } |
916 | +} |
917 | |
918 | === added file 'plugins/system-update/InstallationFailed.qml' |
919 | --- plugins/system-update/InstallationFailed.qml 1970-01-01 00:00:00 +0000 |
920 | +++ plugins/system-update/InstallationFailed.qml 2016-08-16 11:46:43 +0000 |
921 | @@ -0,0 +1,34 @@ |
922 | +/* |
923 | + * This file is part of system-settings |
924 | + * |
925 | + * Copyright (C) 2016 Canonical Ltd. |
926 | + * |
927 | + * This program is free software: you can redistribute it and/or modify it |
928 | + * under the terms of the GNU General Public License version 3, as published |
929 | + * by the Free Software Foundation. |
930 | + * |
931 | + * This program is distributed in the hope that it will be useful, but |
932 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
933 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
934 | + * PURPOSE. See the GNU General Public License for more details. |
935 | + * |
936 | + * You should have received a copy of the GNU General Public License along |
937 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
938 | + */ |
939 | +import QtQuick 2.4 |
940 | +import Ubuntu.Components 1.3 |
941 | +import Ubuntu.Components.Popups 1.3 |
942 | + |
943 | +Dialog { |
944 | + id: dialogueError |
945 | + objectName: "installationFailed" |
946 | + title: i18n.tr("Installation failed") |
947 | + |
948 | + Button { |
949 | + text: i18n.tr("OK") |
950 | + color: UbuntuColors.orange |
951 | + onClicked: { |
952 | + PopupUtils.close(dialogueError); |
953 | + } |
954 | + } |
955 | +} |
956 | |
957 | === added file 'plugins/system-update/NotAuthenticatedNotification.qml' |
958 | --- plugins/system-update/NotAuthenticatedNotification.qml 1970-01-01 00:00:00 +0000 |
959 | +++ plugins/system-update/NotAuthenticatedNotification.qml 2016-08-16 11:46:43 +0000 |
960 | @@ -0,0 +1,62 @@ |
961 | +/* |
962 | + * This file is part of system-settings |
963 | + * |
964 | + * Copyright (C) 2016 Canonical Ltd. |
965 | + * |
966 | + * This program is free software: you can redistribute it and/or modify it |
967 | + * under the terms of the GNU General Public License version 3, as published |
968 | + * by the Free Software Foundation. |
969 | + * |
970 | + * This program is distributed in the hope that it will be useful, but |
971 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
972 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
973 | + * PURPOSE. See the GNU General Public License for more details. |
974 | + * |
975 | + * You should have received a copy of the GNU General Public License along |
976 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
977 | + * |
978 | + */ |
979 | + |
980 | +import QtQuick 2.4 |
981 | +import Ubuntu.Components 1.3 |
982 | + |
983 | +Column { |
984 | + id: credentialsNotification |
985 | + objectName: "credentialsNotification" |
986 | + |
987 | + property bool enabled: true |
988 | + signal requestAuthentication() |
989 | + |
990 | + spacing: units.gu(2) |
991 | + anchors { |
992 | + left: parent.left |
993 | + right: parent.right |
994 | + } |
995 | + |
996 | + Label { |
997 | + text: i18n.tr("Sign in to Ubuntu One to receive updates for apps.") |
998 | + horizontalAlignment: Text.AlignHCenter |
999 | + verticalAlignment: Text.AlignBottom |
1000 | + wrapMode: Text.Wrap |
1001 | + height: implicitHeight + units.gu(2) |
1002 | + enabled: parent.enabled |
1003 | + anchors { |
1004 | + left: parent.left |
1005 | + leftMargin: units.gu(10) |
1006 | + right: parent.right |
1007 | + rightMargin: units.gu(10) |
1008 | + } |
1009 | + } |
1010 | + |
1011 | + Button { |
1012 | + id: btn |
1013 | + objectName: "updateRequestAuthButton" |
1014 | + text: i18n.tr("Sign In…") |
1015 | + anchors.horizontalCenter: parent.horizontalCenter |
1016 | + enabled: parent.enabled |
1017 | + onClicked: { |
1018 | + credentialsNotification.requestAuthentication(); |
1019 | + parent.enabled = false; |
1020 | + } |
1021 | + } |
1022 | +} |
1023 | |
1024 | === modified file 'plugins/system-update/PageComponent.qml' |
1025 | --- plugins/system-update/PageComponent.qml 2016-06-29 14:33:15 +0000 |
1026 | +++ plugins/system-update/PageComponent.qml 2016-08-16 11:46:43 +0000 |
1027 | @@ -1,10 +1,11 @@ |
1028 | /* |
1029 | * This file is part of system-settings |
1030 | * |
1031 | - * Copyright (C) 2013-2014 Canonical Ltd. |
1032 | + * Copyright (C) 2013-2016 Canonical Ltd. |
1033 | * |
1034 | * Contact: Didier Roche <didier.roches@canonical.com> |
1035 | - * Contact: Diego Sarmentero <diego.sarmentero@canonical.com> |
1036 | + * Diego Sarmentero <diego.sarmentero@canonical.com> |
1037 | + * Jonas G. Drange <jonas.drange@canonical.com> |
1038 | * |
1039 | * This program is free software: you can redistribute it and/or modify it |
1040 | * under the terms of the GNU General Public License version 3, as published |
1041 | @@ -29,27 +30,43 @@ |
1042 | import Ubuntu.SystemSettings.Update 1.0 |
1043 | import Ubuntu.Connectivity 1.0 |
1044 | |
1045 | - |
1046 | ItemPage { |
1047 | id: root |
1048 | objectName: "systemUpdatesPage" |
1049 | |
1050 | - title: installingImageUpdate.visible ? "" : i18n.tr("Updates") |
1051 | - flickable: installingImageUpdate.visible ? null : scrollWidget |
1052 | - |
1053 | - property bool installAll: false |
1054 | - property bool includeSystemUpdate: false |
1055 | - property bool systemUpdateInProgress: false |
1056 | - property int updatesAvailable: 0 |
1057 | - property bool isCharging: indicatorPower.deviceState === "charging" |
1058 | - property bool batterySafeForUpdate: isCharging || chargeLevel > 25 |
1059 | - property var chargeLevel: indicatorPower.batteryLevel || 0 |
1060 | - property var notificationAction; |
1061 | - property string errorDialogText: "" |
1062 | - |
1063 | - onUpdatesAvailableChanged: { |
1064 | - if (updatesAvailable < 1 && root.state != "SEARCHING") |
1065 | - root.state = "NOUPDATES"; |
1066 | + header: PageHeader { |
1067 | + title: i18n.tr("Updates") |
1068 | + flickable: scrollWidget |
1069 | + } |
1070 | + |
1071 | + |
1072 | + property bool batchMode: false |
1073 | + property bool havePower: (indicatorPower.deviceState === "charging") || |
1074 | + (indicatorPower.batteryLevel > 25) |
1075 | + property bool online: NetworkingStatus.online |
1076 | + property bool authenticated: UpdateManager.authenticated |
1077 | + property bool forceCheck: false |
1078 | + |
1079 | + property int updatesCount: { |
1080 | + var count = 0; |
1081 | + if (authenticated) { |
1082 | + count += clickRepeater.count; |
1083 | + } |
1084 | + count += imageRepeater.count; |
1085 | + return count; |
1086 | + } |
1087 | + |
1088 | + function check(force) { |
1089 | + if (force === true) { |
1090 | + UpdateManager.check(UpdateManager.CheckAll); |
1091 | + } else { |
1092 | + if (imageRepeater.count === 0 && clickRepeater.count === 0) { |
1093 | + UpdateManager.check(UpdateManager.CheckAll); |
1094 | + } else { |
1095 | + // Only check 30 minutes after last successful check. |
1096 | + UpdateManager.check(UpdateManager.CheckIfNecessary); |
1097 | + } |
1098 | + } |
1099 | } |
1100 | |
1101 | QDBusActionGroup { |
1102 | @@ -57,703 +74,407 @@ |
1103 | busType: 1 |
1104 | busName: "com.canonical.indicator.power" |
1105 | objectPath: "/com/canonical/indicator/power" |
1106 | - property variant batteryLevel: action("battery-level").state |
1107 | - property variant deviceState: action("device-state").state |
1108 | + property var batteryLevel: action("battery-level").state || 0 |
1109 | + property var deviceState: action("device-state").state |
1110 | Component.onCompleted: start() |
1111 | } |
1112 | |
1113 | - Connections { |
1114 | - id: networkingStatus |
1115 | - target: NetworkingStatus |
1116 | - onOnlineChanged: { |
1117 | - if (NetworkingStatus.online) { |
1118 | - activity.running = true; |
1119 | - root.state = "SEARCHING"; |
1120 | - UpdateManager.checkUpdates(); |
1121 | - } else { |
1122 | - activity.running = false; |
1123 | - } |
1124 | - } |
1125 | - } |
1126 | - |
1127 | Setup { |
1128 | id: uoaConfig |
1129 | + objectName: "uoaConfig" |
1130 | applicationId: "ubuntu-system-settings" |
1131 | providerId: "ubuntuone" |
1132 | |
1133 | onFinished: { |
1134 | - credentialsNotification.visible = false; |
1135 | - root.state = "SEARCHING"; |
1136 | - if (NetworkingStatus.online) |
1137 | - UpdateManager.checkUpdates(); |
1138 | - } |
1139 | - } |
1140 | - |
1141 | - Component { |
1142 | - id: dialogInstallComponent |
1143 | - Dialog { |
1144 | - id: dialogueInstall |
1145 | - title: i18n.tr("Update System") |
1146 | - text: root.batterySafeForUpdate ? i18n.tr("The device needs to restart to install the system update.") : i18n.tr("Connect the device to power before installing the system update.") |
1147 | - |
1148 | - Button { |
1149 | - text: i18n.tr("Restart & Install") |
1150 | - visible: root.batterySafeForUpdate ? true : false |
1151 | - color: theme.palette.normal.positive |
1152 | - onClicked: { |
1153 | - installingImageUpdate.visible = true; |
1154 | - UpdateManager.applySystemUpdate(); |
1155 | - PopupUtils.close(dialogueInstall); |
1156 | - } |
1157 | - } |
1158 | - Button { |
1159 | - text: i18n.tr("Cancel") |
1160 | - onClicked: { |
1161 | - updateList.currentIndex = 0; |
1162 | - var item = updateList.currentItem; |
1163 | - var modelItem = UpdateManager.model[0]; |
1164 | - item.actionButton.text = i18n.tr("Install"); |
1165 | - item.progressBar.opacity = 0; |
1166 | - modelItem.updateReady = true; |
1167 | - modelItem.selected = false; |
1168 | - root.systemUpdateInProgress = false; |
1169 | - PopupUtils.close(dialogueInstall); |
1170 | - } |
1171 | - } |
1172 | - } |
1173 | - } |
1174 | - |
1175 | - Component { |
1176 | - id: dialogErrorComponent |
1177 | - Dialog { |
1178 | - id: dialogueError |
1179 | - title: i18n.tr("Installation failed") |
1180 | - text: root.errorDialogText |
1181 | - |
1182 | - Button { |
1183 | - text: i18n.tr("OK") |
1184 | - color: theme.palette.normal.positive |
1185 | - onClicked: { |
1186 | - PopupUtils.close(dialogueError); |
1187 | - } |
1188 | - } |
1189 | - } |
1190 | - } |
1191 | - |
1192 | - //states |
1193 | - states: [ |
1194 | - State { |
1195 | - name: "SEARCHING" |
1196 | - PropertyChanges { target: installAllButton; visible: false} |
1197 | - PropertyChanges { target: checkForUpdatesArea; visible: true} |
1198 | - PropertyChanges { target: updateNotification; visible: false} |
1199 | - PropertyChanges { target: activity; running: NetworkingStatus.online} |
1200 | - }, |
1201 | - State { |
1202 | - name: "NOUPDATES" |
1203 | - PropertyChanges { target: updateNotification; text: i18n.tr("Software is up to date")} |
1204 | - PropertyChanges { target: updateNotification; visible: true} |
1205 | - PropertyChanges { target: updateList; visible: false} |
1206 | - PropertyChanges { target: installAllButton; visible: false} |
1207 | - }, |
1208 | - State { |
1209 | - name: "SYSTEMUPDATEFAILED" |
1210 | - PropertyChanges { target: installingImageUpdate; visible: false} |
1211 | - PropertyChanges { target: installAllButton; visible: false} |
1212 | - PropertyChanges { target: checkForUpdatesArea; visible: false} |
1213 | - PropertyChanges { target: updateNotification; visible: false} |
1214 | - }, |
1215 | - State { |
1216 | - name: "UPDATE" |
1217 | - PropertyChanges { target: updateList; visible: true} |
1218 | - PropertyChanges { target: installAllButton; visible: root.updatesAvailable > 1} |
1219 | - PropertyChanges { target: updateNotification; visible: false} |
1220 | - } |
1221 | - ] |
1222 | - |
1223 | - Connections { |
1224 | - id: updateManager |
1225 | - target: UpdateManager |
1226 | - objectName: "updateManager" |
1227 | - |
1228 | - Component.onCompleted: { |
1229 | - credentialsNotification.visible = false; |
1230 | - root.state = "SEARCHING"; |
1231 | - if (NetworkingStatus.online) |
1232 | - UpdateManager.checkUpdates(); |
1233 | - } |
1234 | - |
1235 | - onUpdateAvailableFound: { |
1236 | - root.updatesAvailable = UpdateManager.model.length; |
1237 | - if (root.updatesAvailable > 0) |
1238 | - root.includeSystemUpdate = UpdateManager.model[0].systemUpdate |
1239 | - root.state = "UPDATE"; |
1240 | - root.installAll = downloading; |
1241 | - } |
1242 | - |
1243 | - onUpdatesNotFound: { |
1244 | - if (!credentialsNotification.visible) { |
1245 | - root.state = "NOUPDATES"; |
1246 | + if (reply.errorName) { |
1247 | + console.warn('Online Accounts failed:', reply.errorName); |
1248 | } |
1249 | - } |
1250 | - |
1251 | - onCheckFinished: { |
1252 | - checkForUpdatesArea.visible = false; |
1253 | - } |
1254 | - |
1255 | - onCredentialsNotFound: { |
1256 | - credentialsNotification.visible = true; |
1257 | - } |
1258 | - |
1259 | - onCredentialsDeleted: { |
1260 | - credentialsNotification.visible = true; |
1261 | - } |
1262 | - |
1263 | - onSystemUpdateDownloaded: { |
1264 | - root.installAll = false; |
1265 | - if (root.includeSystemUpdate) |
1266 | - UpdateManager.model[0].status = Update.Downloaded; |
1267 | - } |
1268 | - |
1269 | - onSystemUpdateFailed: { |
1270 | - root.state = "SYSTEMUPDATEFAILED"; |
1271 | - root.errorDialogText = i18n.tr("Sorry, the system update failed."); |
1272 | - PopupUtils.open(dialogErrorComponent); |
1273 | - } |
1274 | - |
1275 | - onUpdateProcessFailed: { |
1276 | - root.state = "SYSTEMUPDATEFAILED"; |
1277 | - root.errorDialogText = i18n.tr("Sorry, the system update failed."); |
1278 | - PopupUtils.open(dialogErrorComponent); |
1279 | - } |
1280 | - |
1281 | - onServerError: { |
1282 | - activity.running = false; |
1283 | - } |
1284 | - |
1285 | - onNetworkError: { |
1286 | - activity.running = false; |
1287 | - } |
1288 | - |
1289 | - onRebooting: { |
1290 | - installingImageUpdate.message = i18n.tr("Restarting…"); |
1291 | - } |
1292 | - } |
1293 | + UpdateManager.check(UpdateManager.CheckClick); |
1294 | + notauthNotification.enabled = true; |
1295 | + } |
1296 | + } |
1297 | + |
1298 | + DownloadHandler { |
1299 | + id: downloadHandler |
1300 | + updateModel: UpdateManager.model |
1301 | + } |
1302 | + |
1303 | Flickable { |
1304 | id: scrollWidget |
1305 | - |
1306 | - anchors.top: parent.top |
1307 | - anchors.left: parent.left |
1308 | - anchors.right: parent.right |
1309 | - anchors.bottom: configuration.top |
1310 | - |
1311 | - contentHeight: contentItem.childrenRect.height |
1312 | - boundsBehavior: (contentHeight > root.height) ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds |
1313 | + anchors { |
1314 | + top: parent.top |
1315 | + left: parent.left |
1316 | + right: parent.right |
1317 | + bottom: configuration.top |
1318 | + } |
1319 | clip: true |
1320 | - /* Set the direction to workaround https://bugreports.qt-project.org/browse/QTBUG-31905 |
1321 | - otherwise the UI might end up in a situation where scrolling doesn't work */ |
1322 | + contentHeight: content.height |
1323 | + boundsBehavior: (contentHeight > parent.height) ? |
1324 | + Flickable.DragAndOvershootBounds : |
1325 | + Flickable.StopAtBounds |
1326 | flickableDirection: Flickable.VerticalFlick |
1327 | |
1328 | Column { |
1329 | - id: columnId |
1330 | - anchors { |
1331 | - left: parent.left |
1332 | - right: parent.right |
1333 | + id: content |
1334 | + anchors { left: parent.left; right: parent.right } |
1335 | + |
1336 | + Global { |
1337 | + id: glob |
1338 | + objectName: "global" |
1339 | + anchors { left: parent.left; right: parent.right } |
1340 | + |
1341 | + height: hidden ? 0 : units.gu(8) |
1342 | + clip: true |
1343 | + status: UpdateManager.status |
1344 | + batchMode: root.batchMode |
1345 | + requireRestart: imageRepeater.count > 0 |
1346 | + updatesCount: root.updatesCount |
1347 | + online: root.online |
1348 | + onStop: UpdateManager.cancel() |
1349 | + |
1350 | + onRequestInstall: { |
1351 | + if (requireRestart) { |
1352 | + var popup = PopupUtils.open( |
1353 | + Qt.resolvedUrl("ImageUpdatePrompt.qml"), null, { |
1354 | + havePowerForUpdate: root.havePower |
1355 | + } |
1356 | + ); |
1357 | + popup.requestSystemUpdate.connect(function () { |
1358 | + install(); |
1359 | + }); |
1360 | + } else { |
1361 | + install(); |
1362 | + } |
1363 | + } |
1364 | + onInstall: { |
1365 | + root.batchMode = true |
1366 | + if (requireRestart) { |
1367 | + postAllBatchHandler.target = root; |
1368 | + } else { |
1369 | + postClickBatchHandler.target = root; |
1370 | + } |
1371 | + } |
1372 | } |
1373 | - height: childrenRect.height |
1374 | - |
1375 | - ListItem.Base { |
1376 | - id: checkForUpdatesArea |
1377 | - objectName: "checkForUpdatesArea" |
1378 | - showDivider: false |
1379 | - visible: false |
1380 | - |
1381 | - ActivityIndicator { |
1382 | - id: activity |
1383 | - running: checkForUpdatesArea.visible |
1384 | - visible: activity.running |
1385 | - anchors { |
1386 | - left: parent.left |
1387 | - top: parent.top |
1388 | - } |
1389 | - height: parent.height |
1390 | + |
1391 | + Rectangle { |
1392 | + id: overlay |
1393 | + objectName: "overlay" |
1394 | + anchors { |
1395 | + left: parent.left |
1396 | + leftMargin: units.gu(2) |
1397 | + right: parent.right |
1398 | + rightMargin: units.gu(2) |
1399 | } |
1400 | + visible: placeholder.text |
1401 | + color: theme.palette.normal.background |
1402 | + height: units.gu(10) |
1403 | |
1404 | Label { |
1405 | - text: activity.running ? i18n.tr("Checking for updates…") : i18n.tr("Connect to the Internet to check for updates") |
1406 | + id: placeholder |
1407 | + objectName: "overlayText" |
1408 | + anchors.fill: parent |
1409 | verticalAlignment: Text.AlignVCenter |
1410 | - wrapMode: Text.Wrap |
1411 | - anchors { |
1412 | - left: activity.running ? activity.right : parent.left |
1413 | - top: parent.top |
1414 | - right: parent.right |
1415 | - rightMargin: units.gu(2) |
1416 | - leftMargin: units.gu(2) |
1417 | - } |
1418 | - height: parent.height |
1419 | - } |
1420 | - } |
1421 | - |
1422 | - ListItem.SingleControl { |
1423 | - height: installAllButton.visible ? units.gu(8) : units.gu(2) |
1424 | - highlightWhenPressed: false |
1425 | - control: Button { |
1426 | - id: installAllButton |
1427 | - objectName: "installAllButton" |
1428 | - property string primaryText: includeSystemUpdate ? |
1429 | - i18n.tr("Install %1 update…", "Install %1 updates…", root.updatesAvailable).arg(root.updatesAvailable) : |
1430 | - i18n.tr("Install %1 update", "Install %1 updates", root.updatesAvailable).arg(root.updatesAvailable) |
1431 | - property string secondaryText: i18n.tr("Pause All") |
1432 | - color: theme.palette.normal.positive |
1433 | - text: root.installAll ? secondaryText : primaryText |
1434 | - width: parent.width - units.gu(4) |
1435 | - |
1436 | - onClicked: { |
1437 | - for (var i=0; i < updateList.count; i++) { |
1438 | - updateList.currentIndex = i; |
1439 | - var item = updateList.currentItem; |
1440 | - var modelItem = UpdateManager.model[i]; |
1441 | - if (item.installing || item.installed) |
1442 | - continue; |
1443 | - console.warn("AllClicked: " + modelItem.updateState + " " + modelItem.updateReady + " " + modelItem.selected); |
1444 | - if (item.retry) { |
1445 | - item.retry = false; |
1446 | - UpdateManager.retryDownload(modelItem.packageName); |
1447 | - continue; |
1448 | - } |
1449 | - if (root.installAll && !modelItem.updateReady && modelItem.selected) { |
1450 | - item.pause(); |
1451 | - continue; |
1452 | - } |
1453 | - console.warn("Past pause"); |
1454 | - if (!root.installAll && !modelItem.updateReady && modelItem.selected) { |
1455 | - item.resume(); |
1456 | - continue; |
1457 | - } |
1458 | - console.warn("Past resume"); |
1459 | - if (!root.installAll && !modelItem.updateState && !modelItem.updateReady && !modelItem.selected) { |
1460 | - item.start(); |
1461 | - continue; |
1462 | - } |
1463 | - console.warn("Past start"); |
1464 | - } |
1465 | - root.installAll = !root.installAll; |
1466 | - } |
1467 | - } |
1468 | - showDivider: false |
1469 | - } |
1470 | - |
1471 | - ListView { |
1472 | - id: updateList |
1473 | - objectName: "updateList" |
1474 | - anchors { |
1475 | - left: parent.left |
1476 | - right: parent.right |
1477 | - } |
1478 | - model: UpdateManager.model |
1479 | - height: childrenRect.height |
1480 | - interactive: false |
1481 | - spacing: 0 |
1482 | - |
1483 | - delegate: ListItem.Subtitled { |
1484 | - id: listItem |
1485 | - anchors { |
1486 | - left: parent.left |
1487 | - right: parent.right |
1488 | - topMargin: units.gu(1) |
1489 | - bottomMargin: units.gu(1) |
1490 | - } |
1491 | - iconSource: Qt.resolvedUrl(modelData.iconUrl) |
1492 | - iconFrame: modelData.systemUpdate ? false : true |
1493 | - height: visible ? textArea.height + units.gu(2) : 0 |
1494 | - highlightWhenPressed: false |
1495 | - showDivider: false |
1496 | - visible: opacity > 0 |
1497 | - opacity: installed ? 0 : 1 |
1498 | - Behavior on opacity { PropertyAnimation { duration: UbuntuAnimation.SleepyDuration } } |
1499 | - |
1500 | - property alias actionButton: buttonAppUpdate |
1501 | - property alias progressBar: progress |
1502 | - property bool installing: !modelData.systemUpdate && (modelData.updateReady || (progressBar.value === progressBar.maximumValue)) |
1503 | - property bool installed: false |
1504 | - property bool retry: false |
1505 | - |
1506 | - function pause () { |
1507 | - console.warn("PAUSE: " + modelData.packageName); |
1508 | - if (modelData.systemUpdate) |
1509 | - return UpdateManager.pauseDownload(modelData.packageName); |
1510 | - modelData.updateState = false; |
1511 | - tracker.pause(); |
1512 | - } |
1513 | - |
1514 | - function resume () { |
1515 | - console.warn("RESUME: " + modelData.packageName); |
1516 | - if (modelData.systemUpdate) |
1517 | - return UpdateManager.startDownload(modelData.packageName); |
1518 | - modelData.updateState = true; |
1519 | - tracker.resume(); |
1520 | - } |
1521 | - |
1522 | - function start () { |
1523 | - console.warn("START: " + modelData.packageName); |
1524 | - modelData.selected = true; |
1525 | - modelData.updateState = true; |
1526 | - UpdateManager.startDownload(modelData.packageName); |
1527 | - } |
1528 | - |
1529 | - function forceDownload () { |
1530 | - console.warn("FORCE DOWNLOAD: " + modelData.packageName); |
1531 | - modelData.selected = true; |
1532 | - modelData.updateState = true; |
1533 | - UpdateManager.forceAllowGSMDownload(modelData.packageName); |
1534 | - } |
1535 | - |
1536 | - Column { |
1537 | - id: textArea |
1538 | - objectName: "textArea" |
1539 | - anchors { |
1540 | - left: parent.left |
1541 | - right: parent.right |
1542 | - } |
1543 | - spacing: units.gu(0.5) |
1544 | - |
1545 | - Item { |
1546 | - anchors { |
1547 | - left: parent.left |
1548 | - right: parent.right |
1549 | - } |
1550 | - height: buttonAppUpdate.height |
1551 | - |
1552 | - Label { |
1553 | - id: labelTitle |
1554 | - objectName: "labelTitle" |
1555 | - anchors { |
1556 | - left: parent.left |
1557 | - right: buttonAppUpdate.visible ? buttonAppUpdate.left : parent.right |
1558 | - verticalCenter: parent.verticalCenter |
1559 | - } |
1560 | - text: modelData.title |
1561 | - font.bold: true |
1562 | - elide: Text.ElideMiddle |
1563 | - } |
1564 | - |
1565 | - Button { |
1566 | - id: buttonAppUpdate |
1567 | - objectName: "buttonAppUpdate" |
1568 | - anchors.right: parent.right |
1569 | - height: labelTitle.height + units.gu(1) |
1570 | - enabled: !installing |
1571 | - text: { |
1572 | - if (retry) |
1573 | - return i18n.tr("Retry"); |
1574 | - if (modelData.systemUpdate) { |
1575 | - if (modelData.updateReady) { |
1576 | - return i18n.tr("Install…"); |
1577 | - } else if ((!modelData.updateState && !modelData.selected) || modelData.status === Update.NotStarted) { |
1578 | - return i18n.tr("Download"); |
1579 | - } |
1580 | - } |
1581 | - if (modelData.updateState || modelData.status === Update.Downloading) { |
1582 | - return i18n.tr("Pause"); |
1583 | - } else if (modelData.selected) { |
1584 | - return i18n.tr("Resume"); |
1585 | - } |
1586 | - return i18n.tr("Update"); |
1587 | - } |
1588 | - |
1589 | - onClicked: { |
1590 | - if (retry) { |
1591 | - retry = false; |
1592 | - return UpdateManager.retryDownload(modelData.packageName); |
1593 | - } |
1594 | - if (modelData.updateState) |
1595 | - return pause(); |
1596 | - if (!modelData.updateState && modelData.selected) |
1597 | - return resume(); |
1598 | - if (!modelData.updateState && !modelData.selected && !modelData.updateReady) |
1599 | - return start(); |
1600 | - if (modelData.systemUpdate && modelData.status === Update.NotStarted) |
1601 | - return forceDownload(); |
1602 | - if (modelData.updateReady) |
1603 | - PopupUtils.open(dialogInstallComponent); |
1604 | - } |
1605 | - } |
1606 | - } |
1607 | - |
1608 | - Item { |
1609 | - id: labelUpdateStatus |
1610 | - anchors { |
1611 | - left: parent.left |
1612 | - right: parent.right |
1613 | - } |
1614 | - height: childrenRect.height |
1615 | - visible: opacity > 0 |
1616 | - opacity: (modelData.updateState && modelData.selected && !modelData.updateReady) || (installing || installed) ? 1 : 0 |
1617 | - Behavior on opacity { PropertyAnimation { duration: UbuntuAnimation.SleepyDuration } } |
1618 | - Label { |
1619 | - objectName: "labelUpdateStatus" |
1620 | - anchors.left: parent.left |
1621 | - anchors.right: updateStatusLabel.left |
1622 | - elide: Text.ElideMiddle |
1623 | - fontSize: "small" |
1624 | - text: { |
1625 | - if (retry) |
1626 | - return modelData.error; |
1627 | - if (installing) |
1628 | - return i18n.tr("Installing"); |
1629 | - if (installed) |
1630 | - return i18n.tr("Installed"); |
1631 | - return i18n.tr("Downloading"); |
1632 | - } |
1633 | - } |
1634 | - Label { |
1635 | - id: updateStatusLabel |
1636 | - anchors.right: parent.right |
1637 | - visible: !labelSize.visible && !installing && !installed |
1638 | - fontSize: "small" |
1639 | - text: { |
1640 | - if (!labelUpdateStatus.visible) |
1641 | - return Utilities.formatSize(modelData.binaryFilesize); |
1642 | - |
1643 | - return i18n.tr("%1 of %2").arg( |
1644 | - Utilities.formatSize(modelData.binaryFilesize * (progress.value * 0.01))).arg( |
1645 | - Utilities.formatSize(modelData.binaryFilesize) |
1646 | - ); |
1647 | - } |
1648 | - } |
1649 | - } |
1650 | - |
1651 | - ProgressBar { |
1652 | - id: progress |
1653 | - objectName: "progress" |
1654 | - height: units.gu(2) |
1655 | - anchors { |
1656 | - left: parent.left |
1657 | - right: parent.right |
1658 | - } |
1659 | - visible: opacity > 0 |
1660 | - opacity: modelData.selected && !modelData.updateReady && !installed ? 1 : 0 |
1661 | - value: modelData.systemUpdate ? modelData.downloadProgress : tracker.progress |
1662 | - minimumValue: 0 |
1663 | - maximumValue: 100 |
1664 | - |
1665 | - DownloadTracker { |
1666 | - id: tracker |
1667 | - objectName: "tracker" |
1668 | - packageName: modelData.packageName |
1669 | - title: modelData.title |
1670 | - showInIndicator: false |
1671 | - clickToken: modelData.clickToken |
1672 | - download: modelData.downloadUrl |
1673 | - downloadSha512: modelData.downloadSha512 |
1674 | - |
1675 | - onFinished: { |
1676 | - progress.visible = false; |
1677 | - buttonAppUpdate.visible = false; |
1678 | - installed = true; |
1679 | - installing = false; |
1680 | - root.updatesAvailable -= 1; |
1681 | - modelData.updateRequired = false; |
1682 | - UpdateManager.updateClickScope(); |
1683 | - } |
1684 | - |
1685 | - onProcessing: { |
1686 | - console.warn("onProcessing: " + modelData.packageName + " " + path); |
1687 | - buttonAppUpdate.enabled = false; |
1688 | - installing = true; |
1689 | - modelData.updateState = false; |
1690 | - } |
1691 | - |
1692 | - onStarted: { |
1693 | - console.warn("onStarted: " + modelData.packageName + " " + success); |
1694 | - if (success) |
1695 | - modelData.updateState = true; |
1696 | - else |
1697 | - modelData.updateState = false; |
1698 | - } |
1699 | - |
1700 | - onPaused: { |
1701 | - console.warn("onPaused: " + modelData.packageName + " " + success); |
1702 | - if (success) |
1703 | - modelData.updateState = false; |
1704 | - else |
1705 | - modelData.updateState = true; |
1706 | - } |
1707 | - |
1708 | - onResumed: { |
1709 | - console.warn("onResumed: " + modelData.packageName + " " + success); |
1710 | - if (success) |
1711 | - modelData.updateState = true; |
1712 | - else |
1713 | - modelData.updateState = false; |
1714 | - } |
1715 | - |
1716 | - onCanceled: { |
1717 | - console.warn("onCanceled: " + modelData.packageName + " " + success); |
1718 | - if (success) { |
1719 | - modelData.updateState = false; |
1720 | - modelData.selected = false; |
1721 | - } |
1722 | - } |
1723 | - |
1724 | - onErrorFound: { |
1725 | - console.warn("onErrorFound: " + modelData.packageName + " " + error); |
1726 | - modelData.updateState = false; |
1727 | - retry = true; |
1728 | - installing = false; |
1729 | - } |
1730 | - } |
1731 | - |
1732 | - Behavior on opacity { PropertyAnimation { duration: UbuntuAnimation.SleepyDuration } } |
1733 | - } |
1734 | - |
1735 | - Item { |
1736 | - anchors { |
1737 | - left: parent.left |
1738 | - right: parent.right |
1739 | - } |
1740 | - height: childrenRect.height |
1741 | - Label { |
1742 | - id: labelVersion |
1743 | - objectName: "labelVersion" |
1744 | - anchors.left: parent.left |
1745 | - text: modelData.remoteVersion ? i18n.tr("Version: ") + modelData.remoteVersion : "" |
1746 | - elide: Text.ElideRight |
1747 | - fontSize: "small" |
1748 | - } |
1749 | - |
1750 | - Label { |
1751 | - id: labelSize |
1752 | - objectName: "labelSize" |
1753 | - anchors.right: parent.right |
1754 | - text: Utilities.formatSize(modelData.binaryFilesize) |
1755 | - fontSize: "small" |
1756 | - visible: !labelUpdateStatus.visible && !installing && !installed |
1757 | - } |
1758 | - } |
1759 | - } |
1760 | - } |
1761 | - } |
1762 | - |
1763 | - Column { |
1764 | - id: credentialsNotification |
1765 | - objectName: "credentialsNotification" |
1766 | - |
1767 | - visible: false |
1768 | - |
1769 | - spacing: units.gu(2) |
1770 | - anchors { |
1771 | - left: parent.left |
1772 | - right: parent.right |
1773 | - } |
1774 | - ListItem.ThinDivider {} |
1775 | - |
1776 | - Label { |
1777 | - text: i18n.tr("Sign in to Ubuntu One to receive updates for apps.") |
1778 | horizontalAlignment: Text.AlignHCenter |
1779 | - wrapMode: Text.Wrap |
1780 | - anchors { |
1781 | - left: parent.left |
1782 | - right: parent.right |
1783 | - } |
1784 | - } |
1785 | - Button { |
1786 | - text: i18n.tr("Sign In…") |
1787 | - anchors { |
1788 | - left: parent.left |
1789 | - right: parent.right |
1790 | - leftMargin: units.gu(2) |
1791 | - rightMargin: units.gu(2) |
1792 | - } |
1793 | - onClicked: uoaConfig.exec() |
1794 | - } |
1795 | - |
1796 | - } |
1797 | - } |
1798 | - } |
1799 | - |
1800 | - Rectangle { |
1801 | - id: updateNotification |
1802 | - objectName: "updateNotification" |
1803 | - anchors { |
1804 | - bottom: configuration.top |
1805 | - left: parent.left |
1806 | - right: parent.right |
1807 | - top: parent.top |
1808 | - } |
1809 | - visible: false |
1810 | - property string text: "" |
1811 | - |
1812 | - color: "transparent" |
1813 | - |
1814 | - Label { |
1815 | - anchors.centerIn: updateNotification |
1816 | - text: updateNotification.text |
1817 | - width: updateNotification.width |
1818 | - horizontalAlignment: Text.AlignHCenter |
1819 | - wrapMode: Text.Wrap |
1820 | - } |
1821 | - } |
1822 | - |
1823 | - Rectangle { |
1824 | - id: installingImageUpdate |
1825 | - objectName: "installingImageUpdate" |
1826 | - anchors.fill: root |
1827 | - visible: false |
1828 | - z: 10 |
1829 | - color: "#221e1c" |
1830 | - property string message: i18n.tr("Installing update…") |
1831 | - |
1832 | - Column { |
1833 | - anchors.centerIn: parent |
1834 | - spacing: units.gu(2) |
1835 | - |
1836 | - Image { |
1837 | - source: Qt.resolvedUrl("file:///usr/share/icons/suru/places/scalable/distributor-logo.svg") |
1838 | - anchors.horizontalCenter: parent.horizontalCenter |
1839 | - height: width |
1840 | - width: 96 |
1841 | - NumberAnimation on rotation { |
1842 | - from: 0 |
1843 | - to: 360 |
1844 | - running: installingImageUpdate.visible == true |
1845 | - loops: Animation.Infinite |
1846 | - duration: 2000 |
1847 | - } |
1848 | - } |
1849 | - |
1850 | - ProgressBar { |
1851 | - indeterminate: true |
1852 | - anchors.horizontalCenter: parent.horizontalCenter |
1853 | - } |
1854 | - |
1855 | - Label { |
1856 | - text: installingImageUpdate.message |
1857 | - anchors.horizontalCenter: parent.horizontalCenter |
1858 | - } |
1859 | - } |
1860 | - } |
1861 | + wrapMode: Text.WordWrap |
1862 | + text: { |
1863 | + var s = UpdateManager.status; |
1864 | + if (!root.online) { |
1865 | + return i18n.tr("Connect to the Internet to check for updates."); |
1866 | + } else if (s === UpdateManager.StatusIdle && updatesCount === 0) { |
1867 | + return i18n.tr("Software is up to date"); |
1868 | + } else if (s === UpdateManager.StatusServerError || |
1869 | + s === UpdateManager.StatusNetworkError) { |
1870 | + return i18n.tr("The update server is not responding. Try again later."); |
1871 | + } |
1872 | + return ""; |
1873 | + } |
1874 | + } |
1875 | + } |
1876 | + |
1877 | + SettingsItemTitle { |
1878 | + id: updatesAvailableHeader |
1879 | + text: i18n.tr("Updates Available") |
1880 | + visible: imageUpdateCol.visible || clickUpdatesCol.visible |
1881 | + } |
1882 | + |
1883 | + Column { |
1884 | + id: imageUpdateCol |
1885 | + objectName: "imageUpdates" |
1886 | + anchors { left: parent.left; right: parent.right } |
1887 | + visible: { |
1888 | + var s = UpdateManager.status; |
1889 | + var haveUpdates = imageRepeater.count > 0; |
1890 | + switch (s) { |
1891 | + case UpdateManager.StatusCheckingClickUpdates: |
1892 | + case UpdateManager.StatusIdle: |
1893 | + return haveUpdates && online; |
1894 | + } |
1895 | + return false; |
1896 | + } |
1897 | + |
1898 | + Repeater { |
1899 | + id: imageRepeater |
1900 | + model: UpdateManager.imageUpdates |
1901 | + |
1902 | + delegate: UpdateDelegate { |
1903 | + objectName: "imageUpdatesDelegate-" + index |
1904 | + width: imageUpdateCol.width |
1905 | + updateState: model.updateState |
1906 | + progress: model.progress |
1907 | + version: SystemImage.versionTag ? |
1908 | + SystemImage.versionTag : remoteVersion |
1909 | + size: model.size |
1910 | + changelog: model.changelog |
1911 | + error: model.error |
1912 | + kind: model.kind |
1913 | + iconUrl: model.iconUrl |
1914 | + name: title |
1915 | + |
1916 | + onResume: download() |
1917 | + onRetry: download() |
1918 | + onDownload: { |
1919 | + if (SystemImage.downloadMode < 2) { |
1920 | + SystemImage.downloadUpdate(); |
1921 | + SystemImage.forceAllowGSMDownload(); |
1922 | + } else { |
1923 | + SystemImage.downloadUpdate(); |
1924 | + } |
1925 | + } |
1926 | + onPause: SystemImage.pauseDownload(); |
1927 | + onInstall: { |
1928 | + var popup = PopupUtils.open( |
1929 | + Qt.resolvedUrl("ImageUpdatePrompt.qml"), null, { |
1930 | + havePowerForUpdate: root.havePower |
1931 | + } |
1932 | + ); |
1933 | + popup.requestSystemUpdate.connect(SystemImage.applyUpdate); |
1934 | + } |
1935 | + } |
1936 | + } |
1937 | + } |
1938 | + |
1939 | + Column { |
1940 | + id: clickUpdatesCol |
1941 | + objectName: "clickUpdates" |
1942 | + anchors { left: parent.left; right: parent.right } |
1943 | + visible: { |
1944 | + var s = UpdateManager.status; |
1945 | + var haveUpdates = clickRepeater.count > 0; |
1946 | + switch (s) { |
1947 | + case UpdateManager.StatusCheckingImageUpdates: |
1948 | + case UpdateManager.StatusIdle: |
1949 | + return haveUpdates && online && authenticated; |
1950 | + } |
1951 | + return false; |
1952 | + } |
1953 | + |
1954 | + Repeater { |
1955 | + id: clickRepeater |
1956 | + model: UpdateManager.clickUpdates |
1957 | + |
1958 | + delegate: ClickUpdateDelegate { |
1959 | + objectName: "clickUpdatesDelegate" + index |
1960 | + width: clickUpdatesCol.width |
1961 | + updateState: model.updateState |
1962 | + progress: model.progress |
1963 | + version: remoteVersion |
1964 | + size: model.size |
1965 | + name: title |
1966 | + iconUrl: model.iconUrl |
1967 | + kind: model.kind |
1968 | + changelog: model.changelog |
1969 | + error: model.error |
1970 | + signedUrl: signedDownloadUrl |
1971 | + |
1972 | + onInstall: downloadHandler.createDownload(model); |
1973 | + onPause: downloadHandler.pauseDownload(model) |
1974 | + onResume: downloadHandler.resumeDownload(model) |
1975 | + onRetry: { |
1976 | + /* This creates a new signed URL with which we can |
1977 | + retry the download. See onSignedUrlChanged. */ |
1978 | + UpdateManager.retry(model.identifier, |
1979 | + model.revision); |
1980 | + } |
1981 | + |
1982 | + onSignedUrlChanged: { |
1983 | + // If we have a signedUrl, user intend to retry. |
1984 | + if (signedUrl) { |
1985 | + downloadHandler.retryDownload(model); |
1986 | + } |
1987 | + } |
1988 | + |
1989 | + Connections { |
1990 | + target: glob |
1991 | + onInstall: install() |
1992 | + } |
1993 | + |
1994 | + /* If we a downloadId, we expect UDM to restore it |
1995 | + after some time. Workaround for lp:1603770. */ |
1996 | + Timer { |
1997 | + id: downloadTimeout |
1998 | + interval: 30000 |
1999 | + running: true |
2000 | + onTriggered: { |
2001 | + var s = updateState; |
2002 | + if (model.downloadId |
2003 | + || s === Update.StateQueuedForDownload |
2004 | + || s === Update.StateDownloading) { |
2005 | + downloadHandler.assertDownloadExist(model); |
2006 | + } |
2007 | + } |
2008 | + } |
2009 | + } |
2010 | + } |
2011 | + } |
2012 | + |
2013 | + NotAuthenticatedNotification { |
2014 | + id: notauthNotification |
2015 | + objectName: "noAuthenticationNotification" |
2016 | + visible: { |
2017 | + var s = UpdateManager.status; |
2018 | + switch (s) { |
2019 | + case UpdateManager.StatusCheckingImageUpdates: |
2020 | + case UpdateManager.StatusIdle: |
2021 | + return !authenticated && online; |
2022 | + } |
2023 | + return false; |
2024 | + } |
2025 | + anchors { |
2026 | + left: parent.left |
2027 | + right: parent.right |
2028 | + } |
2029 | + onRequestAuthentication: uoaConfig.exec() |
2030 | + } |
2031 | + |
2032 | + SettingsItemTitle { |
2033 | + text: i18n.tr("Recent updates") |
2034 | + visible: installedCol.visible |
2035 | + } |
2036 | + |
2037 | + Column { |
2038 | + id: installedCol |
2039 | + objectName: "installedUpdates" |
2040 | + anchors { left: parent.left; right: parent.right } |
2041 | + visible: installedRepeater.count > 0 |
2042 | + |
2043 | + Repeater { |
2044 | + id: installedRepeater |
2045 | + model: UpdateManager.installedUpdates |
2046 | + |
2047 | + delegate: UpdateDelegate { |
2048 | + objectName: "installedUpdateDelegate-" + index |
2049 | + width: installedCol.width |
2050 | + version: remoteVersion |
2051 | + size: model.size |
2052 | + name: title |
2053 | + kind: model.kind |
2054 | + iconUrl: model.iconUrl |
2055 | + changelog: model.changelog |
2056 | + updateState: Update.StateInstalled |
2057 | + updatedAt: model.updatedAt |
2058 | + |
2059 | + leadingActions: ListItemActions { |
2060 | + actions: [ |
2061 | + Action { |
2062 | + iconName: "delete" |
2063 | + onTriggered: UpdateManager.remove( |
2064 | + model.identifier, model.revision |
2065 | + ) |
2066 | + } |
2067 | + ] |
2068 | + } |
2069 | + |
2070 | + // Launchable if there's a package name on a click. |
2071 | + launchable: (!!packageName && |
2072 | + model.kind === Update.KindClick) |
2073 | + |
2074 | + onLaunch: UpdateManager.launch(identifier, revision); |
2075 | + } |
2076 | + } |
2077 | + } |
2078 | + } // Column inside flickable. |
2079 | + } // Flickable |
2080 | |
2081 | Column { |
2082 | id: configuration |
2083 | |
2084 | - anchors.bottom: parent.bottom |
2085 | - anchors.left: parent.left |
2086 | - anchors.right: parent.right |
2087 | + height: childrenRect.height |
2088 | + |
2089 | + anchors { |
2090 | + bottom: parent.bottom |
2091 | + left: parent.left |
2092 | + right: parent.right |
2093 | + } |
2094 | + |
2095 | ListItem.ThinDivider {} |
2096 | + |
2097 | ListItem.SingleValue { |
2098 | objectName: "configuration" |
2099 | text: i18n.tr("Auto download") |
2100 | value: { |
2101 | - if (UpdateManager.downloadMode === 0) |
2102 | + if (SystemImage.downloadMode === 0) |
2103 | return i18n.tr("Never") |
2104 | - else if (UpdateManager.downloadMode === 1) |
2105 | + else if (SystemImage.downloadMode === 1) |
2106 | return i18n.tr("On wi-fi") |
2107 | - else if (UpdateManager.downloadMode === 2) |
2108 | + else if (SystemImage.downloadMode === 2) |
2109 | return i18n.tr("Always") |
2110 | + else |
2111 | + return i18n.tr("Unknown") |
2112 | } |
2113 | progression: true |
2114 | onClicked: pageStack.push(Qt.resolvedUrl("Configuration.qml")) |
2115 | } |
2116 | } |
2117 | + |
2118 | + Connections { |
2119 | + id: postClickBatchHandler |
2120 | + ignoreUnknownSignals: true |
2121 | + target: null |
2122 | + onUpdatesCountChanged: { |
2123 | + if (target.updatesCount === 0) { |
2124 | + root.batchMode = false; |
2125 | + target = null; |
2126 | + } |
2127 | + } |
2128 | + } |
2129 | + |
2130 | + Connections { |
2131 | + id: postAllBatchHandler |
2132 | + ignoreUnknownSignals: true |
2133 | + target: null |
2134 | + onUpdatesCountChanged: { |
2135 | + if (target.updatesCount === 1) { |
2136 | + SystemImage.updateDownloaded.connect(function () { |
2137 | + SystemImage.applyUpdate(); |
2138 | + }); |
2139 | + SystemImage.downloadUpdate(); |
2140 | + } |
2141 | + } |
2142 | + } |
2143 | + |
2144 | + Connections { |
2145 | + target: NetworkingStatus |
2146 | + onOnlineChanged: { |
2147 | + if (!online) { |
2148 | + UpdateManager.cancel(); |
2149 | + } else { |
2150 | + UpdateManager.check(UpdateManager.CheckAll); |
2151 | + } |
2152 | + } |
2153 | + } |
2154 | + |
2155 | + Connections { |
2156 | + target: SystemImage |
2157 | + onUpdateFailed: { |
2158 | + if (consecutiveFailureCount > SystemImage.failuresBeforeWarning) { |
2159 | + var popup = PopupUtils.open( |
2160 | + Qt.resolvedUrl("InstallationFailed.qml"), null, { |
2161 | + text: lastReason |
2162 | + } |
2163 | + ); |
2164 | + } |
2165 | + } |
2166 | + } |
2167 | + |
2168 | + Component.onCompleted: check() |
2169 | } |
2170 | |
2171 | === added file 'plugins/system-update/UpdateDelegate.qml' |
2172 | --- plugins/system-update/UpdateDelegate.qml 1970-01-01 00:00:00 +0000 |
2173 | +++ plugins/system-update/UpdateDelegate.qml 2016-08-16 11:46:43 +0000 |
2174 | @@ -0,0 +1,412 @@ |
2175 | +/* |
2176 | + * This file is part of system-settings |
2177 | + * |
2178 | + * Copyright (C) 2016 Canonical Ltd. |
2179 | + * |
2180 | + * Contact: Jonas G. Drange <jonas.drange@canonical.com> |
2181 | + * |
2182 | + * This program is free software: you can redistribute it and/or modify it |
2183 | + * under the terms of the GNU General Public License version 3, as published |
2184 | + * by the Free Software Foundation. |
2185 | + * |
2186 | + * This program is distributed in the hope that it will be useful, but |
2187 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
2188 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2189 | + * PURPOSE. See the GNU General Public License for more details. |
2190 | + * |
2191 | + * You should have received a copy of the GNU General Public License along |
2192 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
2193 | + * |
2194 | + */ |
2195 | + |
2196 | +import QtQuick 2.4 |
2197 | +import QtQuick.Layouts 1.1 |
2198 | +import Ubuntu.Components 1.3 |
2199 | +import Ubuntu.Components.ListItems 1.3 as ListItems |
2200 | +import Ubuntu.Components.Themes 1.3 |
2201 | +import Ubuntu.SystemSettings.Update 1.0 |
2202 | + |
2203 | +ListItem { |
2204 | + id: update |
2205 | + |
2206 | + property int updateState // This is an Update::State |
2207 | + property int kind // This is an Update::Kind |
2208 | + property real size |
2209 | + property string version |
2210 | + property string downloadId |
2211 | + property date updatedAt |
2212 | + property bool launchable: false |
2213 | + |
2214 | + property alias name: nameLabel.text |
2215 | + property alias error: errorElementDetail.text |
2216 | + property alias iconUrl: icon.source |
2217 | + property alias changelog: changelogLabel.text |
2218 | + property alias progress: progressBar.value |
2219 | + |
2220 | + signal retry() |
2221 | + signal download() |
2222 | + signal pause() |
2223 | + signal resume() |
2224 | + signal install() |
2225 | + signal launch() |
2226 | + |
2227 | + height: layout.height + (divider.visible ? divider.height : 0) |
2228 | + Behavior on height { |
2229 | + animation: UbuntuNumberAnimation {} |
2230 | + } |
2231 | + |
2232 | + SlotsLayout { |
2233 | + id: layout |
2234 | + mainSlot: ColumnLayout { |
2235 | + spacing: units.gu(1) |
2236 | + // Width the parent, minus the icon and some padding |
2237 | + width: parent.width - (icon.width + (layout.padding.top * 3)) |
2238 | + |
2239 | + RowLayout { |
2240 | + spacing: units.gu(2) |
2241 | + |
2242 | + Label { |
2243 | + id: nameLabel |
2244 | + verticalAlignment: Text.AlignVCenter |
2245 | + elide: Text.ElideMiddle |
2246 | + Layout.fillWidth: true |
2247 | + Layout.fillHeight: true |
2248 | + } |
2249 | + |
2250 | + Button { |
2251 | + id: button |
2252 | + objectName: "updateButton" |
2253 | + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter |
2254 | + visible: { |
2255 | + switch (updateState) { |
2256 | + case Update.StateInstalled: |
2257 | + return launchable; |
2258 | + default: |
2259 | + return true; |
2260 | + } |
2261 | + } |
2262 | + enabled: { |
2263 | + switch(updateState) { |
2264 | + case Update.StateAvailable: |
2265 | + case Update.StateDownloading: |
2266 | + case Update.StateDownloadingAutomatically: |
2267 | + case Update.StateDownloadPaused: |
2268 | + case Update.StateAutomaticDownloadPaused: |
2269 | + case Update.StateInstallPaused: |
2270 | + case Update.StateDownloaded: |
2271 | + case Update.StateFailed: |
2272 | + return true; |
2273 | + |
2274 | + // Enabled if installed and a click app (can launch). |
2275 | + case Update.StateInstalled: |
2276 | + return kind === Update.KindClick; |
2277 | + |
2278 | + case Update.StateInstalling: |
2279 | + case Update.StateInstallingAutomatically: |
2280 | + case Update.StateUnavailable: |
2281 | + case Update.StateInstallFinished: |
2282 | + case Update.StateQueuedForDownload: |
2283 | + case Update.StateUnknown: |
2284 | + default: |
2285 | + return false; |
2286 | + } |
2287 | + } |
2288 | + text: { |
2289 | + switch(updateState) { |
2290 | + case Update.StateUnknown: |
2291 | + case Update.StateUnavailable: |
2292 | + case Update.StateFailed: |
2293 | + return i18n.tr("Retry"); |
2294 | + |
2295 | + case Update.StateAvailable: |
2296 | + case Update.StateQueuedForDownload: |
2297 | + if (update.kind === Update.KindClick) { |
2298 | + return i18n.tr("Update"); |
2299 | + } else { |
2300 | + return i18n.tr("Download"); |
2301 | + } |
2302 | + |
2303 | + case Update.StateDownloadPaused: |
2304 | + case Update.StateAutomaticDownloadPaused: |
2305 | + case Update.StateInstallPaused: |
2306 | + return i18n.tr("Resume"); |
2307 | + |
2308 | + case Update.StateDownloading: |
2309 | + case Update.StateDownloadingAutomatically: |
2310 | + case Update.StateInstalling: |
2311 | + case Update.StateInstallingAutomatically: |
2312 | + case Update.StateInstallFinished: |
2313 | + return i18n.tr("Pause"); |
2314 | + |
2315 | + case Update.StateDownloaded: |
2316 | + if (kind === Update.KindImage) { |
2317 | + return i18n.tr("Install…"); |
2318 | + } else { |
2319 | + return i18n.tr("Install"); |
2320 | + } |
2321 | + |
2322 | + case Update.StateInstalled: |
2323 | + return i18n.tr("Open"); |
2324 | + |
2325 | + default: |
2326 | + console.error("Unknown update state", updateState); |
2327 | + } |
2328 | + } |
2329 | + |
2330 | + onClicked: { |
2331 | + switch (updateState) { |
2332 | + |
2333 | + // Retries. |
2334 | + case Update.StateUnknown: |
2335 | + case Update.StateUnavailable: |
2336 | + case Update.StateFailed: |
2337 | + update.retry(); |
2338 | + break; |
2339 | + |
2340 | + case Update.StateDownloadPaused: |
2341 | + case Update.StateAutomaticDownloadPaused: |
2342 | + case Update.StateInstallPaused: |
2343 | + update.resume(); |
2344 | + break; |
2345 | + |
2346 | + case Update.StateAvailable: |
2347 | + if (kind === Update.KindClick) { |
2348 | + update.install(); |
2349 | + } else { |
2350 | + update.download(); |
2351 | + } |
2352 | + break; |
2353 | + |
2354 | + case Update.StateDownloaded: |
2355 | + update.install(); |
2356 | + break; |
2357 | + |
2358 | + case Update.StateDownloading: |
2359 | + case Update.StateDownloadingAutomatically: |
2360 | + case Update.StateInstalling: |
2361 | + case Update.StateInstallingAutomatically: |
2362 | + update.pause(); |
2363 | + break; |
2364 | + |
2365 | + case Update.StateInstalled: |
2366 | + update.launch(); |
2367 | + break; |
2368 | + } |
2369 | + } |
2370 | + } // Button |
2371 | + } // Name/button RowLayout |
2372 | + |
2373 | + RowLayout { |
2374 | + spacing: units.gu(2) |
2375 | + |
2376 | + ChangelogExpander { |
2377 | + Layout.fillWidth: true |
2378 | + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter |
2379 | + |
2380 | + enabled: update.changelog !== "" |
2381 | + version: update.version |
2382 | + visible: updateState !== Update.StateFailed && downloadLabel.text === "" |
2383 | + expanded: changelogCol.visible |
2384 | + onClicked: changelogCol.visible = !changelogCol.visible |
2385 | + } |
2386 | + |
2387 | + Label { |
2388 | + id: downloadLabel |
2389 | + objectName: "updateDownloadLabel" |
2390 | + |
2391 | + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter |
2392 | + |
2393 | + visible: text !== "" |
2394 | + |
2395 | + fontSize: "small" |
2396 | + text: { |
2397 | + switch (updateState) { |
2398 | + |
2399 | + case Update.StateInstalling: |
2400 | + case Update.StateInstallingAutomatically: |
2401 | + case Update.StateInstallPaused: |
2402 | + return i18n.tr("Installing"); |
2403 | + |
2404 | + case Update.StateInstallPaused: |
2405 | + case Update.StateDownloadPaused: |
2406 | + return i18n.tr("Paused"); |
2407 | + |
2408 | + case Update.StateQueuedForDownload: |
2409 | + return i18n.tr("Waiting to download"); |
2410 | + |
2411 | + case Update.StateDownloading: |
2412 | + return i18n.tr("Downloading"); |
2413 | + |
2414 | + default: |
2415 | + return ""; |
2416 | + } |
2417 | + } |
2418 | + } |
2419 | + |
2420 | + Label { |
2421 | + id: statusLabel |
2422 | + objectName: "updateStatusLabel" |
2423 | + |
2424 | + visible: text !== "" |
2425 | + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter |
2426 | + Layout.fillWidth: true |
2427 | + |
2428 | + horizontalAlignment: Text.AlignRight |
2429 | + fontSize: "small" |
2430 | + |
2431 | + text: { |
2432 | + switch (updateState) { |
2433 | + case Update.StateAvailable: |
2434 | + return Utilities.formatSize(size); |
2435 | + |
2436 | + case Update.StateDownloading: |
2437 | + case Update.StateDownloadingAutomatically: |
2438 | + case Update.StateDownloadPaused: |
2439 | + case Update.StateAutomaticDownloadPaused: |
2440 | + var down = Utilities.formatSize((size / 100) * progress); |
2441 | + var left = Utilities.formatSize(size); |
2442 | + if (progress > 100) { |
2443 | + return left; |
2444 | + } else { |
2445 | + /* TRANSLATORS: %1 is the human readable amount |
2446 | + of bytes downloaded, and %2 is the total to be |
2447 | + downloaded. */ |
2448 | + return i18n.tr("%1 of %2").arg(down).arg(left); |
2449 | + } |
2450 | + |
2451 | + case Update.StateDownloaded: |
2452 | + return i18n.tr("Downloaded"); |
2453 | + |
2454 | + case Update.StateInstallFinished: |
2455 | + return i18n.tr("Installed"); |
2456 | + |
2457 | + case Update.StateInstalled: |
2458 | + /* TRANSLATORS: %1 is the date at which this |
2459 | + update was applied. */ |
2460 | + return i18n.tr("Updated at %1").arg( |
2461 | + updatedAt.toLocaleDateString(Qt.locale(), "d MMMM") |
2462 | + ); |
2463 | + default: |
2464 | + return ""; |
2465 | + } |
2466 | + } |
2467 | + |
2468 | + /* Seems AlignRight causes a rendering issue that can be |
2469 | + fixed by doing an explicit doLayout. */ |
2470 | + Component.onCompleted: doLayout() |
2471 | + } |
2472 | + } |
2473 | + |
2474 | + Column { |
2475 | + id: error |
2476 | + objectName: "updateError" |
2477 | + spacing: units.gu(1) |
2478 | + height: childrenRect.height |
2479 | + Layout.fillWidth: true |
2480 | + visible: errorElementDetail.text |
2481 | + |
2482 | + Label { |
2483 | + id: errorElementTitle |
2484 | + text: i18n.tr("Update failed") |
2485 | + color: UbuntuColors.red |
2486 | + } |
2487 | + |
2488 | + Label { |
2489 | + id: errorElementDetail |
2490 | + anchors { left: parent.left; right: parent.right } |
2491 | + fontSize: "small" |
2492 | + wrapMode: Text.WrapAnywhere |
2493 | + } |
2494 | + } // Error column |
2495 | + |
2496 | + ProgressBar { |
2497 | + id: progressBar |
2498 | + objectName: "updateProgressbar" |
2499 | + |
2500 | + visible: { |
2501 | + switch (updateState) { |
2502 | + case Update.StateQueuedForDownload: |
2503 | + case Update.StateDownloading: |
2504 | + case Update.StateDownloadPaused: |
2505 | + case Update.StateInstalling: |
2506 | + case Update.StateInstallPaused: |
2507 | + return true; |
2508 | + |
2509 | + default: |
2510 | + return false; |
2511 | + } |
2512 | + } |
2513 | + Layout.maximumHeight: units.gu(0.5) |
2514 | + Layout.fillWidth: true |
2515 | + indeterminate: update.progress < 0 || update.progress > 100 |
2516 | + minimumValue: 0 |
2517 | + maximumValue: 100 |
2518 | + showProgressPercentage: false |
2519 | + |
2520 | + Behavior on value { |
2521 | + animation: UbuntuNumberAnimation {} |
2522 | + } |
2523 | + } // Progress bar |
2524 | + |
2525 | + ChangelogExpander { |
2526 | + Layout.fillWidth: true |
2527 | + version: update.version |
2528 | + enabled: update.changelog !== "" |
2529 | + visible: updateState !== Update.StateFailed && downloadLabel.text !== "" |
2530 | + expanded: changelogCol.visible |
2531 | + onClicked: changelogCol.visible = !changelogCol.visible |
2532 | + } |
2533 | + |
2534 | + Column { |
2535 | + id: changelogCol |
2536 | + visible: false |
2537 | + height: childrenRect.height |
2538 | + Layout.fillWidth: true |
2539 | + opacity: visible ? 1 : 0 |
2540 | + |
2541 | + Behavior on opacity { |
2542 | + animation: UbuntuNumberAnimation {} |
2543 | + } |
2544 | + |
2545 | + Label { |
2546 | + id: changelogLabel |
2547 | + anchors { left: parent.left; right: parent.right } |
2548 | + fontSize: "small" |
2549 | + wrapMode: Text.WordWrap |
2550 | + } |
2551 | + } |
2552 | + } // Layout for the rest of the stuff |
2553 | + |
2554 | + Item { |
2555 | + SlotsLayout.position: SlotsLayout.Leading; |
2556 | + width: units.gu(4) |
2557 | + height: width |
2558 | + |
2559 | + Image { |
2560 | + id: icon |
2561 | + visible: kind === Update.KindImage && !fallback.visible |
2562 | + anchors.fill: parent |
2563 | + asynchronous: true |
2564 | + smooth: true |
2565 | + mipmap: true |
2566 | + } |
2567 | + |
2568 | + UbuntuShape { |
2569 | + id: shape |
2570 | + visible: kind !== Update.KindImage && !fallback.visible |
2571 | + anchors.fill: parent |
2572 | + source: icon |
2573 | + } |
2574 | + |
2575 | + Image { |
2576 | + id: fallback |
2577 | + visible: icon.status === Image.Error |
2578 | + source : Qt.resolvedUrl("/usr/share/icons/suru/apps/scalable/ubuntu-logo-symbolic.svg") |
2579 | + anchors.fill: parent |
2580 | + asynchronous: true |
2581 | + smooth: true |
2582 | + mipmap: true |
2583 | + } |
2584 | + } |
2585 | + } |
2586 | +} |
2587 | |
2588 | === added directory 'plugins/system-update/click' |
2589 | === added file 'plugins/system-update/click/apiclient.h' |
2590 | --- plugins/system-update/click/apiclient.h 1970-01-01 00:00:00 +0000 |
2591 | +++ plugins/system-update/click/apiclient.h 2016-08-16 11:46:43 +0000 |
2592 | @@ -0,0 +1,67 @@ |
2593 | +/* |
2594 | + * This file is part of system-settings |
2595 | + * |
2596 | + * Copyright (C) 2016 Canonical Ltd. |
2597 | + * |
2598 | + * This program is free software: you can redistribute it and/or modify it |
2599 | + * under the terms of the GNU General Public License version 3, as published |
2600 | + * by the Free Software Foundation. |
2601 | + * |
2602 | + * This program is distributed in the hope that it will be useful, but |
2603 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
2604 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2605 | + * PURPOSE. See the GNU General Public License for more details. |
2606 | + * |
2607 | + * You should have received a copy of the GNU General Public License along |
2608 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
2609 | + */ |
2610 | + |
2611 | +#ifndef CLICK_APICLIENT_H |
2612 | +#define CLICK_APICLIENT_H |
2613 | + |
2614 | +#include <QObject> |
2615 | +#include <QList> |
2616 | +#include <QString> |
2617 | +#include <QUrl> |
2618 | +#include <QJsonArray> |
2619 | + |
2620 | +namespace UpdatePlugin |
2621 | +{ |
2622 | +namespace Click |
2623 | +{ |
2624 | +// Interface for a Click API client. |
2625 | +class ApiClient : public QObject |
2626 | +{ |
2627 | + Q_OBJECT |
2628 | +public: |
2629 | + explicit ApiClient(QObject *parent = nullptr) : QObject(parent) {}; |
2630 | + virtual ~ApiClient() {}; |
2631 | +public Q_SLOTS: |
2632 | + virtual void cancel() = 0; |
2633 | + |
2634 | + /* Request metadata. |
2635 | + * |
2636 | + * Requests metadata from a server given an URL and list of packages. A |
2637 | + * package is a click_package as described in [1]. |
2638 | + * [1] https://wiki.ubuntu.com/AppStore/Interfaces/ApplicationId |
2639 | + */ |
2640 | + virtual void requestMetadata(const QUrl &url, |
2641 | + const QList<QString> &packages) = 0; |
2642 | + |
2643 | + // Request a token, see lp:1231422. |
2644 | + virtual void requestToken(const QUrl &url) = 0; |
2645 | +Q_SIGNALS: |
2646 | + void metadataRequestSucceeded(const QJsonArray &metadata); |
2647 | + void tokenRequestSucceeded(const QString &token); |
2648 | + void networkError(); |
2649 | + void serverError(); |
2650 | + void credentialError(); |
2651 | + /* This signal is emitted when the client wants to cancel any active |
2652 | + * network requests. |
2653 | + */ |
2654 | + void abortNetworking(); |
2655 | +}; |
2656 | +} // Click |
2657 | +} // UpdatePlugin |
2658 | + |
2659 | +#endif // CLICK_APICLIENT_H |
2660 | |
2661 | === added file 'plugins/system-update/click/apiclient_impl.cpp' |
2662 | --- plugins/system-update/click/apiclient_impl.cpp 1970-01-01 00:00:00 +0000 |
2663 | +++ plugins/system-update/click/apiclient_impl.cpp 2016-08-16 11:46:43 +0000 |
2664 | @@ -0,0 +1,215 @@ |
2665 | +/* |
2666 | + * This file is part of system-settings |
2667 | + * |
2668 | + * Copyright (C) 2016 Canonical Ltd. |
2669 | + * |
2670 | + * This program is free software: you can redistribute it and/or modify it |
2671 | + * under the terms of the GNU General Public License version 3, as published |
2672 | + * by the Free Software Foundation. |
2673 | + * |
2674 | + * This program is distributed in the hope that it will be useful, but |
2675 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
2676 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2677 | + * PURPOSE. See the GNU General Public License for more details. |
2678 | + * |
2679 | + * You should have received a copy of the GNU General Public License along |
2680 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
2681 | + */ |
2682 | + |
2683 | +#include "helpers.h" |
2684 | + |
2685 | +#include "click/apiclient_impl.h" |
2686 | +#include "network/accessmanager_impl.h" |
2687 | + |
2688 | +#include <QJsonArray> |
2689 | +#include <QJsonDocument> |
2690 | +#include <QJsonObject> |
2691 | +#include <QJsonValue> |
2692 | +#include <QJsonParseError> |
2693 | +#include <QScopedPointer> |
2694 | + |
2695 | +#define X_CLICK_TOKEN "X-Click-Token" |
2696 | + |
2697 | +namespace UpdatePlugin |
2698 | +{ |
2699 | +namespace Click |
2700 | +{ |
2701 | +ApiClientImpl::ApiClientImpl(Network::Manager *nam, QObject *parent) |
2702 | + : ApiClient(parent) |
2703 | + , m_nam(nam) |
2704 | +{ |
2705 | + connect(m_nam, SIGNAL(finished(QNetworkReply *)), |
2706 | + this, SLOT(requestFinished(QNetworkReply *))); |
2707 | + connect(m_nam, SIGNAL(sslErrors(QNetworkReply *, const QList<QSslError>&)), |
2708 | + this, SLOT(requestSslFailed(QNetworkReply *, const QList<QSslError>&))); |
2709 | +} |
2710 | + |
2711 | +ApiClientImpl::~ApiClientImpl() |
2712 | +{ |
2713 | + cancel(); |
2714 | +} |
2715 | + |
2716 | +void ApiClientImpl::requestMetadata(const QUrl &url, |
2717 | + const QList<QString> &packages) |
2718 | +{ |
2719 | + // Create list of frameworks. |
2720 | + std::stringstream frameworks; |
2721 | + Q_FOREACH(auto f, Helpers::getAvailableFrameworks()) { |
2722 | + frameworks << "," << f; |
2723 | + } |
2724 | + |
2725 | + // Create JSON bytearray of packages. |
2726 | + QJsonObject serializer; |
2727 | + QJsonArray array; |
2728 | + Q_FOREACH(auto name, packages) { |
2729 | + array.append(QJsonValue(name)); |
2730 | + } |
2731 | + serializer.insert("name", array); |
2732 | + |
2733 | + QJsonDocument doc(serializer); |
2734 | + QByteArray content = doc.toJson(); |
2735 | + |
2736 | + QNetworkRequest request; |
2737 | + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); |
2738 | + request.setRawHeader(QByteArray("X-Ubuntu-Frameworks"), |
2739 | + QByteArray::fromStdString(frameworks.str())); |
2740 | + request.setRawHeader(QByteArray("X-Ubuntu-Architecture"), |
2741 | + QByteArray::fromStdString(Helpers::getArchitecture())); |
2742 | + request.setUrl(url); |
2743 | + request.setOriginatingObject(this); |
2744 | + request.setAttribute(QNetworkRequest::User, "metadata-request"); |
2745 | + |
2746 | + initializeReply(m_nam->post(request, content)); |
2747 | +} |
2748 | + |
2749 | +void ApiClientImpl::requestToken(const QUrl &url) |
2750 | +{ |
2751 | + QNetworkRequest request; |
2752 | + request.setUrl(url); |
2753 | + request.setOriginatingObject(this); |
2754 | + request.setAttribute(QNetworkRequest::User, "token-request"); |
2755 | + initializeReply(m_nam->head(request)); |
2756 | +} |
2757 | + |
2758 | +void ApiClientImpl::initializeReply(QNetworkReply *reply) |
2759 | +{ |
2760 | + connect(this, SIGNAL(abortNetworking()), reply, SLOT(abort())); |
2761 | +} |
2762 | + |
2763 | +void ApiClientImpl::requestSslFailed(QNetworkReply *reply, |
2764 | + const QList<QSslError> &errors) |
2765 | +{ |
2766 | + QString errorString = "SSL error: "; |
2767 | + foreach (const QSslError &err, errors) { |
2768 | + errorString += err.errorString(); |
2769 | + } |
2770 | + qCritical() << Q_FUNC_INFO << errorString; |
2771 | + Q_EMIT serverError(); |
2772 | + reply->deleteLater(); |
2773 | +} |
2774 | + |
2775 | +void ApiClientImpl::requestFinished(QNetworkReply *reply) |
2776 | +{ |
2777 | + if (reply->request().originatingObject() != this) { |
2778 | + return; // We did not create this request. |
2779 | + } |
2780 | + |
2781 | + if (!validReply(reply)) { |
2782 | + // Error signals are already sent. |
2783 | + reply->deleteLater(); |
2784 | + return; |
2785 | + } |
2786 | + |
2787 | + switch (reply->error()) { |
2788 | + case QNetworkReply::NoError: |
2789 | + // Note that requestSucceeded will delete the reply. |
2790 | + requestSucceeded(reply); |
2791 | + return; |
2792 | + case QNetworkReply::TemporaryNetworkFailureError: |
2793 | + case QNetworkReply::UnknownNetworkError: |
2794 | + case QNetworkReply::UnknownProxyError: |
2795 | + case QNetworkReply::UnknownServerError: |
2796 | + Q_EMIT networkError(); |
2797 | + break; |
2798 | + default: |
2799 | + Q_EMIT serverError(); |
2800 | + } |
2801 | + |
2802 | + reply->deleteLater(); |
2803 | +} |
2804 | + |
2805 | +void ApiClientImpl::requestSucceeded(QNetworkReply *reply) |
2806 | +{ |
2807 | + QString rtp = reply->request().attribute(QNetworkRequest::User).toString(); |
2808 | + if (rtp == "token-request") { |
2809 | + if (reply->hasRawHeader(X_CLICK_TOKEN)) { |
2810 | + QString header(reply->rawHeader(X_CLICK_TOKEN)); |
2811 | + Q_EMIT tokenRequestSucceeded(header); |
2812 | + } else { |
2813 | + Q_EMIT tokenRequestSucceeded(""); |
2814 | + } |
2815 | + } else if (rtp == "metadata-request") { |
2816 | + handleMetadataReply(reply); |
2817 | + } else { |
2818 | + // We are not to handle this reply, so do an early return. |
2819 | + return; |
2820 | + } |
2821 | + |
2822 | + reply->deleteLater(); |
2823 | +} |
2824 | + |
2825 | +void ApiClientImpl::handleMetadataReply(QNetworkReply *reply) |
2826 | +{ |
2827 | + QScopedPointer<QJsonParseError> jsonError(new QJsonParseError); |
2828 | + auto document = QJsonDocument::fromJson(reply->readAll(), |
2829 | + jsonError.data()); |
2830 | + |
2831 | + if (document.isArray()) { |
2832 | + Q_EMIT metadataRequestSucceeded(document.array()); |
2833 | + } else { |
2834 | + qCritical() << Q_FUNC_INFO << "Got invalid click metadata."; |
2835 | + Q_EMIT serverError(); |
2836 | + } |
2837 | + |
2838 | + if (jsonError->error != QJsonParseError::NoError) { |
2839 | + qCritical() << Q_FUNC_INFO << "Could not parse click metadata:" |
2840 | + << jsonError->errorString(); |
2841 | + Q_EMIT serverError(); |
2842 | + } |
2843 | +} |
2844 | + |
2845 | +bool ApiClientImpl::validReply(const QNetworkReply *reply) |
2846 | +{ |
2847 | + auto statusAttr = reply->attribute( |
2848 | + QNetworkRequest::HttpStatusCodeAttribute); |
2849 | + if (!statusAttr.isValid()) { |
2850 | + Q_EMIT networkError(); |
2851 | + qCritical() << Q_FUNC_INFO << "Could not parse status code."; |
2852 | + return false; |
2853 | + } |
2854 | + |
2855 | + int httpStatus = statusAttr.toInt(); |
2856 | + |
2857 | + if (httpStatus == 401 || httpStatus == 403) { |
2858 | + qCritical() << Q_FUNC_INFO |
2859 | + << QString("Server responded with %1.").arg(httpStatus); |
2860 | + Q_EMIT credentialError(); |
2861 | + return false; |
2862 | + } |
2863 | + |
2864 | + if (httpStatus == 404) { |
2865 | + qCritical() << Q_FUNC_INFO << "Server responded with 404."; |
2866 | + Q_EMIT serverError(); |
2867 | + return false; |
2868 | + } |
2869 | + |
2870 | + return true; |
2871 | +} |
2872 | + |
2873 | +void ApiClientImpl::cancel() |
2874 | +{ |
2875 | + // Tell each reply to abort. See initializeReply(). |
2876 | + Q_EMIT abortNetworking(); |
2877 | +} |
2878 | +} // Click |
2879 | +} // UpdatePlugin |
2880 | |
2881 | === added file 'plugins/system-update/click/apiclient_impl.h' |
2882 | --- plugins/system-update/click/apiclient_impl.h 1970-01-01 00:00:00 +0000 |
2883 | +++ plugins/system-update/click/apiclient_impl.h 2016-08-16 11:46:43 +0000 |
2884 | @@ -0,0 +1,56 @@ |
2885 | +/* |
2886 | + * This file is part of system-settings |
2887 | + * |
2888 | + * Copyright (C) 2016 Canonical Ltd. |
2889 | + * |
2890 | + * This program is free software: you can redistribute it and/or modify it |
2891 | + * under the terms of the GNU General Public License version 3, as published |
2892 | + * by the Free Software Foundation. |
2893 | + * |
2894 | + * This program is distributed in the hope that it will be useful, but |
2895 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
2896 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2897 | + * PURPOSE. See the GNU General Public License for more details. |
2898 | + * |
2899 | + * You should have received a copy of the GNU General Public License along |
2900 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
2901 | + */ |
2902 | + |
2903 | +#ifndef CLICK_APICLIENT_IMPL_H |
2904 | +#define CLICK_APICLIENT_IMPL_H |
2905 | + |
2906 | +#include "click/apiclient.h" |
2907 | +#include "network/accessmanager.h" |
2908 | + |
2909 | +namespace UpdatePlugin |
2910 | +{ |
2911 | +namespace Click |
2912 | +{ |
2913 | +class ApiClientImpl : public ApiClient |
2914 | +{ |
2915 | + Q_OBJECT |
2916 | +public: |
2917 | + explicit ApiClientImpl(UpdatePlugin::Network::Manager *nam, |
2918 | + QObject *parent = nullptr); |
2919 | + virtual ~ApiClientImpl(); |
2920 | +public slots: |
2921 | + virtual void cancel() override; |
2922 | + virtual void requestMetadata(const QUrl &url, |
2923 | + const QList<QString> &packages) override; |
2924 | + virtual void requestToken(const QUrl &url) override; |
2925 | +protected slots: |
2926 | + void requestSucceeded(QNetworkReply *reply); |
2927 | + void requestFinished(QNetworkReply *reply); |
2928 | + void requestSslFailed(QNetworkReply *reply, |
2929 | + const QList<QSslError> &errors); |
2930 | +private: |
2931 | + void initializeReply(QNetworkReply *reply); |
2932 | + bool validReply(const QNetworkReply *reply); |
2933 | + void handleMetadataReply(QNetworkReply *reply); |
2934 | + |
2935 | + Network::Manager *m_nam; |
2936 | +}; |
2937 | +} // Click |
2938 | +} // UpdatePlugin |
2939 | + |
2940 | +#endif // CLICK_APICLIENT_IMPL_H |
2941 | |
2942 | === added file 'plugins/system-update/click/manager.h' |
2943 | --- plugins/system-update/click/manager.h 1970-01-01 00:00:00 +0000 |
2944 | +++ plugins/system-update/click/manager.h 2016-08-16 11:46:43 +0000 |
2945 | @@ -0,0 +1,67 @@ |
2946 | +/* |
2947 | + * This file is part of system-settings |
2948 | + * |
2949 | + * Copyright (C) 2016 Canonical Ltd. |
2950 | + * |
2951 | + * This program is free software: you can redistribute it and/or modify it |
2952 | + * under the terms of the GNU General Public License version 3, as published |
2953 | + * by the Free Software Foundation. |
2954 | + * |
2955 | + * This program is distributed in the hope that it will be useful, but |
2956 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
2957 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2958 | + * PURPOSE. See the GNU General Public License for more details. |
2959 | + * |
2960 | + * You should have received a copy of the GNU General Public License along |
2961 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
2962 | + */ |
2963 | + |
2964 | +#ifndef CLICK_MANAGER_H |
2965 | +#define CLICK_MANAGER_H |
2966 | + |
2967 | +#include <QObject> |
2968 | +#include <QString> |
2969 | +#include <QDebug> |
2970 | + |
2971 | +namespace UpdatePlugin |
2972 | +{ |
2973 | +namespace Click |
2974 | +{ |
2975 | +/* Interface for a Click package manager. Note that this interface does not |
2976 | + * handle actual downloads and installations. See DownloadHandler, which is |
2977 | + * the component that communicates with Ubuntu Download Manager. |
2978 | + */ |
2979 | +class Manager : public QObject |
2980 | +{ |
2981 | + Q_OBJECT |
2982 | +public: |
2983 | + explicit Manager(QObject *parent = nullptr) : QObject(parent) {}; |
2984 | + virtual ~Manager() {}; |
2985 | + virtual void check() = 0; |
2986 | + virtual void cancel() = 0; |
2987 | + |
2988 | + /* Launch app. |
2989 | + * |
2990 | + * Tries to launch an app, but will only succeed if a APP_ID can be created |
2991 | + */ |
2992 | + virtual bool launch(const QString &identifier) = 0; |
2993 | + |
2994 | + /* Retry app. |
2995 | + * |
2996 | + * Currently, this merely updates the signedDownloadUrl on an Update. |
2997 | + */ |
2998 | + virtual void retry(const QString &identifier, const uint &revision) = 0; |
2999 | + virtual bool authenticated() const = 0; |
3000 | + virtual bool checkingForUpdates() const = 0; |
3001 | +Q_SIGNALS: |
3002 | + void authenticatedChanged(); |
3003 | + void checkingForUpdatesChanged(); |
3004 | + void checkCompleted(); |
3005 | + void networkError(); |
3006 | + void serverError(); |
3007 | + void credentialError(); |
3008 | +}; |
3009 | +} // Click |
3010 | +} // UpdatePlugin |
3011 | + |
3012 | +#endif // CLICK_MANAGER_H |
3013 | |
3014 | === added file 'plugins/system-update/click/manager_impl.cpp' |
3015 | --- plugins/system-update/click/manager_impl.cpp 1970-01-01 00:00:00 +0000 |
3016 | +++ plugins/system-update/click/manager_impl.cpp 2016-08-16 11:46:43 +0000 |
3017 | @@ -0,0 +1,562 @@ |
3018 | +/* |
3019 | + * This file is part of system-settings |
3020 | + * |
3021 | + * Copyright (C) 2016 Canonical Ltd. |
3022 | + * |
3023 | + * This program is free software: you can redistribute it and/or modify it |
3024 | + * under the terms of the GNU General Public License version 3, as published |
3025 | + * by the Free Software Foundation. |
3026 | + * |
3027 | + * This program is distributed in the hope that it will be useful, but |
3028 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
3029 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3030 | + * PURPOSE. See the GNU General Public License for more details. |
3031 | + * |
3032 | + * You should have received a copy of the GNU General Public License along |
3033 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
3034 | + */ |
3035 | + |
3036 | +#include "helpers.h" |
3037 | +#include "click/apiclient_impl.h" |
3038 | +#include "click/manager_impl.h" |
3039 | +#include "click/manifest_impl.h" |
3040 | +#include "click/sessiontoken_impl.h" |
3041 | +#include "click/sso_impl.h" |
3042 | +#include "click/tokendownloader_factory_impl.h" |
3043 | +#include "network/accessmanager_impl.h" |
3044 | +#include "../../src/i18n.h" |
3045 | + |
3046 | +#include <ubuntu-app-launch.h> |
3047 | + |
3048 | +#include <QDateTime> |
3049 | +#include <QFinalState> |
3050 | +#include <QState> |
3051 | +#include <QJsonDocument> |
3052 | +#include <QJsonObject> |
3053 | +#include <QList> |
3054 | + |
3055 | +namespace UpdatePlugin |
3056 | +{ |
3057 | +namespace Click |
3058 | +{ |
3059 | +ManagerImpl::ManagerImpl(UpdateModel *model, Network::Manager *nam, |
3060 | + QObject *parent) |
3061 | + : ManagerImpl(model, |
3062 | + nam, |
3063 | + new ApiClientImpl(nam), |
3064 | + new ManifestImpl, |
3065 | + new SSOImpl, |
3066 | + new TokenDownloaderFactoryImpl, |
3067 | + new SessionTokenImpl, |
3068 | + parent) |
3069 | +{ |
3070 | + m_client->setParent(this); |
3071 | + m_manifest->setParent(this); |
3072 | + m_sso->setParent(this); |
3073 | +} |
3074 | + |
3075 | +ManagerImpl::ManagerImpl(UpdateModel *model, |
3076 | + Network::Manager *nam, |
3077 | + ApiClient *client, |
3078 | + Manifest *manifest, |
3079 | + SSO *sso, |
3080 | + TokenDownloaderFactory *tokenDownloadFactory, |
3081 | + SessionToken *token, |
3082 | + QObject *parent) |
3083 | + : Manager(parent) |
3084 | + , m_model(model) |
3085 | + , m_nam(nam) |
3086 | + , m_client(client) |
3087 | + , m_manifest(manifest) |
3088 | + , m_sso(sso) |
3089 | + , m_tokenDownloadFactory(tokenDownloadFactory) |
3090 | + , m_sessionToken(token) |
3091 | +{ |
3092 | + /* Request a manifest. |
3093 | + * |
3094 | + * This will produce a manifest with which we will synchronize our |
3095 | + * database. |
3096 | + */ |
3097 | + m_manifest->request(); |
3098 | + |
3099 | + connect(this, SIGNAL(stateChanged()), this, SLOT(handleStateChange())); |
3100 | + connect(this, SIGNAL(stateChanged()), this, SIGNAL(checkingForUpdatesChanged())); |
3101 | + connect(m_client, SIGNAL(metadataRequestSucceeded(const QJsonArray&)), |
3102 | + this, SLOT(parseMetadata(const QJsonArray&))); |
3103 | + connect(m_client, SIGNAL(networkError()), this, SIGNAL(networkError())); |
3104 | + connect(m_client, SIGNAL(serverError()), this, SIGNAL(serverError())); |
3105 | + connect(m_client, SIGNAL(credentialError()), |
3106 | + this, SIGNAL(credentialError())); |
3107 | + connect(m_client, &ApiClient::serverError, this, [this]() { |
3108 | + setState(State::Failed); |
3109 | + }); |
3110 | + connect(m_client, &ApiClient::networkError, this, [this]() { |
3111 | + setState(State::Failed); |
3112 | + }); |
3113 | + connect(m_client, SIGNAL(credentialError()), |
3114 | + this, SLOT(handleCredentialsFailed())); |
3115 | + connect(this, SIGNAL(checkCanceled()), m_client, SLOT(cancel())); |
3116 | + |
3117 | + connect(m_manifest, SIGNAL(requestSucceeded(const QJsonArray&)), |
3118 | + this, SLOT(handleManifest(const QJsonArray&))); |
3119 | + connect(m_manifest, &Manifest::requestFailed, this, [this]() { |
3120 | + setState(State::Complete); |
3121 | + }); |
3122 | + connect(m_sso, SIGNAL(credentialsFound(SessionToken*)), |
3123 | + this, SLOT(handleCredentials(SessionToken*))); |
3124 | + connect(m_sso, SIGNAL(credentialsNotFound()), |
3125 | + this, SLOT(handleCredentialsAbsence())); |
3126 | + connect(m_sso, SIGNAL(credentialsDeleted()), |
3127 | + this, SLOT(handleCredentialsAbsence())); |
3128 | + |
3129 | + /* Describes a state machine for checking. The rationale for these |
3130 | + transitions are that |
3131 | + * we can cancel a check at any time, but this may not necessarily |
3132 | + propagate to every subsystem. So if a subsystem responds with data |
3133 | + after a check has been canceled (or completed), it does not start or |
3134 | + stop a check erroneously. |
3135 | + * Some parts of the check (e.g. requesting the manifest) should be |
3136 | + allowed to happen outside a check. |
3137 | + * While we're waiting for e.g. tokens to download, it's neater to have |
3138 | + this state as an explicit one, instead of implicit state using |
3139 | + conditional branching. |
3140 | + */ |
3141 | + m_transitions[State::Idle] << State::Manifest |
3142 | + << State::Failed; |
3143 | + |
3144 | + m_transitions[State::Manifest] << State::Metadata |
3145 | + << State::Complete |
3146 | + << State::Failed |
3147 | + << State::Canceled; |
3148 | + |
3149 | + m_transitions[State::Metadata] << State::Tokens |
3150 | + << State::TokenComplete |
3151 | + << State::Complete |
3152 | + << State::Failed |
3153 | + << State::Canceled; |
3154 | + |
3155 | + m_transitions[State::Tokens] << State::TokenComplete |
3156 | + << State::Complete |
3157 | + << State::Failed |
3158 | + << State::Canceled; |
3159 | + |
3160 | + m_transitions[State::TokenComplete] << State::Tokens |
3161 | + << State::Complete |
3162 | + << State::Failed |
3163 | + << State::Canceled; |
3164 | + |
3165 | + m_transitions[State::Complete] << State::Idle; |
3166 | + m_transitions[State::Canceled] << State::Idle; |
3167 | + m_transitions[State::Failed] << State::Idle; |
3168 | +} |
3169 | + |
3170 | +ManagerImpl::~ManagerImpl() |
3171 | +{ |
3172 | + setState(State::Canceled); |
3173 | +} |
3174 | + |
3175 | +void ManagerImpl::setState(const State &state) |
3176 | +{ |
3177 | + if (m_state != state && m_transitions[m_state].contains(state)) { |
3178 | + m_state = state; |
3179 | + Q_EMIT stateChanged(); |
3180 | + } |
3181 | +} |
3182 | + |
3183 | +ManagerImpl::State ManagerImpl::state() const |
3184 | +{ |
3185 | + return m_state; |
3186 | +} |
3187 | + |
3188 | +void ManagerImpl::handleStateChange() |
3189 | +{ |
3190 | + switch (m_state) { |
3191 | + case State::Idle: |
3192 | + m_candidates.clear(); |
3193 | + break; |
3194 | + case State::Manifest: |
3195 | + m_manifest->request(); |
3196 | + break; |
3197 | + case State::Metadata: |
3198 | + requestMetadata(); |
3199 | + break; |
3200 | + case State::Tokens: |
3201 | + break; |
3202 | + case State::TokenComplete: |
3203 | + completionCheck(); |
3204 | + break; |
3205 | + case State::Failed: |
3206 | + case State::Canceled: |
3207 | + Q_EMIT checkCanceled(); |
3208 | + case State::Complete: |
3209 | + Q_EMIT checkCompleted(); |
3210 | + setState(State::Idle); |
3211 | + break; |
3212 | + } |
3213 | +} |
3214 | + |
3215 | +void ManagerImpl::setup(const TokenDownloader *downloader) |
3216 | +{ |
3217 | + connect(downloader, SIGNAL(downloadSucceeded(QSharedPointer<Update>)), |
3218 | + this, SLOT(handleTokenDownload(QSharedPointer<Update>))); |
3219 | + connect(downloader, SIGNAL(downloadFailed(QSharedPointer<Update>)), |
3220 | + this, SLOT(handleTokenDownloadFailure(QSharedPointer<Update>))); |
3221 | + connect(downloader, SIGNAL(credentialError()), |
3222 | + this, SLOT(handleCredentialsFailed())); |
3223 | + connect(this, SIGNAL(checkCanceled()), downloader, SLOT(cancel())); |
3224 | +} |
3225 | + |
3226 | +void ManagerImpl::check() |
3227 | +{ |
3228 | + if (checkingForUpdates()) { |
3229 | + qWarning() << Q_FUNC_INFO << "Check was already in progress."; |
3230 | + return; |
3231 | + } |
3232 | + |
3233 | + if (!m_sessionToken->isValid() && !Helpers::isIgnoringCredentials()) { |
3234 | + qWarning() << Q_FUNC_INFO << "Can't check: invalid session token."; |
3235 | + m_sso->requestCredentials(); |
3236 | + return; |
3237 | + } |
3238 | + |
3239 | + setState(State::Manifest); |
3240 | +} |
3241 | + |
3242 | +void ManagerImpl::retry(const QString &identifier, const uint &revision) |
3243 | +{ |
3244 | + /* We will not do the token dance here, but rather just create a new signed |
3245 | + downloadUrl that is valid for 5 minutes. QML will create the actual |
3246 | + UDM download. */ |
3247 | + auto update = m_model->get(identifier, revision); |
3248 | + if (update) { |
3249 | + if (m_sessionToken->isValid() && !Helpers::isIgnoringCredentials()) { |
3250 | + QString url = m_sessionToken->signUrl( |
3251 | + update->downloadUrl(), QStringLiteral("GET"), true |
3252 | + ); |
3253 | + update->setSignedDownloadUrl( |
3254 | + QString("%1?%2").arg(update->downloadUrl(), url) |
3255 | + ); |
3256 | + update->setError(""); |
3257 | + update->setState(Update::State::StateAvailable); |
3258 | + } else { |
3259 | + qWarning() << Q_FUNC_INFO << "Can't retry: invalid session token."; |
3260 | + update->setError(SystemSettings::_("Installation failed.")); |
3261 | + update->setState(Update::State::StateFailed); |
3262 | + } |
3263 | + update->setProgress(0); |
3264 | + update->setToken(""); |
3265 | + update->setDownloadId(""); |
3266 | + m_model->update(update); |
3267 | + } |
3268 | +} |
3269 | + |
3270 | +void ManagerImpl::cancel() |
3271 | +{ |
3272 | + setState(State::Canceled); |
3273 | +} |
3274 | + |
3275 | +bool ManagerImpl::launch(const QString &identifier) |
3276 | +{ |
3277 | + bool success = false; |
3278 | + gchar *appId = ubuntu_app_launch_triplet_to_app_id( |
3279 | + identifier.toLatin1().data(), nullptr, nullptr |
3280 | + ); |
3281 | + if (appId) { |
3282 | + success = ubuntu_app_launch_start_application(appId, nullptr); |
3283 | + } |
3284 | + g_free(appId); |
3285 | + return success; |
3286 | +} |
3287 | + |
3288 | +void ManagerImpl::handleManifest(const QJsonArray &manifest) |
3289 | +{ |
3290 | + auto updates = parseManifest(manifest); |
3291 | + synchronize(updates); |
3292 | + |
3293 | + Q_FOREACH(auto update, updates) { |
3294 | + m_candidates[update->identifier()] = update; |
3295 | + } |
3296 | + if (updates.size() == 0) { |
3297 | + setState(State::Complete); |
3298 | + return; |
3299 | + } |
3300 | + |
3301 | + setState(State::Metadata); |
3302 | +} |
3303 | + |
3304 | +void ManagerImpl::synchronize( |
3305 | + const QList<QSharedPointer<Update> > &manifestUpdates |
3306 | +) |
3307 | +{ |
3308 | + /* Runs through all DB updates and if the exist in the manifest, each |
3309 | + update is “synchronized” with data from the manifest, i.e. marked as |
3310 | + installed if installed. If not found, this means the app might be |
3311 | + uninstalled, and we remove the DB entry. */ |
3312 | + auto dbUpdates = m_model->db()->updates(); |
3313 | + Q_FOREACH(auto dbUpdate, dbUpdates) { |
3314 | + if (dbUpdate->kind() != Update::Kind::KindClick) { |
3315 | + continue; |
3316 | + } |
3317 | + bool found = false; |
3318 | + Q_FOREACH(auto manifestUpdate, manifestUpdates) { |
3319 | + /* The local version of a click in the manifest, matched exactly a |
3320 | + a remote version in one of our db updates. */ |
3321 | + if (manifestUpdate->localVersion() == dbUpdate->remoteVersion()) { |
3322 | + m_model->setInstalled(dbUpdate->identifier(), |
3323 | + dbUpdate->revision()); |
3324 | + found = true; |
3325 | + } else if (manifestUpdate->identifier() == dbUpdate->identifier()) { |
3326 | + // Fast forward the local version. |
3327 | + dbUpdate->setLocalVersion(manifestUpdate->localVersion()); |
3328 | + |
3329 | + // Is update in need of update, but at the same time installed? |
3330 | + if (dbUpdate->isUpdateRequired() && dbUpdate->installed()) { |
3331 | + dbUpdate->setInstalled(false); |
3332 | + dbUpdate->setState(Update::State::StateAvailable); |
3333 | + dbUpdate->setDownloadId(""); |
3334 | + dbUpdate->setError(""); |
3335 | + m_model->update(dbUpdate); |
3336 | + } |
3337 | + found = true; |
3338 | + } |
3339 | + } |
3340 | + if (!found) { |
3341 | + m_model->remove(dbUpdate); |
3342 | + } |
3343 | + } |
3344 | +} |
3345 | + |
3346 | +QList<QSharedPointer<Update> > ManagerImpl::parseManifest(const QJsonArray &manifest) |
3347 | +{ |
3348 | + QList<QSharedPointer<Update> > updates; |
3349 | + for (int i = 0; i < manifest.size(); i++) { |
3350 | + const auto object = manifest.at(i).toObject(); |
3351 | + auto name = object.value("name").toString(); |
3352 | + |
3353 | + // No name? Bail! |
3354 | + if (Q_UNLIKELY(name.isEmpty())) { |
3355 | + continue; |
3356 | + } |
3357 | + |
3358 | + auto update = QSharedPointer<Update>(new Update); |
3359 | + update->setIdentifier(name); |
3360 | + update->setTitle(object.value("title").toString()); |
3361 | + update->setLocalVersion(object.value("version").toString()); |
3362 | + update->setKind(Update::Kind::KindClick); |
3363 | + |
3364 | + /* We'll also need the package name, which will be the first key inside |
3365 | + the “hooks” key that contains a “desktop”. */ |
3366 | + if (object.contains("hooks") && object.value("hooks").isObject()) { |
3367 | + auto hooks = object.value("hooks").toObject(); |
3368 | + Q_FOREACH(const auto &key, hooks.keys()) { |
3369 | + if (hooks[key].isObject() && |
3370 | + hooks[key].toObject().contains("desktop")) { |
3371 | + update->setPackageName(key); |
3372 | + } |
3373 | + } |
3374 | + } |
3375 | + updates << update; |
3376 | + } |
3377 | + return updates; |
3378 | +} |
3379 | + |
3380 | +void ManagerImpl::completionCheck() |
3381 | +{ |
3382 | + /* Check if tokens are all fetched, or any update has since been marked as |
3383 | + installed. Return early if that's the case. */ |
3384 | + Q_FOREACH(const auto &identifier, m_candidates.keys()) { |
3385 | + if (m_candidates[identifier]->token().isEmpty() || |
3386 | + m_candidates[identifier]->installed()) { |
3387 | + setState(State::Tokens); |
3388 | + return; |
3389 | + } |
3390 | + } |
3391 | + |
3392 | + setState(State::Complete); |
3393 | +} |
3394 | + |
3395 | +void ManagerImpl::handleTokenDownload(QSharedPointer<Update> update) |
3396 | +{ |
3397 | + auto dl = qobject_cast<TokenDownloader*>(QObject::sender()); |
3398 | + dl->disconnect(); |
3399 | + |
3400 | + // Token reported as downloaded, but empty so discard it as a candidate. |
3401 | + if (update->token().isEmpty()) { |
3402 | + m_candidates.remove(update->identifier()); |
3403 | + } |
3404 | + |
3405 | + /* Assume the original update was changed during the download of token and |
3406 | + fetch a new one from the database. */ |
3407 | + auto freshUpdate = m_model->fetch(update); |
3408 | + if (freshUpdate) { |
3409 | + freshUpdate->setToken(update->token()); |
3410 | + m_model->add(freshUpdate); |
3411 | + } else { |
3412 | + m_model->add(update); |
3413 | + } |
3414 | + |
3415 | + setState(State::TokenComplete); |
3416 | + dl->deleteLater(); |
3417 | +} |
3418 | + |
3419 | +void ManagerImpl::handleTokenDownloadFailure(QSharedPointer<Update> update) |
3420 | +{ |
3421 | + auto dl = qobject_cast<TokenDownloader*>(QObject::sender()); |
3422 | + |
3423 | + // Assume the original update was changed during the download of token. |
3424 | + auto freshUpdate = m_model->get(update); |
3425 | + if (freshUpdate) { |
3426 | + freshUpdate->setToken(""); |
3427 | + m_model->add(freshUpdate); |
3428 | + } else { |
3429 | + update->setToken(""); |
3430 | + m_model->add(update); |
3431 | + } |
3432 | + |
3433 | + // We're done with it. |
3434 | + m_candidates.remove(update->identifier()); |
3435 | + setState(State::TokenComplete); |
3436 | + |
3437 | + dl->deleteLater(); |
3438 | +} |
3439 | + |
3440 | +void ManagerImpl::handleCredentials(SessionToken *token) |
3441 | +{ |
3442 | + // We'll take ownership of this token. |
3443 | + m_sessionToken = std::unique_ptr<SessionToken>(token); |
3444 | + |
3445 | + if (!m_sessionToken->isValid() && !Helpers::isIgnoringCredentials()) { |
3446 | + qWarning() << Q_FUNC_INFO << "Got invalid session token."; |
3447 | + setAuthenticated(false); |
3448 | + return; |
3449 | + } |
3450 | + |
3451 | + setAuthenticated(true); |
3452 | + |
3453 | + cancel(); |
3454 | + check(); |
3455 | +} |
3456 | + |
3457 | +void ManagerImpl::handleCredentialsAbsence() |
3458 | +{ |
3459 | + m_sessionToken = std::unique_ptr<SessionToken>(new SessionTokenImpl()); |
3460 | + setAuthenticated(false); |
3461 | + cancel(); |
3462 | +} |
3463 | + |
3464 | +void ManagerImpl::handleCredentialsFailed() |
3465 | +{ |
3466 | + m_sso->invalidateCredentials(); |
3467 | + m_sessionToken = std::unique_ptr<SessionToken>(new SessionTokenImpl()); |
3468 | + |
3469 | + // We've invalidated the token, and the user is now not authenticated. |
3470 | + setAuthenticated(false); |
3471 | + cancel(); |
3472 | +} |
3473 | + |
3474 | +void ManagerImpl::requestMetadata() |
3475 | +{ |
3476 | + QString urlApps = Helpers::clickMetadataUrl(); |
3477 | + QString authHeader; |
3478 | + if (!Helpers::isIgnoringCredentials()) { |
3479 | + authHeader = m_sessionToken->signUrl( |
3480 | + urlApps, QStringLiteral("POST"), true |
3481 | + ); |
3482 | + } |
3483 | + QUrl url(urlApps); |
3484 | + url.setQuery(authHeader); |
3485 | + m_client->requestMetadata(url, m_candidates.keys()); |
3486 | +} |
3487 | + |
3488 | +void ManagerImpl::parseMetadata(const QJsonArray &array) |
3489 | +{ |
3490 | + auto now = QDateTime::currentDateTimeUtc(); |
3491 | + for (int i = 0; i < array.size(); i++) { |
3492 | + auto object = array.at(i).toObject(); |
3493 | + auto identifier = object["name"].toString(); |
3494 | + auto revision = object["revision"].toInt(); |
3495 | + // Check if we already have it's metadata. |
3496 | + auto dbUpdate = m_model->get(identifier, revision); |
3497 | + if (dbUpdate) { |
3498 | + /* If this update is less than 24 hours old (to us), and it has a |
3499 | + token, we ignore it. */ |
3500 | + if (dbUpdate->createdAt().secsTo(now) <= 86400 |
3501 | + && !dbUpdate->token().isEmpty()) { |
3502 | + m_candidates.remove(identifier); |
3503 | + setState(State::TokenComplete); |
3504 | + continue; |
3505 | + } |
3506 | + } |
3507 | + |
3508 | + auto version = object["version"].toString(); |
3509 | + auto icon_url = object["icon_url"].toString(); |
3510 | + auto url = object["download_url"].toString(); |
3511 | + auto download_sha512 = object["download_sha512"].toString(); |
3512 | + auto changelog = object["changelog"].toString(); |
3513 | + auto size = object["binary_filesize"].toInt(); |
3514 | + auto title = object["title"].toString(); |
3515 | + |
3516 | + if (m_candidates.contains(identifier)) { |
3517 | + auto update = m_candidates.value(identifier); |
3518 | + update->setRemoteVersion(version); |
3519 | + |
3520 | + if (update->isUpdateRequired()) { |
3521 | + update->setIconUrl(icon_url); |
3522 | + update->setDownloadUrl(url); |
3523 | + update->setBinaryFilesize(size); |
3524 | + update->setDownloadHash(download_sha512); |
3525 | + update->setChangelog(changelog); |
3526 | + update->setTitle(title); |
3527 | + update->setRevision(revision); |
3528 | + update->setState(Update::State::StateAvailable); |
3529 | + |
3530 | + QStringList command; |
3531 | + command << Helpers::whichPkcon() |
3532 | + << "-p" << "install-local" << "$file"; |
3533 | + update->setCommand(command); |
3534 | + |
3535 | + // Download a token. |
3536 | + QString signedHeaderUrl(m_sessionToken->signUrl( |
3537 | + update->downloadUrl(), QStringLiteral("HEAD"), true |
3538 | + )); |
3539 | + auto dl = m_tokenDownloadFactory->create(m_nam, update); |
3540 | + setup(dl); |
3541 | + dl->download(signedHeaderUrl); |
3542 | + } else { |
3543 | + // Update not required, let's remove it. |
3544 | + m_candidates.remove(update->identifier()); |
3545 | + setState(State::TokenComplete); |
3546 | + } |
3547 | + } |
3548 | + } |
3549 | + |
3550 | + /* Remove clicks that did not have the necessary metadata. They could be |
3551 | + locally installed, or removed from upstream. */ |
3552 | + foreach (const auto &identifier, m_candidates.keys()) { |
3553 | + if (m_candidates.value(identifier)->remoteVersion().isEmpty()) { |
3554 | + m_candidates.remove(identifier); |
3555 | + setState(State::TokenComplete); |
3556 | + } |
3557 | + } |
3558 | + setState(State::Tokens); |
3559 | +} |
3560 | + |
3561 | +bool ManagerImpl::authenticated() const |
3562 | +{ |
3563 | + return m_authenticated || Helpers::isIgnoringCredentials(); |
3564 | +} |
3565 | + |
3566 | +bool ManagerImpl::checkingForUpdates() const |
3567 | +{ |
3568 | + return m_state != State::Idle; |
3569 | +} |
3570 | + |
3571 | +void ManagerImpl::setAuthenticated(const bool authenticated) |
3572 | +{ |
3573 | + if (authenticated != m_authenticated) { |
3574 | + m_authenticated = authenticated; |
3575 | + Q_EMIT authenticatedChanged(); |
3576 | + } |
3577 | +} |
3578 | +} // Click |
3579 | +} // UpdatePlugin |
3580 | |
3581 | === added file 'plugins/system-update/click/manager_impl.h' |
3582 | --- plugins/system-update/click/manager_impl.h 1970-01-01 00:00:00 +0000 |
3583 | +++ plugins/system-update/click/manager_impl.h 2016-08-16 11:46:43 +0000 |
3584 | @@ -0,0 +1,122 @@ |
3585 | +/* |
3586 | + * This file is part of system-settings |
3587 | + * |
3588 | + * Copyright (C) 2016 Canonical Ltd. |
3589 | + * |
3590 | + * This program is free software: you can redistribute it and/or modify it |
3591 | + * under the terms of the GNU General Public License version 3, as published |
3592 | + * by the Free Software Foundation. |
3593 | + * |
3594 | + * This program is distributed in the hope that it will be useful, but |
3595 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
3596 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3597 | + * PURPOSE. See the GNU General Public License for more details. |
3598 | + * |
3599 | + * You should have received a copy of the GNU General Public License along |
3600 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
3601 | + */ |
3602 | + |
3603 | +#ifndef CLICK_MANAGER_IMPL_H |
3604 | +#define CLICK_MANAGER_IMPL_H |
3605 | + |
3606 | +#include "updatemodel.h" |
3607 | + |
3608 | +#include "click/apiclient.h" |
3609 | +#include "click/manager.h" |
3610 | +#include "click/manifest.h" |
3611 | +#include "click/sso.h" |
3612 | +#include "click/sessiontoken.h" |
3613 | +#include "click/tokendownloader.h" |
3614 | +#include "click/tokendownloader_factory.h" |
3615 | + |
3616 | +#include "network/accessmanager.h" |
3617 | + |
3618 | +#include <memory> |
3619 | +#include <QMap> |
3620 | +#include <QJsonArray> |
3621 | +#include <QSharedPointer> |
3622 | +#include <QScopedPointer> |
3623 | + |
3624 | +namespace UpdatePlugin |
3625 | +{ |
3626 | +namespace Click |
3627 | +{ |
3628 | +class ManagerImpl : public Manager |
3629 | +{ |
3630 | + Q_OBJECT |
3631 | +public: |
3632 | + explicit ManagerImpl(UpdateModel *model, Network::Manager *nam, |
3633 | + QObject *parent = nullptr); |
3634 | + |
3635 | + // This constructor enables testing. |
3636 | + explicit ManagerImpl(UpdateModel *model, |
3637 | + Network::Manager *nam, |
3638 | + ApiClient *client, |
3639 | + Manifest *manifest, |
3640 | + SSO *sso, |
3641 | + TokenDownloaderFactory *tokenDownloadFactory, |
3642 | + SessionToken *token, |
3643 | + QObject *parent = nullptr); |
3644 | + ~ManagerImpl(); |
3645 | + |
3646 | + virtual void check() override; |
3647 | + virtual bool launch(const QString &identifier) override; |
3648 | + virtual void cancel() override; |
3649 | + virtual void retry(const QString &identifier, const uint &revision) override; |
3650 | + |
3651 | + virtual bool authenticated() const override; |
3652 | + virtual bool checkingForUpdates() const override; |
3653 | +private Q_SLOTS: |
3654 | + void parseMetadata(const QJsonArray &array); |
3655 | + void handleManifest(const QJsonArray &manifest); |
3656 | + void handleTokenDownload(QSharedPointer<Update> update); |
3657 | + void handleTokenDownloadFailure(QSharedPointer<Update> update); |
3658 | + void handleCredentials(SessionToken *token); |
3659 | + void handleCredentialsAbsence(); |
3660 | + void handleCredentialsFailed(); |
3661 | + void requestMetadata(); |
3662 | + void completionCheck(); |
3663 | + void handleStateChange(); |
3664 | +Q_SIGNALS: |
3665 | + void checkCanceled(); |
3666 | + void stateChanged(); |
3667 | +private: |
3668 | + enum class State { Idle, Manifest, Metadata, Tokens, |
3669 | + TokenComplete, Failed, Complete, Canceled }; |
3670 | + void setState(const State &state); |
3671 | + State state() const; |
3672 | + void setAuthenticated(const bool authenticated); |
3673 | + |
3674 | + /* Set up connections on a TokenDownloader. */ |
3675 | + void setup(const TokenDownloader *downloader); |
3676 | + |
3677 | + /* Synchronize db updates with a manifest. |
3678 | + * |
3679 | + * Any app in database not in the manifest, is removed. If an db update's |
3680 | + * remote version matches a manifest update's local version, we assume it to be |
3681 | + * installed. Any Update's local version is replaced by any new local version. |
3682 | + */ |
3683 | + void synchronize(const QList<QSharedPointer<Update> > &manifestUpdates); |
3684 | + |
3685 | + /* Parse a manifest. |
3686 | + * |
3687 | + * Return a list of Updates from a parsed manifest. |
3688 | + */ |
3689 | + QList<QSharedPointer<Update> > parseManifest(const QJsonArray &manifest); |
3690 | + |
3691 | + UpdateModel *m_model; |
3692 | + Network::Manager *m_nam; |
3693 | + ApiClient *m_client; |
3694 | + Manifest *m_manifest; |
3695 | + SSO *m_sso; |
3696 | + std::unique_ptr<TokenDownloaderFactory> m_tokenDownloadFactory; |
3697 | + QMap<QString, QSharedPointer<Update>> m_candidates; |
3698 | + std::unique_ptr<SessionToken> m_sessionToken; |
3699 | + bool m_authenticated = true; |
3700 | + State m_state = State::Idle; |
3701 | + QMap<State, QList<State> > m_transitions; |
3702 | +}; |
3703 | +} // Click |
3704 | +} // UpdatePlugin |
3705 | + |
3706 | +#endif // CLICK_MANAGER_IMPL_H |
3707 | |
3708 | === added file 'plugins/system-update/click/manifest.h' |
3709 | --- plugins/system-update/click/manifest.h 1970-01-01 00:00:00 +0000 |
3710 | +++ plugins/system-update/click/manifest.h 2016-08-16 11:46:43 +0000 |
3711 | @@ -0,0 +1,47 @@ |
3712 | +/* |
3713 | + * This file is part of system-settings |
3714 | + * |
3715 | + * Copyright (C) 2016 Canonical Ltd. |
3716 | + * |
3717 | + * This program is free software: you can redistribute it and/or modify it |
3718 | + * under the terms of the GNU General Public License version 3, as published |
3719 | + * by the Free Software Foundation. |
3720 | + * |
3721 | + * This program is distributed in the hope that it will be useful, but |
3722 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
3723 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3724 | + * PURPOSE. See the GNU General Public License for more details. |
3725 | + * |
3726 | + * You should have received a copy of the GNU General Public License along |
3727 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
3728 | + */ |
3729 | + |
3730 | +#ifndef CLICK_MANIFEST_H |
3731 | +#define CLICK_MANIFEST_H |
3732 | + |
3733 | +#include <QObject> |
3734 | +#include <QJsonArray> |
3735 | + |
3736 | +#include <QDebug> |
3737 | + |
3738 | +namespace UpdatePlugin |
3739 | +{ |
3740 | +namespace Click |
3741 | +{ |
3742 | +// Interface for a manifest producer. |
3743 | +class Manifest : public QObject |
3744 | +{ |
3745 | + Q_OBJECT |
3746 | +public: |
3747 | + explicit Manifest(QObject *parent = nullptr) : QObject(parent) {}; |
3748 | + virtual ~Manifest() {}; |
3749 | +public slots: |
3750 | + virtual void request() = 0; |
3751 | +Q_SIGNALS: |
3752 | + void requestSucceeded(const QJsonArray &manifest); |
3753 | + void requestFailed(); |
3754 | +}; |
3755 | +} // Click |
3756 | +} // UpdatePlugin |
3757 | + |
3758 | +#endif // CLICK_MANIFEST_H |
3759 | |
3760 | === added file 'plugins/system-update/click/manifest_impl.cpp' |
3761 | --- plugins/system-update/click/manifest_impl.cpp 1970-01-01 00:00:00 +0000 |
3762 | +++ plugins/system-update/click/manifest_impl.cpp 2016-08-16 11:46:43 +0000 |
3763 | @@ -0,0 +1,97 @@ |
3764 | +/* |
3765 | + * This file is part of system-settings |
3766 | + * |
3767 | + * Copyright (C) 2016 Canonical Ltd. |
3768 | + * |
3769 | + * This program is free software: you can redistribute it and/or modify it |
3770 | + * under the terms of the GNU General Public License version 3, as published |
3771 | + * by the Free Software Foundation. |
3772 | + * |
3773 | + * This program is distributed in the hope that it will be useful, but |
3774 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
3775 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3776 | + * PURPOSE. See the GNU General Public License for more details. |
3777 | + * |
3778 | + * You should have received a copy of the GNU General Public License along |
3779 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
3780 | + */ |
3781 | + |
3782 | +#include "click/manifest_impl.h" |
3783 | +#include "helpers.h" |
3784 | + |
3785 | +#include <QJsonDocument> |
3786 | +#include <QJsonObject> |
3787 | +#include <QJsonValue> |
3788 | + |
3789 | +namespace UpdatePlugin |
3790 | +{ |
3791 | +namespace Click |
3792 | +{ |
3793 | +ManifestImpl::ManifestImpl(QObject *parent) |
3794 | + : Manifest(parent) |
3795 | + , m_process() |
3796 | +{ |
3797 | + connect(&m_process, SIGNAL(finished(const int&)), |
3798 | + this, SLOT(handleProcessSuccess(const int&))); |
3799 | +} |
3800 | + |
3801 | +ManifestImpl::~ManifestImpl() |
3802 | +{ |
3803 | + if (m_process.state() != QProcess::NotRunning) { |
3804 | + m_process.kill(); |
3805 | + m_process.waitForFinished(1); |
3806 | + } |
3807 | +} |
3808 | + |
3809 | +void ManifestImpl::request() |
3810 | +{ |
3811 | + QStringList args("list"); |
3812 | + args << "--manifest"; |
3813 | + QString command = Helpers::whichClick(); |
3814 | + m_process.start(command, args); |
3815 | + if (!m_process.waitForStarted()) { |
3816 | + handleProcessError(m_process.error()); |
3817 | + } |
3818 | +} |
3819 | + |
3820 | +void ManifestImpl::handleProcessSuccess(const int &exitCode) |
3821 | +{ |
3822 | + Q_UNUSED(exitCode); |
3823 | + |
3824 | + QString output(m_process.readAllStandardOutput()); |
3825 | + auto document = QJsonDocument::fromJson(output.toUtf8()); |
3826 | + if (document.isArray()) { |
3827 | + Q_EMIT requestSucceeded(document.array()); |
3828 | + } else { |
3829 | + Q_EMIT requestFailed(); |
3830 | + } |
3831 | +} |
3832 | + |
3833 | +void ManifestImpl::handleProcessError(const QProcess::ProcessError &error) |
3834 | +{ |
3835 | + QString err; |
3836 | + switch (error) { |
3837 | + case QProcess::FailedToStart: |
3838 | + err = "Failed to start"; |
3839 | + break; |
3840 | + case QProcess::Crashed: |
3841 | + err = "Crashed"; |
3842 | + break; |
3843 | + case QProcess::Timedout: |
3844 | + err = "Timed out"; |
3845 | + break; |
3846 | + case QProcess::WriteError: |
3847 | + err = "Write error"; |
3848 | + break; |
3849 | + case QProcess::ReadError: |
3850 | + err = "Read error"; |
3851 | + break; |
3852 | + case QProcess::UnknownError: |
3853 | + err = "Unknown error"; |
3854 | + break; |
3855 | + } |
3856 | + qCritical() << Q_FUNC_INFO << "Manifest failed to execute process:" << err; |
3857 | + Q_EMIT requestFailed(); |
3858 | +} |
3859 | +} // Click |
3860 | +} // UpdatePlugin |
3861 | |
3862 | === added file 'plugins/system-update/click/manifest_impl.h' |
3863 | --- plugins/system-update/click/manifest_impl.h 1970-01-01 00:00:00 +0000 |
3864 | +++ plugins/system-update/click/manifest_impl.h 2016-08-16 11:46:43 +0000 |
3865 | @@ -0,0 +1,47 @@ |
3866 | +/* |
3867 | + * This file is part of system-settings |
3868 | + * |
3869 | + * Copyright (C) 2016 Canonical Ltd. |
3870 | + * |
3871 | + * This program is free software: you can redistribute it and/or modify it |
3872 | + * under the terms of the GNU General Public License version 3, as published |
3873 | + * by the Free Software Foundation. |
3874 | + * |
3875 | + * This program is distributed in the hope that it will be useful, but |
3876 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
3877 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3878 | + * PURPOSE. See the GNU General Public License for more details. |
3879 | + * |
3880 | + * You should have received a copy of the GNU General Public License along |
3881 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
3882 | + */ |
3883 | + |
3884 | +#ifndef CLICK_MANIFEST_IMPL_H |
3885 | +#define CLICK_MANIFEST_IMPL_H |
3886 | + |
3887 | +#include "click/manifest.h" |
3888 | + |
3889 | +#include <QProcess> |
3890 | + |
3891 | +namespace UpdatePlugin |
3892 | +{ |
3893 | +namespace Click |
3894 | +{ |
3895 | +class ManifestImpl : public Manifest |
3896 | +{ |
3897 | + Q_OBJECT |
3898 | +public: |
3899 | + explicit ManifestImpl(QObject *parent = nullptr); |
3900 | + ~ManifestImpl(); |
3901 | +public Q_SLOTS: |
3902 | + virtual void request() override; |
3903 | +private Q_SLOTS: |
3904 | + void handleProcessSuccess(const int &exitCode); |
3905 | + void handleProcessError(const QProcess::ProcessError &error); |
3906 | +private: |
3907 | + QProcess m_process; |
3908 | +}; |
3909 | +} // Click |
3910 | +} // UpdatePlugin |
3911 | + |
3912 | +#endif // CLICK_MANIFEST_IMPL_H |
3913 | |
3914 | === added file 'plugins/system-update/click/sessiontoken.h' |
3915 | --- plugins/system-update/click/sessiontoken.h 1970-01-01 00:00:00 +0000 |
3916 | +++ plugins/system-update/click/sessiontoken.h 2016-08-16 11:46:43 +0000 |
3917 | @@ -0,0 +1,42 @@ |
3918 | +/* |
3919 | + * This file is part of system-settings |
3920 | + * |
3921 | + * Copyright (C) 2016 Canonical Ltd. |
3922 | + * |
3923 | + * This program is free software: you can redistribute it and/or modify it |
3924 | + * under the terms of the GNU General Public License version 3, as published |
3925 | + * by the Free Software Foundation. |
3926 | + * |
3927 | + * This program is distributed in the hope that it will be useful, but |
3928 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
3929 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3930 | + * PURPOSE. See the GNU General Public License for more details. |
3931 | + * |
3932 | + * You should have received a copy of the GNU General Public License along |
3933 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
3934 | + */ |
3935 | + |
3936 | +#ifndef CLICK_SESSIONTOKEN_H |
3937 | +#define CLICK_SESSIONTOKEN_H |
3938 | + |
3939 | +#include <QString> |
3940 | + |
3941 | +namespace UpdatePlugin |
3942 | +{ |
3943 | +namespace Click |
3944 | +{ |
3945 | +// Interface for a session token. |
3946 | +class SessionToken |
3947 | +{ |
3948 | +public: |
3949 | + explicit SessionToken() {}; |
3950 | + virtual ~SessionToken() {}; |
3951 | + virtual bool isValid() const = 0; |
3952 | + virtual QString signUrl(const QString url, |
3953 | + const QString method, |
3954 | + bool asQuery = false) const = 0; |
3955 | +}; |
3956 | +} // Click |
3957 | +} // UpdatePlugin |
3958 | + |
3959 | +#endif // CLICK_SESSIONTOKEN_H |
3960 | |
3961 | === added file 'plugins/system-update/click/sessiontoken_impl.cpp' |
3962 | --- plugins/system-update/click/sessiontoken_impl.cpp 1970-01-01 00:00:00 +0000 |
3963 | +++ plugins/system-update/click/sessiontoken_impl.cpp 2016-08-16 11:46:43 +0000 |
3964 | @@ -0,0 +1,48 @@ |
3965 | +/* |
3966 | + * This file is part of system-settings |
3967 | + * |
3968 | + * Copyright (C) 2016 Canonical Ltd. |
3969 | + * |
3970 | + * This program is free software: you can redistribute it and/or modify it |
3971 | + * under the terms of the GNU General Public License version 3, as published |
3972 | + * by the Free Software Foundation. |
3973 | + * |
3974 | + * This program is distributed in the hope that it will be useful, but |
3975 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
3976 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3977 | + * PURPOSE. See the GNU General Public License for more details. |
3978 | + * |
3979 | + * You should have received a copy of the GNU General Public License along |
3980 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
3981 | + */ |
3982 | + |
3983 | +#include "click/sessiontoken_impl.h" |
3984 | + |
3985 | +#include <QDebug> |
3986 | +namespace UpdatePlugin |
3987 | +{ |
3988 | +namespace Click |
3989 | +{ |
3990 | +SessionTokenImpl::SessionTokenImpl() : SessionTokenImpl(UbuntuOne::Token()) |
3991 | +{ |
3992 | +} |
3993 | + |
3994 | +SessionTokenImpl::SessionTokenImpl(const UbuntuOne::Token &token) |
3995 | + : SessionToken() |
3996 | + , m_token(token) |
3997 | +{ |
3998 | +} |
3999 | + |
4000 | +bool SessionTokenImpl::isValid() const |
4001 | +{ |
4002 | + return m_token.isValid(); |
4003 | +} |
4004 | + |
4005 | +QString SessionTokenImpl::signUrl(const QString url, |
4006 | + const QString method, |
4007 | + bool asQuery) const |
4008 | +{ |
4009 | + return m_token.signUrl(url, method, asQuery); |
4010 | +} |
4011 | +} // Click |
4012 | +} // UpdatePlugin |
4013 | |
4014 | === added file 'plugins/system-update/click/sessiontoken_impl.h' |
4015 | --- plugins/system-update/click/sessiontoken_impl.h 1970-01-01 00:00:00 +0000 |
4016 | +++ plugins/system-update/click/sessiontoken_impl.h 2016-08-16 11:46:43 +0000 |
4017 | @@ -0,0 +1,48 @@ |
4018 | +/* |
4019 | + * This file is part of system-settings |
4020 | + * |
4021 | + * Copyright (C) 2016 Canonical Ltd. |
4022 | + * |
4023 | + * This program is free software: you can redistribute it and/or modify it |
4024 | + * under the terms of the GNU General Public License version 3, as published |
4025 | + * by the Free Software Foundation. |
4026 | + * |
4027 | + * This program is distributed in the hope that it will be useful, but |
4028 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4029 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4030 | + * PURPOSE. See the GNU General Public License for more details. |
4031 | + * |
4032 | + * You should have received a copy of the GNU General Public License along |
4033 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4034 | + */ |
4035 | + |
4036 | +#ifndef CLICK_SESSIONTOKEN_IMPL_H |
4037 | +#define CLICK_SESSIONTOKEN_IMPL_H |
4038 | + |
4039 | +#include "sessiontoken.h" |
4040 | + |
4041 | +#include <token.h> |
4042 | + |
4043 | +namespace UpdatePlugin |
4044 | +{ |
4045 | +namespace Click |
4046 | +{ |
4047 | +class SessionTokenImpl : public SessionToken |
4048 | +{ |
4049 | +public: |
4050 | + // Creates an invalid SessionToken. |
4051 | + explicit SessionTokenImpl(); |
4052 | + // Creates a SessionToken using a UbuntuOne Token. |
4053 | + explicit SessionTokenImpl(const UbuntuOne::Token &token); |
4054 | + virtual ~SessionTokenImpl() {}; |
4055 | + virtual bool isValid() const override; |
4056 | + virtual QString signUrl(const QString url, |
4057 | + const QString method, |
4058 | + bool asQuery = false) const override; |
4059 | +private: |
4060 | + UbuntuOne::Token m_token; |
4061 | +}; |
4062 | +} // Click |
4063 | +} // UpdatePlugin |
4064 | + |
4065 | +#endif // CLICK_SESSIONTOKEN_IMPL_H |
4066 | |
4067 | === added file 'plugins/system-update/click/sso.h' |
4068 | --- plugins/system-update/click/sso.h 1970-01-01 00:00:00 +0000 |
4069 | +++ plugins/system-update/click/sso.h 2016-08-16 11:46:43 +0000 |
4070 | @@ -0,0 +1,56 @@ |
4071 | +/* |
4072 | + * This file is part of system-settings |
4073 | + * |
4074 | + * Copyright (C) 2016 Canonical Ltd. |
4075 | + * |
4076 | + * This program is free software: you can redistribute it and/or modify it |
4077 | + * under the terms of the GNU General Public License version 3, as published |
4078 | + * by the Free Software Foundation. |
4079 | + * |
4080 | + * This program is distributed in the hope that it will be useful, but |
4081 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4082 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4083 | + * PURPOSE. See the GNU General Public License for more details. |
4084 | + * |
4085 | + * You should have received a copy of the GNU General Public License along |
4086 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4087 | + */ |
4088 | + |
4089 | +#ifndef CLICK_SSO_H |
4090 | +#define CLICK_SSO_H |
4091 | + |
4092 | +#include "sessiontoken.h" |
4093 | + |
4094 | +#include <QObject> |
4095 | +#include <QString> |
4096 | +#include <QDebug> |
4097 | + |
4098 | +namespace UpdatePlugin |
4099 | +{ |
4100 | +namespace Click |
4101 | +{ |
4102 | +// Interface for a SSO client. |
4103 | +class SSO : public QObject |
4104 | +{ |
4105 | + Q_OBJECT |
4106 | +public: |
4107 | + explicit SSO(QObject *parent = nullptr) : QObject(parent) {}; |
4108 | + virtual ~SSO() {}; |
4109 | + virtual void requestCredentials() = 0; |
4110 | + virtual void invalidateCredentials() = 0; |
4111 | + |
4112 | +Q_SIGNALS: |
4113 | + /* This signal is emitted when credentials are found. |
4114 | + * |
4115 | + * Note: It is the responsibility of the receiver to delete this token when |
4116 | + * done with it, as the token will not be deleted by SSO, nor used/accessed |
4117 | + * further. |
4118 | + */ |
4119 | + void credentialsFound(SessionToken *token); |
4120 | + void credentialsNotFound(); |
4121 | + void credentialsDeleted(); |
4122 | +}; |
4123 | +} // Click |
4124 | +} // UpdatePlugin |
4125 | + |
4126 | +#endif // CLICK_SSO_H |
4127 | |
4128 | === added file 'plugins/system-update/click/sso_impl.cpp' |
4129 | --- plugins/system-update/click/sso_impl.cpp 1970-01-01 00:00:00 +0000 |
4130 | +++ plugins/system-update/click/sso_impl.cpp 2016-08-16 11:46:43 +0000 |
4131 | @@ -0,0 +1,55 @@ |
4132 | +/* |
4133 | + * This file is part of system-settings |
4134 | + * |
4135 | + * Copyright (C) 2016 Canonical Ltd. |
4136 | + * |
4137 | + * This program is free software: you can redistribute it and/or modify it |
4138 | + * under the terms of the GNU General Public License version 3, as published |
4139 | + * by the Free Software Foundation. |
4140 | + * |
4141 | + * This program is distributed in the hope that it will be useful, but |
4142 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4143 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4144 | + * PURPOSE. See the GNU General Public License for more details. |
4145 | + * |
4146 | + * You should have received a copy of the GNU General Public License along |
4147 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4148 | + */ |
4149 | + |
4150 | +#include "click/sessiontoken_impl.h" |
4151 | +#include "click/sso_impl.h" |
4152 | + |
4153 | +namespace UpdatePlugin |
4154 | +{ |
4155 | +namespace Click |
4156 | +{ |
4157 | +SSOImpl::SSOImpl(QObject *parent) |
4158 | + : SSO(parent) |
4159 | + , m_service(new UbuntuOne::SSOService()) |
4160 | +{ |
4161 | + m_service->setParent(this); |
4162 | + |
4163 | + connect(m_service, SIGNAL(credentialsFound(const Token&)), |
4164 | + this, SLOT(handleCredentialsFound(const Token&))); |
4165 | + connect(m_service, SIGNAL(credentialsNotFound()), |
4166 | + this, SIGNAL(credentialsNotFound())); |
4167 | + connect(m_service, SIGNAL(credentialsDeleted()), |
4168 | + this, SIGNAL(credentialsDeleted())); |
4169 | +} |
4170 | + |
4171 | +void SSOImpl::requestCredentials() |
4172 | +{ |
4173 | + m_service->getCredentials(); |
4174 | +} |
4175 | + |
4176 | +void SSOImpl::invalidateCredentials() |
4177 | +{ |
4178 | + m_service->invalidateCredentials(); |
4179 | +} |
4180 | + |
4181 | +void SSOImpl::handleCredentialsFound(const Token &token) |
4182 | +{ |
4183 | + Q_EMIT credentialsFound(new SessionTokenImpl(token)); |
4184 | +} |
4185 | +} // Click |
4186 | +} // UpdatePlugin |
4187 | |
4188 | === added file 'plugins/system-update/click/sso_impl.h' |
4189 | --- plugins/system-update/click/sso_impl.h 1970-01-01 00:00:00 +0000 |
4190 | +++ plugins/system-update/click/sso_impl.h 2016-08-16 11:46:43 +0000 |
4191 | @@ -0,0 +1,54 @@ |
4192 | +/* |
4193 | + * This file is part of system-settings |
4194 | + * |
4195 | + * Copyright (C) 2016 Canonical Ltd. |
4196 | + * |
4197 | + * This program is free software: you can redistribute it and/or modify it |
4198 | + * under the terms of the GNU General Public License version 3, as published |
4199 | + * by the Free Software Foundation. |
4200 | + * |
4201 | + * This program is distributed in the hope that it will be useful, but |
4202 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4203 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4204 | + * PURPOSE. See the GNU General Public License for more details. |
4205 | + * |
4206 | + * You should have received a copy of the GNU General Public License along |
4207 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4208 | + */ |
4209 | + |
4210 | +#ifndef CLICK_SSO_IMPL_H |
4211 | +#define CLICK_SSO_IMPL_H |
4212 | + |
4213 | +#include "click/sso.h" |
4214 | + |
4215 | +#include <token.h> |
4216 | +#include <ssoservice.h> |
4217 | + |
4218 | +#include <QObject> |
4219 | +#include <QString> |
4220 | + |
4221 | +/* Having the full namespaced name in a slot seems to confuse |
4222 | +Qt at runtime, so we need this declaration. */ |
4223 | +using namespace UbuntuOne; |
4224 | + |
4225 | +namespace UpdatePlugin |
4226 | +{ |
4227 | +namespace Click |
4228 | +{ |
4229 | +class SSOImpl : public SSO |
4230 | +{ |
4231 | + Q_OBJECT |
4232 | +public: |
4233 | + explicit SSOImpl(QObject *parent = nullptr); |
4234 | + virtual ~SSOImpl() {}; |
4235 | + virtual void requestCredentials() override; |
4236 | + virtual void invalidateCredentials() override; |
4237 | +private Q_SLOTS: |
4238 | + void handleCredentialsFound(const Token &token); |
4239 | +private: |
4240 | + UbuntuOne::SSOService *m_service; |
4241 | +}; |
4242 | +} // Click |
4243 | +} // UpdatePlugin |
4244 | + |
4245 | +#endif // CLICK_SSO_IMPL_H |
4246 | |
4247 | === added file 'plugins/system-update/click/tokendownloader.h' |
4248 | --- plugins/system-update/click/tokendownloader.h 1970-01-01 00:00:00 +0000 |
4249 | +++ plugins/system-update/click/tokendownloader.h 2016-08-16 11:46:43 +0000 |
4250 | @@ -0,0 +1,74 @@ |
4251 | +/* |
4252 | + * This file is part of system-settings |
4253 | + * |
4254 | + * Copyright (C) 2016 Canonical Ltd. |
4255 | + * |
4256 | + * This program is free software: you can redistribute it and/or modify it |
4257 | + * under the terms of the GNU General Public License version 3, as published |
4258 | + * by the Free Software Foundation. |
4259 | + * |
4260 | + * This program is distributed in the hope that it will be useful, but |
4261 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4262 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4263 | + * PURPOSE. See the GNU General Public License for more details. |
4264 | + * |
4265 | + * You should have received a copy of the GNU General Public License along |
4266 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4267 | + */ |
4268 | + |
4269 | +#ifndef CLICK_TOKEN_DOWNLOADER_H |
4270 | +#define CLICK_TOKEN_DOWNLOADER_H |
4271 | + |
4272 | +#include "update.h" |
4273 | +#include "click/apiclient.h" |
4274 | + |
4275 | +#include <QObject> |
4276 | +#include <QSharedPointer> |
4277 | + |
4278 | +namespace UpdatePlugin |
4279 | +{ |
4280 | +namespace Click |
4281 | +{ |
4282 | +/* Performs the dance described in [1]. |
4283 | + * |
4284 | + * This dance is only performed at check time, not for retries and other |
4285 | + * scenarios in which a click download is expected to happen within 5 minutes. |
4286 | + * The token this downloader downloads is valid for 24 hours. |
4287 | + * |
4288 | + * [1] lp:1231422 |
4289 | + */ |
4290 | +class TokenDownloader : public QObject |
4291 | +{ |
4292 | + Q_OBJECT |
4293 | +public: |
4294 | + explicit TokenDownloader(ApiClient *client, |
4295 | + QSharedPointer<Update> update, |
4296 | + QObject *parent = nullptr) |
4297 | + : QObject(parent) |
4298 | + , m_client(client) |
4299 | + , m_update(update) |
4300 | + { |
4301 | + } |
4302 | + virtual ~TokenDownloader() {}; |
4303 | + |
4304 | + /* Downloads a token. |
4305 | + * |
4306 | + * URL should be a oauth signed URL, to be used to perform a HEAD request. |
4307 | + * For details, see lp:1231422. |
4308 | + */ |
4309 | + virtual void download(const QString &url) = 0; |
4310 | + virtual ApiClient* client() const = 0; |
4311 | +public Q_SLOTS: |
4312 | + virtual void cancel() = 0; |
4313 | +Q_SIGNALS: |
4314 | + void downloadSucceeded(QSharedPointer<Update> update); |
4315 | + void downloadFailed(QSharedPointer<Update> update); |
4316 | + void credentialError(); |
4317 | +protected: |
4318 | + ApiClient *m_client; |
4319 | + QSharedPointer<Update> m_update; |
4320 | +}; |
4321 | +} // Click |
4322 | +} // UpdatePlugin |
4323 | + |
4324 | +#endif // CLICK_TOKEN_DOWNLOADER_H |
4325 | |
4326 | === added file 'plugins/system-update/click/tokendownloader_factory.h' |
4327 | --- plugins/system-update/click/tokendownloader_factory.h 1970-01-01 00:00:00 +0000 |
4328 | +++ plugins/system-update/click/tokendownloader_factory.h 2016-08-16 11:46:43 +0000 |
4329 | @@ -0,0 +1,44 @@ |
4330 | +/* |
4331 | + * This file is part of system-settings |
4332 | + * |
4333 | + * Copyright (C) 2016 Canonical Ltd. |
4334 | + * |
4335 | + * This program is free software: you can redistribute it and/or modify it |
4336 | + * under the terms of the GNU General Public License version 3, as published |
4337 | + * by the Free Software Foundation. |
4338 | + * |
4339 | + * This program is distributed in the hope that it will be useful, but |
4340 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4341 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4342 | + * PURPOSE. See the GNU General Public License for more details. |
4343 | + * |
4344 | + * You should have received a copy of the GNU General Public License along |
4345 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4346 | + */ |
4347 | + |
4348 | +#ifndef CLICK_TOKEN_DOWNLOADER_FACTORY_H |
4349 | +#define CLICK_TOKEN_DOWNLOADER_FACTORY_H |
4350 | + |
4351 | +#include "click/tokendownloader.h" |
4352 | +#include "network/accessmanager.h" |
4353 | + |
4354 | +namespace UpdatePlugin |
4355 | +{ |
4356 | +namespace Click |
4357 | +{ |
4358 | +class TokenDownloaderFactory : public QObject |
4359 | +{ |
4360 | +public: |
4361 | + virtual ~TokenDownloaderFactory() {}; |
4362 | + /* Create a TokenDownloader. |
4363 | + * |
4364 | + * The application is responsible for deleting the TokenDownloader once it |
4365 | + * finishes. |
4366 | + */ |
4367 | + virtual TokenDownloader* create(Network::Manager *nam, |
4368 | + QSharedPointer<Update> update) = 0; |
4369 | +}; |
4370 | +} // Click |
4371 | +} // UpdatePlugin |
4372 | + |
4373 | +#endif // CLICK_TOKEN_DOWNLOADER_FACTORY_H |
4374 | |
4375 | === added file 'plugins/system-update/click/tokendownloader_factory_impl.cpp' |
4376 | --- plugins/system-update/click/tokendownloader_factory_impl.cpp 1970-01-01 00:00:00 +0000 |
4377 | +++ plugins/system-update/click/tokendownloader_factory_impl.cpp 2016-08-16 11:46:43 +0000 |
4378 | @@ -0,0 +1,36 @@ |
4379 | +/* |
4380 | + * This file is part of system-settings |
4381 | + * |
4382 | + * Copyright (C) 2016 Canonical Ltd. |
4383 | + * |
4384 | + * This program is free software: you can redistribute it and/or modify it |
4385 | + * under the terms of the GNU General Public License version 3, as published |
4386 | + * by the Free Software Foundation. |
4387 | + * |
4388 | + * This program is distributed in the hope that it will be useful, but |
4389 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4390 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4391 | + * PURPOSE. See the GNU General Public License for more details. |
4392 | + * |
4393 | + * You should have received a copy of the GNU General Public License along |
4394 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4395 | + */ |
4396 | + |
4397 | +#include "click/apiclient_impl.h" |
4398 | +#include "click/tokendownloader_impl.h" |
4399 | +#include "click/tokendownloader_factory_impl.h" |
4400 | + |
4401 | +namespace UpdatePlugin |
4402 | +{ |
4403 | +namespace Click |
4404 | +{ |
4405 | +TokenDownloader* TokenDownloaderFactoryImpl::create(Network::Manager *nam, |
4406 | + QSharedPointer<Update> update) |
4407 | +{ |
4408 | + auto client = new Click::ApiClientImpl(nam); |
4409 | + auto downloader = new TokenDownloaderImpl(client, update); |
4410 | + client->setParent(downloader); |
4411 | + return downloader; |
4412 | +} |
4413 | +} // Click |
4414 | +} // UpdatePlugin |
4415 | |
4416 | === added file 'plugins/system-update/click/tokendownloader_factory_impl.h' |
4417 | --- plugins/system-update/click/tokendownloader_factory_impl.h 1970-01-01 00:00:00 +0000 |
4418 | +++ plugins/system-update/click/tokendownloader_factory_impl.h 2016-08-16 11:46:43 +0000 |
4419 | @@ -0,0 +1,37 @@ |
4420 | +/* |
4421 | + * This file is part of system-settings |
4422 | + * |
4423 | + * Copyright (C) 2016 Canonical Ltd. |
4424 | + * |
4425 | + * This program is free software: you can redistribute it and/or modify it |
4426 | + * under the terms of the GNU General Public License version 3, as published |
4427 | + * by the Free Software Foundation. |
4428 | + * |
4429 | + * This program is distributed in the hope that it will be useful, but |
4430 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4431 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4432 | + * PURPOSE. See the GNU General Public License for more details. |
4433 | + * |
4434 | + * You should have received a copy of the GNU General Public License along |
4435 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4436 | + */ |
4437 | + |
4438 | +#ifndef CLICK_TOKEN_DOWNLOADER_FACTORY_IMPL_H |
4439 | +#define CLICK_TOKEN_DOWNLOADER_FACTORY_IMPL_H |
4440 | + |
4441 | +#include "click/tokendownloader_factory.h" |
4442 | + |
4443 | +namespace UpdatePlugin |
4444 | +{ |
4445 | +namespace Click |
4446 | +{ |
4447 | +class TokenDownloaderFactoryImpl : public TokenDownloaderFactory |
4448 | +{ |
4449 | +public: |
4450 | + virtual TokenDownloader* create(Network::Manager *nam, |
4451 | + QSharedPointer<Update> update) override; |
4452 | +}; |
4453 | +} // Click |
4454 | +} // UpdatePlugin |
4455 | + |
4456 | +#endif // CLICK_TOKEN_DOWNLOADER_FACTORY_IMPL_H |
4457 | |
4458 | === added file 'plugins/system-update/click/tokendownloader_impl.cpp' |
4459 | --- plugins/system-update/click/tokendownloader_impl.cpp 1970-01-01 00:00:00 +0000 |
4460 | +++ plugins/system-update/click/tokendownloader_impl.cpp 2016-08-16 11:46:43 +0000 |
4461 | @@ -0,0 +1,81 @@ |
4462 | +/* |
4463 | + * This file is part of system-settings |
4464 | + * |
4465 | + * Copyright (C) 2016 Canonical Ltd. |
4466 | + * |
4467 | + * This program is free software: you can redistribute it and/or modify it |
4468 | + * under the terms of the GNU General Public License version 3, as published |
4469 | + * by the Free Software Foundation. |
4470 | + * |
4471 | + * This program is distributed in the hope that it will be useful, but |
4472 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4473 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4474 | + * PURPOSE. See the GNU General Public License for more details. |
4475 | + * |
4476 | + * You should have received a copy of the GNU General Public License along |
4477 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4478 | + */ |
4479 | + |
4480 | +#include "click/apiclient_impl.h" |
4481 | +#include "click/tokendownloader_impl.h" |
4482 | +#include "helpers.h" |
4483 | + |
4484 | +namespace UpdatePlugin |
4485 | +{ |
4486 | +namespace Click |
4487 | +{ |
4488 | +TokenDownloaderImpl::TokenDownloaderImpl(ApiClient *client, |
4489 | + QSharedPointer<Update> update, |
4490 | + QObject *parent) |
4491 | + : TokenDownloader(client, update, parent) |
4492 | +{ |
4493 | + connect(m_client, SIGNAL(tokenRequestSucceeded(const QString)), |
4494 | + this, SLOT(handleSuccess(const QString))); |
4495 | + connect(m_client, SIGNAL(networkError()), |
4496 | + this, SLOT(handleFailure())); |
4497 | + connect(m_client, SIGNAL(serverError()), |
4498 | + this, SLOT(handleFailure())); |
4499 | + connect(m_client, SIGNAL(credentialError()), |
4500 | + this, SLOT(handleFailure())); |
4501 | + connect(m_client, SIGNAL(credentialError()), |
4502 | + this, SIGNAL(credentialError())); |
4503 | +} |
4504 | + |
4505 | +TokenDownloaderImpl::~TokenDownloaderImpl() |
4506 | +{ |
4507 | + cancel(); |
4508 | +} |
4509 | + |
4510 | +ApiClient* TokenDownloaderImpl::client() const |
4511 | +{ |
4512 | + return m_client; |
4513 | +} |
4514 | + |
4515 | +void TokenDownloaderImpl::cancel() |
4516 | +{ |
4517 | + m_client->cancel(); |
4518 | +} |
4519 | + |
4520 | +void TokenDownloaderImpl::download(const QString &url) |
4521 | +{ |
4522 | + QUrl query(m_update->downloadUrl()); |
4523 | + query.setQuery(url); |
4524 | + m_client->requestToken(query); |
4525 | +} |
4526 | + |
4527 | +void TokenDownloaderImpl::handleSuccess(const QString &token) |
4528 | +{ |
4529 | + m_update->setToken(token); |
4530 | + if (token.isEmpty()) { |
4531 | + downloadFailed(m_update); |
4532 | + } else { |
4533 | + downloadSucceeded(m_update); |
4534 | + } |
4535 | +} |
4536 | + |
4537 | +void TokenDownloaderImpl::handleFailure() |
4538 | +{ |
4539 | + Q_EMIT downloadFailed(m_update); |
4540 | +} |
4541 | +}// Click |
4542 | +}// UpdatePlugin |
4543 | |
4544 | === added file 'plugins/system-update/click/tokendownloader_impl.h' |
4545 | --- plugins/system-update/click/tokendownloader_impl.h 1970-01-01 00:00:00 +0000 |
4546 | +++ plugins/system-update/click/tokendownloader_impl.h 2016-08-16 11:46:43 +0000 |
4547 | @@ -0,0 +1,47 @@ |
4548 | +/* |
4549 | + * This file is part of system-settings |
4550 | + * |
4551 | + * Copyright (C) 2016 Canonical Ltd. |
4552 | + * |
4553 | + * This program is free software: you can redistribute it and/or modify it |
4554 | + * under the terms of the GNU General Public License version 3, as published |
4555 | + * by the Free Software Foundation. |
4556 | + * |
4557 | + * This program is distributed in the hope that it will be useful, but |
4558 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4559 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4560 | + * PURPOSE. See the GNU General Public License for more details. |
4561 | + * |
4562 | + * You should have received a copy of the GNU General Public License along |
4563 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4564 | + */ |
4565 | + |
4566 | +#ifndef CLICK_TOKEN_DOWNLOADER_IMPL_H |
4567 | +#define CLICK_TOKEN_DOWNLOADER_IMPL_H |
4568 | + |
4569 | +#include "click/tokendownloader.h" |
4570 | + |
4571 | +namespace UpdatePlugin |
4572 | +{ |
4573 | +namespace Click |
4574 | +{ |
4575 | +class TokenDownloaderImpl : public TokenDownloader |
4576 | +{ |
4577 | + Q_OBJECT |
4578 | +public: |
4579 | + explicit TokenDownloaderImpl(ApiClient *client, |
4580 | + QSharedPointer<Update> update, |
4581 | + QObject *parent = nullptr); |
4582 | + virtual ~TokenDownloaderImpl(); |
4583 | + virtual void download(const QString &url) override; |
4584 | + virtual ApiClient* client() const override; |
4585 | +public Q_SLOTS: |
4586 | + virtual void cancel() override; |
4587 | +protected Q_SLOTS: |
4588 | + void handleSuccess(const QString &token); |
4589 | + void handleFailure(); |
4590 | +}; |
4591 | +} // Click |
4592 | +} // UpdatePlugin |
4593 | + |
4594 | +#endif // CLICK_TOKEN_DOWNLOADER_IMPL_H |
4595 | |
4596 | === removed file 'plugins/system-update/download_tracker.cpp' |
4597 | --- plugins/system-update/download_tracker.cpp 2015-09-25 18:33:19 +0000 |
4598 | +++ plugins/system-update/download_tracker.cpp 1970-01-01 00:00:00 +0000 |
4599 | @@ -1,204 +0,0 @@ |
4600 | -/* |
4601 | - * Copyright (C) 2014-2015 - Canonical Ltd. |
4602 | - * |
4603 | - * This program is free software: you can redistribute it and/or modify it |
4604 | - * under the terms of the GNU Lesser General Public License, as |
4605 | - * published by the Free Software Foundation; either version 2.1 or 3.0 |
4606 | - * of the License. |
4607 | - * |
4608 | - * This program is distributed in the hope that it will be useful, but |
4609 | - * WITHOUT ANY WARRANTY; without even the implied warranties of |
4610 | - * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR |
4611 | - * PURPOSE. See the applicable version of the GNU Lesser General Public |
4612 | - * License for more details. |
4613 | - * |
4614 | - * You should have received a copy of both the GNU Lesser General Public |
4615 | - * License along with this program. If not, see <http://www.gnu.org/licenses/> |
4616 | - * |
4617 | - * Authored by: Diego Sarmentero <diego.sarmentero@canonical.com> |
4618 | - */ |
4619 | - |
4620 | -#include <QProcessEnvironment> |
4621 | -#include <ubuntu/download_manager/download_struct.h> |
4622 | -#include <ubuntu/download_manager/error.h> |
4623 | - |
4624 | -#include "download_tracker.h" |
4625 | -#include "network.h" |
4626 | - |
4627 | -namespace { |
4628 | - const QString DOWNLOAD_COMMAND = "post-download-command"; |
4629 | - const QString PACKAGE_NAME = "package-name"; |
4630 | - const QString TITLE = "title"; |
4631 | - const QString SHOW_IN_INDICATOR = "indicator-shown"; |
4632 | - const QString PKCON_COMMAND = "pkcon"; |
4633 | - const QString DOWNLOAD_MANAGER_SHA512 = "sha512"; |
4634 | -} |
4635 | - |
4636 | -namespace UpdatePlugin { |
4637 | - |
4638 | -DownloadTracker::DownloadTracker(QObject *parent) : |
4639 | - QObject(parent), |
4640 | - m_clickToken(QString::null), |
4641 | - m_downloadUrl(QString::null), |
4642 | - m_download(nullptr), |
4643 | - m_manager(nullptr), |
4644 | - m_progress(0) |
4645 | -{ |
4646 | -} |
4647 | - |
4648 | -void DownloadTracker::setDownload(const QString& url) |
4649 | -{ |
4650 | - if (!url.isEmpty()) { |
4651 | - m_downloadUrl = url; |
4652 | - startService(); |
4653 | - } |
4654 | -} |
4655 | - |
4656 | -void DownloadTracker::setClickToken(const QString& token) |
4657 | -{ |
4658 | - if (!token.isEmpty()) { |
4659 | - m_clickToken = token; |
4660 | - startService(); |
4661 | - } |
4662 | -} |
4663 | - |
4664 | -void DownloadTracker::setPackageName(const QString& package) |
4665 | -{ |
4666 | - if (!package.isEmpty()) { |
4667 | - m_packageName = package; |
4668 | - startService(); |
4669 | - } |
4670 | -} |
4671 | - |
4672 | -void DownloadTracker::setTitle(const QString& title) |
4673 | -{ |
4674 | - if (!title.isEmpty()) { |
4675 | - m_title = title; |
4676 | - startService(); |
4677 | - } |
4678 | -} |
4679 | - |
4680 | -void DownloadTracker::startService() |
4681 | -{ |
4682 | - if (!m_clickToken.isEmpty() && !m_downloadUrl.isEmpty() && !m_packageName.isEmpty() && !m_title.isEmpty()) { |
4683 | - if (m_manager == nullptr) { |
4684 | - m_manager = Manager::createSessionManager("", this); |
4685 | - |
4686 | - if (!connect(m_manager, &Manager::downloadCreated, |
4687 | - this, &DownloadTracker::bindDownload)) { |
4688 | - qWarning() << "Could not connect to Manager::downloadCreated!"; |
4689 | - } |
4690 | - } |
4691 | - QVariantMap vmap; |
4692 | - QStringList args; |
4693 | - QString command = getPkconCommand(); |
4694 | - args << command << "-p" << "install-local" << "$file"; |
4695 | - vmap[DOWNLOAD_COMMAND] = args; |
4696 | - vmap[PACKAGE_NAME] = m_packageName; |
4697 | - vmap[TITLE] = m_title; |
4698 | - vmap[SHOW_IN_INDICATOR] = m_show_in_indicator; |
4699 | - StringMap map; |
4700 | - map[X_CLICK_TOKEN] = m_clickToken; |
4701 | - DownloadStruct dstruct(m_downloadUrl, m_download_sha512, DOWNLOAD_MANAGER_SHA512, vmap, map); |
4702 | - m_manager->createDownload(dstruct); |
4703 | - } |
4704 | -} |
4705 | - |
4706 | -void DownloadTracker::bindDownload(Download* download) |
4707 | -{ |
4708 | - m_download = download; |
4709 | - if (!connect(m_download, &Download::finished, |
4710 | - this, &DownloadTracker::onDownloadFinished)) { |
4711 | - qWarning() << "Could not connect to Download::finished"; |
4712 | - } |
4713 | - if (!connect(m_download, &Download::canceled, |
4714 | - this, &DownloadTracker::onDownloadCanceled)) { |
4715 | - qWarning() << "Could not connect to Download::canceled"; |
4716 | - } |
4717 | - if (!connect(m_download, &Download::paused, |
4718 | - this, &DownloadTracker::paused)) { |
4719 | - qWarning() << "Could not connect to Download::paused"; |
4720 | - } |
4721 | - if (!connect(m_download, &Download::resumed, |
4722 | - this, &DownloadTracker::resumed)) { |
4723 | - qWarning() << "Could not connect to Download::resumed"; |
4724 | - } |
4725 | - if (!connect(m_download, &Download::started, |
4726 | - this, &DownloadTracker::started)) { |
4727 | - qWarning() << "Could not connect to Download::started"; |
4728 | - } |
4729 | - if (!connect(m_download, static_cast<void(Download::*)(Error*)>(&Download::error), |
4730 | - this, &DownloadTracker::registerError)) { |
4731 | - qWarning() << "Could not connect to Download::error"; |
4732 | - } |
4733 | - |
4734 | - if (!connect(m_download, static_cast<void(Download::*)(qulonglong, qulonglong)>(&Download::progress), |
4735 | - this, &DownloadTracker::setProgress)) { |
4736 | - qWarning() << "Could not connect to Download::progress"; |
4737 | - } |
4738 | - |
4739 | - if (!connect(m_download, &Download::processing, |
4740 | - this, &DownloadTracker::processing)) { |
4741 | - qWarning() << "Could not connect to Download::processing"; |
4742 | - } |
4743 | - |
4744 | - m_download->start(); |
4745 | -} |
4746 | - |
4747 | -void DownloadTracker::registerError(Error* error) |
4748 | -{ |
4749 | - Q_EMIT errorFound(error->errorString()); |
4750 | - |
4751 | - // we need to ensure that the resources are cleaned |
4752 | - m_download->deleteLater(); |
4753 | - m_download = nullptr; |
4754 | -} |
4755 | - |
4756 | -void DownloadTracker::onDownloadFinished(const QString& path) |
4757 | -{ |
4758 | - // once a download is finished we need to clean the resources |
4759 | - m_download->deleteLater(); |
4760 | - m_download = nullptr; |
4761 | - Q_EMIT finished(path); |
4762 | -} |
4763 | - |
4764 | -void DownloadTracker::onDownloadCanceled(bool wasCanceled) |
4765 | -{ |
4766 | - if (wasCanceled) { |
4767 | - m_download->deleteLater(); |
4768 | - m_download = nullptr; |
4769 | - } |
4770 | - Q_EMIT canceled(wasCanceled); |
4771 | -} |
4772 | - |
4773 | -void DownloadTracker::pause() |
4774 | -{ |
4775 | - if (m_download != nullptr) { |
4776 | - m_download->pause(); |
4777 | - } |
4778 | -} |
4779 | - |
4780 | -void DownloadTracker::resume() |
4781 | -{ |
4782 | - if (m_download != nullptr) { |
4783 | - m_download->resume(); |
4784 | - } |
4785 | -} |
4786 | - |
4787 | -QString DownloadTracker::getPkconCommand() |
4788 | -{ |
4789 | - QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); |
4790 | - QString command = environment.value("PKCON_COMMAND", QString(PKCON_COMMAND)); |
4791 | - return command; |
4792 | -} |
4793 | - |
4794 | -void DownloadTracker::setProgress(qulonglong received, qulonglong total) |
4795 | -{ |
4796 | - if (total > 0) { |
4797 | - qulonglong result = (received * 100); |
4798 | - m_progress = static_cast<int>(result / total); |
4799 | - emit progressChanged(); |
4800 | - } |
4801 | -} |
4802 | - |
4803 | -} |
4804 | |
4805 | === removed file 'plugins/system-update/download_tracker.h' |
4806 | --- plugins/system-update/download_tracker.h 2015-09-25 18:33:19 +0000 |
4807 | +++ plugins/system-update/download_tracker.h 1970-01-01 00:00:00 +0000 |
4808 | @@ -1,106 +0,0 @@ |
4809 | -/* |
4810 | - * Copyright (C) 2014 - Canonical Ltd. |
4811 | - * |
4812 | - * This program is free software: you can redistribute it and/or modify it |
4813 | - * under the terms of the GNU Lesser General Public License, as |
4814 | - * published by the Free Software Foundation; either version 2.1 or 3.0 |
4815 | - * of the License. |
4816 | - * |
4817 | - * This program is distributed in the hope that it will be useful, but |
4818 | - * WITHOUT ANY WARRANTY; without even the implied warranties of |
4819 | - * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR |
4820 | - * PURPOSE. See the applicable version of the GNU Lesser General Public |
4821 | - * License for more details. |
4822 | - * |
4823 | - * You should have received a copy of both the GNU Lesser General Public |
4824 | - * License along with this program. If not, see <http://www.gnu.org/licenses/> |
4825 | - * |
4826 | - * Authored by: Diego Sarmentero <diego.sarmentero@canonical.com> |
4827 | - */ |
4828 | - |
4829 | - |
4830 | -#ifndef DOWNLOADTRACKER_H |
4831 | -#define DOWNLOADTRACKER_H |
4832 | - |
4833 | -#include <QObject> |
4834 | -#include <QtQml> |
4835 | -#include <QList> |
4836 | -#include <QString> |
4837 | -#include <ubuntu/download_manager/download.h> |
4838 | -#include <ubuntu/download_manager/manager.h> |
4839 | - |
4840 | -using Ubuntu::DownloadManager::Download; |
4841 | -using Ubuntu::DownloadManager::Manager; |
4842 | - |
4843 | -namespace Ubuntu { namespace DownloadManager { class Error; } } |
4844 | - |
4845 | -namespace UpdatePlugin { |
4846 | - |
4847 | -class DownloadTracker : public QObject |
4848 | -{ |
4849 | - Q_OBJECT |
4850 | - Q_PROPERTY(QString clickToken READ clickToken WRITE setClickToken) |
4851 | - Q_PROPERTY(QString download READ download WRITE setDownload) |
4852 | - Q_PROPERTY(QString packageName READ packageName WRITE setPackageName) |
4853 | - Q_PROPERTY(QString title READ title WRITE setTitle) |
4854 | - Q_PROPERTY(bool showInIndicator READ showInIndicator WRITE setShowInIndicator) |
4855 | - Q_PROPERTY(QString downloadSha512 READ downloadSha512 WRITE setDownloadSha512) |
4856 | - Q_PROPERTY(int progress READ progress NOTIFY progressChanged) |
4857 | - |
4858 | -public: |
4859 | - explicit DownloadTracker(QObject *parent = 0); |
4860 | - ~DownloadTracker() {} |
4861 | - |
4862 | - Q_INVOKABLE void pause(); |
4863 | - Q_INVOKABLE void resume(); |
4864 | - |
4865 | - QString download() { return m_downloadUrl; } |
4866 | - QString clickToken() { return m_clickToken; } |
4867 | - QString packageName() { return m_packageName; } |
4868 | - QString title() { return m_title; } |
4869 | - bool showInIndicator() { return m_show_in_indicator; } |
4870 | - QString downloadSha512() { return m_download_sha512; } |
4871 | - int progress() { return m_progress; } |
4872 | - void setDownload(const QString& url); |
4873 | - void setClickToken(const QString& token); |
4874 | - void setPackageName(const QString& package); |
4875 | - void setTitle(const QString& title); |
4876 | - void setDownloadSha512(const QString &sha512) { m_download_sha512 = sha512; } |
4877 | - void setShowInIndicator(bool show_in_indicator) { m_show_in_indicator = show_in_indicator; } |
4878 | - |
4879 | -public Q_SLOTS: |
4880 | - void bindDownload(Download* download); |
4881 | - void setProgress(qulonglong received, qulonglong total); |
4882 | - void registerError(Ubuntu::DownloadManager::Error* error); |
4883 | - void onDownloadFinished(const QString& path); |
4884 | - void onDownloadCanceled(bool wasCanceled); |
4885 | - |
4886 | -Q_SIGNALS: |
4887 | - void error(const QString &errorMessage); |
4888 | - void finished(const QString &path); |
4889 | - void started(bool success); |
4890 | - void canceled(bool success); |
4891 | - void paused(bool success); |
4892 | - void resumed(bool success); |
4893 | - void processing(const QString &path); |
4894 | - void progressChanged(); |
4895 | - void errorFound(const QString &error); |
4896 | - |
4897 | -private: |
4898 | - QString m_clickToken = QString::null; |
4899 | - QString m_downloadUrl = QString::null; |
4900 | - QString m_packageName = QString::null; |
4901 | - QString m_title = QString::null; |
4902 | - bool m_show_in_indicator = false; |
4903 | - Download* m_download = nullptr; |
4904 | - Manager* m_manager = nullptr; |
4905 | - int m_progress = 0; |
4906 | - QString m_download_sha512 = QString::null; |
4907 | - |
4908 | - void startService(); |
4909 | - QString getPkconCommand(); |
4910 | -}; |
4911 | - |
4912 | -} |
4913 | - |
4914 | -#endif // DOWNLOADTRACKER_H |
4915 | |
4916 | === added file 'plugins/system-update/helpers.cpp' |
4917 | --- plugins/system-update/helpers.cpp 1970-01-01 00:00:00 +0000 |
4918 | +++ plugins/system-update/helpers.cpp 2016-08-16 11:46:43 +0000 |
4919 | @@ -0,0 +1,108 @@ |
4920 | +/* |
4921 | + * This file is part of system-settings |
4922 | + * |
4923 | + * Copyright (C) 2013-2016 Canonical Ltd. |
4924 | + * |
4925 | + * This program is free software: you can redistribute it and/or modify it |
4926 | + * under the terms of the GNU General Public License version 3, as published |
4927 | + * by the Free Software Foundation. |
4928 | + * |
4929 | + * This program is distributed in the hope that it will be useful, but |
4930 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4931 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4932 | + * PURPOSE. See the GNU General Public License for more details. |
4933 | + * |
4934 | + * You should have received a copy of the GNU General Public License along |
4935 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4936 | + */ |
4937 | + |
4938 | +#include "helpers.h" |
4939 | +#include <QProcessEnvironment> |
4940 | + |
4941 | +namespace UpdatePlugin |
4942 | +{ |
4943 | + |
4944 | +QString Helpers::getFrameworksDir() |
4945 | +{ |
4946 | + QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); |
4947 | + return environment.value("FRAMEWORKS_FOLDER", |
4948 | + QStringLiteral("/usr/share/click/frameworks/")); |
4949 | +} |
4950 | + |
4951 | +std::vector<std::string> Helpers::getAvailableFrameworks() |
4952 | +{ |
4953 | + std::vector<std::string> result; |
4954 | + for (auto f : listFolder(getFrameworksDir().toStdString(), "*.framework")) { |
4955 | + result.push_back(f.substr(0, f.size() - 10)); |
4956 | + } |
4957 | + return result; |
4958 | +} |
4959 | + |
4960 | +std::string Helpers::getArchitecture() |
4961 | +{ |
4962 | + static const std::string deb_arch |
4963 | + { architectureFromDpkg() }; |
4964 | + return deb_arch; |
4965 | +} |
4966 | + |
4967 | +std::vector<std::string> Helpers::listFolder(const std::string &folder, |
4968 | + const std::string &pattern) |
4969 | +{ |
4970 | + std::vector<std::string> result; |
4971 | + |
4972 | + QDir dir(QString::fromStdString(folder), QString::fromStdString(pattern), |
4973 | + QDir::Unsorted, QDir::Readable | QDir::Files); |
4974 | + QStringList entries = dir.entryList(); |
4975 | + for (int i = 0; i < entries.size(); ++i) { |
4976 | + QString filename = entries.at(i); |
4977 | + result.push_back(filename.toStdString()); |
4978 | + } |
4979 | + |
4980 | + return result; |
4981 | +} |
4982 | + |
4983 | +std::string Helpers::architectureFromDpkg() |
4984 | +{ |
4985 | + QString program("dpkg"); |
4986 | + QStringList arguments; |
4987 | + arguments << "--print-architecture"; |
4988 | + QProcess archDetector; |
4989 | + archDetector.start(program, arguments); |
4990 | + if (!archDetector.waitForFinished()) { |
4991 | + qWarning() << "Architecture detection failed."; |
4992 | + } |
4993 | + auto output = archDetector.readAllStandardOutput(); |
4994 | + auto ostr = QString::fromUtf8(output); |
4995 | + |
4996 | + return ostr.trimmed().toStdString(); |
4997 | +} |
4998 | + |
4999 | +QString Helpers::clickMetadataUrl() |
5000 | +{ |
FAILED: Continuous integration, rev:1796 /jenkins. canonical. com/system- apps/job/ lp-ubuntu- system- settings- ci/61/ /jenkins. canonical. com/system- apps/job/ build/1078/ console /jenkins. canonical. com/system- apps/job/ build-0- fetch/1078 /jenkins. canonical. com/system- apps/job/ build-1- sourcepkg/ release= vivid+overlay/ 975 /jenkins. canonical. com/system- apps/job/ build-1- sourcepkg/ release= xenial+ overlay/ 975 /jenkins. canonical. com/system- apps/job/ build-1- sourcepkg/ release= yakkety/ 975 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= vivid+overlay/ 964/console /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 964/console /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= yakkety/ 964/console /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= vivid+overlay/ 964/console /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 964/console /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= yakkety/ 964/console /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= vivid+overlay/ 964/console /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 964/console /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= yakkety/ 964/console
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/system- apps/job/ lp-ubuntu- system- settings- ci/61/rebuild
https:/