Merge lp:~cimi/unity8/card-social into lp:unity8

Proposed by Andrea Cimitan on 2016-03-07
Status: Superseded
Proposed branch: lp:~cimi/unity8/card-social
Merge into: lp:unity8
Prerequisite: lp:~aacid/unity8/cardCreatorFixedHeaderSizeOptimization
Diff against target: 5750 lines (+3514/-919)
79 files modified
debian/control (+2/-2)
plugins/Dash/CardCreator.js (+44/-1)
plugins/Dash/CardSocialActions.qml (+94/-0)
plugins/Dash/ScopeStyle.qml (+1/-1)
plugins/Dash/qmldir (+1/-0)
qml/Dash/CardGrid.qml (+1/-0)
qml/Dash/CardHorizontalList.qml (+1/-0)
qml/Dash/CardTool.qml (+25/-7)
qml/Dash/CardVerticalJournal.qml (+1/-0)
qml/Dash/DashContent.qml (+2/-2)
qml/Dash/DashNavigation.qml (+170/-89)
qml/Dash/DashNavigationButton.qml (+0/-233)
qml/Dash/DashNavigationHeader.qml (+73/-0)
qml/Dash/DashNavigationList.qml (+33/-87)
qml/Dash/DashPageHeader.qml (+148/-140)
qml/Dash/DashRenderer.qml (+6/-0)
qml/Dash/Filters/FilterOptionSelector.qml (+91/-0)
qml/Dash/Filters/FilterRangeInput.qml (+136/-0)
qml/Dash/Filters/FilterValueSlider.qml (+87/-0)
qml/Dash/Filters/FilterWidget.qml (+29/-0)
qml/Dash/Filters/FilterWidgetFactory.qml (+79/-0)
qml/Dash/FiltersPopover.qml (+105/-0)
qml/Dash/GenericScopeView.qml (+81/-47)
qml/Dash/PageHeaderExtraPanel.qml (+175/-0)
tests/mocks/Unity/CMakeLists.txt (+14/-1)
tests/mocks/Unity/fake_categories.cpp (+4/-1)
tests/mocks/Unity/fake_filters.cpp (+125/-0)
tests/mocks/Unity/fake_filters.h (+46/-0)
tests/mocks/Unity/fake_navigation.cpp (+9/-10)
tests/mocks/Unity/fake_optionselectorfilter.cpp (+65/-0)
tests/mocks/Unity/fake_optionselectorfilter.h (+52/-0)
tests/mocks/Unity/fake_optionselectoroptions.cpp (+77/-0)
tests/mocks/Unity/fake_optionselectoroptions.h (+47/-0)
tests/mocks/Unity/fake_rangeinputfilter.cpp (+167/-0)
tests/mocks/Unity/fake_rangeinputfilter.h (+79/-0)
tests/mocks/Unity/fake_resultsmodel.cpp (+2/-0)
tests/mocks/Unity/fake_scope.cpp (+61/-36)
tests/mocks/Unity/fake_scope.h (+20/-7)
tests/mocks/Unity/fake_unity_plugin.cpp (+7/-0)
tests/mocks/Unity/fake_valuesliderfilter.cpp (+84/-0)
tests/mocks/Unity/fake_valuesliderfilter.h (+55/-0)
tests/mocks/Unity/fake_valueslidervalues.cpp (+51/-0)
tests/mocks/Unity/fake_valueslidervalues.h (+36/-0)
tests/plugins/Dash/cardcreator/1.res (+1/-1)
tests/plugins/Dash/cardcreator/1.res.cardcreator (+1/-1)
tests/plugins/Dash/cardcreator/10.res (+1/-1)
tests/plugins/Dash/cardcreator/10.res.cardcreator (+1/-1)
tests/plugins/Dash/cardcreator/11.res (+1/-1)
tests/plugins/Dash/cardcreator/11.res.cardcreator (+1/-1)
tests/plugins/Dash/cardcreator/12.res (+146/-0)
tests/plugins/Dash/cardcreator/12.res.cardcreator (+145/-0)
tests/plugins/Dash/cardcreator/12.tst (+3/-0)
tests/plugins/Dash/cardcreator/2.res (+1/-1)
tests/plugins/Dash/cardcreator/2.res.cardcreator (+1/-1)
tests/plugins/Dash/cardcreator/3.res (+1/-1)
tests/plugins/Dash/cardcreator/3.res.cardcreator (+1/-1)
tests/plugins/Dash/cardcreator/4.res (+1/-1)
tests/plugins/Dash/cardcreator/4.res.cardcreator (+1/-1)
tests/plugins/Dash/cardcreator/5.res (+1/-1)
tests/plugins/Dash/cardcreator/5.res.cardcreator (+1/-1)
tests/plugins/Dash/cardcreator/6.res (+1/-1)
tests/plugins/Dash/cardcreator/6.res.cardcreator (+1/-1)
tests/plugins/Dash/cardcreator/7.res (+1/-1)
tests/plugins/Dash/cardcreator/7.res.cardcreator (+1/-1)
tests/plugins/Dash/cardcreator/8.res (+1/-1)
tests/plugins/Dash/cardcreator/8.res.cardcreator (+1/-1)
tests/plugins/Dash/cardcreator/9.res (+1/-1)
tests/plugins/Dash/cardcreator/9.res.cardcreator (+1/-1)
tests/qmltests/CMakeLists.txt (+4/-0)
tests/qmltests/Dash/CardHelpers.js (+9/-7)
tests/qmltests/Dash/Filters/tst_FilterOptionSelector.qml (+96/-0)
tests/qmltests/Dash/Filters/tst_FilterRangeInput.qml (+247/-0)
tests/qmltests/Dash/Filters/tst_FilterValueSlider.qml (+101/-0)
tests/qmltests/Dash/Filters/tst_FilterWidgetFactory.qml (+57/-0)
tests/qmltests/Dash/tst_Card.qml (+38/-3)
tests/qmltests/Dash/tst_DashContent.qml (+234/-206)
tests/qmltests/Dash/tst_DashPageHeader.qml (+24/-15)
tests/qmltests/Dash/tst_GenericScopeView.qml (+1/-1)
tests/qmltests/Dash/tst_PreviewView.qml (+1/-1)
To merge this branch: bzr merge lp:~cimi/unity8/card-social
Reviewer Review Type Date Requested Status
Unity8 CI Bot continuous-integration 2016-03-07 Needs Fixing on 2016-03-21
Albert Astals Cid (community) 2016-03-07 Needs Fixing on 2016-03-14
PS Jenkins bot continuous-integration 2016-03-07 Pending
Review via email: mp+288287@code.launchpad.net

This proposal supersedes a proposal from 2016-03-04.

This proposal has been superseded by a proposal from 2016-03-21.

Commit Message

Add social actions to cards

Description of the Change

 * Are there any related MPs required for this MP to build/function as expected? Please list.
yes
https://code.launchpad.net/~stolowski/unity-scopes-shell/social-attributes/+merge/287808
https://code.launchpad.net/~stolowski/unity-api/social-attributes-role/+merge/287802
 * Did you perform an exploratory manual test run of your code change and any related functionality?
will with silo, locally tested with mocks
 * Did you make sure that your branch does not contain spurious tags?
y
 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
ye
 * If you changed the UI, has there been a design review?
y

To post a comment you must log in.
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal

columns: width > units.gu(12) ? 4 : 2

where does this units.gu(12) come from?

review: Needs Information
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2115
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~cimi/unity8/card-social/+merge/285769/+edit-commit-message

https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/332/
Executed test runs:
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build/454/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/477
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/495
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/495
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/491
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/491/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/491/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/491
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/491/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/491/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/491
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/491/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/491/console

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/332/rebuild

review: Needs Fixing (continuous-integration)
Andrea Cimitan (cimi) wrote : Posted in a previous version of this proposal

14 gu is a small card in CardTool, minus the 1gu*2 per side.... we want
just small cards to have 4 columns
> Review: Needs Information
>
> columns: width > units.gu(12) ? 4 : 2
>
> where does this units.gu(12) come from?

PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2115
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~cimi/unity8/card-social/+merge/285769/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/unity8-ci/7267/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6429
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/682/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/1972
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/675
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1867
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1867
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/674
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/673
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4921
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6440
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6440/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27505
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/351/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/680
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/680/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27506

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity8-ci/7267/rebuild

review: Needs Fixing (continuous-integration)
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2116
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~cimi/unity8/card-social/+merge/285769/+edit-commit-message

https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/364/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/497
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay/149
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial/149
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/520
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/538
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/538
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/534
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/534/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/534
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/534/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/534
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/534/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/534
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/534/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/534
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/534/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/534
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/534/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/364/rebuild

review: Needs Fixing (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2116
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~cimi/unity8/card-social/+merge/285769/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/unity8-ci/7302/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6492
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/717/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/2007
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/710
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1902
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1902
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/709
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/708
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4957
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6503
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6503/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27619
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/367/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/715
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/715/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27618

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity8-ci/7302/rebuild

review: Needs Fixing (continuous-integration)
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2118
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~cimi/unity8/card-social/+merge/285769/+edit-commit-message

https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/365/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/498
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay/150
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial/150
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/521
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/539
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/539
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/535
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/535/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/535
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/535/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/535
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/535/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/535
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/535/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/535
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/535/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/535
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/535/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/365/rebuild

review: Needs Fixing (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2118
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~cimi/unity8/card-social/+merge/285769/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/unity8-ci/7308/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-vivid-touch/6499
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-xenial-touch/723/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-vivid/2013
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/unity8-qmluitest-xenial-amd64/716
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-amd64-ci/1908
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-vivid-i386-ci/1908
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-amd64-ci/715
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-xenial-i386-ci/714
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-vivid-touch/4963
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6510
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-vivid-armhf/6510/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27631
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-xenial-touch/372/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/721
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-xenial-armhf/721/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27630

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity8-ci/7308/rebuild

review: Needs Fixing (continuous-integration)
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal

Need commit message and description

review: Needs Fixing
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2119
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~cimi/unity8/card-social/+merge/285769/+edit-commit-message

https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/562/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/753
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/771
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/771
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/767
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/767/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/767
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/767/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/767
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/767/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/767
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/767/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/767
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/767/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/767
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/767/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/562/rebuild

review: Needs Fixing (continuous-integration)
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2120
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~cimi/unity8/card-social/+merge/285769/+edit-commit-message

https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/589/
Executed test runs:
    None: https://unity8-jenkins.ubuntu.com/job/lp-generic-update-mp/686/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/782
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/798
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/798

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/589/rebuild

review: Needs Fixing (continuous-integration)
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2120
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~cimi/unity8/card-social/+merge/285769/+edit-commit-message

https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/591/
Executed test runs:
    None: https://unity8-jenkins.ubuntu.com/job/lp-generic-update-mp/688/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/784
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/800/console
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/800/console
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/798/console
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/798/console
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/798/console
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/798/console
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/798/console
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/798/console

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/591/rebuild

review: Needs Fixing (continuous-integration)
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2123
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/602/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=qmluitests.sh/338
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial,testname=qmluitests.sh/338
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=phone-armhf,release=vivid+overlay,testname=autopilot.sh/338
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/793
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/806
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/806
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/808
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/808/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/808
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/808/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/808
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/808/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/808
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/808/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/808
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/808/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/808
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/808/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/602/rebuild

review: Needs Fixing (continuous-integration)
Albert Astals Cid (aacid) wrote :

The social actions won't work in a CardCarousel.

Are we OK with that?

review: Needs Information
Paweł Stołowski (stolowski) wrote :

> The social actions won't work in a CardCarousel.
>
> Are we OK with that?

Should be checked with Patricia I think.

lp:~cimi/unity8/card-social updated on 2016-03-07
2128. By Andrea Cimitan on 2016-03-07

Reworked one if/else

Albert Astals Cid (aacid) wrote :

The socialActions contents of 12.tst don't look correct, note that that is components and for components the only thing we care about is whether it exists or not and max-count (i.e. CardTool.qml) so it needs fixing to as not to confuse people of what we expect there.

review: Needs Fixing
lp:~cimi/unity8/card-social updated on 2016-03-07
2129. By Andrea Cimitan on 2016-03-07

As review

Andrea Cimitan (cimi) wrote :

> The socialActions contents of 12.tst don't look correct, note that that is
> components and for components the only thing we care about is whether it
> exists or not and max-count (i.e. CardTool.qml) so it needs fixing to as not
> to confuse people of what we expect there.
oops fixed

Albert Astals Cid (aacid) wrote :

> > The socialActions contents of 12.tst don't look correct, note that that is
> > components and for components the only thing we care about is whether it
> > exists or not and max-count (i.e. CardTool.qml) so it needs fixing to as not
> > to confuse people of what we expect there.
> oops fixed

I think there's actually the same issue in tests/mocks/Unity/fake_categories.cpp

Albert Astals Cid (aacid) wrote :

> > The social actions won't work in a CardCarousel.
> >
> > Are we OK with that?
>
> Should be checked with Patricia I think.

Seems they don't want them on Carousel, so let's filter them out on the CardTool level and write a console.log if we do the filtering so that scope authors can try to figure out why it doesn't work

lp:~cimi/unity8/card-social updated on 2016-03-07
2130. By Andrea Cimitan on 2016-03-07

Change mocks to be more generic

Albert Astals Cid (aacid) wrote :

var hasSocialActions = hasTitle && components["socialActions"] || false;

needs to be social-actions

actions["max-count"] needs to die as we discussed some days ago

The cardLoader in CardTool needs to be like http://paste.ubuntu.com/15348262/ since now we can't reuse fields for components and cardDAta keys

You can not use

import "../../../qml/Components/ListItems" as ListItems

in CardSocialActions.qml since you get

file:///usr/lib/arm-linux-gnueabihf/unity8/qml/Dash/CardCreator.js:943: Error: Qt.createQmlObject(): failed to create object:
    :149:1: Type CardSocialActions unavailable
    file:///usr/lib/arm-linux-gnueabihf/unity8/qml/Dash/CardSocialActions.qml:20:1: "../../../qml/Components/ListItems": no such directory

review: Needs Fixing
Albert Astals Cid (aacid) wrote :

Text conflict in debian/control
Text conflict in qml/Dash/GenericScopeView.qml
Text conflict in tests/plugins/Dash/cardcreator/9.res.cardcreator
3 conflicts encountered.

review: Needs Fixing
lp:~cimi/unity8/card-social updated on 2016-03-21
2131. By Andrea Cimitan on 2016-03-14

merge

2132. By Andrea Cimitan on 2016-03-21

Merges

lp:~cimi/unity8/card-social updated on 2016-05-04
2133. By Andrea Cimitan on 2016-04-01

Fix for review

2134. By Andrea Cimitan on 2016-04-06

as review

2135. By Andrea Cimitan on 2016-05-04

merged trunk

2136. By Andrea Cimitan on 2016-05-04

fixed card creator test

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2016-03-10 22:42:34 +0000
3+++ debian/control 2016-03-21 16:06:44 +0000
4@@ -29,7 +29,7 @@
5 libqt5xmlpatterns5-dev,
6 libsystemsettings-dev,
7 libudev-dev,
8- libunity-api-dev (>= 7.107),
9+ libunity-api-dev (>= 7.108),
10 libusermetricsoutput1-dev,
11 # Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop
12 libx11-dev[!armhf],
13@@ -133,7 +133,7 @@
14 unity-application-impl-13,
15 unity-notifications-impl-3,
16 unity-plugin-scopes | unity-scopes-impl,
17- unity-scopes-impl-10,
18+ unity-scopes-impl-11,
19 unity8-fake-env | unity-application-impl,
20 ${misc:Depends},
21 Breaks: unity8 (<< 7.86),
22
23=== modified file 'plugins/Dash/CardCreator.js'
24--- plugins/Dash/CardCreator.js 2016-03-10 16:53:04 +0000
25+++ plugins/Dash/CardCreator.js 2016-03-21 16:06:44 +0000
26@@ -358,6 +358,17 @@
27 model: cardData && cardData["attributes"]; \n\
28 }\n';
29
30+// %1 is used as anchors of socialActionsRow
31+// %2 is used as color of socialActionsRow
32+var kSocialActionsRowCode = 'CardSocialActions { \n\
33+ id: socialActionsRow; \n\
34+ objectName: "socialActionsRow"; \n\
35+ anchors { %1 } \n\
36+ color: %2; \n\
37+ model: cardData && cardData["socialActions"]; \n\
38+ onClicked: root.action(actionId); \n\
39+ }\n';
40+
41 // %1 is used as top anchor of summary
42 // %2 is used as topMargin anchor of summary
43 // %3 is used as color of summary
44@@ -444,9 +455,11 @@
45 var hasSubtitle = hasTitle && components["subtitle"] || false;
46 var hasHeaderRow = hasMascot && hasTitle;
47 var hasAttributes = hasTitle && components["attributes"] && components["attributes"]["field"] || false;
48+ var hasSocialActions = hasTitle && components["social-actions"] || false;
49 var isAudio = template["quick-preview-type"] === "audio";
50 var asynchronous = isCardTool ? "false" : "true";
51
52+ code += 'signal action(var actionId);\n';
53 if (isAudio) {
54 // For now we only support audio cards with [optional] art, title, subtitle
55 // in horizontal mode
56@@ -848,6 +861,34 @@
57 code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(summaryColor);
58 }
59
60+ if (hasSocialActions) {
61+ var socialAnchors;
62+ var socialTopAnchor;
63+
64+ if (hasSummary) socialTopAnchor = 'summary.bottom;';
65+ else if (isHorizontal && hasArt) socialTopAnchor = 'artShapeHolder.bottom;';
66+ else if (headerAsOverlay && hasArt) socialTopAnchor = 'artShapeHolder.bottom;';
67+ else if (hasHeaderRow) socialTopAnchor = 'row.bottom;';
68+ else if (hasTitleContainer) socialTopAnchor = 'headerTitleContainer.bottom;';
69+ else if (hasMascot) socialTopAnchor = 'mascotImage.bottom;';
70+ else if (hasAttributes) socialTopAnchor = 'attributesRow.bottom;';
71+ else if (hasSubtitle) socialTopAnchor = 'subtitleLabel.bottom;';
72+ else if (hasTitle) socialTopAnchor = 'titleLabel.bottom;';
73+ else if (hasArt) socialTopAnchor = 'artShapeHolder.bottom;';
74+ else socialTopAnchor = 'parent.top';
75+
76+ socialAnchors = 'top: ' + socialTopAnchor + ' left: parent.left; right: parent.right; topMargin: units.gu(1);'
77+
78+ var socialColor;
79+ if (hasBackground) {
80+ socialColor = summaryColorWithBackground;
81+ } else {
82+ socialColor = 'root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText';
83+ }
84+
85+ code += kSocialActionsRowCode.arg(socialAnchors).arg(socialColor);
86+ }
87+
88 var touchdownAnchors;
89 if (hasBackground) {
90 touchdownAnchors = 'fill: backgroundLoader';
91@@ -859,7 +900,9 @@
92 code += kTouchdownCode.arg(touchdownAnchors);
93
94 var implicitHeight = 'implicitHeight: ';
95- if (hasSummary) {
96+ if (hasSocialActions) {
97+ implicitHeight += 'socialActionsRow.y + socialActionsRow.height + units.gu(1);\n';
98+ } else if (hasSummary) {
99 implicitHeight += 'summary.y + summary.height + units.gu(1);\n';
100 } else if (isAudio) {
101 implicitHeight += 'audioButton.height;\n';
102
103=== added file 'plugins/Dash/CardSocialActions.qml'
104--- plugins/Dash/CardSocialActions.qml 1970-01-01 00:00:00 +0000
105+++ plugins/Dash/CardSocialActions.qml 2016-03-21 16:06:44 +0000
106@@ -0,0 +1,94 @@
107+/*
108+ * Copyright 2016 Canonical Ltd.
109+ *
110+ * This program is free software; you can redistribute it and/or modify
111+ * it under the terms of the GNU General Public License as published by
112+ * the Free Software Foundation; version 3.
113+ *
114+ * This program is distributed in the hope that it will be useful,
115+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
116+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
117+ * GNU General Public License for more details.
118+ *
119+ * You should have received a copy of the GNU General Public License
120+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
121+ */
122+
123+import QtQuick 2.4
124+import QtQuick.Layouts 1.1
125+import Ubuntu.Components 1.3
126+
127+Column {
128+ id: socialActions
129+ spacing: units.gu(0.5)
130+
131+ property alias model: repeater.model
132+ property color color: theme.palette.normal.baseText
133+
134+ signal clicked(var actionId)
135+
136+ Rectangle {
137+ id: divider
138+ visible: repeater.count > 0
139+ anchors {
140+ left: parent.left;
141+ right: parent.right;
142+ leftMargin:units.dp(1);
143+ rightMargin: units.dp(1);
144+ }
145+ color: Qt.darker(theme.palette.normal.background, 1.12)
146+ height: visible ? units.dp(1) : 0
147+ }
148+
149+ Row {
150+ id: row
151+ anchors {
152+ left: parent.left
153+ right: parent.right
154+ leftMargin: units.gu(1)
155+ rightMargin: units.gu(1)
156+ }
157+ spacing: units.gu(2)
158+ readonly property int visibleItems: {
159+ if (width <= units.gu(12)) // small card
160+ return 2;
161+ else if (width <= units.gu(21)) // medium card
162+ return 3;
163+ else // large or horizontal card
164+ return 4;
165+ }
166+
167+ Repeater {
168+ id: repeater
169+ delegate: Loader {
170+ height: units.gu(2)
171+ active: index < row.visibleItems
172+ sourceComponent: AbstractButton {
173+ objectName: "delegate" + index
174+ height: units.gu(2)
175+ width: icon.width
176+ Icon {
177+ id: icon
178+ objectName: "icon"
179+
180+ readonly property url urlIcon: modelData && modelData["icon"] || ""
181+ readonly property url urlTemporaryIcon: "temporaryIcon" in modelData && modelData["temporaryIcon"] || ""
182+
183+ height: units.gu(2)
184+ // FIXME Workaround for bug https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1421293
185+ width: implicitWidth > 0 && implicitHeight > 0 ? (implicitWidth / implicitHeight * height) : implicitWidth
186+ source: urlIcon
187+ color: socialActions.color
188+
189+ onUrlIconChanged: {
190+ if (urlIcon) source = urlIcon
191+ }
192+ }
193+
194+ onClicked: socialActions.clicked(modelData["id"]);
195+ onPressedChanged: if (pressed && icon.urlTemporaryIcon != "") icon.source = icon.urlTemporaryIcon
196+ }
197+ }
198+ }
199+ }
200+}
201
202=== modified file 'plugins/Dash/ScopeStyle.qml'
203--- plugins/Dash/ScopeStyle.qml 2015-07-15 15:07:19 +0000
204+++ plugins/Dash/ScopeStyle.qml 2016-03-21 16:06:44 +0000
205@@ -58,7 +58,7 @@
206 readonly property url headerLogo: "logo" in d.headerStyle ? d.headerStyle["logo"] : ""
207
208 /// Background style for the header
209- readonly property url headerBackground: "background" in d.headerStyle ? d.headerStyle["background"] : "color:///#f5f5f5"
210+ readonly property url headerBackground: "background" in d.headerStyle ? d.headerStyle["background"] : "color:///#ffffff"
211
212 /// Foreground color for the header
213 readonly property color headerForeground: "foreground-color" in d.headerStyle ? d.headerStyle["foreground-color"] : foreground
214
215=== modified file 'plugins/Dash/qmldir'
216--- plugins/Dash/qmldir 2015-05-18 22:17:21 +0000
217+++ plugins/Dash/qmldir 2016-03-21 16:06:44 +0000
218@@ -5,6 +5,7 @@
219 singleton DashAudioPlayer 0.1 DashAudioPlayer.qml
220 ScopeStyle 0.1 ScopeStyle.qml
221 CardAttributes 0.1 CardAttributes.qml
222+CardSocialActions 0.1 CardSocialActions.qml
223 CroppedImageMinimumSourceSize 0.1 CroppedImageMinimumSourceSize.qml
224 AudioProgressBar 0.1 AudioProgressBar.qml
225 CardAudioProgress 0.1 CardAudioProgress.qml
226
227=== modified file 'qml/Dash/CardGrid.qml'
228--- qml/Dash/CardGrid.qml 2016-02-16 15:09:55 +0000
229+++ qml/Dash/CardGrid.qml 2016-03-21 16:06:44 +0000
230@@ -78,6 +78,7 @@
231 target: loader.item
232 onClicked: root.clicked(index, result, loader.item, model)
233 onPressAndHold: root.pressAndHold(index, result, model)
234+ onAction: root.action(index, result, actionId)
235 }
236 }
237 }
238
239=== modified file 'qml/Dash/CardHorizontalList.qml'
240--- qml/Dash/CardHorizontalList.qml 2016-02-16 15:09:55 +0000
241+++ qml/Dash/CardHorizontalList.qml 2016-03-21 16:06:44 +0000
242@@ -59,6 +59,7 @@
243 target: loader.item
244 onClicked: root.clicked(index, result, loader.item, model)
245 onPressAndHold: root.pressAndHold(index, result, model)
246+ onAction: root.action(index, result, actionId)
247 }
248 }
249 }
250
251=== modified file 'qml/Dash/CardTool.qml'
252--- qml/Dash/CardTool.qml 2016-02-17 10:51:17 +0000
253+++ qml/Dash/CardTool.qml 2016-03-21 16:06:44 +0000
254@@ -162,7 +162,7 @@
255 id: attributesModel
256 property int numOfAttributes: 0
257 property var model: []
258- property bool hasAttributes: {
259+ readonly property bool hasAttributes: {
260 var attributes = components["attributes"];
261 var hasAttributesFlag = (attributes != undefined) && (attributes["field"] != undefined);
262
263@@ -182,16 +182,33 @@
264 }
265 }
266
267+ Item {
268+ id: socialActionsModel
269+ property var model: []
270+ readonly property bool hasActions: {
271+ var actions = components["social-actions"];
272+ var hasActionsFlag = (actions != undefined);
273+
274+ model = []
275+ if (hasActionsFlag) {
276+ model.push( {"id":"text", "icon":"image://theme/ok" } );
277+ }
278+ return hasActionsFlag
279+ }
280+ }
281+
282 Loader {
283 id: cardLoader
284- readonly property var fields: ["art", "mascot", "title", "subtitle", "summary", "attributes"]
285+ readonly property var cfields: ["art", "mascot", "title", "subtitle", "summary", "attributes", "social-actions"]
286+ readonly property var dfields: ["art", "mascot", "title", "subtitle", "summary", "attributes", "socialActions"]
287 readonly property var maxData: {
288 "art": Qt.resolvedUrl("graphics/pixel.png"),
289 "mascot": Qt.resolvedUrl("graphics/pixel.png"),
290 "title": "—\n—",
291 "subtitle": "—",
292 "summary": "—\n—\n—\n—\n—",
293- "attributes": attributesModel.model
294+ "attributes": attributesModel.model,
295+ "socialActions": socialActionsModel.model
296 }
297 sourceComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components, true);
298 onLoaded: {
299@@ -206,13 +223,14 @@
300 }
301 function updateCardData() {
302 var data = {};
303- for (var k in fields) {
304- var component = cardTool.components[fields[k]];
305- var key = fields[k];
306+ for (var k in cfields) {
307+ var ckey = cfields[k];
308+ var component = cardTool.components[ckey];
309 if ((typeof component === "string" && component.length > 0) ||
310 (typeof component === "object" && component !== null
311 && typeof component["field"] === "string" && component["field"].length > 0)) {
312- data[key] = maxData[key];
313+ var dkey = dfields[k];
314+ data[dkey] = maxData[dkey];
315 }
316 }
317 item.cardData = data;
318
319=== modified file 'qml/Dash/CardVerticalJournal.qml'
320--- qml/Dash/CardVerticalJournal.qml 2016-02-16 15:09:55 +0000
321+++ qml/Dash/CardVerticalJournal.qml 2016-03-21 16:06:44 +0000
322@@ -78,6 +78,7 @@
323 target: loader.item
324 onClicked: root.clicked(index, result, loader.item, model)
325 onPressAndHold: root.pressAndHold(index, result, model)
326+ onAction: root.action(index, result, actionId)
327 }
328 }
329 }
330
331=== modified file 'qml/Dash/DashContent.qml'
332--- qml/Dash/DashContent.qml 2015-08-03 13:48:14 +0000
333+++ qml/Dash/DashContent.qml 2016-03-21 16:06:44 +0000
334@@ -108,7 +108,7 @@
335 objectName: "dashContentList"
336
337 interactive: !dashContent.forceNonInteractive && dashContent.scopes.loaded && currentItem
338- && !currentItem.moving && !currentItem.navigationDisableParentInteractive && !currentItem.subPageShown
339+ && !currentItem.moving && !currentItem.subPageShown && !currentItem.extraPanelShown
340 anchors.fill: parent
341 orientation: ListView.Horizontal
342 boundsBehavior: Flickable.DragAndOvershootBounds
343@@ -170,7 +170,7 @@
344 objectName: "scopeLoader" + index
345
346 readonly property bool moving: item ? item.moving : false
347- readonly property bool navigationDisableParentInteractive: item ? item.navigationDisableParentInteractive : false
348+ readonly property bool extraPanelShown: item ? item.extraPanelShown : false
349 readonly property bool subPageShown: item ? item.subPageShown : false
350 readonly property var categoryView: item ? item.categoryView : null
351 readonly property var theScope: scope
352
353=== modified file 'qml/Dash/DashNavigation.qml'
354--- qml/Dash/DashNavigation.qml 2015-07-15 15:07:19 +0000
355+++ qml/Dash/DashNavigation.qml 2016-03-21 16:06:44 +0000
356@@ -17,101 +17,182 @@
357 import QtQuick 2.4
358 import Ubuntu.Components 1.3
359 import Dash 0.1
360-import "../Components"
361
362 Item {
363 id: root
364 objectName: "dashNavigation"
365
366+ // set by parent
367 property var scope: null
368- property var scopeStyle: null
369-
370- property alias windowWidth: blackRect.width
371- property alias windowHeight: blackRect.height
372- readonly property var openList: {
373- if (navigationButton.showList) return navigationButton.listView;
374- if (altNavigationButton.showList) return altNavigationButton.listView;
375- return null;
376- }
377- readonly property bool disableParentInteractive: {
378- return navigationButton.showList || altNavigationButton.showList ||
379- navigationButton.inverseMousePressed || altNavigationButton.inverseMousePressed;
380- }
381-
382- // FIXME this is only here for highlight purposes (see Background.qml, too)
383- readonly property var background: backgroundItem
384+ property real availableHeight
385+
386+ signal leafClicked()
387+
388+ // internal
389+ readonly property var currentNavigation: scope && scope.hasNavigation ? scope.getNavigation(scope.currentNavigationId) : null
390+ // Are we drilling down the tree or up?
391+ property bool isEnteringChildren: false
392
393 visible: height != 0
394- height: navigationButton.currentNavigation || altNavigationButton.currentNavigation ? units.gu(5) : 0
395-
396- QtObject {
397- id: d
398- readonly property color foregroundColor: root.scopeStyle
399- ? root.scopeStyle.getTextColor(backgroundItem.luminance)
400- : theme.palette.normal.baseText
401- readonly property bool bothVisible: altNavigationButton.visible && navigationButton.visible
402- readonly property real navigationWidth: root.width >= units.gu(60) ? units.gu(40) : root.width
403- readonly property real buttonWidth: navigationWidth / (bothVisible ? 2 : 1)
404- }
405-
406- Rectangle {
407- id: blackRect
408- objectName: "blackRect"
409- color: "black"
410- opacity: openList && openList.currentItem && openList.currentItem.visible ? 0.5 : 0
411- Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
412- anchors { left: parent.left; right: parent.right }
413- visible: opacity > 0
414- }
415-
416- Background {
417- id: backgroundItem
418- anchors.fill: parent
419- style: scopeStyle ? scopeStyle.navigationBackground : "color:///#f5f5f5"
420- }
421-
422- Image {
423- fillMode: Image.Stretch
424- source: scopeStyle.backgroundLuminance > 0.2 ? "graphics/navigation_shadow.png" : "graphics/navigation_shadow_light.png"
425- anchors { top: parent.bottom; left: parent.left; right: parent.right }
426- }
427-
428- DashNavigationButton {
429- id: altNavigationButton
430- objectName: "altNavigationButton"
431- height: root.height
432- width: d.buttonWidth
433- scope: root.scope
434- scopeStyle: root.scopeStyle
435- foregroundColor: d.foregroundColor
436- listView.width: d.navigationWidth
437- isAltNavigation: true
438- showDivider: navigationButton.visible || root.width > d.navigationWidth
439- // needed so that InverseMouseArea is above navigationButton
440- z: listView.height > 0 ? 1 : 0
441- }
442-
443- DashNavigationButton {
444- id: navigationButton
445- objectName: "navigationButton"
446- height: root.height
447- width: altNavigationButton.visible ? d.buttonWidth : d.navigationWidth
448- x: altNavigationButton.visible ? d.buttonWidth : 0
449- scope: root.scope
450- scopeStyle: root.scopeStyle
451- foregroundColor: d.foregroundColor
452- listView.width: d.navigationWidth
453- listView.x: -x
454- showDivider: root.width > d.navigationWidth
455- }
456-
457- Image {
458- fillMode: Image.Stretch
459- source: backgroundItem.luminance > 0.7 ? "graphics/navigation_shadow.png" : "graphics/navigation_shadow_light.png"
460- x: navigationButton.listView.height > 0 ? altNavigationButton.x : navigationButton.x
461- width: d.buttonWidth
462- rotation: 180
463- anchors.bottom: parent.bottom
464- visible: d.bothVisible && (navigationButton.listView.height > 0 || altNavigationButton.listView.height > 0)
465- }
466+ implicitHeight: scope && scope.hasNavigation ? navigationListView.y + navigationListView.height : 0
467+
468+ function resetNavigation() {
469+ if (navigationModel.count > 1) {
470+ clear();
471+ }
472+ }
473+
474+ Column {
475+ id: headersColumn
476+ anchors {
477+ top: parent.top
478+ left: parent.left
479+ right: parent.right
480+ }
481+
482+ function pop(popsNeeded) {
483+ if (popsNeeded == 0)
484+ return;
485+ isEnteringChildren = false;
486+ navigationListView.currentIndex = navigationListView.currentIndex - popsNeeded;
487+ navigationModel.setProperty(navigationListView.currentIndex, "nullifyNavigation", false);
488+ navigationModel.remove(navigationModel.count - popsNeeded, popsNeeded);
489+
490+ popsNeeded = Math.min(headersModel.count, popsNeeded);
491+ // This is effectively deleting ourselves, so needs to be the last thing of the function
492+ headersModel.remove(headersModel.count - popsNeeded, popsNeeded);
493+ }
494+
495+ Repeater {
496+ model: ListModel {
497+ id: headersModel
498+ // Roles
499+ // headerText: the text to show
500+ // navigationId: the navigation Id that represents
501+ // parentNavigationId: the parent navigation Id
502+ }
503+ delegate: DashNavigationHeader {
504+ objectName: "dashNavigationHeader" + index
505+ height: index == 0 && headersModel.count > 1 ? 0 : units.gu(5)
506+ width: headersColumn.width
507+
508+ backVisible: index != 0
509+ text: headerText
510+
511+ onBackClicked: {
512+ scope.setNavigationState(parentNavigationId);
513+
514+ var popsNeeded = headersModel.count - index;
515+ headersColumn.pop(popsNeeded);
516+ }
517+
518+ onTextClicked: {
519+ scope.setNavigationState(navigationId);
520+
521+ var popsNeeded = headersModel.count - index - 1;
522+ headersColumn.pop(popsNeeded);
523+
524+ root.leafClicked();
525+ }
526+ }
527+ }
528+ }
529+
530+ ListView {
531+ id: navigationListView
532+ objectName: "navigationListView"
533+ orientation: ListView.Horizontal
534+ interactive: false
535+ model: ListModel {
536+ id: navigationModel
537+ // We have two roles
538+ // navigationId: the navigation id of the navigation the list represents
539+ // nullifyNavigation: overrides navigationId to be null
540+ // This is used to "clear" the delegate when going "right" on the tree
541+ }
542+ anchors {
543+ top: headersColumn.bottom
544+ left: parent.left
545+ right: parent.right
546+ }
547+ readonly property int maxHeight: root.availableHeight - navigationListView.y
548+ property int prevHeight: maxHeight
549+ height: currentItem ? currentItem.height : maxHeight
550+
551+ onHeightChanged: {
552+ if (currentItem) {
553+ prevHeight = currentItem.desiredHeight;
554+ }
555+ }
556+ highlightMoveDuration: UbuntuAnimation.FastDuration
557+ delegate: DashNavigationList {
558+ objectName: "navigation" + index
559+ visible: height > 0
560+ width: navigationListView.width
561+ property real desiredHeight: {
562+ if (navigation && navigation.loaded && x == navigationListView.contentX)
563+ {
564+ return Math.min(implicitHeight, navigationListView.maxHeight);
565+ } else {
566+ return navigationListView.prevHeight;
567+ }
568+ }
569+ height: desiredHeight
570+ navigation: (nullifyNavigation || !scope) ? null : scope.getNavigation(navigationId)
571+ currentNavigation: root.currentNavigation
572+ onEnterNavigation: { // var newNavigationId, string newNavigationLabel, bool hasChildren
573+ scope.setNavigationState(newNavigationId);
574+ // We only need to add a new item to the model
575+ // if we have children, otherwise just load it
576+ if (hasChildren) {
577+ isEnteringChildren = true;
578+ navigationModel.append({"navigationId": newNavigationId, "nullifyNavigation": false});
579+ headersModel.append({"headerText": newNavigationLabel,
580+ "navigationId": newNavigationId,
581+ "parentNavigationId": navigationId
582+ });
583+ navigationListView.currentIndex++;
584+ } else {
585+ root.leafClicked();
586+ }
587+ }
588+ }
589+ onContentXChanged: {
590+ if (navigationListView.highlightMoveDuration == 0)
591+ return;
592+
593+ if (contentX == width * navigationListView.currentIndex) {
594+ if (isEnteringChildren) {
595+ navigationModel.setProperty(navigationListView.currentIndex - 1, "nullifyNavigation", true);
596+ }
597+ }
598+ }
599+ }
600+
601+ property bool isFirstLoad: false
602+ onScopeChanged: clear();
603+ function clear() {
604+ navigationModel.clear();
605+ headersModel.clear();
606+ isFirstLoad = true;
607+ }
608+ function setNewNavigation() {
609+ if (isFirstLoad && currentNavigation && currentNavigation.loaded) {
610+ isFirstLoad = false;
611+ if (currentNavigation.count > 0) {
612+ navigationModel.append({"navigationId": scope.currentNavigationId, "nullifyNavigation": false});
613+ } else {
614+ navigationModel.append({"navigationId": currentNavigation.parentNavigationId, "nullifyNavigation": false});
615+ }
616+ headersModel.append({"headerText": currentNavigation.allLabel != "" ? currentNavigation.allLabel : currentNavigation.label,
617+ "navigationId": currentNavigation.navigationId,
618+ "parentNavigationId": currentNavigation.parentNavigationId
619+ });
620+ }
621+ }
622+ Connections {
623+ target: currentNavigation
624+ onLoadedChanged: setNewNavigation();
625+ }
626+ onCurrentNavigationChanged: setNewNavigation();
627 }
628
629=== removed file 'qml/Dash/DashNavigationButton.qml'
630--- qml/Dash/DashNavigationButton.qml 2015-07-15 15:07:19 +0000
631+++ qml/Dash/DashNavigationButton.qml 1970-01-01 00:00:00 +0000
632@@ -1,233 +0,0 @@
633-/*
634- * Copyright (C) 2014,2015 Canonical, Ltd.
635- *
636- * This program is free software; you can redistribute it and/or modify
637- * it under the terms of the GNU General Public License as published by
638- * the Free Software Foundation; version 3.
639- *
640- * This program is distributed in the hope that it will be useful,
641- * but WITHOUT ANY WARRANTY; without even the implied warranty of
642- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
643- * GNU General Public License for more details.
644- *
645- * You should have received a copy of the GNU General Public License
646- * along with this program. If not, see <http://www.gnu.org/licenses/>.
647- */
648-
649-import QtQuick 2.4
650-import Ubuntu.Components 1.3
651-
652-AbstractButton {
653- id: root
654- objectName: "dashNavigation"
655-
656- // Set by parent
657- property var scope: null
658- property var scopeStyle: null
659- property color foregroundColor: theme.palette.normal.baseText
660- property bool isAltNavigation: false
661- property bool showDivider: false
662-
663- // Used by parent
664- readonly property var currentNavigation: scope && scope[hasNavigation] ? getNavigation(scope[currentNavigationId]) : null
665- readonly property alias listView: navigationListView
666- readonly property bool inverseMousePressed: inverseMouseArea.pressed
667- property bool showList: false
668-
669- // Internal
670- // Are we drilling down the tree or up?
671- property bool isGoingBack: false
672- readonly property string hasNavigation: isAltNavigation ? "hasAltNavigation" : "hasNavigation"
673- readonly property string currentNavigationId: isAltNavigation ? "currentAltNavigationId" : "currentNavigationId"
674- function getNavigation(navId) {
675- if (isAltNavigation) {
676- return scope.getAltNavigation(navId);
677- } else {
678- return scope.getNavigation(navId);
679- }
680- }
681-
682- visible: root.currentNavigation != null
683-
684- onClicked: {
685- navigationListView.updateMaxHeight();
686- root.showList = !root.showList;
687- }
688-
689- Label {
690- anchors.fill: parent
691- anchors.margins: units.gu(2)
692- anchors.rightMargin: units.gu(5)
693- verticalAlignment: Text.AlignVCenter
694- text: root.currentNavigation ? root.currentNavigation.label : ""
695- color: root.foregroundColor
696- elide: Text.ElideRight
697- maximumLineCount: 1
698- }
699-
700- Icon {
701- anchors.verticalCenter: parent.verticalCenter
702- anchors.right: parent.right
703- anchors.rightMargin: units.gu(2)
704- name: showList ? "up" : "down"
705- height: units.gu(2)
706- width: height
707- color: root.foregroundColor
708- }
709-
710- // navigationListView is outside root
711- ListView {
712- id: navigationListView
713- objectName: "navigationListView"
714- visible: height > 0
715- orientation: ListView.Horizontal
716- interactive: false
717- clip: root.width != windowWidth
718- model: ListModel {
719- id: navigationModel
720- // We have two roles
721- // navigationId: the navigation id of the navigation the list represents
722- // nullifyNavigation: overrides navigationId to be null
723- // This is used to "clear" the delegate when going "right" on the tree
724- }
725- anchors.top: root.bottom
726- property int maxHeight: -1
727- Component.onCompleted: updateMaxHeight();
728- function updateMaxHeight()
729- {
730- maxHeight = (windowHeight - mapToItem(null, 0, 0).y) - units.gu(8);
731- }
732- property int prevHeight: maxHeight
733- height: currentItem ? currentItem.height : maxHeight
734- onHeightChanged: {
735- if (root.showList) {
736- prevHeight = currentItem.desiredHeight;
737- }
738- }
739- highlightMoveDuration: UbuntuAnimation.FastDuration
740- delegate: DashNavigationList {
741- objectName: "navigation" + index
742- visible: height > 0
743- width: navigationListView.width
744- scopeStyle: root.scopeStyle
745- foregroundColor: root.foregroundColor
746- property real desiredHeight: {
747- if (root.showList) {
748- if (navigation && navigation.loaded && x == navigationListView.contentX)
749- {
750- navigationListView.updateMaxHeight();
751- return Math.min(implicitHeight, navigationListView.maxHeight);
752- } else {
753- return navigationListView.prevHeight;
754- }
755- } else {
756- return 0;
757- }
758- }
759- height: desiredHeight
760- navigation: (nullifyNavigation || !scope) ? null : getNavigation(navigationId)
761- currentNavigation: root.currentNavigation
762- onEnterNavigation: {
763- scope.setNavigationState(newNavigationId, isAltNavigation);
764- // We only need to add a new item to the model
765- // if we have children, otherwise just load it
766- if (hasChildren) {
767- isGoingBack = false;
768- navigationModel.append({"navigationId": newNavigationId, "nullifyNavigation": false});
769- navigationListView.currentIndex++;
770- } else {
771- showList = false;
772- }
773- }
774- onGoBackToParentClicked: {
775- if (navigationListView.currentIndex == 0) {
776- // This can happen if we jumped to the non root of a deep tree and the user
777- // is now going back, create space in the list for the list to move "left"
778- var aux = navigationListView.highlightMoveDuration;
779- navigationListView.highlightMoveDuration = 0;
780- navigationModel.insert(0, {"navigationId": navigation.parentNavigationId, "nullifyNavigation": false});
781- navigationListView.currentIndex = navigationListView.currentIndex + 1;
782- navigationListView.contentX = width * navigationListView.currentIndex;
783- navigationListView.highlightMoveDuration = aux;
784- }
785-
786- scope.setNavigationState(navigation.parentNavigationId, isAltNavigation);
787- isGoingBack = true;
788- navigationModel.setProperty(navigationListView.currentIndex - 1, "nullifyNavigation", false);
789- navigationListView.currentIndex--;
790- }
791- onAllNavigationClicked: {
792- showList = false;
793- if (root.currentNavigation.parentNavigationId == navigation.navigationId) {
794- // For leaves we have to go to the parent too
795- scope.setNavigationState(root.currentNavigation.parentNavigationId, isAltNavigation);
796- }
797- }
798- }
799- onContentXChanged: {
800- if (navigationListView.highlightMoveDuration == 0)
801- return;
802-
803- if (contentX == width * navigationListView.currentIndex) {
804- if (isGoingBack) {
805- navigationModel.remove(navigationListView.currentIndex + 1);
806- } else {
807- navigationModel.setProperty(navigationListView.currentIndex - 1, "nullifyNavigation", true);
808- }
809- }
810- }
811- }
812-
813- Image {
814- anchors {
815- top: navigationListView.bottom
816- left: navigationListView.left
817- right: navigationListView.right
818- }
819- fillMode: Image.Stretch
820- source: "graphics/navigation_shadow.png"
821- visible: root.showList
822- }
823-
824- property bool isFirstLoad: false
825- onScopeChanged: {
826- navigationModel.clear();
827- isFirstLoad = true;
828- }
829- function setNewNavigation() {
830- if (isFirstLoad && currentNavigation && currentNavigation.loaded) {
831- isFirstLoad = false;
832- if (currentNavigation.count > 0) {
833- navigationModel.append({"navigationId": scope[currentNavigationId], "nullifyNavigation": false});
834- } else {
835- navigationModel.append({"navigationId": currentNavigation.parentNavigationId, "nullifyNavigation": false});
836- }
837- }
838- }
839- Connections {
840- target: currentNavigation
841- onLoadedChanged: setNewNavigation();
842- }
843- onCurrentNavigationChanged: setNewNavigation();
844-
845- InverseMouseArea {
846- id: inverseMouseArea
847- anchors.fill: navigationListView
848- enabled: root.showList
849- onPressed: root.showList = false
850- }
851-
852- Rectangle {
853- visible: root.showDivider
854- anchors {
855- top: parent.top
856- topMargin: units.dp(1)
857- bottom: parent.bottom
858- left: parent.right
859- leftMargin: -units.dp(0.5)
860- }
861- width: units.dp(1)
862- color: root.foregroundColor
863- opacity: 0.2
864- }
865-}
866
867=== added file 'qml/Dash/DashNavigationHeader.qml'
868--- qml/Dash/DashNavigationHeader.qml 1970-01-01 00:00:00 +0000
869+++ qml/Dash/DashNavigationHeader.qml 2016-03-21 16:06:44 +0000
870@@ -0,0 +1,73 @@
871+/*
872+ * Copyright (C) 2014 Canonical, Ltd.
873+ *
874+ * This program is free software; you can redistribute it and/or modify
875+ * it under the terms of the GNU General Public License as published by
876+ * the Free Software Foundation; version 3.
877+ *
878+ * This program is distributed in the hope that it will be useful,
879+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
880+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
881+ * GNU General Public License for more details.
882+ *
883+ * You should have received a copy of the GNU General Public License
884+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
885+ */
886+
887+import QtQuick 2.4
888+import Ubuntu.Components 1.3
889+import Ubuntu.Components.ListItems 1.3 as ListItem
890+
891+Row {
892+ id: root
893+
894+ property alias backVisible: backImageItem.visible
895+ property alias textEnabled: textItem.enabled
896+ property alias text: textLabel.text
897+
898+ readonly property alias backButtonWidth: backImageItem.width
899+
900+ signal backClicked()
901+ signal textClicked()
902+
903+ ListItem.Standard {
904+ id: backImageItem
905+ objectName: "backButton"
906+ height: parent.height
907+ width: height
908+ showDivider: false
909+
910+ Icon {
911+ id: backImage
912+ anchors.centerIn: parent
913+ name: "back"
914+ height: units.gu(2)
915+ width: height
916+ }
917+
918+ onClicked: root.backClicked();
919+ }
920+
921+ ListItem.Standard {
922+ id: textItem
923+ height: parent.height
924+ showDivider: false
925+
926+ Label {
927+ id: textLabel
928+ anchors {
929+ verticalCenter: parent.verticalCenter
930+ left: parent.left
931+ right: parent.right
932+ leftMargin: backImageItem.visible ? 0 : units.gu(2)
933+ rightMargin: units.gu(2)
934+ }
935+ color: "#5D5D5D"
936+ wrapMode: Text.Wrap
937+ maximumLineCount: 2
938+ elide: Text.ElideMiddle
939+ }
940+
941+ onClicked: root.textClicked();
942+ }
943+}
944
945=== modified file 'qml/Dash/DashNavigationList.qml'
946--- qml/Dash/DashNavigationList.qml 2015-11-19 16:55:31 +0000
947+++ qml/Dash/DashNavigationList.qml 2016-03-21 16:06:44 +0000
948@@ -16,27 +16,17 @@
949
950 import QtQuick 2.4
951 import Ubuntu.Components 1.3
952-import Ubuntu.Components.ListItems 1.3 as ListItem
953 import "../Components"
954
955 Item {
956 id: root
957 property var navigation: null
958 property var currentNavigation: null
959- property var scopeStyle: null
960- property color foregroundColor: theme.palette.normal.baseText
961- signal enterNavigation(var newNavigationId, bool hasChildren)
962- signal goBackToParentClicked()
963- signal allNavigationClicked()
964+ signal enterNavigation(var newNavigationId, string newNavigationLabel, bool hasChildren)
965
966 readonly property int itemHeight: units.gu(5)
967 implicitHeight: flickable.contentHeight
968
969- Background {
970- style: root.scopeStyle ? root.scopeStyle.navigationBackground : "color:///#f5f5f5"
971- anchors.fill: parent
972- }
973-
974 clip: true
975
976 Behavior on height {
977@@ -59,89 +49,45 @@
978 id: column
979 width: parent.width
980
981- ListItem.Standard {
982- id: backButton
983- objectName: "backButton"
984- visible: navigation && !navigation.isRoot || false
985- height: itemHeight
986-
987- onClicked: root.goBackToParentClicked();
988-
989- Icon {
990- id: backImage
991- anchors {
992- verticalCenter: parent.verticalCenter
993- left: parent.left
994- leftMargin: units.gu(2)
995- }
996- name: "back"
997- height: units.gu(2)
998- width: height
999- color: root.foregroundColor
1000- }
1001-
1002- Label {
1003- anchors {
1004- verticalCenter: parent.verticalCenter
1005- left: backImage.right
1006- right: parent.right
1007- leftMargin: units.gu(0.5)
1008- rightMargin: units.gu(2)
1009- }
1010- text: navigation ? navigation.parentLabel : ""
1011- color: root.foregroundColor
1012- wrapMode: Text.Wrap
1013- maximumLineCount: 2
1014- elide: Text.ElideMiddle
1015- }
1016- }
1017-
1018- ListItem.Standard {
1019- id: allButton
1020- objectName: "allButton"
1021- visible: navigation && (!navigation.isRoot || (!navigation.hidden && root.currentNavigation && !root.currentNavigation.isRoot && root.currentNavigation.parentNavigationId == navigation.navigationId)) || false
1022- height: itemHeight
1023-
1024- Label {
1025- anchors {
1026- verticalCenter: parent.verticalCenter
1027- left: parent.left
1028- right: parent.right
1029- leftMargin: units.gu(2)
1030- rightMargin: units.gu(2)
1031- }
1032- text: navigation ? (navigation.allLabel != "" ? navigation.allLabel : navigation.label) : ""
1033- font.bold: true
1034- color: root.foregroundColor
1035- wrapMode: Text.Wrap
1036- maximumLineCount: 2
1037- elide: Text.ElideMiddle
1038- }
1039-
1040- onClicked: root.allNavigationClicked();
1041- }
1042-
1043 Repeater {
1044 model: navigation && navigation.loaded ? navigation : null
1045 clip: true
1046- delegate: ListItem.Standard {
1047+ delegate: ListItem {
1048 objectName: root.objectName + "child" + index
1049 height: root.itemHeight
1050- showDivider: index != navigation.count - 1
1051- selected: isActive
1052-
1053- onClicked: root.enterNavigation(navigationId, hasChildren)
1054+ width: column.width
1055+ anchors {
1056+ left: column.left
1057+ right: column.right
1058+ leftMargin: units.gu(2)
1059+ rightMargin: units.gu(2)
1060+ }
1061+
1062+ onClicked: root.enterNavigation(navigationId, allLabel != "" ? allLabel : label, hasChildren)
1063+
1064+ Icon {
1065+ id: leftIcon
1066+ anchors {
1067+ verticalCenter: parent.verticalCenter
1068+ left: parent.left
1069+ }
1070+ height: units.gu(2)
1071+ width: height
1072+ name: "tick"
1073+ color: "#3EB34F"
1074+ visible: isActive
1075+ }
1076
1077 Label {
1078 anchors {
1079 verticalCenter: parent.verticalCenter
1080- left: parent.left
1081- leftMargin: units.gu(2)
1082- right: rightIcon.visible ? rightIcon.left : parent.right
1083- rightMargin: rightIcon.visible ? units.gu(0.5) : units.gu(2)
1084+ left: leftIcon.right
1085+ leftMargin: units.gu(1)
1086+ right: rightIcon.left
1087+ rightMargin: units.gu(2)
1088 }
1089 text: label
1090- color: root.foregroundColor
1091+ color: isActive ? "#333333" : "#888888"
1092 wrapMode: Text.Wrap
1093 maximumLineCount: 2
1094 elide: Text.ElideMiddle
1095@@ -152,14 +98,14 @@
1096 anchors {
1097 verticalCenter: parent.verticalCenter
1098 right: parent.right
1099- rightMargin: units.gu(2)
1100 }
1101 height: units.gu(2)
1102 width: height
1103- name: hasChildren ? "go-next" : "tick"
1104- color: root.foregroundColor
1105- visible: hasChildren || isActive
1106+ name: "go-next"
1107+ visible: hasChildren
1108 }
1109+
1110+ divider.visible: index != navigation.count - 1
1111 }
1112 }
1113 }
1114
1115=== modified file 'qml/Dash/DashPageHeader.qml'
1116--- qml/Dash/DashPageHeader.qml 2016-01-25 10:48:16 +0000
1117+++ qml/Dash/DashPageHeader.qml 2016-03-21 16:06:44 +0000
1118@@ -17,41 +17,45 @@
1119 import QtQuick 2.4
1120 import Ubuntu.Components 1.3
1121 import Ubuntu.Components.Themes.Ambiance 1.3
1122-import Ubuntu.Components.Popups 1.3
1123 import Ubuntu.Components.ListItems 1.3
1124 import "../Components"
1125-import "../Components/SearchHistoryModel"
1126
1127 Item {
1128 id: root
1129 objectName: "pageHeader"
1130- implicitHeight: headerContainer.height + bottomContainer.height + (showSignatureLine ? units.gu(2) : 0)
1131+ implicitHeight: headerContainer.height + signatureLineHeight
1132+ readonly property real signatureLineHeight: showSignatureLine ? units.gu(2) : 0
1133
1134+ property int activeFiltersCount: 0
1135+ property bool scopeHasFilters: false
1136 property bool showBackButton: false
1137 property bool backIsClose: false
1138 property string title
1139+ property var extraPanel
1140+ property string navigationTag
1141
1142 property bool storeEntryEnabled: false
1143 property bool searchEntryEnabled: false
1144 property bool settingsEnabled: false
1145 property bool favoriteEnabled: false
1146 property bool favorite: false
1147- property ListModel searchHistory: SearchHistoryModel
1148+ property ListModel searchHistory
1149 property alias searchQuery: searchTextField.text
1150 property alias searchHint: searchTextField.placeholderText
1151 property bool showSignatureLine: true
1152
1153- property alias bottomItem: bottomContainer.children
1154 property int paginationCount: 0
1155 property int paginationIndex: -1
1156
1157 property var scopeStyle: null
1158
1159+ signal clearSearch(bool keepPanelOpen)
1160 signal backClicked()
1161 signal storeClicked()
1162 signal settingsClicked()
1163 signal favoriteClicked()
1164 signal searchTextFieldFocused()
1165+ signal showFiltersPopup(var item)
1166
1167 onScopeStyleChanged: refreshLogo()
1168 onSearchQueryChanged: {
1169@@ -60,6 +64,12 @@
1170 headerContainer.showSearch = true;
1171 }
1172 }
1173+ onNavigationTagChanged: {
1174+ // Make sure we are at the search page if the navigation tag changes behind our feet
1175+ if (navigationTag) {
1176+ headerContainer.showSearch = true;
1177+ }
1178+ }
1179
1180 function triggerSearch() {
1181 if (searchEntryEnabled) {
1182@@ -69,12 +79,14 @@
1183 }
1184
1185 function closePopup(keepFocus) {
1186- if (headerContainer.popover != null) {
1187- headerContainer.popover.unfocusOnDestruction = !keepFocus;
1188- PopupUtils.close(headerContainer.popover);
1189+ if (extraPanel.visible) {
1190+ extraPanel.visible = false;
1191 } else if (!keepFocus) {
1192 unfocus();
1193 }
1194+ if (!searchTextField.text && !root.navigationTag && searchHistory.count == 0) {
1195+ headerContainer.showSearch = false;
1196+ }
1197 }
1198
1199 function resetSearch(keepFocus) {
1200@@ -87,22 +99,17 @@
1201
1202 function unfocus() {
1203 searchTextField.focus = false;
1204- if (!searchTextField.text) {
1205+ if (!searchTextField.text && !root.navigationTag) {
1206 headerContainer.showSearch = false;
1207 }
1208 }
1209
1210- function openSearchHistory() {
1211+ function openPopup() {
1212 if (openSearchAnimation.running) {
1213- openSearchAnimation.openSearchHistory = true;
1214- } else if (root.searchHistory.count > 0 && headerContainer.popover == null) {
1215- headerContainer.popover = PopupUtils.open(popoverComponent, searchTextField,
1216- {
1217- "contentWidth": searchTextField.width,
1218- "edgeMargins": units.gu(1)
1219- }
1220- );
1221- searchTextField.forceActiveFocus();
1222+ openSearchAnimation.openPopup = true;
1223+ } else if (extraPanel.hasContents) {
1224+ // Show extraPanel
1225+ extraPanel.visible = true;
1226 }
1227 }
1228
1229@@ -121,13 +128,11 @@
1230 }
1231
1232 InverseMouseArea {
1233- anchors { fill: parent; margins: units.gu(1); bottomMargin: units.gu(3) + bottomContainer.height }
1234+ anchors { fill: parent; margins: units.gu(1); bottomMargin: units.gu(3) + (extraPanel ? extraPanel.height : 0) }
1235 visible: headerContainer.showSearch
1236 onPressed: {
1237+ extraPanel.visible = false;
1238 closePopup(/* keepFocus */false);
1239- if (!searchTextField.text) {
1240- headerContainer.showSearch = false;
1241- }
1242 mouse.accepted = false;
1243 }
1244 }
1245@@ -143,7 +148,6 @@
1246 contentY: showSearch ? 0 : height
1247
1248 property bool showSearch: false
1249- property var popover: null
1250
1251 Background {
1252 id: background
1253@@ -154,12 +158,12 @@
1254 Behavior on contentY {
1255 UbuntuNumberAnimation {
1256 id: openSearchAnimation
1257- property bool openSearchHistory: false
1258+ property bool openPopup: false
1259
1260 onRunningChanged: {
1261- if (!running && openSearchAnimation.openSearchHistory) {
1262- openSearchAnimation.openSearchHistory = false;
1263- root.openSearchHistory();
1264+ if (!running && openSearchAnimation.openPopup) {
1265+ openSearchAnimation.openPopup = false;
1266+ root.openPopup();
1267 }
1268 }
1269 }
1270@@ -183,61 +187,123 @@
1271 backgroundColor: "transparent"
1272 config: PageHeadConfiguration {
1273 foregroundColor: root.scopeStyle ? root.scopeStyle.headerForeground : theme.palette.normal.baseText
1274- backAction: Action {
1275- iconName: "back"
1276- onTriggered: {
1277- root.resetSearch();
1278+ }
1279+ property var contents: Item {
1280+ anchors.fill: parent
1281+
1282+ TextField {
1283+ id: searchTextField
1284+ objectName: "searchTextField"
1285+ inputMethodHints: Qt.ImhNoPredictiveText
1286+ hasClearButton: false
1287+ anchors {
1288+ top: parent.top
1289+ topMargin: units.gu(1)
1290+ left: parent.left
1291+ bottom: parent.bottom
1292+ bottomMargin: units.gu(1)
1293+ right: settingsButton.left
1294+ rightMargin: settingsButton.visible ? 0 : units.gu(2)
1295+ }
1296+
1297+ primaryItem: Rectangle {
1298+ color: "#F5F4F5"
1299+ width: root.navigationTag != "" ? tagLabel.width + units.gu(2) : 0
1300+ height: root.navigationTag != "" ? tagLabel.height + units.gu(1) : 0
1301+ radius: units.gu(0.5)
1302+ Label {
1303+ id: tagLabel
1304+ text: root.navigationTag
1305+ anchors.centerIn: parent
1306+ color: "#333333"
1307+ }
1308+ }
1309+
1310+ secondaryItem: AbstractButton {
1311+ id: clearButton
1312+ height: searchTextField.height
1313+ width: height
1314+ enabled: searchTextField.text.length > 0 || root.navigationTag != ""
1315+
1316+ Image {
1317+ objectName: "clearIcon"
1318+ anchors.fill: parent
1319+ anchors.margins: units.gu(1)
1320+ source: "image://theme/clear"
1321+ opacity: parent.enabled
1322+ visible: opacity > 0
1323+ Behavior on opacity {
1324+ UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
1325+ }
1326+ }
1327+
1328+ onClicked: {
1329+ root.clearSearch(true);
1330+ }
1331+ }
1332+
1333+ onActiveFocusChanged: {
1334+ if (activeFocus) {
1335+ root.searchTextFieldFocused();
1336+ root.openPopup();
1337+ }
1338+ }
1339+
1340+ onTextChanged: {
1341+ if (text != "") {
1342+ closePopup(/* keepFocus */true);
1343+ }
1344+ }
1345+ }
1346+
1347+ AbstractButton {
1348+ id: settingsButton
1349+
1350+ width: root.scopeHasFilters ? height : 0
1351+ visible: width > 0
1352+ anchors {
1353+ top: parent.top
1354+ right: cancelButton.left
1355+ bottom: parent.bottom
1356+ rightMargin: units.gu(-1)
1357+ }
1358+
1359+ Icon {
1360+ anchors.fill: parent
1361+ anchors.margins: units.gu(2)
1362+ name: "filters"
1363+ color: root.activeFiltersCount > 0 ? UbuntuColors.orange : Qt.rgba(0.0, 0.0, 0.0, 0.0)
1364+ }
1365+
1366+ onClicked: {
1367+ root.showFiltersPopup(settingsButton);
1368+ }
1369+ }
1370+
1371+ AbstractButton {
1372+ id: cancelButton
1373+ width: cancelLabel.width + cancelLabel.anchors.rightMargin + cancelLabel.anchors.leftMargin
1374+ anchors {
1375+ top: parent.top
1376+ right: parent.right
1377+ bottom: parent.bottom
1378+ }
1379+ onClicked: {
1380+ root.clearSearch(false);
1381 headerContainer.showSearch = false;
1382 }
1383- }
1384- }
1385- property var contents: TextField {
1386- id: searchTextField
1387- objectName: "searchTextField"
1388- inputMethodHints: Qt.ImhNoPredictiveText
1389- hasClearButton: false
1390- anchors {
1391- fill: parent
1392- leftMargin: units.gu(1)
1393- topMargin: units.gu(1)
1394- bottomMargin: units.gu(1)
1395- rightMargin: root.width > units.gu(60) ? root.width - units.gu(40) : units.gu(1)
1396- }
1397-
1398- secondaryItem: AbstractButton {
1399- height: searchTextField.height
1400- width: height
1401- enabled: searchTextField.text.length > 0
1402-
1403- Image {
1404- objectName: "clearIcon"
1405- anchors.fill: parent
1406- anchors.margins: units.gu(.75)
1407- source: "image://theme/clear"
1408- opacity: searchTextField.text.length > 0
1409- visible: opacity > 0
1410- Behavior on opacity {
1411- UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
1412+ Label {
1413+ id: cancelLabel
1414+ text: i18n.tr("Cancel")
1415+ color: header.panelForegroundColor
1416+ verticalAlignment: Text.AlignVCenter
1417+ anchors {
1418+ verticalCenter: parent.verticalCenter
1419+ right: parent.right
1420+ rightMargin: units.gu(2)
1421+ leftMargin: units.gu(1)
1422 }
1423 }
1424-
1425- onClicked: {
1426- root.resetSearch(true);
1427- root.openSearchHistory();
1428- }
1429- }
1430-
1431- onActiveFocusChanged: {
1432- if (activeFocus) {
1433- root.searchTextFieldFocused();
1434- root.openSearchHistory();
1435- }
1436- }
1437-
1438- onTextChanged: {
1439- if (text != "") {
1440- closePopup(/* keepFocus */true);
1441- }
1442 }
1443 }
1444 }
1445@@ -322,47 +388,6 @@
1446 }
1447 }
1448
1449- Component {
1450- id: popoverComponent
1451- Popover {
1452- id: popover
1453- autoClose: false
1454-
1455- property bool unfocusOnDestruction: false
1456-
1457- Component.onDestruction: {
1458- headerContainer.popover = null;
1459- if (unfocusOnDestruction) {
1460- root.unfocus();
1461- }
1462- }
1463-
1464- Column {
1465- anchors {
1466- top: parent.top
1467- left: parent.left
1468- right: parent.right
1469- }
1470-
1471- Repeater {
1472- id: recentSearches
1473- objectName: "recentSearches"
1474- model: searchHistory
1475-
1476- delegate: Standard {
1477- showDivider: index < recentSearches.count - 1
1478- text: query
1479- onClicked: {
1480- searchHistory.addQuery(text);
1481- searchTextField.text = text;
1482- closePopup(/* keepFocus */false);
1483- }
1484- }
1485- }
1486- }
1487- }
1488- }
1489-
1490 Rectangle {
1491 id: bottomBorder
1492 visible: showSignatureLine
1493@@ -370,7 +395,7 @@
1494 top: headerContainer.bottom
1495 left: parent.left
1496 right: parent.right
1497- bottom: bottomContainer.top
1498+ bottom: parent.bottom
1499 }
1500
1501 color: root.scopeStyle ? root.scopeStyle.headerDividerColor : "#e0e0e0"
1502@@ -411,7 +436,7 @@
1503 id: bottomHighlight
1504 visible: bottomBorder.visible
1505 anchors {
1506- top: bottomContainer.top
1507+ top: parent.bottom
1508 left: parent.left
1509 right: parent.right
1510 }
1511@@ -419,30 +444,13 @@
1512 height: units.dp(1)
1513 opacity: 0.6
1514
1515- // FIXME this should be a shader when bottomItem exists
1516- // to support image backgrounds
1517 Rectangle {
1518 anchors.fill: parent
1519- color: if (bottomItem && bottomItem.background) {
1520- Qt.lighter(Qt.rgba(bottomItem.background.topColor.r,
1521- bottomItem.background.topColor.g,
1522- bottomItem.background.topColor.b, 1.0), 1.2);
1523- } else if (!bottomItem && root.scopeStyle) {
1524+ color: if (root.scopeStyle) {
1525 Qt.lighter(Qt.rgba(root.scopeStyle.background.r,
1526 root.scopeStyle.background.g,
1527 root.scopeStyle.background.b, 1.0), 1.2);
1528 } else "#CCFFFFFF"
1529 }
1530 }
1531-
1532- Item {
1533- id: bottomContainer
1534-
1535- anchors {
1536- left: parent.left
1537- right: parent.right
1538- bottom: parent.bottom
1539- }
1540- height: childrenRect.height
1541- }
1542 }
1543
1544=== modified file 'qml/Dash/DashRenderer.qml'
1545--- qml/Dash/DashRenderer.qml 2015-07-15 15:07:19 +0000
1546+++ qml/Dash/DashRenderer.qml 2016-03-21 16:06:44 +0000
1547@@ -57,4 +57,10 @@
1548 /// @param result result model of the clicked item, used for activation
1549 /// @param itemModel model of the item
1550 signal pressAndHold(int index, var result, var itemModel)
1551+
1552+ /// Emitted when the user clicked on an item action
1553+ /// @param index is the index of the clicked item
1554+ /// @param result result model of the clicked item, used for activation
1555+ /// @param actionId id of the clicked action
1556+ signal action(int index, var result, var actionId)
1557 }
1558
1559=== added directory 'qml/Dash/Filters'
1560=== added file 'qml/Dash/Filters/FilterOptionSelector.qml'
1561--- qml/Dash/Filters/FilterOptionSelector.qml 1970-01-01 00:00:00 +0000
1562+++ qml/Dash/Filters/FilterOptionSelector.qml 2016-03-21 16:06:44 +0000
1563@@ -0,0 +1,91 @@
1564+/*
1565+ * Copyright (C) 2015 Canonical, Ltd.
1566+ *
1567+ * This program is free software; you can redistribute it and/or modify
1568+ * it under the terms of the GNU General Public License as published by
1569+ * the Free Software Foundation; version 3.
1570+ *
1571+ * This program is distributed in the hope that it will be useful,
1572+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1573+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1574+ * GNU General Public License for more details.
1575+ *
1576+ * You should have received a copy of the GNU General Public License
1577+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1578+ */
1579+
1580+import QtQuick 2.4
1581+import Ubuntu.Components 1.3
1582+import Ubuntu.Components.ListItems 1.3 as ListItems
1583+
1584+/*! Option Selector Filter Widget. */
1585+
1586+FilterWidget {
1587+ id: root
1588+
1589+ implicitHeight: expandingItem.height
1590+
1591+ ListItems.Expandable {
1592+ id: expandingItem
1593+ objectName: "expandingItem"
1594+
1595+ expandedHeight: collapsedHeight + column.height
1596+ width: parent.width
1597+ showDivider: false
1598+
1599+ onClicked: {
1600+ expanded = !expanded;
1601+ forceActiveFocus();
1602+ }
1603+
1604+ Item {
1605+ id: holder
1606+ anchors.top: parent.top
1607+ height: expandingItem.collapsedHeight
1608+ width: parent.width
1609+
1610+ Label {
1611+ anchors.left: parent.left
1612+ anchors.right: dropDown.left
1613+ anchors.verticalCenter: parent.verticalCenter
1614+ text: widgetData.label || ""
1615+ }
1616+
1617+ Image {
1618+ id: dropDown
1619+ height: units.gu(3)
1620+ fillMode: Image.PreserveAspectFit
1621+ anchors.right: parent.right
1622+ anchors.verticalCenter: parent.verticalCenter
1623+ source: expandingItem.expanded ? "image://theme/up" : "image://theme/down"
1624+ }
1625+ }
1626+
1627+ Column {
1628+ id: column
1629+ anchors.top: holder.bottom
1630+ width: parent.width
1631+ Repeater {
1632+ model: widgetData.options
1633+
1634+ ListItems.Standard {
1635+ text: label
1636+ objectName: root.objectName + "label" + index;
1637+
1638+ Image {
1639+ height: units.gu(3)
1640+ fillMode: Image.PreserveAspectFit
1641+ anchors.right: parent.right
1642+ anchors.verticalCenter: parent.verticalCenter
1643+ source: "image://theme/tick"
1644+ visible: checked
1645+ }
1646+
1647+ onClicked: {
1648+ widgetData.options.setChecked(index, !checked);
1649+ }
1650+ }
1651+ }
1652+ }
1653+ }
1654+}
1655
1656=== added file 'qml/Dash/Filters/FilterRangeInput.qml'
1657--- qml/Dash/Filters/FilterRangeInput.qml 1970-01-01 00:00:00 +0000
1658+++ qml/Dash/Filters/FilterRangeInput.qml 2016-03-21 16:06:44 +0000
1659@@ -0,0 +1,136 @@
1660+/*
1661+ * Copyright (C) 2015 Canonical, Ltd.
1662+ *
1663+ * This program is free software; you can redistribute it and/or modify
1664+ * it under the terms of the GNU General Public License as published by
1665+ * the Free Software Foundation; version 3.
1666+ *
1667+ * This program is distributed in the hope that it will be useful,
1668+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1669+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1670+ * GNU General Public License for more details.
1671+ *
1672+ * You should have received a copy of the GNU General Public License
1673+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1674+ */
1675+
1676+import QtQuick 2.4
1677+import QtQuick.Layouts 1.1
1678+import Ubuntu.Components 1.3
1679+
1680+/*! Range Input Filter Widget. */
1681+
1682+FilterWidget {
1683+ id: root
1684+
1685+ implicitHeight: field1.height + units.gu(2)
1686+
1687+ function setFieldValue(field, hasValue, value) {
1688+ if (hasValue) {
1689+ // Need this othewise if we are on 4.5 and backspace instead of
1690+ // having 4. in the text field we end up with 4 which is confusing
1691+ if (field.text != value) {
1692+ field.text = value;
1693+ }
1694+ } else {
1695+ field.text = "";
1696+ }
1697+ }
1698+
1699+ Connections {
1700+ target: widgetData
1701+ onStartValueChanged: root.setFieldValue(field1, widgetData.hasStartValue, widgetData.startValue);
1702+ onHasStartValueChanged: root.setFieldValue(field1, widgetData.hasStartValue, widgetData.startValue);
1703+ onEndValueChanged: root.setFieldValue(field2, widgetData.hasEndValue, widgetData.endValue);
1704+ onHasEndValueChanged: root.setFieldValue(field2, widgetData.hasEndValue, widgetData.endValue);
1705+ }
1706+
1707+ onWidgetDataChanged: {
1708+ if (widgetData) {
1709+ root.setFieldValue(field1, widgetData.hasStartValue, widgetData.startValue);
1710+ root.setFieldValue(field2, widgetData.hasEndValue, widgetData.endValue);
1711+ } else {
1712+ root.setFieldValue(field1, false, -1);
1713+ root.setFieldValue(field2, false, -1);
1714+ }
1715+ }
1716+
1717+ RowLayout {
1718+ anchors {
1719+ fill: parent
1720+ topMargin: units.gu(1)
1721+ bottomMargin: units.gu(1)
1722+ }
1723+
1724+ Item {
1725+ Layout.fillWidth: true
1726+ }
1727+
1728+ Label {
1729+ text: widgetData.startPrefixLabel
1730+ verticalAlignment: Text.AlignVCenter
1731+ }
1732+
1733+ TextField {
1734+ id: field1
1735+ objectName: "startValueField"
1736+ implicitWidth: units.gu(9)
1737+ verticalAlignment: Text.AlignVCenter
1738+ inputMethodHints: Qt.ImhFormattedNumbersOnly
1739+ validator: DoubleValidator {
1740+ notation: DoubleValidator.StandardNotation
1741+ }
1742+ onTextChanged: {
1743+ if (text === "") widgetData.eraseStartValue();
1744+ else widgetData.startValue = text;
1745+ }
1746+ }
1747+
1748+ Label {
1749+ text: widgetData.startPostfixLabel
1750+ verticalAlignment: Text.AlignVCenter
1751+ }
1752+
1753+ Item {
1754+ Layout.fillWidth: true
1755+ }
1756+
1757+ Label {
1758+ text: widgetData.centralLabel
1759+ verticalAlignment: Text.AlignVCenter
1760+ }
1761+
1762+ Item {
1763+ Layout.fillWidth: true
1764+ }
1765+
1766+ Label {
1767+ text: widgetData.endPrefixLabel
1768+ verticalAlignment: Text.AlignVCenter
1769+ }
1770+
1771+ TextField {
1772+ id: field2
1773+ objectName: "endValueField"
1774+ implicitWidth: units.gu(9)
1775+ verticalAlignment: Text.AlignVCenter
1776+ inputMethodHints: Qt.ImhFormattedNumbersOnly
1777+ validator: DoubleValidator {
1778+ notation: DoubleValidator.StandardNotation
1779+ }
1780+ onTextChanged: {
1781+ if (text === "") widgetData.eraseEndValue();
1782+ else widgetData.endValue = text;
1783+ }
1784+ }
1785+
1786+ Label {
1787+ text: widgetData.endPostfixLabel
1788+ verticalAlignment: Text.AlignVCenter
1789+ }
1790+
1791+ Item {
1792+ Layout.fillWidth: true
1793+ }
1794+ }
1795+}
1796
1797=== added file 'qml/Dash/Filters/FilterValueSlider.qml'
1798--- qml/Dash/Filters/FilterValueSlider.qml 1970-01-01 00:00:00 +0000
1799+++ qml/Dash/Filters/FilterValueSlider.qml 2016-03-21 16:06:44 +0000
1800@@ -0,0 +1,87 @@
1801+/*
1802+ * Copyright (C) 2015 Canonical, Ltd.
1803+ *
1804+ * This program is free software; you can redistribute it and/or modify
1805+ * it under the terms of the GNU General Public License as published by
1806+ * the Free Software Foundation; version 3.
1807+ *
1808+ * This program is distributed in the hope that it will be useful,
1809+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1810+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1811+ * GNU General Public License for more details.
1812+ *
1813+ * You should have received a copy of the GNU General Public License
1814+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1815+ */
1816+
1817+import QtQuick 2.4
1818+import QtQuick.Layouts 1.1
1819+import Ubuntu.Components 1.3
1820+
1821+/*! Value Slider Filter Widget. */
1822+
1823+FilterWidget {
1824+ id: root
1825+
1826+ implicitHeight: childrenRect.height + units.gu(2)
1827+
1828+ Connections {
1829+ target: widgetData
1830+ // One would think that this is not needed since
1831+ // we have value: widgetData.value on the slider
1832+ // but it is, otherwise reset doesn't seem to work
1833+ onValueChanged: {
1834+ if (widgetData.value !== slider.value) {
1835+ slider.value = widgetData.value;
1836+ }
1837+ }
1838+ }
1839+
1840+ Slider {
1841+ id: slider
1842+ objectName: "slider"
1843+
1844+ anchors {
1845+ top: parent.top
1846+ topMargin: units.gu(1)
1847+ left: parent.left
1848+ leftMargin: units.gu(2)
1849+ right: parent.right
1850+ rightMargin: units.gu(2)
1851+ }
1852+
1853+ minimumValue: widgetData.minValue
1854+ maximumValue: widgetData.maxValue
1855+ value: widgetData.value
1856+ onValueChanged: {
1857+ widgetData.value = value;
1858+ }
1859+ onPressedChanged: {
1860+ if (pressed) forceActiveFocus();
1861+ }
1862+
1863+ readonly property Item thumb: __internals.thumb
1864+ readonly property real barMinusThumb: __internals.barMinusThumb
1865+ }
1866+
1867+ Repeater {
1868+ objectName: "repeater"
1869+ model: widgetData.values
1870+ delegate: Label {
1871+ anchors {
1872+ top: slider.bottom
1873+ // The slider is too tall, so move a bit up
1874+ topMargin: -units.gu(1)
1875+ }
1876+ text: label
1877+ visible: value <= widgetData.maxValue && value >= widgetData.minValue
1878+ x: {
1879+ var halfThumbDifference = (width - slider.thumb.width) / 2;
1880+ var result = (value - widgetData.minValue) * slider.barMinusThumb / (widgetData.maxValue - widgetData.minValue) - halfThumbDifference;
1881+ result = Math.max(result, 0);
1882+ result = Math.min(result, slider.width - width);
1883+ return units.gu(2) + result;
1884+ }
1885+ }
1886+ }
1887+}
1888
1889=== added file 'qml/Dash/Filters/FilterWidget.qml'
1890--- qml/Dash/Filters/FilterWidget.qml 1970-01-01 00:00:00 +0000
1891+++ qml/Dash/Filters/FilterWidget.qml 2016-03-21 16:06:44 +0000
1892@@ -0,0 +1,29 @@
1893+/*
1894+ * Copyright (C) 2015 Canonical, Ltd.
1895+ *
1896+ * This program is free software; you can redistribute it and/or modify
1897+ * it under the terms of the GNU General Public License as published by
1898+ * the Free Software Foundation; version 3.
1899+ *
1900+ * This program is distributed in the hope that it will be useful,
1901+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1902+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1903+ * GNU General Public License for more details.
1904+ *
1905+ * You should have received a copy of the GNU General Public License
1906+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1907+ */
1908+
1909+import QtQuick 2.4
1910+
1911+/*! Interface for filter widgets. */
1912+
1913+Item {
1914+ //! The widget identifier
1915+ property string widgetId
1916+
1917+ //! Variable used to contain widget's data
1918+ property var widgetData: null
1919+
1920+ objectName: widgetId
1921+}
1922
1923=== added file 'qml/Dash/Filters/FilterWidgetFactory.qml'
1924--- qml/Dash/Filters/FilterWidgetFactory.qml 1970-01-01 00:00:00 +0000
1925+++ qml/Dash/Filters/FilterWidgetFactory.qml 2016-03-21 16:06:44 +0000
1926@@ -0,0 +1,79 @@
1927+/*
1928+ * Copyright (C) 2015 Canonical, Ltd.
1929+ *
1930+ * This program is free software; you can redistribute it and/or modify
1931+ * it under the terms of the GNU General Public License as published by
1932+ * the Free Software Foundation; version 3.
1933+ *
1934+ * This program is distributed in the hope that it will be useful,
1935+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1936+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1937+ * GNU General Public License for more details.
1938+ *
1939+ * You should have received a copy of the GNU General Public License
1940+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1941+ */
1942+
1943+import QtQuick 2.4
1944+import Ubuntu.Components 1.3
1945+import Unity 0.2
1946+
1947+//! \brief This component loads the widgets based on widgetType.
1948+
1949+Item {
1950+ id: root
1951+ //! Identifier of the widget.
1952+ property string widgetId: ""
1953+
1954+ //! Type of the widget to display.
1955+ property int widgetType
1956+
1957+ //! Widget data, forwarded to the widget as is.
1958+ property var widgetData: null
1959+
1960+ implicitHeight: title.height + title.anchors.topMargin + loader.height
1961+
1962+ Label {
1963+ id: title
1964+ text: widgetData ? widgetData.title : ""
1965+ height: text != "" ? implicitHeight : 0
1966+
1967+ anchors {
1968+ top: parent.top
1969+ left: parent.left
1970+ right: parent.right
1971+
1972+ topMargin: height > 0 ? units.gu(1) : 0
1973+ leftMargin: units.gu(2)
1974+ rightMargin: anchors.leftMargin
1975+ }
1976+ }
1977+
1978+ property alias active: loader.active
1979+
1980+ Loader {
1981+ id: loader
1982+
1983+ anchors {
1984+ top: title.bottom
1985+ left: parent.left
1986+ right: parent.right
1987+ }
1988+
1989+ source: widgetSource
1990+
1991+ readonly property url widgetSource: {
1992+ switch (widgetType) {
1993+ case Filters.OptionSelectorFilter: return "FilterOptionSelector.qml";
1994+ case Filters.RangeInputFilter: return "FilterRangeInput.qml";
1995+ case Filters.ValueSliderFilter: return "FilterValueSlider.qml";
1996+ default: return "";
1997+ }
1998+ }
1999+
2000+ onLoaded: {
2001+ item.widgetId = Qt.binding(function() { return root.widgetId } )
2002+ item.widgetData = Qt.binding(function() { return root.widgetData } )
2003+ }
2004+ }
2005+}
2006
2007=== added file 'qml/Dash/FiltersPopover.qml'
2008--- qml/Dash/FiltersPopover.qml 1970-01-01 00:00:00 +0000
2009+++ qml/Dash/FiltersPopover.qml 2016-03-21 16:06:44 +0000
2010@@ -0,0 +1,105 @@
2011+/*
2012+ * Copyright (C) 2013-2015 Canonical, Ltd.
2013+ *
2014+ * This program is free software; you can redistribute it and/or modify
2015+ * it under the terms of the GNU General Public License as published by
2016+ * the Free Software Foundation; version 3.
2017+ *
2018+ * This program is distributed in the hope that it will be useful,
2019+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2020+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2021+ * GNU General Public License for more details.
2022+ *
2023+ * You should have received a copy of the GNU General Public License
2024+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2025+ */
2026+
2027+import QtQuick 2.4
2028+import Ubuntu.Components 1.3
2029+import Ubuntu.Components.Popups 1.3
2030+import Ubuntu.Components.ListItems 1.3 as ListItems
2031+import "Filters" as Filters
2032+
2033+Popover {
2034+ id: root
2035+ objectName: "filtersPopover"
2036+
2037+ Flickable {
2038+ id: flickable
2039+ anchors {
2040+ top: parent.top
2041+ left: parent.left
2042+ right: parent.right
2043+ }
2044+ height: {
2045+ // Popover doesn't like being 75% or bigger than the screen (counting the "empty" part on top)
2046+ var posToRootParent = flickable.mapToItem(null, 0, 0).y;
2047+ var threeQuartersParent = root.parent.height * 3 / 4 - posToRootParent - 1;
2048+ var parentAndKeyboard = root.parent.height - posToRootParent - (Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height + units.gu(3) : 0)
2049+ return Math.min(parentAndKeyboard, Math.min(threeQuartersParent, column.height));
2050+ }
2051+ clip: true
2052+ contentHeight: column.height
2053+ contentWidth: width
2054+
2055+ Column {
2056+ id: column
2057+ width: parent.width
2058+
2059+ Item {
2060+ width: parent.width
2061+ height: resetLabel.height + units.gu(3)
2062+
2063+ Label {
2064+ anchors {
2065+ left: parent.left
2066+ right: resetLabel.left
2067+ margins: units.gu(2)
2068+ verticalCenter: parent.verticalCenter
2069+ }
2070+ text: i18n.tr("Refine your results")
2071+ }
2072+ Label {
2073+ id: resetLabel
2074+ anchors {
2075+ right: parent.right
2076+ rightMargin: units.gu(2)
2077+ verticalCenter: parent.verticalCenter
2078+ }
2079+ text: i18n.tr("Reset")
2080+
2081+ AbstractButton {
2082+ anchors {
2083+ fill: parent
2084+ rightMargin: units.gu(-2)
2085+ leftMargin: units.gu(-2)
2086+ topMargin: units.gu(-1)
2087+ bottomMargin: units.gu(-1)
2088+ }
2089+ onClicked: {
2090+ scopeView.scope.resetFilters();
2091+ }
2092+ }
2093+ }
2094+ }
2095+
2096+ Repeater {
2097+ id: repeater
2098+ model: scopeView.scope.filters
2099+
2100+ delegate: Filters.FilterWidgetFactory {
2101+ width: parent.width
2102+
2103+ widgetId: id
2104+ widgetType: type
2105+ widgetData: filter
2106+
2107+ ListItems.ThinDivider {
2108+ anchors.bottom: parent.bottom
2109+ visible: index != repeater.count - 1
2110+ }
2111+ }
2112+ }
2113+ }
2114+ }
2115+}
2116
2117=== modified file 'qml/Dash/GenericScopeView.qml'
2118--- qml/Dash/GenericScopeView.qml 2016-03-10 22:39:17 +0000
2119+++ qml/Dash/GenericScopeView.qml 2016-03-21 16:06:44 +0000
2120@@ -16,6 +16,8 @@
2121
2122 import QtQuick 2.4
2123 import Ubuntu.Components 1.3
2124+import Ubuntu.Components.Popups 1.3
2125+import "../Components/SearchHistoryModel"
2126 import Utils 0.1
2127 import Unity 0.2
2128 import Dash 0.1
2129@@ -25,7 +27,6 @@
2130 FocusScope {
2131 id: scopeView
2132
2133- readonly property bool navigationDisableParentInteractive: pageHeaderLoader.item ? pageHeaderLoader.item.bottomItem[0].disableParentInteractive : false
2134 property bool forceNonInteractive: false
2135 property var scope: null
2136 property UnitySortFilterProxyModel categories: categoryFilter
2137@@ -34,14 +35,15 @@
2138 property bool hasBackAction: false
2139 property bool enableHeightBehaviorOnNextCreation: false
2140 property var categoryView: categoryView
2141- property bool showPageHeader: true
2142 readonly property alias subPageShown: subPageLoader.subPageShown
2143+ readonly property alias extraPanelShown: peExtraPanel.visible
2144 property int paginationCount: 0
2145 property int paginationIndex: 0
2146 property bool visibleToParent: false
2147 property alias pageHeaderTotallyVisible: categoryView.pageHeaderTotallyVisible
2148 property var holdingList: null
2149 property bool wasCurrentOnMoveStart: false
2150+ property var filtersPopover: null
2151
2152 property var scopeStyle: ScopeStyle {
2153 style: scope ? scope.customizations : {}
2154@@ -68,8 +70,7 @@
2155 }
2156
2157 function resetSearch() {
2158- if(pageHeaderLoader.item && showPageHeader)
2159- pageHeaderLoader.item.resetSearch()
2160+ categoryView.pageHeader.resetSearch()
2161 }
2162
2163 property var maybePreviewResult;
2164@@ -120,24 +121,26 @@
2165 if (!holdingList || !holdingList.moving) {
2166 wasCurrentOnMoveStart = scopeView.isCurrent;
2167 }
2168- if (pageHeaderLoader.item && showPageHeader) {
2169- pageHeaderLoader.item.resetSearch();
2170- }
2171+ categoryView.pageHeader.resetSearch();
2172 subPageLoader.closeSubPage();
2173+ if (filtersPopover) {
2174+ PopupUtils.close(filtersPopover)
2175+ scopeView.filtersPopover = null;
2176+ }
2177 }
2178
2179 Binding {
2180 target: scopeView.scope
2181 property: "searchQuery"
2182- value: pageHeaderLoader.item ? pageHeaderLoader.item.searchQuery : ""
2183- when: isCurrent && showPageHeader
2184+ value: categoryView.pageHeader.searchQuery
2185+ when: isCurrent
2186 }
2187
2188 Binding {
2189- target: pageHeaderLoader.item
2190+ target: categoryView.pageHeader
2191 property: "searchQuery"
2192 value: scopeView.scope ? scopeView.scope.searchQuery : ""
2193- when: isCurrent && showPageHeader
2194+ when: isCurrent
2195 }
2196
2197 Connections {
2198@@ -189,8 +192,8 @@
2199 property string expandedCategoryId: ""
2200 property int runMaximizeAfterSizeChanges: 0
2201
2202- readonly property bool pageHeaderTotallyVisible: scopeView.showPageHeader &&
2203- ((headerItemShownHeight == 0 && categoryView.contentY <= categoryView.originY) || (headerItemShownHeight == pageHeaderLoader.item.height))
2204+ readonly property bool pageHeaderTotallyVisible:
2205+ ((headerItemShownHeight == 0 && categoryView.contentY <= categoryView.originY) || (headerItemShownHeight == categoryView.pageHeader.height))
2206
2207 onExpandedCategoryIdChanged: {
2208 var firstCreated = firstCreatedIndex();
2209@@ -387,6 +390,10 @@
2210 scopeView.itemPressedAndHeld(result, baseItem.category);
2211 }
2212
2213+ onAction: { // (int index, var result, var actionId)
2214+ scope.activateAction(result, baseItem.categoryId, actionId);
2215+ }
2216+
2217 function categoryItemCount() {
2218 var categoryItemCount = -1;
2219 if (!rendererLoader.expanded && !seeAllLabel.visible && target.collapsedItemCount > 0) {
2220@@ -615,41 +622,68 @@
2221 }
2222 }
2223
2224- pageHeader: scopeView.showPageHeader ? pageHeaderLoader : null
2225- Loader {
2226- id: pageHeaderLoader
2227+ pageHeader: DashPageHeader {
2228+ objectName: "scopePageHeader"
2229 width: parent.width
2230- sourceComponent: scopeView.showPageHeader ? pageHeaderComponent : undefined
2231- Component {
2232- id: pageHeaderComponent
2233- DashPageHeader {
2234- objectName: "scopePageHeader"
2235- width: parent.width
2236- title: scopeView.scope ? scopeView.scope.name : ""
2237- searchHint: scopeView.scope && scopeView.scope.searchHint || i18n.ctr("Label: Hint for dash search line edit", "Search")
2238- showBackButton: scopeView.hasBackAction
2239- searchEntryEnabled: true
2240- settingsEnabled: scopeView.scope && scopeView.scope.settings && scopeView.scope.settings.count > 0 || false
2241- favoriteEnabled: scopeView.scope && scopeView.scope.id !== "clickscope"
2242- favorite: scopeView.scope && scopeView.scope.favorite
2243- scopeStyle: scopeView.scopeStyle
2244- paginationCount: scopeView.paginationCount
2245- paginationIndex: scopeView.paginationIndex
2246-
2247- bottomItem: DashNavigation {
2248- scope: scopeView.scope
2249- anchors { left: parent.left; right: parent.right }
2250- windowHeight: scopeView.height
2251- windowWidth: scopeView.width
2252- scopeStyle: scopeView.scopeStyle
2253- }
2254-
2255- onBackClicked: scopeView.backClicked()
2256- onSettingsClicked: subPageLoader.openSubPage("settings")
2257- onFavoriteClicked: scopeView.scope.favorite = !scopeView.scope.favorite
2258- onSearchTextFieldFocused: scopeView.showHeader()
2259+ title: scopeView.scope ? scopeView.scope.name : ""
2260+ extraPanel: peExtraPanel
2261+ searchHistory: SearchHistoryModel
2262+ searchHint: scopeView.scope && scopeView.scope.searchHint || i18n.ctr("Label: Hint for dash search line edit", "Search")
2263+ scopeHasFilters: scopeView.scope.filters != null
2264+ activeFiltersCount: scopeView.scope.activeFiltersCount
2265+ showBackButton: scopeView.hasBackAction
2266+ searchEntryEnabled: true
2267+ settingsEnabled: scopeView.scope && scopeView.scope.settings && scopeView.scope.settings.count > 0 || false
2268+ favoriteEnabled: scopeView.scope && scopeView.scope.id !== "clickscope"
2269+ favorite: scopeView.scope && scopeView.scope.favorite
2270+ navigationTag: scopeView.scope ? scopeView.scope.primaryNavigationTag : ""
2271+ scopeStyle: scopeView.scopeStyle
2272+ paginationCount: scopeView.paginationCount
2273+ paginationIndex: scopeView.paginationIndex
2274+
2275+ onBackClicked: scopeView.backClicked()
2276+ onSettingsClicked: subPageLoader.openSubPage("settings")
2277+ onFavoriteClicked: scopeView.scope.favorite = !scopeView.scope.favorite
2278+ onSearchTextFieldFocused: scopeView.showHeader()
2279+ onClearSearch: { // keepPanelOpen
2280+ var panelOpen = peExtraPanel.visible;
2281+ resetSearch(keepPanelOpen);
2282+ scopeView.scope.resetPrimaryNavigationTag();
2283+ peExtraPanel.resetNavigation();
2284+ if ((panelOpen || searchHistory.count > 0) && keepPanelOpen) {
2285+ openPopup();
2286 }
2287 }
2288+ onShowFiltersPopup: { // item
2289+ extraPanel.visible = false;
2290+ scopeView.filtersPopover = PopupUtils.open(Qt.resolvedUrl("FiltersPopover.qml"), item, { "contentWidth": scopeView.width - units.gu(2) } );
2291+ }
2292+ }
2293+
2294+ PageHeaderExtraPanel {
2295+ id: peExtraPanel
2296+ objectName: "peExtraPanel"
2297+ width: parent.width >= units.gu(60) ? units.gu(40) : parent.width
2298+ anchors {
2299+ top: categoryView.pageHeader.bottom
2300+ topMargin: -categoryView.pageHeader.signatureLineHeight
2301+ }
2302+ z: 1
2303+ visible: false
2304+
2305+ searchHistory: SearchHistoryModel
2306+ scope: scopeView.scope
2307+ windowHeight: scopeView.height
2308+
2309+ onHistoryItemClicked: {
2310+ SearchHistoryModel.addQuery(text);
2311+ categoryView.pageHeader.searchQuery = text;
2312+ }
2313+
2314+ onDashNavigationLeafClicked: {
2315+ categoryView.pageHeader.closePopup();
2316+ categoryView.pageHeader.unfocus();
2317+ }
2318 }
2319 }
2320
2321@@ -658,7 +692,7 @@
2322 anchors.left: parent.left
2323 anchors.right: parent.right
2324 anchors.bottom: parent.bottom
2325- height: parent.height - pullToRefresh.contentY + (pageHeaderLoader.item ? pageHeaderLoader.item.bottomItem[0].height - pageHeaderLoader.item.height : 0)
2326+ height: parent.height - pullToRefresh.contentY - categoryView.pageHeader.height
2327 clip: true
2328
2329 PullToRefresh {
2330@@ -793,7 +827,7 @@
2331 open = true;
2332 }
2333
2334- onOpenChanged: pageHeaderLoader.item.unfocus()
2335+ onOpenChanged: categoryView.pageHeader.unfocus()
2336
2337 onVisibleChanged: if (!visible) subPage = ""
2338
2339
2340=== added file 'qml/Dash/PageHeaderExtraPanel.qml'
2341--- qml/Dash/PageHeaderExtraPanel.qml 1970-01-01 00:00:00 +0000
2342+++ qml/Dash/PageHeaderExtraPanel.qml 2016-03-21 16:06:44 +0000
2343@@ -0,0 +1,175 @@
2344+/*
2345+ * Copyright (C) 2013-2015 Canonical, Ltd.
2346+ *
2347+ * This program is free software; you can redistribute it and/or modify
2348+ * it under the terms of the GNU General Public License as published by
2349+ * the Free Software Foundation; version 3.
2350+ *
2351+ * This program is distributed in the hope that it will be useful,
2352+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2353+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2354+ * GNU General Public License for more details.
2355+ *
2356+ * You should have received a copy of the GNU General Public License
2357+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2358+ */
2359+
2360+import QtQuick 2.4
2361+import Ubuntu.Components 1.3
2362+import Ubuntu.Components.ListItems 1.3 as ListItems
2363+import "Filters" as Filters
2364+
2365+Item {
2366+ id: root
2367+
2368+ readonly property real searchesHeight: recentSearchesRepeater.count > 0 ? searchColumn.height + recentSearchesLabels.height + recentSearchesLabels.anchors.topMargin : 0
2369+
2370+ implicitHeight: searchesHeight + dashNavigation.implicitHeight + dashNavigation.anchors.topMargin + primaryFilter.height + primaryFilter.anchors.topMargin
2371+
2372+ // Set by parent
2373+ property ListModel searchHistory
2374+ property var scope: null
2375+ property real windowHeight
2376+
2377+ // Used by PageHeader
2378+ readonly property bool hasContents: searchHistory.count > 0 || scope && scope.hasNavigation || scope && scope.primaryNavigationFilter
2379+
2380+ signal historyItemClicked(string text)
2381+ signal dashNavigationLeafClicked()
2382+
2383+ function resetNavigation() {
2384+ dashNavigation.resetNavigation();
2385+ }
2386+
2387+ Rectangle {
2388+ color: "white"
2389+ anchors.fill: parent
2390+ }
2391+
2392+ ListItems.ThinDivider {
2393+ anchors.top: parent.top
2394+ }
2395+
2396+ Label {
2397+ id: recentSearchesLabels
2398+ text: i18n.tr("Recent Searches")
2399+ visible: recentSearchesRepeater.count > 0
2400+ anchors {
2401+ top: parent.top
2402+ left: parent.left
2403+ margins: units.gu(2)
2404+ topMargin: units.gu(3)
2405+ }
2406+ }
2407+
2408+ Label {
2409+ text: i18n.tr("Clear All")
2410+ fontSize: "small"
2411+ visible: recentSearchesRepeater.count > 0
2412+ anchors {
2413+ top: parent.top
2414+ right: parent.right
2415+ margins: units.gu(2)
2416+ topMargin: units.gu(3)
2417+ }
2418+
2419+ AbstractButton {
2420+ anchors.fill: parent
2421+ onClicked: searchHistory.clear();
2422+ }
2423+ }
2424+
2425+ Column {
2426+ id: searchColumn
2427+ anchors {
2428+ top: recentSearchesLabels.bottom
2429+ left: parent.left
2430+ right: parent.right
2431+ }
2432+
2433+ Repeater {
2434+ id: recentSearchesRepeater
2435+ objectName: "recentSearchesRepeater"
2436+ model: searchHistory
2437+
2438+ delegate: ListItem {
2439+ anchors {
2440+ left: parent.left
2441+ right: parent.right
2442+ leftMargin: units.gu(2)
2443+ rightMargin: units.gu(2)
2444+ }
2445+ height: units.gu(5)
2446+
2447+ Icon {
2448+ id: searchIcon
2449+ anchors {
2450+ verticalCenter: parent.verticalCenter
2451+ left: parent.left
2452+ }
2453+ height: units.gu(1.5)
2454+ width: height
2455+ name: "search"
2456+ }
2457+
2458+ Label {
2459+ anchors {
2460+ verticalCenter: parent.verticalCenter
2461+ left: searchIcon.right
2462+ leftMargin: units.gu(1)
2463+ right: parent.right
2464+ }
2465+ text: query
2466+ color: "#888888"
2467+ }
2468+
2469+ divider.visible: index != repeater.count - 1 || (scope && scope.hasNavigation) || primaryFilter.active
2470+
2471+ onClicked: root.historyItemClicked(query)
2472+ }
2473+ }
2474+ }
2475+
2476+ DashNavigation {
2477+ id: dashNavigation
2478+ scope: root.scope
2479+ anchors {
2480+ top: recentSearchesRepeater.count > 0 ? searchColumn.bottom : parent.top
2481+ topMargin: implicitHeight && recentSearchesRepeater.count > 0 ? units.gu(2) : 0
2482+ left: parent.left
2483+ right: parent.right
2484+ }
2485+ availableHeight: windowHeight * 4 / 6 - searchesHeight
2486+
2487+ onLeafClicked: root.dashNavigationLeafClicked();
2488+ }
2489+
2490+ Filters.FilterWidgetFactory {
2491+ id: primaryFilter
2492+ active: scope && !scope.hasNavigation
2493+
2494+ property var filter: active ? scope.primaryNavigationFilter : null
2495+
2496+ anchors {
2497+ top: recentSearchesRepeater.count > 0 ? searchColumn.bottom : parent.top
2498+ topMargin: active && recentSearchesRepeater.count > 0 ? units.gu(2) : 0
2499+ left: parent.left
2500+ right: parent.right
2501+ }
2502+
2503+ widgetId: filter ? filter.filterId : ""
2504+ widgetType: filter ? filter.filterType : -1
2505+ widgetData: filter
2506+ }
2507+
2508+ // This is outside the item
2509+ Image {
2510+ anchors {
2511+ top: parent.bottom
2512+ left: parent.left
2513+ right: parent.right
2514+ }
2515+ fillMode: Image.Stretch
2516+ source: "graphics/navigation_shadow.png"
2517+ }
2518+}
2519
2520=== modified file 'tests/mocks/Unity/CMakeLists.txt'
2521--- tests/mocks/Unity/CMakeLists.txt 2016-02-19 12:42:44 +0000
2522+++ tests/mocks/Unity/CMakeLists.txt 2016-03-21 16:06:44 +0000
2523@@ -8,7 +8,7 @@
2524 add_subdirectory(Screens)
2525
2526 pkg_search_module(GOBJECT gobject-2.0 REQUIRED)
2527-pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=10)
2528+pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=11)
2529
2530 include_directories(
2531 ${CMAKE_CURRENT_BINARY_DIR}
2532@@ -29,15 +29,28 @@
2533 fake_resultsmodel.cpp
2534 fake_previewmodel.cpp
2535 fake_previewwidgetmodel.cpp
2536+ fake_filters.cpp
2537+ fake_optionselectorfilter.cpp
2538+ fake_optionselectoroptions.cpp
2539+ fake_rangeinputfilter.cpp
2540+ fake_valuesliderfilter.cpp
2541+ fake_valueslidervalues.cpp
2542 fake_unity_plugin.cpp
2543 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/CategoriesInterface.h
2544+ ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/FilterBaseInterface.h
2545+ ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/FiltersInterface.h
2546 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/NavigationInterface.h
2547+ ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/OptionSelectorFilterInterface.h
2548+ ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/OptionSelectorOptionsInterface.h
2549 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewModelInterface.h
2550 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewWidgetModelInterface.h
2551+ ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/RangeInputFilterInterface.h
2552 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/ResultsModelInterface.h
2553 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/ScopeInterface.h
2554 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/ScopesInterface.h
2555 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/SettingsModelInterface.h
2556+ ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/ValueSliderFilterInterface.h
2557+ ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/ValueSliderValuesInterface.h
2558 )
2559
2560 # Workaround for gcc failure LP: #1417664
2561
2562=== modified file 'tests/mocks/Unity/fake_categories.cpp'
2563--- tests/mocks/Unity/fake_categories.cpp 2016-01-14 09:26:28 +0000
2564+++ tests/mocks/Unity/fake_categories.cpp 2016-03-21 16:06:44 +0000
2565@@ -88,7 +88,7 @@
2566 }
2567 case RoleComponents:
2568 {
2569- QVariantMap map, artMap, attributeMap;
2570+ QVariantMap map, artMap, attributeMap, socialActionMap;
2571 if (index.row() % 2 != 0) {
2572 artMap["aspect-ratio"] = QString("1.%1").arg(index.row());
2573 } else {
2574@@ -99,6 +99,9 @@
2575 map["title"] = "HOLA";
2576 map["subtitle"] = "HOLA";
2577 attributeMap["field"] = "attribute";
2578+ socialActionMap["icon"] = "icon";
2579+ socialActionMap["id"] = "socialHola";
2580+ map["socialActions"] = socialActionMap;
2581 map["attributes"] = attributeMap;
2582 return map;
2583 }
2584
2585=== added file 'tests/mocks/Unity/fake_filters.cpp'
2586--- tests/mocks/Unity/fake_filters.cpp 1970-01-01 00:00:00 +0000
2587+++ tests/mocks/Unity/fake_filters.cpp 2016-03-21 16:06:44 +0000
2588@@ -0,0 +1,125 @@
2589+/*
2590+ * Copyright (C) 2015 Canonical, Ltd.
2591+ *
2592+ * This program is free software; you can redistribute it and/or modify
2593+ * it under the terms of the GNU General Public License as published by
2594+ * the Free Software Foundation; version 3.
2595+ *
2596+ * This program is distributed in the hope that it will be useful,
2597+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2598+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2599+ * GNU General Public License for more details.
2600+ *
2601+ * You should have received a copy of the GNU General Public License
2602+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2603+ */
2604+
2605+#include "fake_filters.h"
2606+
2607+#include "fake_optionselectorfilter.h"
2608+#include "fake_rangeinputfilter.h"
2609+#include "fake_valuesliderfilter.h"
2610+#include "fake_scope.h"
2611+
2612+Filters::Filters(Scope* parent)
2613+ : unity::shell::scopes::FiltersInterface(parent)
2614+{
2615+ addFilter(new FakeOptionSelectorFilter("OSF1", "Tag1", "Which Cake you like More", false, QStringList() << "cheese" << "carrot" << "chocolate", this));
2616+
2617+ FakeRangeInputFilter *rif = new FakeRangeInputFilter("RIF1", "Tag3", this);
2618+ rif->setTitle("How much do you want to walk?");
2619+ rif->setCentralLabel("to");
2620+ rif->setStartPostfixLabel("m");
2621+ rif->setEndPostfixLabel("m");
2622+ addFilter(rif);
2623+
2624+ QMap<double, QString> labels;
2625+ labels[15] = "Default";
2626+ labels[50] = "50";
2627+ labels[100] = "100";
2628+ FakeValueSliderFilter *vsf = new FakeValueSliderFilter("VS1", "Tag4", 15, 10, 150, labels, this);
2629+ addFilter(vsf);
2630+
2631+ addFilter(new FakeOptionSelectorFilter("OSF2", "Tag2", "Which Countries have you been to?", true, QStringList() << "Germany" << "UK" << "New Zealand", this));
2632+}
2633+
2634+void Filters::addFilter(unity::shell::scopes::FilterBaseInterface *f)
2635+{
2636+ switch (f->filterType()) {
2637+ case FiltersInterface::OptionSelectorFilter: {
2638+ FakeOptionSelectorFilter *osf = static_cast<FakeOptionSelectorFilter *>(f);
2639+ connect(osf, &FakeOptionSelectorFilter::isActiveChanged, this, &Filters::activeFiltersCountChanged);
2640+ }
2641+ break;
2642+
2643+ case FiltersInterface::RangeInputFilter: {
2644+ FakeRangeInputFilter *rif = static_cast<FakeRangeInputFilter *>(f);
2645+ connect(rif, &FakeRangeInputFilter::isActiveChanged, this, &Filters::activeFiltersCountChanged);
2646+ }
2647+ break;
2648+
2649+ case FiltersInterface::ValueSliderFilter: {
2650+ // Not counting value slider as active in the mock
2651+ }
2652+
2653+ case Invalid:
2654+ break;
2655+ }
2656+ m_filters << f;
2657+}
2658+
2659+int Filters::rowCount(const QModelIndex &parent) const
2660+{
2661+ if (parent.isValid())
2662+ return 0;
2663+
2664+ return m_filters.count();
2665+}
2666+
2667+QVariant Filters::data(const QModelIndex &index, int role) const
2668+{
2669+ const int row = index.row();
2670+ if (row < 0 || row >= m_filters.count())
2671+ return QVariant();
2672+
2673+ unity::shell::scopes::FilterBaseInterface *filter = m_filters[row];
2674+
2675+ switch (role) {
2676+ case RoleFilterId:
2677+ return filter->filterId();
2678+ case RoleFilterType:
2679+ return filter->filterType();
2680+ case RoleFilter:
2681+ return QVariant::fromValue<unity::shell::scopes::FilterBaseInterface *>(filter);
2682+ default:
2683+ return QVariant();
2684+ }
2685+}
2686+
2687+int Filters::activeFiltersCount() const
2688+{
2689+ int active = 0;
2690+ Q_FOREACH(unity::shell::scopes::FilterBaseInterface *f, m_filters) {
2691+ switch (f->filterType()) {
2692+ case FiltersInterface::OptionSelectorFilter: {
2693+ FakeOptionSelectorFilter *osf = static_cast<FakeOptionSelectorFilter *>(f);
2694+ if (osf->isActive()) ++active;
2695+ }
2696+ break;
2697+
2698+ case FiltersInterface::RangeInputFilter: {
2699+ FakeRangeInputFilter *rif = static_cast<FakeRangeInputFilter *>(f);
2700+ if (rif->isActive()) ++active;
2701+ }
2702+ break;
2703+
2704+ case FiltersInterface::ValueSliderFilter: {
2705+ // Not counting value slider as active in the mock
2706+ }
2707+
2708+ case Invalid:
2709+ break;
2710+ }
2711+ }
2712+ return active;
2713+}
2714
2715=== added file 'tests/mocks/Unity/fake_filters.h'
2716--- tests/mocks/Unity/fake_filters.h 1970-01-01 00:00:00 +0000
2717+++ tests/mocks/Unity/fake_filters.h 2016-03-21 16:06:44 +0000
2718@@ -0,0 +1,46 @@
2719+/*
2720+ * Copyright (C) 2015 Canonical, Ltd.
2721+ *
2722+ * This program is free software; you can redistribute it and/or modify
2723+ * it under the terms of the GNU General Public License as published by
2724+ * the Free Software Foundation; version 3.
2725+ *
2726+ * This program is distributed in the hope that it will be useful,
2727+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2728+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2729+ * GNU General Public License for more details.
2730+ *
2731+ * You should have received a copy of the GNU General Public License
2732+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2733+ */
2734+
2735+#ifndef FAKE_FILTERS_H
2736+#define FAKE_FILTERS_H
2737+
2738+#include <unity/shell/scopes/FiltersInterface.h>
2739+#include <unity/shell/scopes/FilterBaseInterface.h>
2740+
2741+class Scope;
2742+
2743+class Filters : public unity::shell::scopes::FiltersInterface
2744+{
2745+ Q_OBJECT
2746+
2747+public:
2748+ Filters(Scope* parent);
2749+
2750+ int rowCount(const QModelIndex &parent) const override;
2751+ QVariant data(const QModelIndex &index, int role) const override;
2752+
2753+ int activeFiltersCount() const;
2754+
2755+Q_SIGNALS:
2756+ void activeFiltersCountChanged();
2757+
2758+private:
2759+ void addFilter(unity::shell::scopes::FilterBaseInterface* f);
2760+
2761+ QVector<unity::shell::scopes::FilterBaseInterface*> m_filters;
2762+};
2763+
2764+#endif
2765
2766=== modified file 'tests/mocks/Unity/fake_navigation.cpp'
2767--- tests/mocks/Unity/fake_navigation.cpp 2015-08-19 13:56:21 +0000
2768+++ tests/mocks/Unity/fake_navigation.cpp 2016-03-21 16:06:44 +0000
2769@@ -32,7 +32,6 @@
2770 {
2771 QTimer::singleShot(1500, this, &Navigation::slotLoaded);
2772 connect(scope, &Scope::currentNavigationIdChanged, this, &Navigation::slotCurrentNavigationChanged);
2773- connect(scope, &Scope::currentAltNavigationIdChanged, this, &Navigation::slotCurrentNavigationChanged);
2774 }
2775
2776 QString Navigation::navigationId() const
2777@@ -78,17 +77,17 @@
2778
2779 bool Navigation::isRoot() const
2780 {
2781- return m_navigationId == "root" || m_navigationId == "altroot";
2782+ return m_navigationId == "root";
2783 }
2784
2785 bool Navigation::hidden() const
2786 {
2787- return m_navigationId == "altroot";
2788+ return false;
2789 }
2790
2791 int Navigation::rowCount(const QModelIndex & /*parent*/) const
2792 {
2793- if (!m_loaded || m_navigationId.startsWith("child") || m_navigationId.startsWith("altrootChild") || m_navigationId == "middle3")
2794+ if (!m_loaded ||(m_navigationId.startsWith("child") && !m_navigationId.startsWith("childmiddle4")) || m_navigationId == "middle3")
2795 return 0;
2796 else
2797 return 8;
2798@@ -102,16 +101,16 @@
2799 return QString("middle%1").arg(index.row());
2800 else if (m_navigationId.startsWith("middle"))
2801 return QString("child%1%2").arg(m_navigationId).arg(index.row());
2802+ else if (m_navigationId.startsWith("childmiddle"))
2803+ return QString("grandchild%1%2").arg(m_navigationId).arg(index.row());
2804 case RoleLabel:
2805 return QString("%1Child%2").arg(m_navigationId).arg(index.row());
2806+ case RoleAllLabel:
2807+ return QString("all%1Child%2").arg(m_navigationId).arg(index.row());
2808 case RoleHasChildren:
2809- return m_navigationId == "root" && index.row() != 3;
2810+ return (m_navigationId == "root" && index.row() != 3) || (m_navigationId == "middle4");
2811 case RoleIsActive:
2812- if (m_navigationId.startsWith("alt")) {
2813- return m_scope->currentAltNavigationId() == data(index, RoleNavigationId);
2814- } else {
2815- return m_scope->currentNavigationId() == data(index, RoleNavigationId);
2816- }
2817+ return m_scope->currentNavigationId() == data(index, RoleNavigationId);
2818 }
2819 return QVariant();
2820 }
2821
2822=== added file 'tests/mocks/Unity/fake_optionselectorfilter.cpp'
2823--- tests/mocks/Unity/fake_optionselectorfilter.cpp 1970-01-01 00:00:00 +0000
2824+++ tests/mocks/Unity/fake_optionselectorfilter.cpp 2016-03-21 16:06:44 +0000
2825@@ -0,0 +1,65 @@
2826+/*
2827+ * Copyright (C) 2015 Canonical, Ltd.
2828+ *
2829+ * This program is free software; you can redistribute it and/or modify
2830+ * it under the terms of the GNU General Public License as published by
2831+ * the Free Software Foundation; version 3.
2832+ *
2833+ * This program is distributed in the hope that it will be useful,
2834+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2835+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2836+ * GNU General Public License for more details.
2837+ *
2838+ * You should have received a copy of the GNU General Public License
2839+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2840+ */
2841+
2842+#include "fake_optionselectorfilter.h"
2843+
2844+#include "fake_optionselectoroptions.h"
2845+
2846+FakeOptionSelectorFilter::FakeOptionSelectorFilter(const QString &id, const QString &tag, const QString &label, bool multiselect, const QStringList &optionLabels, QObject* parent)
2847+ : unity::shell::scopes::OptionSelectorFilterInterface(parent),
2848+ m_filterId(id),
2849+ m_filterTag(tag),
2850+ m_label(label),
2851+ m_multiSelect(multiselect)
2852+{
2853+ m_options = new FakeOptionSelectorOptions(optionLabels, this);
2854+ connect(m_options, &FakeOptionSelectorOptions::anyCheckedChanged, this, &FakeOptionSelectorFilter::isActiveChanged);
2855+}
2856+
2857+QString FakeOptionSelectorFilter::filterId() const
2858+{
2859+ return m_filterId;
2860+}
2861+
2862+QString FakeOptionSelectorFilter::filterTag() const
2863+{
2864+ return m_filterTag;
2865+}
2866+
2867+QString FakeOptionSelectorFilter::title() const
2868+{
2869+ return m_title;
2870+}
2871+
2872+QString FakeOptionSelectorFilter::label() const
2873+{
2874+ return m_label;
2875+}
2876+
2877+bool FakeOptionSelectorFilter::multiSelect() const
2878+{
2879+ return m_multiSelect;
2880+}
2881+
2882+unity::shell::scopes::OptionSelectorOptionsInterface* FakeOptionSelectorFilter::options() const
2883+{
2884+ return m_options;
2885+}
2886+
2887+bool FakeOptionSelectorFilter::isActive() const
2888+{
2889+ return m_options->anyChecked();
2890+}
2891
2892=== added file 'tests/mocks/Unity/fake_optionselectorfilter.h'
2893--- tests/mocks/Unity/fake_optionselectorfilter.h 1970-01-01 00:00:00 +0000
2894+++ tests/mocks/Unity/fake_optionselectorfilter.h 2016-03-21 16:06:44 +0000
2895@@ -0,0 +1,52 @@
2896+/*
2897+ * Copyright (C) 2015 Canonical, Ltd.
2898+ *
2899+ * This program is free software; you can redistribute it and/or modify
2900+ * it under the terms of the GNU General Public License as published by
2901+ * the Free Software Foundation; version 3.
2902+ *
2903+ * This program is distributed in the hope that it will be useful,
2904+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2905+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2906+ * GNU General Public License for more details.
2907+ *
2908+ * You should have received a copy of the GNU General Public License
2909+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2910+ */
2911+
2912+#ifndef FAKE_OPTIONSELECTORFILTER_H
2913+#define FAKE_OPTIONSELECTORFILTER_H
2914+
2915+#include <unity/shell/scopes/OptionSelectorFilterInterface.h>
2916+
2917+class FakeOptionSelectorOptions;
2918+
2919+class FakeOptionSelectorFilter : public unity::shell::scopes::OptionSelectorFilterInterface
2920+{
2921+ Q_OBJECT
2922+
2923+public:
2924+ FakeOptionSelectorFilter(const QString &id, const QString &tag, const QString &label, bool multiselect, const QStringList &optionLabels, QObject* parent);
2925+
2926+ QString filterId() const override;
2927+ QString filterTag() const override;
2928+ QString title() const override;
2929+ QString label() const override;
2930+ bool multiSelect() const override;
2931+ unity::shell::scopes::OptionSelectorOptionsInterface* options() const override;
2932+
2933+ bool isActive() const;
2934+
2935+Q_SIGNALS:
2936+ void isActiveChanged();
2937+
2938+private:
2939+ QString m_filterId;
2940+ QString m_filterTag;
2941+ QString m_title;
2942+ QString m_label;
2943+ bool m_multiSelect;
2944+ FakeOptionSelectorOptions* m_options;
2945+};
2946+
2947+#endif
2948
2949=== added file 'tests/mocks/Unity/fake_optionselectoroptions.cpp'
2950--- tests/mocks/Unity/fake_optionselectoroptions.cpp 1970-01-01 00:00:00 +0000
2951+++ tests/mocks/Unity/fake_optionselectoroptions.cpp 2016-03-21 16:06:44 +0000
2952@@ -0,0 +1,77 @@
2953+/*
2954+ * Copyright (C) 2015 Canonical, Ltd.
2955+ *
2956+ * This program is free software; you can redistribute it and/or modify
2957+ * it under the terms of the GNU General Public License as published by
2958+ * the Free Software Foundation; version 3.
2959+ *
2960+ * This program is distributed in the hope that it will be useful,
2961+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2962+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2963+ * GNU General Public License for more details.
2964+ *
2965+ * You should have received a copy of the GNU General Public License
2966+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2967+ */
2968+
2969+#include "fake_optionselectoroptions.h"
2970+
2971+#include "fake_optionselectorfilter.h"
2972+
2973+FakeOptionSelectorOptions::FakeOptionSelectorOptions(const QStringList &optionLabels, FakeOptionSelectorFilter* parent)
2974+ : unity::shell::scopes::OptionSelectorOptionsInterface(parent),
2975+ m_optionLabels(optionLabels)
2976+{
2977+}
2978+
2979+int FakeOptionSelectorOptions::rowCount(const QModelIndex &parent) const
2980+{
2981+ if (parent.isValid())
2982+ return 0;
2983+
2984+ return m_optionLabels.count();
2985+}
2986+
2987+QVariant FakeOptionSelectorOptions::data(const QModelIndex &index, int role) const
2988+{
2989+ const int row = index.row();
2990+ if (row < 0 || row >= m_optionLabels.count())
2991+ return QVariant();
2992+
2993+ switch (role) {
2994+ case RoleOptionId: {
2995+ const QString id = static_cast<FakeOptionSelectorFilter*>(parent())->filterId() + QString::number(row);
2996+ return id;
2997+ }
2998+ case RoleOptionLabel:
2999+ return m_optionLabels[row];
3000+ case RoleOptionChecked:
3001+ return m_checkedIndexes.contains(row);
3002+ default:
3003+ return QVariant();
3004+ }
3005+
3006+}
3007+
3008+void FakeOptionSelectorOptions::setChecked(int row, bool checked)
3009+{
3010+ if (checked) {
3011+ if (!static_cast<FakeOptionSelectorFilter*>(parent())->multiSelect()) {
3012+ if (!m_checkedIndexes.isEmpty()) {
3013+ setChecked(*m_checkedIndexes.begin(), false);
3014+ }
3015+ Q_ASSERT(m_checkedIndexes.isEmpty());
3016+ }
3017+ m_checkedIndexes << row;
3018+ } else {
3019+ m_checkedIndexes.remove(row);
3020+ }
3021+ const QModelIndex idx = index(row, 0);
3022+ Q_EMIT dataChanged(idx, idx, QVector<int>() << RoleOptionChecked);
3023+ Q_EMIT anyCheckedChanged();
3024+}
3025+
3026+bool FakeOptionSelectorOptions::anyChecked() const
3027+{
3028+ return !m_checkedIndexes.isEmpty();
3029+}
3030
3031=== added file 'tests/mocks/Unity/fake_optionselectoroptions.h'
3032--- tests/mocks/Unity/fake_optionselectoroptions.h 1970-01-01 00:00:00 +0000
3033+++ tests/mocks/Unity/fake_optionselectoroptions.h 2016-03-21 16:06:44 +0000
3034@@ -0,0 +1,47 @@
3035+/*
3036+ * Copyright (C) 2015 Canonical, Ltd.
3037+ *
3038+ * This program is free software; you can redistribute it and/or modify
3039+ * it under the terms of the GNU General Public License as published by
3040+ * the Free Software Foundation; version 3.
3041+ *
3042+ * This program is distributed in the hope that it will be useful,
3043+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3044+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3045+ * GNU General Public License for more details.
3046+ *
3047+ * You should have received a copy of the GNU General Public License
3048+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3049+ */
3050+
3051+#ifndef FAKE_OPTIONSELECTOROPTIONS_H
3052+#define FAKE_OPTIONSELECTOROPTIONS_H
3053+
3054+#include <unity/shell/scopes/OptionSelectorFilterInterface.h>
3055+
3056+#include <QSet>
3057+
3058+class FakeOptionSelectorFilter;
3059+
3060+class FakeOptionSelectorOptions : public unity::shell::scopes::OptionSelectorOptionsInterface
3061+{
3062+ Q_OBJECT
3063+
3064+public:
3065+ FakeOptionSelectorOptions(const QStringList &optionLabels, FakeOptionSelectorFilter* parent);
3066+
3067+ int rowCount(const QModelIndex &parent) const override;
3068+ QVariant data(const QModelIndex &index, int role) const override;
3069+ Q_INVOKABLE void setChecked(int index, bool checked) override;
3070+
3071+ bool anyChecked() const;
3072+
3073+Q_SIGNALS:
3074+ void anyCheckedChanged();
3075+
3076+private:
3077+ QStringList m_optionLabels;
3078+ QSet<int> m_checkedIndexes;
3079+};
3080+
3081+#endif
3082
3083=== added file 'tests/mocks/Unity/fake_rangeinputfilter.cpp'
3084--- tests/mocks/Unity/fake_rangeinputfilter.cpp 1970-01-01 00:00:00 +0000
3085+++ tests/mocks/Unity/fake_rangeinputfilter.cpp 2016-03-21 16:06:44 +0000
3086@@ -0,0 +1,167 @@
3087+/*
3088+ * Copyright (C) 2015 Canonical, Ltd.
3089+ *
3090+ * This program is free software; you can redistribute it and/or modify
3091+ * it under the terms of the GNU General Public License as published by
3092+ * the Free Software Foundation; version 3.
3093+ *
3094+ * This program is distributed in the hope that it will be useful,
3095+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3096+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3097+ * GNU General Public License for more details.
3098+ *
3099+ * You should have received a copy of the GNU General Public License
3100+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3101+ */
3102+
3103+#include "fake_rangeinputfilter.h"
3104+
3105+FakeRangeInputFilter::FakeRangeInputFilter(const QString &id, const QString &tag, QObject* parent)
3106+ : unity::shell::scopes::RangeInputFilterInterface(parent),
3107+ m_filterId(id),
3108+ m_filterTag(tag),
3109+ m_hasStartValue(false),
3110+ m_hasEndValue(false),
3111+ m_startValue(-1),
3112+ m_endValue(-1)
3113+{
3114+ connect(this, &FakeRangeInputFilter::hasStartValueChanged, this, &FakeRangeInputFilter::isActiveChanged);
3115+ connect(this, &FakeRangeInputFilter::hasEndValueChanged, this, &FakeRangeInputFilter::isActiveChanged);
3116+}
3117+
3118+QString FakeRangeInputFilter::filterId() const
3119+{
3120+ return m_filterId;
3121+}
3122+
3123+QString FakeRangeInputFilter::filterTag() const
3124+{
3125+ return m_filterTag;
3126+}
3127+
3128+QString FakeRangeInputFilter::title() const
3129+{
3130+ return m_title;
3131+}
3132+
3133+double FakeRangeInputFilter::startValue() const
3134+{
3135+ return m_startValue;
3136+}
3137+
3138+double FakeRangeInputFilter::endValue() const
3139+{
3140+ return m_endValue;
3141+}
3142+
3143+void FakeRangeInputFilter::setStartValue(double value)
3144+{
3145+ if (m_startValue != value) {
3146+ m_startValue = value;
3147+ Q_EMIT startValueChanged();
3148+ }
3149+ if (!m_hasStartValue) {
3150+ m_hasStartValue = true;
3151+ Q_EMIT hasStartValueChanged();
3152+ }
3153+}
3154+
3155+void FakeRangeInputFilter::setEndValue(double value)
3156+{
3157+ if (m_endValue != value) {
3158+ m_endValue = value;
3159+ Q_EMIT endValueChanged();
3160+ }
3161+ if (!m_hasEndValue) {
3162+ m_hasEndValue = true;
3163+ Q_EMIT hasEndValueChanged();
3164+ }
3165+}
3166+
3167+QString FakeRangeInputFilter::startPrefixLabel() const
3168+{
3169+ return m_startPrefixLabel;
3170+}
3171+
3172+QString FakeRangeInputFilter::startPostfixLabel() const
3173+{
3174+ return m_startPostfixLabel;
3175+}
3176+
3177+QString FakeRangeInputFilter::centralLabel() const
3178+{
3179+ return m_centralLabel;
3180+}
3181+
3182+QString FakeRangeInputFilter::endPrefixLabel() const
3183+{
3184+ return m_endPrefixLabel;
3185+}
3186+
3187+QString FakeRangeInputFilter::endPostfixLabel() const
3188+{
3189+ return m_endPostfixLabel;
3190+}
3191+
3192+bool FakeRangeInputFilter::hasStartValue() const
3193+{
3194+ return m_hasStartValue;
3195+}
3196+
3197+bool FakeRangeInputFilter::hasEndValue() const
3198+{
3199+ return m_hasEndValue;
3200+}
3201+
3202+void FakeRangeInputFilter::eraseStartValue()
3203+{
3204+ m_hasStartValue = false;
3205+ Q_EMIT hasStartValueChanged();
3206+}
3207+
3208+void FakeRangeInputFilter::eraseEndValue()
3209+{
3210+ m_hasEndValue = false;
3211+ Q_EMIT hasEndValueChanged();
3212+}
3213+
3214+bool FakeRangeInputFilter::isActive() const
3215+{
3216+ return hasStartValue() && hasEndValue();
3217+}
3218+
3219+void FakeRangeInputFilter::setTitle(const QString &title)
3220+{
3221+ m_title = title;
3222+ Q_EMIT titleChanged();
3223+}
3224+
3225+void FakeRangeInputFilter::setStartPrefixLabel(const QString &startPrefixLabel)
3226+{
3227+ m_startPrefixLabel = startPrefixLabel;
3228+ Q_EMIT startPrefixLabelChanged();
3229+}
3230+
3231+void FakeRangeInputFilter::setStartPostfixLabel(const QString &startPostfixLabel)
3232+{
3233+ m_startPostfixLabel = startPostfixLabel;
3234+ Q_EMIT startPostfixLabelChanged();
3235+}
3236+
3237+void FakeRangeInputFilter::setCentralLabel(const QString &centralLabel)
3238+{
3239+ m_centralLabel = centralLabel;
3240+ Q_EMIT centralLabelChanged();
3241+}
3242+
3243+void FakeRangeInputFilter::setEndPrefixLabel(const QString &endPrefixLabel)
3244+{
3245+ m_endPrefixLabel = endPrefixLabel;
3246+ Q_EMIT endPrefixLabelChanged();
3247+}
3248+
3249+void FakeRangeInputFilter::setEndPostfixLabel(const QString &endPostfixLabel)
3250+{
3251+ m_endPostfixLabel = endPostfixLabel;
3252+ Q_EMIT endPostfixLabelChanged();
3253+}
3254
3255=== added file 'tests/mocks/Unity/fake_rangeinputfilter.h'
3256--- tests/mocks/Unity/fake_rangeinputfilter.h 1970-01-01 00:00:00 +0000
3257+++ tests/mocks/Unity/fake_rangeinputfilter.h 2016-03-21 16:06:44 +0000
3258@@ -0,0 +1,79 @@
3259+/*
3260+ * Copyright (C) 2015 Canonical, Ltd.
3261+ *
3262+ * This program is free software; you can redistribute it and/or modify
3263+ * it under the terms of the GNU General Public License as published by
3264+ * the Free Software Foundation; version 3.
3265+ *
3266+ * This program is distributed in the hope that it will be useful,
3267+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3268+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3269+ * GNU General Public License for more details.
3270+ *
3271+ * You should have received a copy of the GNU General Public License
3272+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3273+ */
3274+
3275+#ifndef FAKE_RANGEINPUTFILTER_H
3276+#define FAKE_RANGEINPUTFILTER_H
3277+
3278+#include <unity/shell/scopes/RangeInputFilterInterface.h>
3279+
3280+class FakeRangeInputFilter : public unity::shell::scopes::RangeInputFilterInterface
3281+{
3282+ Q_OBJECT
3283+
3284+public:
3285+ FakeRangeInputFilter(const QString &id, const QString &tag, QObject* parent);
3286+
3287+ QString filterId() const override;
3288+ QString filterTag() const override;
3289+ QString title() const override;
3290+
3291+ double startValue() const override;
3292+ double endValue() const override;
3293+ void setStartValue(double value) override;
3294+ void setEndValue(double value) override;
3295+ QString startPrefixLabel() const override;
3296+ QString startPostfixLabel() const override;
3297+ QString centralLabel() const override;
3298+ QString endPrefixLabel() const override;
3299+ QString endPostfixLabel() const override;
3300+ bool hasStartValue() const override;
3301+ bool hasEndValue() const override;
3302+
3303+ void eraseStartValue() override;
3304+ void eraseEndValue() override;
3305+
3306+ // Not part of the iface, for mock/testing purposes
3307+ bool isActive() const;
3308+
3309+ void setTitle(const QString &title);
3310+ void setStartPrefixLabel(const QString &startPrefixLabel);
3311+ void setStartPostfixLabel(const QString &startPostfixLabel);
3312+ void setCentralLabel(const QString &centralLabel);
3313+ void setEndPrefixLabel(const QString &endPrefixLabel);
3314+ void setEndPostfixLabel(const QString &endPostfixLabel);
3315+
3316+Q_SIGNALS:
3317+ void isActiveChanged();
3318+
3319+private:
3320+ QString m_filterId;
3321+ QString m_filterTag;
3322+ QString m_title;
3323+
3324+ bool m_hasStartValue;
3325+ bool m_hasEndValue;
3326+
3327+ double m_startValue;
3328+ double m_endValue;
3329+
3330+ QString m_startPrefixLabel;
3331+ QString m_startPostfixLabel;
3332+ QString m_centralLabel;
3333+ QString m_endPrefixLabel;
3334+ QString m_endPostfixLabel;
3335+};
3336+
3337+#endif
3338
3339=== modified file 'tests/mocks/Unity/fake_resultsmodel.cpp'
3340--- tests/mocks/Unity/fake_resultsmodel.cpp 2015-11-23 15:41:34 +0000
3341+++ tests/mocks/Unity/fake_resultsmodel.cpp 2016-03-21 16:06:44 +0000
3342@@ -72,6 +72,8 @@
3343 case RoleUri:
3344 case RoleCategoryId:
3345 case RoleDndUri:
3346+ case RoleAttributes:
3347+ case RoleSocialActions:
3348 return QString();
3349 case RoleResult:
3350 return QString("Result.%1.%2").arg(m_categoryId).arg(index.row());
3351
3352=== modified file 'tests/mocks/Unity/fake_scope.cpp'
3353--- tests/mocks/Unity/fake_scope.cpp 2016-02-22 12:59:40 +0000
3354+++ tests/mocks/Unity/fake_scope.cpp 2016-03-21 16:06:44 +0000
3355@@ -1,5 +1,5 @@
3356 /*
3357- * Copyright (C) 2013, 2014 Canonical, Ltd.
3358+ * Copyright (C) 2013, 2014, 2015 Canonical, Ltd.
3359 *
3360 * This program is free software; you can redistribute it and/or modify
3361 * it under the terms of the GNU General Public License as published by
3362@@ -19,7 +19,9 @@
3363
3364 #include "fake_scope.h"
3365
3366+#include "fake_filters.h"
3367 #include "fake_navigation.h"
3368+#include "fake_optionselectorfilter.h"
3369 #include "fake_resultsmodel.h"
3370 #include "fake_scopes.h"
3371 #include "fake_settingsmodel.h"
3372@@ -37,14 +39,18 @@
3373 , m_searching(false)
3374 , m_favorite(favorite)
3375 , m_isActive(false)
3376+ , m_hasNavigation(true)
3377+ , m_hasPrimaryFilter(true)
3378 , m_currentNavigationId("root")
3379- , m_currentAltNavigationId("altrootChild1")
3380 , m_previewRendererName("preview-generic")
3381 , m_categories(new Categories(categories, this))
3382 , m_openScope(nullptr)
3383 , m_settings(new SettingsModel(this))
3384+ , m_filters(new Filters(this))
3385 , m_returnNullPreview(returnNullPreview)
3386 {
3387+ m_primaryNavigationFilter = new FakeOptionSelectorFilter("OSF3", "PFTag", "Which food you like More", false, QStringList() << "meat" << "vegetables", this);
3388+ connect(m_filters, &Filters::activeFiltersCountChanged, this, &Scope::activeFiltersCountChanged);
3389 }
3390
3391 QString Scope::id() const
3392@@ -229,17 +235,13 @@
3393
3394 bool Scope::hasNavigation() const
3395 {
3396- return true;
3397-}
3398-
3399-QString Scope::currentAltNavigationId() const
3400-{
3401- return m_currentAltNavigationId;
3402-}
3403-
3404-bool Scope::hasAltNavigation() const
3405-{
3406- return true;
3407+ return m_hasNavigation;
3408+}
3409+
3410+void Scope::setHasNavigation(bool hasNavigation)
3411+{
3412+ m_hasNavigation = hasNavigation;
3413+ Q_EMIT hasNavigationChanged();
3414 }
3415
3416 Scope::Status Scope::status() const
3417@@ -276,6 +278,11 @@
3418 Q_EMIT refreshed();
3419 }
3420
3421+void Scope::resetFilters()
3422+{
3423+ qWarning() << "Scope::resetFilters is unimplemented";
3424+}
3425+
3426 void Scope::activateAction(QVariant const& /*result*/, QString const& /*categoryId*/, QString const& /*actionId*/)
3427 {
3428 qFatal("Using Scope::activateAction");
3429@@ -298,29 +305,47 @@
3430 return new Navigation(id, id, "all"+id, parentId, parentLabel, this);
3431 }
3432
3433-unity::shell::scopes::NavigationInterface* Scope::getAltNavigation(QString const& id)
3434-{
3435- if (id.isEmpty())
3436- return nullptr;
3437-
3438- QString parentId;
3439- QString parentLabel;
3440- if (id != "altroot") {
3441- parentId = "altroot";
3442- parentLabel = "altroot";
3443- }
3444- return new Navigation(id, id, "all"+id, parentId, parentLabel, this);
3445-}
3446-
3447-void Scope::setNavigationState(const QString &navigationId, bool isAltNavigation)
3448-{
3449- if (isAltNavigation) {
3450- m_currentAltNavigationId = navigationId;
3451- Q_EMIT currentAltNavigationIdChanged();
3452- } else {
3453- m_currentNavigationId = navigationId;
3454- Q_EMIT currentNavigationIdChanged();
3455- }
3456+void Scope::setNavigationState(const QString &navigationId)
3457+{
3458+ m_currentNavigationId = navigationId;
3459+ Q_EMIT currentNavigationIdChanged();
3460+ Q_EMIT primaryNavigationTagChanged();
3461+}
3462+
3463+unity::shell::scopes::FilterBaseInterface* Scope::primaryNavigationFilter() const
3464+{
3465+ return m_hasPrimaryFilter ? m_primaryNavigationFilter : nullptr;
3466+}
3467+
3468+unity::shell::scopes::FiltersInterface* Scope::filters() const
3469+{
3470+ return m_filters;
3471+}
3472+
3473+QString Scope::primaryNavigationTag() const
3474+{
3475+ if (m_currentNavigationId == "root")
3476+ return QString();
3477+ else
3478+ return const_cast<Scope*>(this)->getNavigation(m_currentNavigationId)->label();
3479+}
3480+
3481+int Scope::activeFiltersCount() const
3482+{
3483+ return m_filters->activeFiltersCount();
3484+}
3485+
3486+void Scope::resetPrimaryNavigationTag()
3487+{
3488+ if (m_currentNavigationId != "root") {
3489+ setNavigationState("root");
3490+ }
3491+}
3492+
3493+void Scope::setHasPrimaryFilter(bool hasPrimaryFilter)
3494+{
3495+ m_hasPrimaryFilter = hasPrimaryFilter;
3496+ Q_EMIT primaryNavigationFilterChanged();
3497 }
3498
3499 void Scope::performQuery(const QString& query)
3500
3501=== modified file 'tests/mocks/Unity/fake_scope.h'
3502--- tests/mocks/Unity/fake_scope.h 2016-02-19 11:42:42 +0000
3503+++ tests/mocks/Unity/fake_scope.h 2016-03-21 16:06:44 +0000
3504@@ -1,5 +1,5 @@
3505 /*
3506- * Copyright (C) 2013, 2014 Canonical, Ltd.
3507+ * Copyright (C) 2013, 2014, 2015 Canonical, Ltd.
3508 *
3509 * This program is free software; you can redistribute it and/or modify
3510 * it under the terms of the GNU General Public License as published by
3511@@ -24,7 +24,9 @@
3512
3513 #include <QTimer>
3514
3515+class Filters;
3516 class Scopes;
3517+class FakeOptionSelectorFilter;
3518
3519 class Scope : public unity::shell::scopes::ScopeInterface
3520 {
3521@@ -68,11 +70,17 @@
3522
3523 QString currentNavigationId() const override;
3524 bool hasNavigation() const override;
3525- QString currentAltNavigationId() const override;
3526- bool hasAltNavigation() const override;
3527 Q_INVOKABLE unity::shell::scopes::NavigationInterface* getNavigation(QString const& navigationId) override;
3528- Q_INVOKABLE unity::shell::scopes::NavigationInterface* getAltNavigation(QString const& altNavigationId) override;
3529- Q_INVOKABLE void setNavigationState(const QString &navigationId, bool isAltNavigation) override;
3530+ Q_INVOKABLE void setNavigationState(const QString &navigationId) override;
3531+ Q_INVOKABLE void setHasNavigation(bool hasNavigation); // This is not invokable in the Interface, here for testing benefits
3532+
3533+ unity::shell::scopes::FilterBaseInterface* primaryNavigationFilter() const override;
3534+ unity::shell::scopes::FiltersInterface* filters() const override;
3535+ QString primaryNavigationTag() const override;
3536+ int activeFiltersCount() const override;
3537+ Q_INVOKABLE void resetPrimaryNavigationTag() override;
3538+ Q_INVOKABLE void setHasPrimaryFilter(bool hasPrimaryFilter); // This is not invokable in the Interface, here for testing benefits
3539+
3540 void performQuery(const QString& query) override;
3541
3542 Status status() const override;
3543@@ -80,7 +88,9 @@
3544
3545 Q_INVOKABLE void refresh() override;
3546
3547- Q_INVOKABLE virtual void activateAction(QVariant const& result, QString const& categoryId, QString const& actionId) override;
3548+ Q_INVOKABLE void resetFilters() override;
3549+
3550+ Q_INVOKABLE void activateAction(QVariant const& result, QString const& categoryId, QString const& actionId) override;
3551
3552 Q_SIGNALS:
3553 // These are not in the Interface, here for testing benefits
3554@@ -99,14 +109,17 @@
3555 bool m_searching;
3556 bool m_favorite;
3557 bool m_isActive;
3558+ bool m_hasNavigation;
3559+ bool m_hasPrimaryFilter;
3560 QString m_currentNavigationId;
3561- QString m_currentAltNavigationId;
3562
3563 QString m_previewRendererName;
3564
3565 unity::shell::scopes::CategoriesInterface* m_categories;
3566 unity::shell::scopes::ScopeInterface* m_openScope;
3567 unity::shell::scopes::SettingsModelInterface* m_settings;
3568+ Filters* m_filters;
3569+ FakeOptionSelectorFilter* m_primaryNavigationFilter;
3570
3571 bool m_returnNullPreview;
3572 };
3573
3574=== modified file 'tests/mocks/Unity/fake_unity_plugin.cpp'
3575--- tests/mocks/Unity/fake_unity_plugin.cpp 2016-02-19 11:42:42 +0000
3576+++ tests/mocks/Unity/fake_unity_plugin.cpp 2016-03-21 16:06:44 +0000
3577@@ -22,11 +22,14 @@
3578 // local
3579 #include "fake_scopes.h"
3580 #include "fake_categories.h"
3581+#include "fake_filters.h"
3582 #include "fake_navigation.h"
3583+#include "fake_optionselectoroptions.h"
3584 #include "fake_previewmodel.h"
3585 #include "fake_previewwidgetmodel.h"
3586 #include "fake_resultsmodel.h"
3587 #include "fake_settingsmodel.h"
3588+#include "fake_valueslidervalues.h"
3589
3590 // External
3591 #include <glib-object.h>
3592@@ -52,4 +55,8 @@
3593 qmlRegisterType<ResultsModel>(uri, 0, 2, "FakeResultsModel");
3594 qmlRegisterType<PreviewModel>(uri, 0, 2, "FakePreviewModel");
3595 qmlRegisterUncreatableType<PreviewWidgetModel>(uri, 0, 2, "PreviewWidgetModel", "Can't create new PreviewWidgetModel in QML. Get them from PreviewModel instance.");
3596+ qmlRegisterUncreatableType<unity::shell::scopes::FiltersInterface>(uri, 0, 2, "Filters", "Can't create Filters object in QML. Get them from Scope instance.");
3597+ qmlRegisterUncreatableType<unity::shell::scopes::FilterBaseInterface>(uri, 0, 2, "Filter", "Can't create Filter object in QML. Get them from Scope instance.");
3598+ qmlRegisterUncreatableType<unity::shell::scopes::OptionSelectorOptionsInterface>(uri, 0, 2, "OptionSelectorOptions", "Can't create OptionSelectorOptions object in QML");
3599+ qmlRegisterUncreatableType<unity::shell::scopes::ValueSliderValuesInterface>(uri, 0, 2, "ValueSliderValues", "Can't create ValueSliderValuesInterface object in QML");
3600 }
3601
3602=== added file 'tests/mocks/Unity/fake_valuesliderfilter.cpp'
3603--- tests/mocks/Unity/fake_valuesliderfilter.cpp 1970-01-01 00:00:00 +0000
3604+++ tests/mocks/Unity/fake_valuesliderfilter.cpp 2016-03-21 16:06:44 +0000
3605@@ -0,0 +1,84 @@
3606+/*
3607+ * Copyright (C) 2015 Canonical, Ltd.
3608+ *
3609+ * This program is free software; you can redistribute it and/or modify
3610+ * it under the terms of the GNU General Public License as published by
3611+ * the Free Software Foundation; version 3.
3612+ *
3613+ * This program is distributed in the hope that it will be useful,
3614+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3615+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3616+ * GNU General Public License for more details.
3617+ *
3618+ * You should have received a copy of the GNU General Public License
3619+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3620+ */
3621+
3622+#include "fake_valuesliderfilter.h"
3623+#include "fake_valueslidervalues.h"
3624+
3625+FakeValueSliderFilter::FakeValueSliderFilter(const QString &id, const QString &tag, double value, double minValue, double maxValue, const QMap<double, QString> &labels, QObject* parent)
3626+ : unity::shell::scopes::ValueSliderFilterInterface(parent),
3627+ m_filterId(id),
3628+ m_filterTag(tag),
3629+ m_value(value),
3630+ m_minValue(minValue),
3631+ m_maxValue(maxValue),
3632+ m_values(new FakeValueSliderValues(labels, this))
3633+{
3634+}
3635+
3636+QString FakeValueSliderFilter::filterId() const
3637+{
3638+ return m_filterId;
3639+}
3640+
3641+QString FakeValueSliderFilter::filterTag() const
3642+{
3643+ return m_filterTag;
3644+}
3645+
3646+QString FakeValueSliderFilter::title() const
3647+{
3648+ return m_title;
3649+}
3650+
3651+double FakeValueSliderFilter::value() const
3652+{
3653+ return m_value;
3654+}
3655+
3656+void FakeValueSliderFilter::setValue(double value)
3657+{
3658+ if (value != m_value) {
3659+ m_value = value;
3660+ Q_EMIT valueChanged();
3661+ }
3662+}
3663+
3664+double FakeValueSliderFilter::minValue() const
3665+{
3666+ return m_minValue;
3667+}
3668+
3669+double FakeValueSliderFilter::maxValue() const
3670+{
3671+ return m_maxValue;
3672+}
3673+
3674+unity::shell::scopes::ValueSliderValuesInterface* FakeValueSliderFilter::values() const
3675+{
3676+ return m_values;
3677+}
3678+
3679+bool FakeValueSliderFilter::isActive() const
3680+{
3681+ // Doesn't really matter
3682+ return false;
3683+}
3684+
3685+void FakeValueSliderFilter::setTitle(const QString &title)
3686+{
3687+ m_title = title;
3688+ Q_EMIT titleChanged();
3689+}
3690
3691=== added file 'tests/mocks/Unity/fake_valuesliderfilter.h'
3692--- tests/mocks/Unity/fake_valuesliderfilter.h 1970-01-01 00:00:00 +0000
3693+++ tests/mocks/Unity/fake_valuesliderfilter.h 2016-03-21 16:06:44 +0000
3694@@ -0,0 +1,55 @@
3695+/*
3696+ * Copyright (C) 2015 Canonical, Ltd.
3697+ *
3698+ * This program is free software; you can redistribute it and/or modify
3699+ * it under the terms of the GNU General Public License as published by
3700+ * the Free Software Foundation; version 3.
3701+ *
3702+ * This program is distributed in the hope that it will be useful,
3703+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3704+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3705+ * GNU General Public License for more details.
3706+ *
3707+ * You should have received a copy of the GNU General Public License
3708+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3709+ */
3710+
3711+#ifndef FAKE_VALUESLIDERFILTER_H
3712+#define FAKE_VALUESLIDERFILTER_H
3713+
3714+#include <unity/shell/scopes/ValueSliderFilterInterface.h>
3715+
3716+class FakeValueSliderFilter : public unity::shell::scopes::ValueSliderFilterInterface
3717+{
3718+ Q_OBJECT
3719+
3720+public:
3721+ FakeValueSliderFilter(const QString &id, const QString &tag, double value, double minValue, double maxValue, const QMap<double, QString> &labels, QObject* parent);
3722+
3723+ QString filterId() const override;
3724+ QString filterTag() const override;
3725+ QString title() const override;
3726+
3727+ double value() const override;
3728+ void setValue(double value) override;
3729+ double minValue() const override;
3730+ double maxValue() const override;
3731+ unity::shell::scopes::ValueSliderValuesInterface* values() const override;
3732+
3733+ // Not part of the iface, for mock/testing purposes
3734+ bool isActive() const;
3735+
3736+ void setTitle(const QString &title);
3737+
3738+private:
3739+ QString m_filterId;
3740+ QString m_filterTag;
3741+ QString m_title;
3742+
3743+ double m_value;
3744+ double m_minValue;
3745+ double m_maxValue;
3746+ unity::shell::scopes::ValueSliderValuesInterface *m_values;
3747+};
3748+
3749+#endif
3750
3751=== added file 'tests/mocks/Unity/fake_valueslidervalues.cpp'
3752--- tests/mocks/Unity/fake_valueslidervalues.cpp 1970-01-01 00:00:00 +0000
3753+++ tests/mocks/Unity/fake_valueslidervalues.cpp 2016-03-21 16:06:44 +0000
3754@@ -0,0 +1,51 @@
3755+/*
3756+ * Copyright (C) 2015 Canonical, Ltd.
3757+ *
3758+ * This program is free software; you can redistribute it and/or modify
3759+ * it under the terms of the GNU General Public License as published by
3760+ * the Free Software Foundation; version 3.
3761+ *
3762+ * This program is distributed in the hope that it will be useful,
3763+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3764+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3765+ * GNU General Public License for more details.
3766+ *
3767+ * You should have received a copy of the GNU General Public License
3768+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3769+ */
3770+
3771+#include "fake_valueslidervalues.h"
3772+
3773+FakeValueSliderValues::FakeValueSliderValues(const QMap<double, QString> &labels, QObject* parent)
3774+ : unity::shell::scopes::ValueSliderValuesInterface(parent)
3775+ , m_labels(labels)
3776+{
3777+}
3778+
3779+int FakeValueSliderValues::rowCount(const QModelIndex &parent) const
3780+{
3781+ if (parent.isValid())
3782+ return 0;
3783+
3784+ return m_labels.count();
3785+}
3786+
3787+QVariant FakeValueSliderValues::data(const QModelIndex &index, int role) const
3788+{
3789+ if (!index.isValid())
3790+ return QVariant();
3791+
3792+ const int row = index.row();
3793+ auto it = m_labels.begin();
3794+ it += row;
3795+
3796+ switch (role) {
3797+ case RoleValue:
3798+ return it.key();
3799+
3800+ case RoleLabel:
3801+ return it.value();
3802+ }
3803+
3804+ return QVariant();
3805+}
3806
3807=== added file 'tests/mocks/Unity/fake_valueslidervalues.h'
3808--- tests/mocks/Unity/fake_valueslidervalues.h 1970-01-01 00:00:00 +0000
3809+++ tests/mocks/Unity/fake_valueslidervalues.h 2016-03-21 16:06:44 +0000
3810@@ -0,0 +1,36 @@
3811+/*
3812+ * Copyright (C) 2015 Canonical, Ltd.
3813+ *
3814+ * This program is free software; you can redistribute it and/or modify
3815+ * it under the terms of the GNU General Public License as published by
3816+ * the Free Software Foundation; version 3.
3817+ *
3818+ * This program is distributed in the hope that it will be useful,
3819+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3820+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3821+ * GNU General Public License for more details.
3822+ *
3823+ * You should have received a copy of the GNU General Public License
3824+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3825+ */
3826+
3827+#ifndef FAKE_VALUESLIDERVALUES_H
3828+#define FAKE_VALUESLIDERVALUES_H
3829+
3830+#include <unity/shell/scopes/ValueSliderValuesInterface.h>
3831+
3832+class FakeValueSliderValues : public unity::shell::scopes::ValueSliderValuesInterface
3833+{
3834+ Q_OBJECT
3835+
3836+public:
3837+ FakeValueSliderValues(const QMap<double, QString> &labels, QObject* parent);
3838+
3839+ int rowCount(const QModelIndex &parent) const override;
3840+ QVariant data(const QModelIndex &index, int role) const override;
3841+
3842+private:
3843+ const QMap<double, QString> m_labels;
3844+};
3845+
3846+#endif
3847
3848=== modified file 'tests/plugins/Dash/cardcreator/1.res'
3849--- tests/plugins/Dash/cardcreator/1.res 2016-02-17 10:51:17 +0000
3850+++ tests/plugins/Dash/cardcreator/1.res 2016-03-21 16:06:44 +0000
3851@@ -11,7 +11,7 @@
3852 property bool showHeader: true;
3853 implicitWidth: childrenRect.width;
3854 enabled: true;
3855-
3856+signal action(var actionId);
3857 readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
3858 Item {
3859 id: artShapeHolder;
3860
3861=== modified file 'tests/plugins/Dash/cardcreator/1.res.cardcreator'
3862--- tests/plugins/Dash/cardcreator/1.res.cardcreator 2016-02-17 10:51:17 +0000
3863+++ tests/plugins/Dash/cardcreator/1.res.cardcreator 2016-03-21 16:06:44 +0000
3864@@ -10,7 +10,7 @@
3865 property bool showHeader: true;
3866 implicitWidth: childrenRect.width;
3867 enabled: true;
3868-
3869+signal action(var actionId);
3870 readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
3871 Item {
3872 id: artShapeHolder;
3873
3874=== modified file 'tests/plugins/Dash/cardcreator/10.res'
3875--- tests/plugins/Dash/cardcreator/10.res 2016-02-17 10:51:17 +0000
3876+++ tests/plugins/Dash/cardcreator/10.res 2016-03-21 16:06:44 +0000
3877@@ -11,7 +11,7 @@
3878 property bool showHeader: true;
3879 implicitWidth: childrenRect.width;
3880 enabled: true;
3881-
3882+signal action(var actionId);
3883 Loader {
3884 id: backgroundLoader;
3885 objectName: "backgroundLoader";
3886
3887=== modified file 'tests/plugins/Dash/cardcreator/10.res.cardcreator'
3888--- tests/plugins/Dash/cardcreator/10.res.cardcreator 2016-02-17 10:51:17 +0000
3889+++ tests/plugins/Dash/cardcreator/10.res.cardcreator 2016-03-21 16:06:44 +0000
3890@@ -10,7 +10,7 @@
3891 property bool showHeader: true;
3892 implicitWidth: childrenRect.width;
3893 enabled: true;
3894-
3895+signal action(var actionId);
3896 Loader {
3897 id: backgroundLoader;
3898 objectName: "backgroundLoader";
3899
3900=== modified file 'tests/plugins/Dash/cardcreator/11.res'
3901--- tests/plugins/Dash/cardcreator/11.res 2016-02-17 10:51:17 +0000
3902+++ tests/plugins/Dash/cardcreator/11.res 2016-03-21 16:06:44 +0000
3903@@ -11,7 +11,7 @@
3904 property bool showHeader: true;
3905 implicitWidth: childrenRect.width;
3906 enabled: true;
3907-
3908+signal action(var actionId);
3909 Loader {
3910 id: backgroundLoader;
3911 objectName: "backgroundLoader";
3912
3913=== modified file 'tests/plugins/Dash/cardcreator/11.res.cardcreator'
3914--- tests/plugins/Dash/cardcreator/11.res.cardcreator 2016-02-17 10:51:17 +0000
3915+++ tests/plugins/Dash/cardcreator/11.res.cardcreator 2016-03-21 16:06:44 +0000
3916@@ -10,7 +10,7 @@
3917 property bool showHeader: true;
3918 implicitWidth: childrenRect.width;
3919 enabled: true;
3920-
3921+signal action(var actionId);
3922 Loader {
3923 id: backgroundLoader;
3924 objectName: "backgroundLoader";
3925
3926=== added file 'tests/plugins/Dash/cardcreator/12.res'
3927--- tests/plugins/Dash/cardcreator/12.res 1970-01-01 00:00:00 +0000
3928+++ tests/plugins/Dash/cardcreator/12.res 2016-03-21 16:06:44 +0000
3929@@ -0,0 +1,146 @@
3930+AbstractButton {
3931+ id: root;
3932+ property var cardData;
3933+ property string artShapeStyle: "inset";
3934+ property string backgroundShapeStyle: "inset";
3935+ property real fontScale: 1.0;
3936+ property var scopeStyle: null;
3937+ property int fixedHeaderHeight: -1;
3938+ property size fixedArtShapeSize: Qt.size(-1, -1);
3939+ readonly property string title: cardData && cardData["title"] || "";
3940+ property bool showHeader: true;
3941+ implicitWidth: childrenRect.width;
3942+ enabled: true;
3943+signal action(var actionId);
3944+readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
3945+Item {
3946+ id: artShapeHolder;
3947+ height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height;
3948+ width: root.fixedArtShapeSize.width > 0 ? root.fixedArtShapeSize.width : artShapeLoader.width;
3949+ anchors { horizontalCenter: parent.horizontalCenter; }
3950+ Loader {
3951+ id: artShapeLoader;
3952+ objectName: "artShapeLoader";
3953+ readonly property string cardArt: cardData && cardData["art"] || "";
3954+ active: cardArt != "";
3955+ asynchronous: true;
3956+ visible: status == Loader.Ready;
3957+ sourceComponent: Item {
3958+ id: artShape;
3959+ objectName: "artShape";
3960+ visible: image.status == Image.Ready;
3961+ readonly property alias image: artImage;
3962+ ShaderEffectSource {
3963+ id: artShapeSource;
3964+ sourceItem: artImage;
3965+ anchors.centerIn: parent;
3966+ width: 1;
3967+ height: 1;
3968+ hideSource: true;
3969+ }
3970+ Loader {
3971+ anchors.fill: parent;
3972+ visible: true;
3973+ sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent;
3974+ Component {
3975+ id: artShapeShapeComponent;
3976+ UbuntuShape {
3977+ source: artShapeSource;
3978+ sourceFillMode: UbuntuShape.PreserveAspectCrop;
3979+ radius: "medium";
3980+ aspect: {
3981+ switch (root.artShapeStyle) {
3982+ case "inset": return UbuntuShape.Inset;
3983+ case "shadow": return UbuntuShape.DropShadow;
3984+ default:
3985+ case "flat": return UbuntuShape.Flat;
3986+ }
3987+ }
3988+ }
3989+ }
3990+ Component {
3991+ id: artShapeIconComponent;
3992+ ProportionalShape { source: artShapeSource; aspect: UbuntuShape.DropShadow; }
3993+ }
3994+ }
3995+ readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
3996+ readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : 0.75;
3997+ Component.onCompleted: { updateWidthHeightBindings(); }
3998+ Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
3999+ function updateWidthHeightBindings() {
4000+ if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
4001+ width = root.fixedArtShapeSize.width;
4002+ height = root.fixedArtShapeSize.height;
4003+ } else {
4004+ width = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.width });
4005+ height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
4006+ }
4007+ }
4008+ CroppedImageMinimumSourceSize {
4009+ id: artImage;
4010+ objectName: "artImage";
4011+ source: artShapeLoader.cardArt;
4012+ asynchronous: true;
4013+ width: root.width;
4014+ height: width / artShape.aspect;
4015+ }
4016+ }
4017+ }
4018+ }
4019+readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin;
4020+Label {
4021+ id: titleLabel;
4022+ objectName: "titleLabel";
4023+ anchors { right: parent.right;
4024+ left: parent.left;
4025+ top: artShapeHolder.bottom;
4026+ topMargin: units.gu(1);
4027+ }
4028+ elide: Text.ElideRight;
4029+ fontSize: "small";
4030+ wrapMode: Text.Wrap;
4031+ maximumLineCount: 2;
4032+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
4033+ color: root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText;
4034+ visible: showHeader ;
4035+ width: undefined;
4036+ text: root.title;
4037+ font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal;
4038+ horizontalAlignment: Text.AlignLeft;
4039+ }
4040+Label {
4041+ id: subtitleLabel;
4042+ objectName: "subtitleLabel";
4043+ anchors { left: titleLabel.left;
4044+ leftMargin: titleLabel.leftMargin;
4045+ right: titleLabel.right;
4046+ top: titleLabel.bottom;
4047+ }
4048+ anchors.topMargin: units.dp(2);
4049+ elide: Text.ElideRight;
4050+ maximumLineCount: 1;
4051+ fontSize: "x-small";
4052+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
4053+ color: root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText;
4054+ visible: titleLabel.visible && titleLabel.text;
4055+ text: cardData && cardData["subtitle"] || "";
4056+ font.weight: Font.Light;
4057+ }
4058+CardSocialActions {
4059+ id: socialActionsRow;
4060+ objectName: "socialActionsRow";
4061+ anchors { top: subtitleLabel.bottom; left: parent.left; right: parent.right; topMargin: units.gu(1); }
4062+ color: root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText;
4063+ model: cardData && cardData["socialActions"];
4064+ onClicked: root.action(actionId);
4065+}
4066+UbuntuShape {
4067+ id: touchdown;
4068+ objectName: "touchdown";
4069+ anchors { fill: artShapeHolder }
4070+ visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
4071+ radius: "medium";
4072+ borderSource: "radius_pressed.sci"
4073+}
4074+implicitHeight: socialActionsRow.y + socialActionsRow.height + units.gu(1);
4075+}
4076
4077=== added file 'tests/plugins/Dash/cardcreator/12.res.cardcreator'
4078--- tests/plugins/Dash/cardcreator/12.res.cardcreator 1970-01-01 00:00:00 +0000
4079+++ tests/plugins/Dash/cardcreator/12.res.cardcreator 2016-03-21 16:06:44 +0000
4080@@ -0,0 +1,145 @@
4081+AbstractButton {
4082+ id: root;
4083+ property var cardData;
4084+ property string artShapeStyle: "inset";
4085+ property string backgroundShapeStyle: "inset";
4086+ property real fontScale: 1.0;
4087+ property var scopeStyle: null;
4088+ property size fixedArtShapeSize: Qt.size(-1, -1);
4089+ readonly property string title: cardData && cardData["title"] || "";
4090+ property bool showHeader: true;
4091+ implicitWidth: childrenRect.width;
4092+ enabled: true;
4093+signal action(var actionId);
4094+readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
4095+Item {
4096+ id: artShapeHolder;
4097+ height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height;
4098+ width: root.fixedArtShapeSize.width > 0 ? root.fixedArtShapeSize.width : artShapeLoader.width;
4099+ anchors { horizontalCenter: parent.horizontalCenter; }
4100+ Loader {
4101+ id: artShapeLoader;
4102+ objectName: "artShapeLoader";
4103+ readonly property string cardArt: cardData && cardData["art"] || "";
4104+ active: cardArt != "";
4105+ asynchronous: false;
4106+ visible: status == Loader.Ready;
4107+ sourceComponent: Item {
4108+ id: artShape;
4109+ objectName: "artShape";
4110+ visible: image.status == Image.Ready;
4111+ readonly property alias image: artImage;
4112+ ShaderEffectSource {
4113+ id: artShapeSource;
4114+ sourceItem: artImage;
4115+ anchors.centerIn: parent;
4116+ width: 1;
4117+ height: 1;
4118+ hideSource: true;
4119+ }
4120+ Loader {
4121+ anchors.fill: parent;
4122+ visible: true;
4123+ sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent;
4124+ Component {
4125+ id: artShapeShapeComponent;
4126+ UbuntuShape {
4127+ source: artShapeSource;
4128+ sourceFillMode: UbuntuShape.PreserveAspectCrop;
4129+ radius: "medium";
4130+ aspect: {
4131+ switch (root.artShapeStyle) {
4132+ case "inset": return UbuntuShape.Inset;
4133+ case "shadow": return UbuntuShape.DropShadow;
4134+ default:
4135+ case "flat": return UbuntuShape.Flat;
4136+ }
4137+ }
4138+ }
4139+ }
4140+ Component {
4141+ id: artShapeIconComponent;
4142+ ProportionalShape { source: artShapeSource; aspect: UbuntuShape.DropShadow; }
4143+ }
4144+ }
4145+ readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
4146+ readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : 0.75;
4147+ Component.onCompleted: { updateWidthHeightBindings(); }
4148+ Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
4149+ function updateWidthHeightBindings() {
4150+ if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
4151+ width = root.fixedArtShapeSize.width;
4152+ height = root.fixedArtShapeSize.height;
4153+ } else {
4154+ width = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.width });
4155+ height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
4156+ }
4157+ }
4158+ CroppedImageMinimumSourceSize {
4159+ id: artImage;
4160+ objectName: "artImage";
4161+ source: artShapeLoader.cardArt;
4162+ asynchronous: false;
4163+ width: root.width;
4164+ height: width / artShape.aspect;
4165+ }
4166+ }
4167+ }
4168+ }
4169+readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin;
4170+Label {
4171+ id: titleLabel;
4172+ objectName: "titleLabel";
4173+ anchors { right: parent.right;
4174+ left: parent.left;
4175+ top: artShapeHolder.bottom;
4176+ topMargin: units.gu(1);
4177+ }
4178+ elide: Text.ElideRight;
4179+ fontSize: "small";
4180+ wrapMode: Text.Wrap;
4181+ maximumLineCount: 2;
4182+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
4183+ color: root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText;
4184+ visible: showHeader ;
4185+ width: undefined;
4186+ text: root.title;
4187+ font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal;
4188+ horizontalAlignment: Text.AlignLeft;
4189+ }
4190+Label {
4191+ id: subtitleLabel;
4192+ objectName: "subtitleLabel";
4193+ anchors { left: titleLabel.left;
4194+ leftMargin: titleLabel.leftMargin;
4195+ right: titleLabel.right;
4196+ top: titleLabel.bottom;
4197+ }
4198+ anchors.topMargin: units.dp(2);
4199+ elide: Text.ElideRight;
4200+ maximumLineCount: 1;
4201+ fontSize: "x-small";
4202+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
4203+ color: root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText;
4204+ visible: titleLabel.visible && titleLabel.text;
4205+ text: cardData && cardData["subtitle"] || "";
4206+ font.weight: Font.Light;
4207+ }
4208+CardSocialActions {
4209+ id: socialActionsRow;
4210+ objectName: "socialActionsRow";
4211+ anchors { top: subtitleLabel.bottom; left: parent.left; right: parent.right; topMargin: units.gu(1); }
4212+ color: root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText;
4213+ model: cardData && cardData["socialActions"];
4214+ onClicked: root.action(actionId);
4215+}
4216+UbuntuShape {
4217+ id: touchdown;
4218+ objectName: "touchdown";
4219+ anchors { fill: artShapeHolder }
4220+ visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
4221+ radius: "medium";
4222+ borderSource: "radius_pressed.sci"
4223+}
4224+implicitHeight: socialActionsRow.y + socialActionsRow.height + units.gu(1);
4225+}
4226
4227=== added file 'tests/plugins/Dash/cardcreator/12.tst'
4228--- tests/plugins/Dash/cardcreator/12.tst 1970-01-01 00:00:00 +0000
4229+++ tests/plugins/Dash/cardcreator/12.tst 2016-03-21 16:06:44 +0000
4230@@ -0,0 +1,3 @@
4231+template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
4232+components: {"art":{"aspect-ratio":0.75,"field":"art"},"subtitle":{"field":"price"},"title":{"field":"title"},"attributes":{},"social-actions":{}}
4233+result: 12.res
4234
4235=== modified file 'tests/plugins/Dash/cardcreator/2.res'
4236--- tests/plugins/Dash/cardcreator/2.res 2016-02-17 10:51:17 +0000
4237+++ tests/plugins/Dash/cardcreator/2.res 2016-03-21 16:06:44 +0000
4238@@ -11,7 +11,7 @@
4239 property bool showHeader: true;
4240 implicitWidth: childrenRect.width;
4241 enabled: true;
4242-
4243+signal action(var actionId);
4244 Loader {
4245 id: backgroundLoader;
4246 objectName: "backgroundLoader";
4247
4248=== modified file 'tests/plugins/Dash/cardcreator/2.res.cardcreator'
4249--- tests/plugins/Dash/cardcreator/2.res.cardcreator 2016-02-17 10:51:17 +0000
4250+++ tests/plugins/Dash/cardcreator/2.res.cardcreator 2016-03-21 16:06:44 +0000
4251@@ -10,7 +10,7 @@
4252 property bool showHeader: true;
4253 implicitWidth: childrenRect.width;
4254 enabled: true;
4255-
4256+signal action(var actionId);
4257 Loader {
4258 id: backgroundLoader;
4259 objectName: "backgroundLoader";
4260
4261=== modified file 'tests/plugins/Dash/cardcreator/3.res'
4262--- tests/plugins/Dash/cardcreator/3.res 2016-02-17 10:51:17 +0000
4263+++ tests/plugins/Dash/cardcreator/3.res 2016-03-21 16:06:44 +0000
4264@@ -11,7 +11,7 @@
4265 property bool showHeader: true;
4266 implicitWidth: childrenRect.width;
4267 enabled: true;
4268-
4269+signal action(var actionId);
4270 readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
4271 Item {
4272 id: artShapeHolder;
4273
4274=== modified file 'tests/plugins/Dash/cardcreator/3.res.cardcreator'
4275--- tests/plugins/Dash/cardcreator/3.res.cardcreator 2016-02-17 10:51:17 +0000
4276+++ tests/plugins/Dash/cardcreator/3.res.cardcreator 2016-03-21 16:06:44 +0000
4277@@ -10,7 +10,7 @@
4278 property bool showHeader: true;
4279 implicitWidth: childrenRect.width;
4280 enabled: true;
4281-
4282+signal action(var actionId);
4283 readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
4284 Item {
4285 id: artShapeHolder;
4286
4287=== modified file 'tests/plugins/Dash/cardcreator/4.res'
4288--- tests/plugins/Dash/cardcreator/4.res 2016-02-17 10:51:17 +0000
4289+++ tests/plugins/Dash/cardcreator/4.res 2016-03-21 16:06:44 +0000
4290@@ -11,7 +11,7 @@
4291 property bool showHeader: true;
4292 implicitWidth: childrenRect.width;
4293 enabled: true;
4294-
4295+signal action(var actionId);
4296 readonly property size artShapeSize: Qt.size(-1, -1);
4297 readonly property int headerHeight: row.height;
4298 Row {
4299
4300=== modified file 'tests/plugins/Dash/cardcreator/4.res.cardcreator'
4301--- tests/plugins/Dash/cardcreator/4.res.cardcreator 2016-02-17 10:51:17 +0000
4302+++ tests/plugins/Dash/cardcreator/4.res.cardcreator 2016-03-21 16:06:44 +0000
4303@@ -10,7 +10,7 @@
4304 property bool showHeader: true;
4305 implicitWidth: childrenRect.width;
4306 enabled: true;
4307-
4308+signal action(var actionId);
4309 readonly property size artShapeSize: Qt.size(-1, -1);
4310 readonly property int headerHeight: row.height;
4311 Row {
4312
4313=== modified file 'tests/plugins/Dash/cardcreator/5.res'
4314--- tests/plugins/Dash/cardcreator/5.res 2016-02-17 10:51:17 +0000
4315+++ tests/plugins/Dash/cardcreator/5.res 2016-03-21 16:06:44 +0000
4316@@ -11,7 +11,7 @@
4317 property bool showHeader: true;
4318 implicitWidth: childrenRect.width;
4319 enabled: false;
4320-
4321+signal action(var actionId);
4322 readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
4323 Item {
4324 id: artShapeHolder;
4325
4326=== modified file 'tests/plugins/Dash/cardcreator/5.res.cardcreator'
4327--- tests/plugins/Dash/cardcreator/5.res.cardcreator 2016-02-17 10:51:17 +0000
4328+++ tests/plugins/Dash/cardcreator/5.res.cardcreator 2016-03-21 16:06:44 +0000
4329@@ -10,7 +10,7 @@
4330 property bool showHeader: true;
4331 implicitWidth: childrenRect.width;
4332 enabled: false;
4333-
4334+signal action(var actionId);
4335 readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
4336 Item {
4337 id: artShapeHolder;
4338
4339=== modified file 'tests/plugins/Dash/cardcreator/6.res'
4340--- tests/plugins/Dash/cardcreator/6.res 2016-02-17 10:51:17 +0000
4341+++ tests/plugins/Dash/cardcreator/6.res 2016-03-21 16:06:44 +0000
4342@@ -11,7 +11,7 @@
4343 property bool showHeader: true;
4344 implicitWidth: childrenRect.width;
4345 enabled: true;
4346-
4347+signal action(var actionId);
4348 Loader {
4349 id: backgroundLoader;
4350 objectName: "backgroundLoader";
4351
4352=== modified file 'tests/plugins/Dash/cardcreator/6.res.cardcreator'
4353--- tests/plugins/Dash/cardcreator/6.res.cardcreator 2016-02-17 10:51:17 +0000
4354+++ tests/plugins/Dash/cardcreator/6.res.cardcreator 2016-03-21 16:06:44 +0000
4355@@ -10,7 +10,7 @@
4356 property bool showHeader: true;
4357 implicitWidth: childrenRect.width;
4358 enabled: true;
4359-
4360+signal action(var actionId);
4361 Loader {
4362 id: backgroundLoader;
4363 objectName: "backgroundLoader";
4364
4365=== modified file 'tests/plugins/Dash/cardcreator/7.res'
4366--- tests/plugins/Dash/cardcreator/7.res 2016-02-17 10:51:17 +0000
4367+++ tests/plugins/Dash/cardcreator/7.res 2016-03-21 16:06:44 +0000
4368@@ -11,7 +11,7 @@
4369 property bool showHeader: true;
4370 implicitWidth: childrenRect.width;
4371 enabled: true;
4372-
4373+signal action(var actionId);
4374 Loader {
4375 id: backgroundLoader;
4376 objectName: "backgroundLoader";
4377
4378=== modified file 'tests/plugins/Dash/cardcreator/7.res.cardcreator'
4379--- tests/plugins/Dash/cardcreator/7.res.cardcreator 2016-02-17 10:51:17 +0000
4380+++ tests/plugins/Dash/cardcreator/7.res.cardcreator 2016-03-21 16:06:44 +0000
4381@@ -10,7 +10,7 @@
4382 property bool showHeader: true;
4383 implicitWidth: childrenRect.width;
4384 enabled: true;
4385-
4386+signal action(var actionId);
4387 Loader {
4388 id: backgroundLoader;
4389 objectName: "backgroundLoader";
4390
4391=== modified file 'tests/plugins/Dash/cardcreator/8.res'
4392--- tests/plugins/Dash/cardcreator/8.res 2016-02-17 10:51:17 +0000
4393+++ tests/plugins/Dash/cardcreator/8.res 2016-03-21 16:06:44 +0000
4394@@ -11,7 +11,7 @@
4395 property bool showHeader: true;
4396 implicitWidth: childrenRect.width;
4397 enabled: true;
4398-
4399+signal action(var actionId);
4400 Loader {
4401 id: backgroundLoader;
4402 objectName: "backgroundLoader";
4403
4404=== modified file 'tests/plugins/Dash/cardcreator/8.res.cardcreator'
4405--- tests/plugins/Dash/cardcreator/8.res.cardcreator 2016-02-17 10:51:17 +0000
4406+++ tests/plugins/Dash/cardcreator/8.res.cardcreator 2016-03-21 16:06:44 +0000
4407@@ -10,7 +10,7 @@
4408 property bool showHeader: true;
4409 implicitWidth: childrenRect.width;
4410 enabled: true;
4411-
4412+signal action(var actionId);
4413 Loader {
4414 id: backgroundLoader;
4415 objectName: "backgroundLoader";
4416
4417=== modified file 'tests/plugins/Dash/cardcreator/9.res'
4418--- tests/plugins/Dash/cardcreator/9.res 2016-03-10 16:53:04 +0000
4419+++ tests/plugins/Dash/cardcreator/9.res 2016-03-21 16:06:44 +0000
4420@@ -11,7 +11,7 @@
4421 property bool showHeader: true;
4422 implicitWidth: childrenRect.width;
4423 enabled: true;
4424-
4425+signal action(var actionId);
4426 readonly property size artShapeSize: Qt.size(-1, -1);
4427 readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin + audioProgressBar.height + audioProgressBar.anchors.topMargin;
4428 Label {
4429
4430=== modified file 'tests/plugins/Dash/cardcreator/9.res.cardcreator'
4431--- tests/plugins/Dash/cardcreator/9.res.cardcreator 2016-03-10 16:53:04 +0000
4432+++ tests/plugins/Dash/cardcreator/9.res.cardcreator 2016-03-21 16:06:44 +0000
4433@@ -10,7 +10,7 @@
4434 property bool showHeader: true;
4435 implicitWidth: childrenRect.width;
4436 enabled: true;
4437-
4438+signal action(var actionId);
4439 readonly property size artShapeSize: Qt.size(-1, -1);
4440 readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin + audioProgressBar.height + audioProgressBar.anchors.topMargin;
4441 Label {
4442
4443=== modified file 'tests/qmltests/CMakeLists.txt'
4444--- tests/qmltests/CMakeLists.txt 2016-03-10 22:41:38 +0000
4445+++ tests/qmltests/CMakeLists.txt 2016-03-21 16:06:44 +0000
4446@@ -53,6 +53,10 @@
4447 add_unity8_qmltest(Dash/Previews PreviewVideoPlayback)
4448 add_unity8_qmltest(Dash/Previews PreviewWidgetFactory)
4449 add_unity8_qmltest(Dash/Previews PreviewZoomableImage)
4450+add_unity8_qmltest(Dash/Filters FilterOptionSelector)
4451+add_unity8_qmltest(Dash/Filters FilterRangeInput)
4452+add_unity8_qmltest(Dash/Filters FilterValueSlider)
4453+add_unity8_qmltest(Dash/Filters FilterWidgetFactory)
4454 add_unity8_qmltest(Dash/ScopeSettings ScopeSettingBoolean)
4455 add_unity8_qmltest(Dash/ScopeSettings ScopeSettingList)
4456 add_unity8_qmltest(Dash/ScopeSettings ScopeSettingNumber)
4457
4458=== modified file 'tests/qmltests/Dash/CardHelpers.js'
4459--- tests/qmltests/Dash/CardHelpers.js 2015-05-15 12:57:48 +0000
4460+++ tests/qmltests/Dash/CardHelpers.js 2016-03-21 16:06:44 +0000
4461@@ -16,7 +16,8 @@
4462
4463 .pragma library
4464
4465-var components = ["title", "art", "subtitle", "mascot", "emblem", "summary", "attributes", "overlayColor", "quickPreviewData"]
4466+var components = ["title", "art", "subtitle", "mascot", "emblem", "summary", "attributes", "social-actions", "overlayColor", "quickPreviewData"]
4467+var dataKeys = ["title", "art", "subtitle", "mascot", "emblem", "summary", "attributes", "socialActions", "overlayColor", "quickPreviewData"]
4468
4469 var defaultLayout = ' \
4470 { \
4471@@ -38,7 +39,8 @@
4472 "mascot": null, \
4473 "emblem": null, \
4474 "summary": null, \
4475- "attributes": { "max-count": 2 } \
4476+ "attributes": { "max-count": 2 },
4477+ "social-actions": null \
4478 }, \
4479 "resources": {} \
4480 }'
4481@@ -52,10 +54,10 @@
4482 "emblem": "emblem", \
4483 "overlayColor": "overlayColor", \
4484 "summary": "summary", \
4485- "attributes": "attributes" \
4486+ "attributes": "attributes", \
4487+ "social-actions": "socialActions" \
4488 }'
4489
4490-
4491 function tryParse(json, errorLabel) {
4492 var o = undefined;
4493 if (errorLabel !== undefined) {
4494@@ -82,12 +84,12 @@
4495 for (var k in components) {
4496 try {
4497 if (typeof layout[components[k]] == "object") {
4498- d[components[k]] = o[layout[components[k]]['field']];
4499+ d[dataKeys[k]] = o[layout[components[k]]['field']];
4500 } else {
4501- d[components[k]] = o[layout[components[k]]];
4502+ d[dataKeys[k]] = o[layout[components[k]]];
4503 }
4504 } catch(err) {
4505- d[components[k]] = undefined;
4506+ d[dataKeys[k]] = undefined;
4507 }
4508 }
4509 }
4510
4511=== added directory 'tests/qmltests/Dash/Filters'
4512=== added file 'tests/qmltests/Dash/Filters/tst_FilterOptionSelector.qml'
4513--- tests/qmltests/Dash/Filters/tst_FilterOptionSelector.qml 1970-01-01 00:00:00 +0000
4514+++ tests/qmltests/Dash/Filters/tst_FilterOptionSelector.qml 2016-03-21 16:06:44 +0000
4515@@ -0,0 +1,96 @@
4516+/*
4517+ * Copyright 2015 Canonical Ltd.
4518+ *
4519+ * This program is free software; you can redistribute it and/or modify
4520+ * it under the terms of the GNU General Public License as published by
4521+ * the Free Software Foundation; version 3.
4522+ *
4523+ * This program is distributed in the hope that it will be useful,
4524+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4525+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4526+ * GNU General Public License for more details.
4527+ *
4528+ * You should have received a copy of the GNU General Public License
4529+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4530+ */
4531+
4532+import QtQuick 2.4
4533+import QtTest 1.0
4534+import "../../../../qml/Dash/Filters"
4535+import Unity.Test 0.1 as UT
4536+import Unity 0.2
4537+import Ubuntu.Components 1.3
4538+
4539+Rectangle {
4540+ id: root
4541+ width: units.gu(60)
4542+ height: units.gu(80)
4543+ color: theme.palette.selected.background
4544+
4545+ property var singleSelectionWidgetData
4546+
4547+ ListModel {
4548+ id: optionsSingleSelect
4549+ ListElement {
4550+ label: "A"
4551+ checked: false
4552+ }
4553+ ListElement {
4554+ label: "B"
4555+ checked: false
4556+ }
4557+ ListElement {
4558+ label: "C"
4559+ checked: false
4560+ }
4561+
4562+ function setChecked(index, checked) {
4563+ for (var i = 0; i < optionsSingleSelect.count; ++i)
4564+ optionsSingleSelect.setProperty(i, "checked", false);
4565+ optionsSingleSelect.setProperty(index, "checked", checked);
4566+ }
4567+ }
4568+
4569+ Component.onCompleted: {
4570+ singleSelectionWidgetData = { label: "Hola", options: optionsSingleSelect }
4571+ }
4572+
4573+ FilterWidgetFactory {
4574+ id: factory
4575+ widgetId: "testOptionSelectorFilter"
4576+ widgetType: Filters.OptionSelectorFilter
4577+ widgetData: singleSelectionWidgetData
4578+ anchors {
4579+ left: parent.left
4580+ right: parent.right
4581+ }
4582+ }
4583+
4584+ UT.UnityTestCase {
4585+ name: "FilterOptionSelector"
4586+ when: windowShown
4587+
4588+ function test_optionSelector() {
4589+ var expandingItem = findChild(factory, "expandingItem");
4590+ // Open the selector
4591+ mouseClick(factory);
4592+ // wait for it to stop growing
4593+ tryCompare(factory, "implicitHeight", expandingItem.expandedHeight);
4594+
4595+ // Check the first option
4596+ var option0 = findChild(factory, "testOptionSelectorFilterlabel0");
4597+ mouseClick(option0);
4598+ verify(optionsSingleSelect.get(0).checked);
4599+
4600+ // Check the second option
4601+ var option1 = findChild(factory, "testOptionSelectorFilterlabel1");
4602+ mouseClick(option1);
4603+ verify(!optionsSingleSelect.get(0).checked);
4604+ verify(optionsSingleSelect.get(1).checked);
4605+
4606+ // Uncheck the second option
4607+ mouseClick(option1);
4608+ verify(!optionsSingleSelect.get(1).checked);
4609+ }
4610+ }
4611+}
4612
4613=== added file 'tests/qmltests/Dash/Filters/tst_FilterRangeInput.qml'
4614--- tests/qmltests/Dash/Filters/tst_FilterRangeInput.qml 1970-01-01 00:00:00 +0000
4615+++ tests/qmltests/Dash/Filters/tst_FilterRangeInput.qml 2016-03-21 16:06:44 +0000
4616@@ -0,0 +1,247 @@
4617+/*
4618+ * Copyright 2015 Canonical Ltd.
4619+ *
4620+ * This program is free software; you can redistribute it and/or modify
4621+ * it under the terms of the GNU General Public License as published by
4622+ * the Free Software Foundation; version 3.
4623+ *
4624+ * This program is distributed in the hope that it will be useful,
4625+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4626+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4627+ * GNU General Public License for more details.
4628+ *
4629+ * You should have received a copy of the GNU General Public License
4630+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4631+ */
4632+
4633+import QtQuick 2.4
4634+import QtTest 1.0
4635+import Ubuntu.Components 1.3
4636+import "../../../../qml/Dash/Filters"
4637+import Unity.Test 0.1 as UT
4638+import Unity 0.2
4639+
4640+Rectangle {
4641+ id: root
4642+ width: units.gu(60)
4643+ height: units.gu(80)
4644+ color: theme.palette.selected.background
4645+
4646+ QtObject {
4647+ id: widgetData1
4648+
4649+ property string title
4650+ property real startValue
4651+ property real endValue
4652+ property bool hasStartValue
4653+ property bool hasEndValue
4654+ property string startPrefixLabel
4655+ property string startPostfixLabel
4656+ property string centralLabel
4657+ property string endPrefixLabel
4658+ property string endPostfixLabel
4659+
4660+ onStartValueChanged: {
4661+ hasStartValue = true;
4662+ }
4663+
4664+ onEndValueChanged: {
4665+ hasEndValue = true;
4666+ }
4667+
4668+ function eraseStartValue() {
4669+ hasStartValue = false;
4670+ }
4671+
4672+ function eraseEndValue() {
4673+ hasEndValue = false;
4674+ }
4675+ }
4676+
4677+ Component.onCompleted: {
4678+ generateData();
4679+ }
4680+
4681+ function generateData() {
4682+ widgetData1.title = title.text
4683+ widgetData1.startValue = startValue.text;
4684+ widgetData1.endValue = endValue.text;
4685+ widgetData1.hasStartValue = startValueHasValue.checked;
4686+ widgetData1.hasEndValue = endValueHasValue.checked;
4687+ widgetData1.startPrefixLabel = startValuePrefixLabel.text;
4688+ widgetData1.startPostfixLabel = startValuePostfixLabel.text;
4689+ widgetData1.centralLabel = centralLabel.text;
4690+ widgetData1.endPrefixLabel = endValuePrefixLabel.text;
4691+ widgetData1.endPostfixLabel = endValuePostfixLabel.text;
4692+
4693+ factory.widgetData = widgetData1;
4694+ }
4695+
4696+ FilterWidgetFactory {
4697+ id: factory
4698+ widgetId: "testRangeInputFilter"
4699+ widgetType: Filters.RangeInputFilter
4700+ anchors {
4701+ left: parent.left
4702+ right: parent.right
4703+ }
4704+ clip: true
4705+ }
4706+
4707+ Column {
4708+ anchors.top: factory.bottom
4709+ width: parent.width
4710+ spacing: units.gu(1)
4711+
4712+ Text {
4713+ text: "Values"
4714+ }
4715+
4716+ Row {
4717+ spacing: units.gu(1)
4718+ Text {
4719+ text: "Title"
4720+ verticalAlignment: Text.AlignVCenter
4721+ height: parent.height
4722+ }
4723+ TextField {
4724+ id: title
4725+ text: ""
4726+ }
4727+ }
4728+
4729+ Row {
4730+ spacing: units.gu(1)
4731+ Text {
4732+ text: "Start Value Prefix Label"
4733+ verticalAlignment: Text.AlignVCenter
4734+ height: parent.height
4735+ }
4736+ TextField {
4737+ id: startValuePrefixLabel
4738+ text: "Pre1"
4739+ }
4740+ }
4741+
4742+ Row {
4743+ spacing: units.gu(1)
4744+ Text {
4745+ text: "Start Value Postfix Label"
4746+ verticalAlignment: Text.AlignVCenter
4747+ height: parent.height
4748+ }
4749+ TextField {
4750+ id: startValuePostfixLabel
4751+ text: "Post1"
4752+ }
4753+ }
4754+
4755+ Row {
4756+ spacing: units.gu(1)
4757+ Text {
4758+ text: "Central Label"
4759+ verticalAlignment: Text.AlignVCenter
4760+ height: parent.height
4761+ }
4762+ TextField {
4763+ id: centralLabel
4764+ text: "to"
4765+ }
4766+ }
4767+
4768+ Row {
4769+ spacing: units.gu(1)
4770+ Text {
4771+ text: "End Value Prefix Label"
4772+ verticalAlignment: Text.AlignVCenter
4773+ height: parent.height
4774+ }
4775+ TextField {
4776+ id: endValuePrefixLabel
4777+ text: "Pre2"
4778+ }
4779+ }
4780+
4781+ Row {
4782+ spacing: units.gu(1)
4783+ Text {
4784+ text: "End Value Postfix Label"
4785+ verticalAlignment: Text.AlignVCenter
4786+ height: parent.height
4787+ }
4788+ TextField {
4789+ id: endValuePostfixLabel
4790+ text: "Post2"
4791+ }
4792+ }
4793+
4794+ Row {
4795+ spacing: units.gu(1)
4796+ Text {
4797+ text: "Start Value"
4798+ verticalAlignment: Text.AlignVCenter
4799+ height: parent.height
4800+ }
4801+ TextField {
4802+ id: startValue
4803+ text: "-1"
4804+ }
4805+ CheckBox {
4806+ id: startValueHasValue
4807+ }
4808+ }
4809+
4810+
4811+ Row {
4812+ spacing: units.gu(1)
4813+ Text {
4814+ text: "End Value"
4815+ verticalAlignment: Text.AlignVCenter
4816+ height: parent.height
4817+ }
4818+ TextField {
4819+ id: endValue
4820+ text: "5"
4821+ }
4822+ CheckBox {
4823+ id: endValueHasValue
4824+ checked: true
4825+ }
4826+ }
4827+
4828+ Button {
4829+ text: "Set Values"
4830+ onClicked: root.generateData();
4831+ }
4832+ }
4833+
4834+ UT.UnityTestCase {
4835+ name: "FilterRangeInput"
4836+ when: windowShown
4837+
4838+ function init() {
4839+ root.generateData();
4840+ }
4841+
4842+ function test_initialStatus() {
4843+ var startValueField = findChild(factory, "startValueField");
4844+ compare(startValueField.text, "");
4845+
4846+ var endValueField = findChild(factory, "endValueField");
4847+ compare(endValueField.text, "5");
4848+ }
4849+
4850+ function test_dotStays() {
4851+ var startValueField = findChild(factory, "startValueField");
4852+ compare(startValueField.text, "");
4853+
4854+ startValueField.text = "4.5";
4855+ compare(startValueField.text, "4.5");
4856+ compare(widgetData1.startValue, 4.5);
4857+
4858+ startValueField.text = "4.";
4859+ compare(startValueField.text, "4.");
4860+ compare(widgetData1.startValue, 4);
4861+ }
4862+ }
4863+}
4864
4865=== added file 'tests/qmltests/Dash/Filters/tst_FilterValueSlider.qml'
4866--- tests/qmltests/Dash/Filters/tst_FilterValueSlider.qml 1970-01-01 00:00:00 +0000
4867+++ tests/qmltests/Dash/Filters/tst_FilterValueSlider.qml 2016-03-21 16:06:44 +0000
4868@@ -0,0 +1,101 @@
4869+/*
4870+ * Copyright 2015 Canonical Ltd.
4871+ *
4872+ * This program is free software; you can redistribute it and/or modify
4873+ * it under the terms of the GNU General Public License as published by
4874+ * the Free Software Foundation; version 3.
4875+ *
4876+ * This program is distributed in the hope that it will be useful,
4877+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4878+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4879+ * GNU General Public License for more details.
4880+ *
4881+ * You should have received a copy of the GNU General Public License
4882+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4883+ */
4884+
4885+import QtQuick 2.4
4886+import QtTest 1.0
4887+import Ubuntu.Components 1.3
4888+import "../../../../qml/Dash/Filters"
4889+import Unity.Test 0.1 as UT
4890+import Unity 0.2
4891+
4892+Rectangle {
4893+ id: root
4894+ width: units.gu(60)
4895+ height: units.gu(80)
4896+ color: theme.palette.selected.background
4897+
4898+ QtObject {
4899+ id: widgetData1
4900+
4901+ property string title
4902+ property int value: 30
4903+ property int minValue: 10
4904+ property int maxValue: 150
4905+
4906+ property ListModel values: ListModel {
4907+ ListElement {
4908+ value: 10
4909+ label: "10"
4910+ }
4911+ ListElement {
4912+ value: 30
4913+ label: "30"
4914+ }
4915+ ListElement {
4916+ value: 100
4917+ label: "100"
4918+ }
4919+ ListElement {
4920+ value: 150
4921+ label: "150"
4922+ }
4923+ }
4924+ }
4925+
4926+ FilterWidgetFactory {
4927+ id: factory
4928+ widgetId: "testRangeValueSlider"
4929+ widgetType: Filters.ValueSliderFilter
4930+ widgetData: widgetData1;
4931+ y: 100
4932+ anchors {
4933+ left: parent.left
4934+ right: parent.right
4935+ }
4936+ }
4937+
4938+ UT.UnityTestCase {
4939+ name: "FilterValueSlider"
4940+ when: windowShown
4941+
4942+ function test_valueChanges() {
4943+ var slider = findChild(factory, "slider");
4944+ compare(slider.value, 30);
4945+
4946+ slider.value = 50
4947+ compare(widgetData1.value, 50);
4948+ }
4949+
4950+ function test_labelPositions() {
4951+ var slider = findChild(factory, "slider");
4952+ var repeater = findChild(factory, "repeater");
4953+
4954+ // It's very hard to check the position of the
4955+ // labels is right, but at least we can check
4956+ // they all have different X positions and the
4957+ // same Y one
4958+ compare(repeater.count, 4);
4959+ for (var i = 0; i < repeater.count; ++i) {
4960+ var itemI = repeater.itemAt(i);
4961+ for (var j = i + 1; j < repeater.count; ++j) {
4962+ var itemJ = repeater.itemAt(j);
4963+ verify(itemI.x != itemJ.x);
4964+ verify(itemI.y == itemJ.y);
4965+ }
4966+ }
4967+ }
4968+ }
4969+}
4970
4971=== added file 'tests/qmltests/Dash/Filters/tst_FilterWidgetFactory.qml'
4972--- tests/qmltests/Dash/Filters/tst_FilterWidgetFactory.qml 1970-01-01 00:00:00 +0000
4973+++ tests/qmltests/Dash/Filters/tst_FilterWidgetFactory.qml 2016-03-21 16:06:44 +0000
4974@@ -0,0 +1,57 @@
4975+/*
4976+ * Copyright 2015 Canonical Ltd.
4977+ *
4978+ * This program is free software; you can redistribute it and/or modify
4979+ * it under the terms of the GNU General Public License as published by
4980+ * the Free Software Foundation; version 3.
4981+ *
4982+ * This program is distributed in the hope that it will be useful,
4983+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4984+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4985+ * GNU General Public License for more details.
4986+ *
4987+ * You should have received a copy of the GNU General Public License
4988+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4989+ */
4990+
4991+import QtQuick 2.4
4992+import QtTest 1.0
4993+import "../../../../qml/Dash/Filters"
4994+import Unity.Test 0.1 as UT
4995+import Unity 0.2
4996+import Ubuntu.Components 1.3
4997+
4998+Rectangle {
4999+ id: root
5000+ width: units.gu(60)
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches