Merge lp:~artmello/content-hub/content-hub-clipboard into lp:content-hub
- content-hub-clipboard
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Ken VanDine |
Approved revision: | 403 |
Merged at revision: | 322 |
Proposed branch: | lp:~artmello/content-hub/content-hub-clipboard |
Merge into: | lp:content-hub |
Prerequisite: | lp:~ken-vandine/content-hub/ual_cpp_multi_instance |
Diff against target: |
2488 lines (+2130/-2) 31 files modified
debian/apparmor/content-hub-clipboard (+15/-0) debian/content-hub.install (+3/-0) debian/control (+1/-0) debian/rules (+1/-0) import/Ubuntu/Content/contenthub.cpp (+46/-0) import/Ubuntu/Content/contenthub.h (+8/-0) include/com/ubuntu/content/hub.h (+8/-1) src/com/ubuntu/content/common.h (+1/-0) src/com/ubuntu/content/detail/com.ubuntu.content.Service.xml (+34/-0) src/com/ubuntu/content/detail/service.cpp (+164/-0) src/com/ubuntu/content/detail/service.h (+11/-1) src/com/ubuntu/content/hub.cpp (+38/-0) tools/CMakeLists.txt (+1/-0) tools/clipboard/CMakeLists.txt (+72/-0) tools/clipboard/ClipboardItemDelegate.qml (+82/-0) tools/clipboard/PreviewImagePage.qml (+54/-0) tools/clipboard/PreviewTextPage.qml (+182/-0) tools/clipboard/clipboardapplication.cpp (+121/-0) tools/clipboard/clipboardapplication.h (+54/-0) tools/clipboard/content-hub-clipboard.desktop (+9/-0) tools/clipboard/main.cpp (+45/-0) tools/clipboard/main.qml (+308/-0) tools/clipboard/paste-data-filter-model.cpp (+60/-0) tools/clipboard/paste-data-filter-model.h (+54/-0) tools/clipboard/paste-data-model.cpp (+350/-0) tools/clipboard/paste-data-model.h (+128/-0) tools/clipboard/paste-data-provider.cpp (+105/-0) tools/clipboard/paste-data-provider.h (+75/-0) tools/clipboard/paste-image-provider.cpp (+53/-0) tools/clipboard/paste-image-provider.h (+39/-0) tools/clipboard/qml.qrc (+8/-0) |
To merge this branch: | bzr merge lp:~artmello/content-hub/content-hub-clipboard |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ken VanDine | Approve | ||
system-apps-ci-bot | continuous-integration | Pending | |
Review via email: mp+317463@code.launchpad.net |
This proposal supersedes a proposal from 2016-11-17.
Commit message
Implement Clipboard UI/backend connection, so users can use it to manage/select latest copied data
Description of the change
Implement Clipboard UI/backend connection, so users can use it to manage/select latest copied data
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:326
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:328
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:329
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:330
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:332
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:333
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:334
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:335
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:336
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:337
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:338
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:339
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:340
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:341
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:342
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:343
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:344
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:345
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:347
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:348
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:350
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:351
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:352
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:353
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:354
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:356
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:358
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:359
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:360
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:363
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:364
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Ken VanDine (ken-vandine) wrote : Posted in a previous version of this proposal | # |
See my inline comments
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:366
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:367
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:368
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:369
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:370
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:371
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:372
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:373
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:374
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:375
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:376
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:377
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:377
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:378
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:379
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Ken VanDine (ken-vandine) wrote : Posted in a previous version of this proposal | # |
Looking good, just remove that FIXME.
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:380
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:381
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:382
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:383
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:384
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:385
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:386
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:388
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:389
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:390
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:391
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:392
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:393
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:394
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:395
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:396
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:397
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:398
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
system-apps-ci-bot (system-apps-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:399
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Ken VanDine (ken-vandine) wrote : Posted in a previous version of this proposal | # |
I'm happy with the code and testing it with the SDK changes it works pretty well. Only issue I found was the dash search. A long press in the dash search does present the user with a "Paste..." action, but nothing happens when selected. This works without the clipboard, which isn't surprising since it was just pasting the top paste on the stack. It must have something to do with launching the clipboard in the trust session. I'm fine with approving this once that's fixed.
Arthur Mello (artmello) wrote : Posted in a previous version of this proposal | # |
> (...) A long press in the dash
> search does present the user with a "Paste..." action, but nothing happens
> when selected.
Just tested this with silo 2179 installed and unity8 8.15+16.
[2017-01-
This seem to be changed recently on uitk staging branch. Fixing this issue the context menu showed up fine and also the Clipbaord ui. Interacting with the ui also worked as expected. I will check with SDK team about this.
Not sure if we are talking about the same issue, but on the described scenario it was working as expected.
Ken VanDine (ken-vandine) wrote : Posted in a previous version of this proposal | # |
I've confirmed with the sdk fix for bug 1659532 the clipboard is raised in the dash search. Works fine.
- 402. By Arthur Mello
-
Update Clipboard service calls to work with new trust session methods
- 403. By Arthur Mello
-
Remove QDbusConnection baseService check since it is failing on some tests
Change sequence for emitting PasteSelected signal to make sure trust session still have focus
Ken VanDine (ken-vandine) wrote : | # |
Test and it works now. Code looks good, thanks!
- 404. By Arthur Mello
-
Merged with trunk
- 405. By Arthur Mello
-
Set the correct Mir property string
- 406. By Arthur Mello
-
Undo Mir string change
Preview Diff
1 | === added file 'debian/apparmor/content-hub-clipboard' |
2 | --- debian/apparmor/content-hub-clipboard 1970-01-01 00:00:00 +0000 |
3 | +++ debian/apparmor/content-hub-clipboard 2017-03-06 18:20:31 +0000 |
4 | @@ -0,0 +1,15 @@ |
5 | +# vim:syntax=apparmor |
6 | +#include <tunables/global> |
7 | + |
8 | +# Mostly unconfined. Don't allow capability or any mount rules. Also ensure that |
9 | +# exec inherits from this profile |
10 | +profile content-hub-clipboard (attach_disconnected) { |
11 | + network, |
12 | + / rwkl, |
13 | + /** rwlkm, |
14 | + /** pix, |
15 | + dbus, |
16 | + signal, |
17 | + ptrace, |
18 | + unix, |
19 | +} |
20 | |
21 | === modified file 'debian/content-hub.install' |
22 | --- debian/content-hub.install 2016-12-07 16:36:53 +0000 |
23 | +++ debian/content-hub.install 2017-03-06 18:20:31 +0000 |
24 | @@ -1,3 +1,4 @@ |
25 | +usr/bin/content-hub-clipboard |
26 | usr/bin/content-hub-peer-picker |
27 | usr/bin/content-hub-send |
28 | usr/bin/content-hub-service |
29 | @@ -9,7 +10,9 @@ |
30 | usr/share/glib-2.0/schemas |
31 | usr/share/locale/*/LC_MESSAGES/content-hub.mo |
32 | usr/share/applications/content-hub-send.desktop |
33 | +usr/share/applications/content-hub-clipboard.desktop |
34 | usr/share/applications/content-hub-peer-picker.desktop |
35 | usr/share/url-dispatcher/urls/content-hub-send.url-dispatcher |
36 | usr/share/content-hub/icons |
37 | +debian/apparmor/content-hub-clipboard etc/apparmor.d |
38 | debian/apparmor/content-hub-peer-picker etc/apparmor.d |
39 | |
40 | === modified file 'debian/control' |
41 | --- debian/control 2017-02-08 18:00:27 +0000 |
42 | +++ debian/control 2017-03-06 18:20:31 +0000 |
43 | @@ -22,6 +22,7 @@ |
44 | libubuntu-app-launch3-dev (>= 0.10), |
45 | qt5-default, |
46 | qtbase5-dev, |
47 | + qtbase5-private-dev, |
48 | qtdeclarative5-dev, |
49 | qtdeclarative5-dev-tools, |
50 | qtdeclarative5-qtquick2-plugin, |
51 | |
52 | === modified file 'debian/rules' |
53 | --- debian/rules 2016-12-14 16:24:46 +0000 |
54 | +++ debian/rules 2017-03-06 18:20:31 +0000 |
55 | @@ -18,6 +18,7 @@ |
56 | |
57 | override_dh_auto_install: |
58 | dh_auto_install |
59 | + dh_apparmor -pcontent-hub --profile-name=content-hub-clipboard |
60 | dh_apparmor -pcontent-hub --profile-name=content-hub-peer-picker |
61 | dh_apparmor -pcontent-hub-testability --profile-name=content-hub-testability |
62 | |
63 | |
64 | === modified file 'import/Ubuntu/Content/contenthub.cpp' |
65 | --- import/Ubuntu/Content/contenthub.cpp 2016-11-15 15:09:33 +0000 |
66 | +++ import/Ubuntu/Content/contenthub.cpp 2017-03-06 18:20:31 +0000 |
67 | @@ -139,6 +139,12 @@ |
68 | connect(m_hub, SIGNAL(peerSelectionCancelled()), |
69 | this, |
70 | SLOT(onPeerSelectionCancelled())); |
71 | + connect(m_hub, SIGNAL(pasteSelected(QByteArray, bool)), |
72 | + this, |
73 | + SLOT(onPasteSelected(QByteArray, bool))); |
74 | + connect(m_hub, SIGNAL(pasteSelectionCancelled()), |
75 | + this, |
76 | + SLOT(onPasteSelectionCancelled())); |
77 | } |
78 | |
79 | void ContentHub::selectPeerForAppId(QString app_id, QString peer_id) |
80 | @@ -167,6 +173,30 @@ |
81 | Q_EMIT(peerSelectionCancelled()); |
82 | } |
83 | |
84 | +void ContentHub::selectPasteForAppId(QString app_id, QString surface_id, QString paste_id, bool pasteAsRichText) |
85 | +{ |
86 | + TRACE() << Q_FUNC_INFO << app_id << surface_id << paste_id << pasteAsRichText; |
87 | + m_hub->selectPasteForAppId(app_id, surface_id, paste_id, pasteAsRichText); |
88 | +} |
89 | + |
90 | +void ContentHub::selectPasteForAppIdCancelled(QString app_id) |
91 | +{ |
92 | + TRACE() << Q_FUNC_INFO << app_id; |
93 | + m_hub->selectPasteForAppIdCancelled(app_id); |
94 | +} |
95 | + |
96 | +void ContentHub::onPasteSelected(QByteArray paste, bool pasteAsRichText) |
97 | +{ |
98 | + TRACE() << Q_FUNC_INFO << paste << pasteAsRichText; |
99 | + Q_EMIT(pasteSelected(paste, pasteAsRichText)); |
100 | +} |
101 | + |
102 | +void ContentHub::onPasteSelectionCancelled() |
103 | +{ |
104 | + TRACE() << Q_FUNC_INFO; |
105 | + Q_EMIT(pasteSelectionCancelled()); |
106 | +} |
107 | + |
108 | ContentHub *ContentHub::instance() |
109 | { |
110 | TRACE() << Q_FUNC_INFO; |
111 | @@ -368,6 +398,17 @@ |
112 | } |
113 | |
114 | /*! |
115 | + * \brief ContentHub::requestPaste raises the list of copied data |
116 | + * pasteSelected is emitted when a paste is selected in the list |
117 | + * \a type |
118 | + */ |
119 | +void ContentHub::requestPaste() |
120 | +{ |
121 | + TRACE() << Q_FUNC_INFO; |
122 | + m_hub->requestPaste(); |
123 | +} |
124 | + |
125 | +/*! |
126 | * \qmlsignal ContentHub::importRequested(ContentTransfer transfer) |
127 | * |
128 | * The signal is triggered when an import is requested. |
129 | @@ -391,3 +432,8 @@ |
130 | * The signal is emitted when the user selects a peer. |
131 | */ |
132 | |
133 | +/*! |
134 | + * \qmlsignal ContentHub::pasteSelected(QString paste) |
135 | + * |
136 | + * The signal is emitted when the user selects a paste. |
137 | + */ |
138 | |
139 | === modified file 'import/Ubuntu/Content/contenthub.h' |
140 | --- import/Ubuntu/Content/contenthub.h 2016-11-15 15:09:33 +0000 |
141 | +++ import/Ubuntu/Content/contenthub.h 2017-03-06 18:20:31 +0000 |
142 | @@ -64,6 +64,10 @@ |
143 | Q_INVOKABLE void selectPeerForAppId(QString, QString); |
144 | Q_INVOKABLE void selectPeerForAppIdCancelled(QString); |
145 | |
146 | + Q_INVOKABLE void requestPaste(); |
147 | + Q_INVOKABLE void selectPasteForAppId(QString, QString, QString, bool); |
148 | + Q_INVOKABLE void selectPasteForAppIdCancelled(QString); |
149 | + |
150 | Q_SIGNALS: |
151 | void importRequested(ContentTransfer *transfer); |
152 | void exportRequested(ContentTransfer *transfer); |
153 | @@ -72,6 +76,8 @@ |
154 | void finishedImportsChanged(); |
155 | void peerSelected(ContentPeer* peer); |
156 | void peerSelectionCancelled(); |
157 | + void pasteSelected(QByteArray paste, bool pasteAsRichText); |
158 | + void pasteSelectionCancelled(); |
159 | |
160 | private Q_SLOTS: |
161 | void handleImport(com::ubuntu::content::Transfer* transfer); |
162 | @@ -80,6 +86,8 @@ |
163 | void updateState(); |
164 | void onPeerSelected(QString); |
165 | void onPeerSelectionCancelled(); |
166 | + void onPasteSelected(QByteArray, bool); |
167 | + void onPasteSelectionCancelled(); |
168 | |
169 | private: |
170 | QString setupPromptSession(); |
171 | |
172 | === modified file 'include/com/ubuntu/content/hub.h' |
173 | --- include/com/ubuntu/content/hub.h 2016-11-15 15:08:38 +0000 |
174 | +++ include/com/ubuntu/content/hub.h 2017-03-06 18:20:31 +0000 |
175 | @@ -73,7 +73,10 @@ |
176 | Q_INVOKABLE virtual void requestPeerForType(Type type, QString handler_id); |
177 | Q_INVOKABLE virtual void selectPeerForAppId(QString app_id, QString peer_id); |
178 | Q_INVOKABLE virtual void selectPeerForAppIdCancelled(QString app_id); |
179 | - |
180 | + Q_INVOKABLE virtual void requestPaste(); |
181 | + Q_INVOKABLE virtual void selectPasteForAppId(QString app_id, QString surface_id, QString paste_id, bool pasteAsRichText); |
182 | + Q_INVOKABLE virtual void selectPasteForAppIdCancelled(QString app_id); |
183 | + |
184 | /// |
185 | // Copy & Paste |
186 | |
187 | @@ -95,11 +98,15 @@ |
188 | void pasteboardChanged(); |
189 | void peerSelected(QString); |
190 | void peerSelectionCancelled(); |
191 | + void pasteSelected(QByteArray, bool); |
192 | + void pasteSelectionCancelled(); |
193 | |
194 | private Q_SLOTS: |
195 | void onPasteFormatsChanged(const QStringList &); |
196 | void onPeerSelected(const QString &, const QString &); |
197 | void onPeerSelectionCancelled(const QString &); |
198 | + void onPasteSelected(const QString &, QByteArray, bool); |
199 | + void onPasteSelectionCancelled(const QString &); |
200 | protected: |
201 | Hub(QObject* = nullptr); |
202 | |
203 | |
204 | === modified file 'src/com/ubuntu/content/common.h' |
205 | --- src/com/ubuntu/content/common.h 2016-10-27 20:32:13 +0000 |
206 | +++ src/com/ubuntu/content/common.h 2017-03-06 18:20:31 +0000 |
207 | @@ -26,6 +26,7 @@ |
208 | const QLatin1String HUB_SERVICE_PATH = QLatin1String("/"); |
209 | const QLatin1String HANDLER_NAME_TEMPLATE = QLatin1String("com.ubuntu.content.handler.%1"); |
210 | const QLatin1String HANDLER_BASE_PATH = QLatin1String("/com/ubuntu/content/handler"); |
211 | +const QString CLIPBOARD_APP_ID = QLatin1String("content-hub-clipboard"); |
212 | const QString PEER_PICKER_APP_ID = QLatin1String("content-hub-peer-picker"); |
213 | |
214 | #endif // COMMON_H |
215 | |
216 | === modified file 'src/com/ubuntu/content/detail/com.ubuntu.content.Service.xml' |
217 | --- src/com/ubuntu/content/detail/com.ubuntu.content.Service.xml 2016-11-15 15:08:38 +0000 |
218 | +++ src/com/ubuntu/content/detail/com.ubuntu.content.Service.xml 2017-03-06 18:20:31 +0000 |
219 | @@ -36,6 +36,11 @@ |
220 | <arg name="type_id" type="s" direction="in" /> |
221 | <arg name="transfer_object" type="o" direction="out" /> |
222 | </method> |
223 | + <method name="RemovePaste"> |
224 | + <arg name="surfaceId" type="s" direction="in" /> |
225 | + <arg name="pasteid" type="s" direction="in" /> |
226 | + <arg name="success" type="b" direction="out" /> |
227 | + </method> |
228 | <method name="CreatePaste"> |
229 | <arg name="app_id" type="s" direction="in" /> |
230 | <arg name="surfaceId" type="s" direction="in" /> |
231 | @@ -43,6 +48,11 @@ |
232 | <arg name="types" type="as" direction="in" /> |
233 | <arg name="success" type="b" direction="out" /> |
234 | </method> |
235 | + <method name="GetPasteSource"> |
236 | + <arg name="surfaceId" type="s" direction="in" /> |
237 | + <arg name="pasteid" type="s" direction="in" /> |
238 | + <arg name="source" type="s" direction="out" /> |
239 | + </method> |
240 | <method name="GetLatestPasteData"> |
241 | <arg name="surfaceId" type="s" direction="in" /> |
242 | <arg name="mimeData" type="ay" direction="out" /> |
243 | @@ -52,6 +62,10 @@ |
244 | <arg name="pasteid" type="s" direction="in" /> |
245 | <arg name="mimeData" type="ay" direction="out" /> |
246 | </method> |
247 | + <method name="GetAllPasteIds"> |
248 | + <arg name="surfaceId" type="s" direction="in" /> |
249 | + <arg name="pastes" type="as" direction="out" /> |
250 | + </method> |
251 | <method name="RegisterImportExportHandler"> |
252 | <arg name="peer_id" type="s" direction="in" /> |
253 | <arg name="handler_object" type="o" direction="in" /> |
254 | @@ -80,6 +94,26 @@ |
255 | <arg name="handler_id" type="s" direction="in" /> |
256 | <arg name="app_id" type="s" direction="in" /> |
257 | </method> |
258 | + <method name="RequestPasteByAppId"> |
259 | + <arg name="app_id" type="s" direction="in" /> |
260 | + </method> |
261 | + <method name="SelectPasteForAppId"> |
262 | + <arg name="app_id" type="s" direction="in" /> |
263 | + <arg name="surface_id" type="s" direction="in" /> |
264 | + <arg name="paste_id" type="s" direction="in" /> |
265 | + <arg name="paste_as_rich_text" type="b" direction="in" /> |
266 | + </method> |
267 | + <method name="SelectPasteForAppIdCancelled"> |
268 | + <arg name="app_id" type="s" direction="in" /> |
269 | + </method> |
270 | + <signal name="PasteSelected"> |
271 | + <arg name="app_id" type="s" /> |
272 | + <arg name="mimedata" type="ay" /> |
273 | + <arg name="pasteAsRichText" type="b" /> |
274 | + </signal> |
275 | + <signal name="PasteSelectionCancelled"> |
276 | + <arg name="app_id" type="s" /> |
277 | + </signal> |
278 | <method name="SelectPeerForAppId"> |
279 | <arg name="app_id" type="s" direction="in" /> |
280 | <arg name="peer_id" type="s" direction="in" /> |
281 | |
282 | === modified file 'src/com/ubuntu/content/detail/service.cpp' |
283 | --- src/com/ubuntu/content/detail/service.cpp 2017-02-03 20:34:14 +0000 |
284 | +++ src/com/ubuntu/content/detail/service.cpp 2017-03-06 18:20:31 +0000 |
285 | @@ -90,6 +90,7 @@ |
286 | QSet<cucd::Transfer*> active_transfers; |
287 | QList<cucd::Paste*> active_pastes; |
288 | QMap<QString, PromptSessionP> active_sessions; |
289 | + QMap<QString, std::shared_ptr<ual::Helper::Instance>> clipboard_instances; |
290 | QMap<QString, std::shared_ptr<ual::Helper::Instance>> peer_picker_instances; |
291 | QStringList pasteFormats; |
292 | QSet<RegHandler*> handlers; |
293 | @@ -436,6 +437,59 @@ |
294 | return true; |
295 | } |
296 | |
297 | +bool cucd::Service::RemovePaste(const QString& surfaceId, const QString& pasteId) |
298 | +{ |
299 | + TRACE() << Q_FUNC_INFO << pasteId; |
300 | + |
301 | + if (!verifiedSurfaceIsFocused(surfaceId)) |
302 | + return false; |
303 | + |
304 | + int id = pasteId.toInt(); |
305 | + QByteArray pasteData = getPasteData(surfaceId, id); |
306 | + if (pasteData.isNull()) |
307 | + return false; |
308 | + |
309 | + QStringList types = deserializeMimeData(pasteData)->formats(); |
310 | + |
311 | + for (int i = d->active_pastes.size() - 1; i >= 0; i--) { |
312 | + if (d->active_pastes.at(i)->Id() == id) |
313 | + d->active_pastes.removeAt(i); |
314 | + else { |
315 | + QByteArray byteArray = d->active_pastes.at(i)->MimeData(); |
316 | + Q_FOREACH (QString f, deserializeMimeData(byteArray)->formats()) { |
317 | + if (types.contains(f)) |
318 | + types.removeAll(f); |
319 | + } |
320 | + } |
321 | + } |
322 | + |
323 | + Q_EMIT(PasteboardChanged()); |
324 | + |
325 | + bool pendingPasteFormatsChangedSignal = false; |
326 | + Q_FOREACH (QString t, types) { |
327 | + TRACE() << Q_FUNC_INFO << "Type: " << t; |
328 | + if (d->pasteFormats.contains(t)) { |
329 | + d->pasteFormats.removeAll(t); |
330 | + pendingPasteFormatsChangedSignal = true; |
331 | + } |
332 | + } |
333 | + if (pendingPasteFormatsChangedSignal) { |
334 | + Q_EMIT(PasteFormatsChanged(d->pasteFormats)); |
335 | + } |
336 | + |
337 | + return true; |
338 | +} |
339 | + |
340 | +QString cucd::Service::GetPasteSource(const QString& surfaceId, const QString& pasteId) |
341 | +{ |
342 | + TRACE() << Q_FUNC_INFO << pasteId; |
343 | + |
344 | + if (d->active_pastes.isEmpty()) |
345 | + return QString(); |
346 | + |
347 | + return getPasteSource(surfaceId, pasteId.toInt()); |
348 | +} |
349 | + |
350 | QByteArray cucd::Service::GetLatestPasteData(const QString& surfaceId) |
351 | { |
352 | TRACE() << Q_FUNC_INFO; |
353 | @@ -456,6 +510,31 @@ |
354 | return getPasteData(surfaceId, pasteId.toInt()); |
355 | } |
356 | |
357 | +QStringList cucd::Service::GetAllPasteIds(const QString& surfaceId) |
358 | +{ |
359 | + TRACE() << Q_FUNC_INFO; |
360 | + |
361 | + if (d->active_pastes.isEmpty()) |
362 | + return QStringList(); |
363 | + |
364 | + return getAllPasteIds(surfaceId); |
365 | +} |
366 | + |
367 | +QString cucd::Service::getPasteSource(const QString &surfaceId, int pasteId) |
368 | +{ |
369 | + if (!verifiedSurfaceIsFocused(surfaceId)) { |
370 | + qWarning().nospace() << "Surface isn't focused. Denying paste."; |
371 | + return QString(); |
372 | + } |
373 | + |
374 | + Q_FOREACH (cucd::Paste *p, d->active_pastes) |
375 | + { |
376 | + if (p->Id() == pasteId) |
377 | + return p->source(); |
378 | + } |
379 | + return QString(); |
380 | +} |
381 | + |
382 | QByteArray cucd::Service::getPasteData(const QString &surfaceId, int pasteId) |
383 | { |
384 | if (!verifiedSurfaceIsFocused(surfaceId)) { |
385 | @@ -471,6 +550,21 @@ |
386 | return QByteArray(); |
387 | } |
388 | |
389 | +QStringList cucd::Service::getAllPasteIds(const QString &surfaceId) |
390 | +{ |
391 | + if (!verifiedSurfaceIsFocused(surfaceId)) { |
392 | + qWarning().nospace() << "Surface isn't focused. Denying paste."; |
393 | + return QStringList(); |
394 | + } |
395 | + |
396 | + QStringList ids; |
397 | + Q_FOREACH (cucd::Paste *p, d->active_pastes) |
398 | + { |
399 | + ids.append(QString::number(p->Id())); |
400 | + } |
401 | + return ids; |
402 | +} |
403 | + |
404 | QDBusObjectPath cucd::Service::CreateTransfer(const QString& dest_id, const QString& src_id, int dir, const QString& type_id) |
405 | { |
406 | TRACE() << Q_FUNC_INFO << "DEST:" << dest_id << "SRC:" << src_id << "DIRECTION:" << dir; |
407 | @@ -987,6 +1081,76 @@ |
408 | return d->pasteFormats; |
409 | } |
410 | |
411 | +void cucd::Service::RequestPasteByAppId(const QString& app_id) |
412 | +{ |
413 | + TRACE() << Q_FUNC_INFO << app_id; |
414 | + |
415 | + gchar * uris[] = { |
416 | + g_strdup(app_id.toStdString().c_str()), |
417 | + NULL |
418 | + }; |
419 | + |
420 | + if (!d->active_sessions.keys().contains(app_id)) { |
421 | + //FIXME: baseService is empty on some test cases |
422 | + //if (!QDBusConnection::sender().baseService().isEmpty()) { |
423 | + uint clientPid = d->connection.interface()->servicePid(this->message().service()); |
424 | + setupPromptSession(app_id, clientPid); |
425 | + //} |
426 | + } |
427 | + |
428 | + if (d->active_sessions.keys().contains(app_id)) { |
429 | + TRACE() << Q_FUNC_INFO << "Invoking Clipboard with session"; |
430 | + PromptSessionP session = d->active_sessions.value(app_id); |
431 | + auto instance = d->app_manager->invoke_application_with_session(CLIPBOARD_APP_ID.toStdString(), session, uris); |
432 | + d->clipboard_instances[app_id] = instance; |
433 | + } else { |
434 | + TRACE() << Q_FUNC_INFO << "Invoking Clipboard"; |
435 | + d->app_manager->invoke_application(CLIPBOARD_APP_ID.toStdString(), uris); |
436 | + } |
437 | +} |
438 | + |
439 | +void cucd::Service::SelectPasteForAppId(const QString& app_id, const QString& surface_id, const QString& paste_id, bool pasteAsRichText) |
440 | +{ |
441 | + TRACE() << Q_FUNC_INFO << app_id << surface_id << paste_id; |
442 | + // Lock this down to only allow the peer picker APP_ID to call this |
443 | + if (aa_profile(this->message().service()) != CLIPBOARD_APP_ID) |
444 | + return; |
445 | + |
446 | + if (d->clipboard_instances.contains(app_id)) { |
447 | + Q_EMIT(PasteSelected(app_id, getPasteData(surface_id, paste_id.toInt()), pasteAsRichText)); |
448 | + |
449 | + auto instance = d->clipboard_instances.value(app_id); |
450 | + if (instance) { |
451 | + try { |
452 | + TRACE() << Q_FUNC_INFO << "Stopping Clipboard"; |
453 | + instance->stop(); |
454 | + } catch (std::runtime_error &e) { |
455 | + qWarning() << Q_FUNC_INFO << "Unable to stop app:" << e.what(); |
456 | + } |
457 | + } |
458 | + d->clipboard_instances.remove(app_id); |
459 | + } |
460 | +} |
461 | + |
462 | +void cucd::Service::SelectPasteForAppIdCancelled(const QString& app_id) |
463 | +{ |
464 | + TRACE() << Q_FUNC_INFO << app_id; |
465 | + if (d->clipboard_instances.contains(app_id)) { |
466 | + auto instance = d->clipboard_instances.value(app_id); |
467 | + if (instance) { |
468 | + try { |
469 | + TRACE() << Q_FUNC_INFO << "Stopping Clipboard"; |
470 | + instance->stop(); |
471 | + } catch (std::runtime_error &e) { |
472 | + qWarning() << Q_FUNC_INFO << "Unable to stop app:" << e.what(); |
473 | + } |
474 | + } |
475 | + d->clipboard_instances.remove(app_id); |
476 | + } |
477 | + |
478 | + Q_EMIT(PasteSelectionCancelled(app_id)); |
479 | +} |
480 | + |
481 | bool cucd::Service::verifiedSurfaceIsFocused(const QString &surfaceId) |
482 | { |
483 | /* Only verify focus when not running under testing */ |
484 | |
485 | === modified file 'src/com/ubuntu/content/detail/service.h' |
486 | --- src/com/ubuntu/content/detail/service.h 2016-11-16 15:22:59 +0000 |
487 | +++ src/com/ubuntu/content/detail/service.h 2017-03-06 18:20:31 +0000 |
488 | @@ -64,10 +64,16 @@ |
489 | QDBusObjectPath CreateExportToPeer(const QString&, const QString&, const QString&); |
490 | QDBusObjectPath CreateShareToPeer(const QString&, const QString&, const QString&); |
491 | bool CreatePaste(const QString&, const QString&, const QByteArray&, const QStringList&); |
492 | + bool RemovePaste(const QString& surfaceId, const QString& pasteId); |
493 | + QString GetPasteSource(const QString& surfaceId, const QString& pasteId); |
494 | QByteArray GetLatestPasteData(const QString& surfaceId); |
495 | QByteArray GetPasteData(const QString& surfaceId, const QString& pasteId); |
496 | + QStringList GetAllPasteIds(const QString& surfaceId); |
497 | QStringList PasteFormats(); |
498 | - |
499 | + void RequestPasteByAppId(const QString&); |
500 | + void SelectPasteForAppId(const QString&, const QString&, const QString&, bool); |
501 | + void SelectPasteForAppIdCancelled(const QString&); |
502 | + |
503 | void RegisterImportExportHandler(const QString&, const QDBusObjectPath& handler); |
504 | void HandlerActive(const QString&); |
505 | void Quit(); |
506 | @@ -80,7 +86,9 @@ |
507 | void onPromptFinished(); |
508 | |
509 | private: |
510 | + QString getPasteSource(const QString &surfaceId, int pasteId); |
511 | QByteArray getPasteData(const QString &surfaceId, int pasteId); |
512 | + QStringList getAllPasteIds(const QString &surfaceId); |
513 | bool should_cancel(int); |
514 | bool verifiedSurfaceIsFocused(const QString &surfaceId); |
515 | struct Private; |
516 | @@ -93,6 +101,8 @@ |
517 | void PasteboardChanged(); |
518 | void PeerSelected(const QString &app_id, const QString &peer_id); |
519 | void PeerSelectionCancelled(const QString &app_id); |
520 | + void PasteSelected(const QString &app_id, QByteArray mimedata, bool pasteAsRichText); |
521 | + void PasteSelectionCancelled(const QString &app_id); |
522 | |
523 | private Q_SLOTS: |
524 | void handle_imports(int); |
525 | |
526 | === modified file 'src/com/ubuntu/content/hub.cpp' |
527 | --- src/com/ubuntu/content/hub.cpp 2016-11-15 15:08:38 +0000 |
528 | +++ src/com/ubuntu/content/hub.cpp 2017-03-06 18:20:31 +0000 |
529 | @@ -95,6 +95,12 @@ |
530 | QObject::connect(d->service, SIGNAL(PeerSelectionCancelled(const QString&)), |
531 | this, |
532 | SLOT(onPeerSelectionCancelled(const QString&))); |
533 | + QObject::connect(d->service, SIGNAL(PasteSelected(const QString&, QByteArray, bool)), |
534 | + this, |
535 | + SLOT(onPasteSelected(const QString&, QByteArray, bool))); |
536 | + QObject::connect(d->service, SIGNAL(PasteSelectionCancelled(const QString&)), |
537 | + this, |
538 | + SLOT(onPasteSelectionCancelled(const QString&))); |
539 | } |
540 | |
541 | cuc::Hub::~Hub() |
542 | @@ -113,6 +119,24 @@ |
543 | d->service->RequestPeerForTypeByAppId(type.id(), handler_id, app_id()); |
544 | } |
545 | |
546 | +void cuc::Hub::requestPaste() |
547 | +{ |
548 | + TRACE() << Q_FUNC_INFO; |
549 | + d->service->RequestPasteByAppId(app_id()); |
550 | +} |
551 | + |
552 | +void cuc::Hub::selectPasteForAppId(QString app_id, QString surface_id, QString paste_id, bool pasteAsRichText) |
553 | +{ |
554 | + TRACE() << Q_FUNC_INFO << app_id << surface_id << paste_id << pasteAsRichText; |
555 | + d->service->SelectPasteForAppId(app_id, surface_id, paste_id, pasteAsRichText); |
556 | +} |
557 | + |
558 | +void cuc::Hub::selectPasteForAppIdCancelled(QString app_id) |
559 | +{ |
560 | + TRACE() << Q_FUNC_INFO << app_id; |
561 | + d->service->SelectPasteForAppIdCancelled(app_id); |
562 | +} |
563 | + |
564 | void cuc::Hub::selectPeerForAppId(QString app_id, QString peer_id) |
565 | { |
566 | TRACE() << Q_FUNC_INFO << app_id << peer_id; |
567 | @@ -165,6 +189,20 @@ |
568 | Q_EMIT(peerSelectionCancelled()); |
569 | } |
570 | |
571 | +void cuc::Hub::onPasteSelected(const QString &id, QByteArray paste, bool pasteAsRichText) |
572 | +{ |
573 | + TRACE() << Q_FUNC_INFO << id << paste << pasteAsRichText; |
574 | + if (id == app_id()) |
575 | + Q_EMIT(pasteSelected(paste, pasteAsRichText)); |
576 | +} |
577 | + |
578 | +void cuc::Hub::onPasteSelectionCancelled(const QString &id) |
579 | +{ |
580 | + TRACE() << Q_FUNC_INFO << id; |
581 | + if (id == app_id()) |
582 | + Q_EMIT(pasteSelectionCancelled()); |
583 | +} |
584 | + |
585 | bool cuc::Hub::eventFilter(QObject *obj, QEvent *event) |
586 | { |
587 | if (event->type() == QEvent::ApplicationActivate) |
588 | |
589 | === modified file 'tools/CMakeLists.txt' |
590 | --- tools/CMakeLists.txt 2016-10-26 17:15:10 +0000 |
591 | +++ tools/CMakeLists.txt 2017-03-06 18:20:31 +0000 |
592 | @@ -14,5 +14,6 @@ |
593 | # |
594 | # Authored by: Ken VanDine <ken.vandine@canonical.com> |
595 | |
596 | +add_subdirectory(clipboard) |
597 | add_subdirectory(send) |
598 | add_subdirectory(peer-picker) |
599 | |
600 | === added directory 'tools/clipboard' |
601 | === added file 'tools/clipboard/CMakeLists.txt' |
602 | --- tools/clipboard/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
603 | +++ tools/clipboard/CMakeLists.txt 2017-03-06 18:20:31 +0000 |
604 | @@ -0,0 +1,72 @@ |
605 | +# Copyright © 2016 Canonical Ltd. |
606 | +# |
607 | +# This program is free software: you can redistribute it and/or modify |
608 | +# it under the terms of the GNU General Public License version 3 as |
609 | +# published by the Free Software Foundation. |
610 | +# |
611 | +# This program is distributed in the hope that it will be useful, |
612 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
613 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
614 | +# GNU General Public License for more details. |
615 | +# |
616 | +# You should have received a copy of the GNU General Public License |
617 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
618 | +# |
619 | +# Authored by: Arthur Mello <arthur.mello@canonical.com> |
620 | + |
621 | +set(CLIPBOARD_APP content-hub-clipboard) |
622 | + |
623 | +include_directories( |
624 | + ${CMAKE_CURRENT_BINARY_DIR} |
625 | + ${CMAKE_SOURCE_DIR}/src/com/ubuntu/content |
626 | + ${CMAKE_BINARY_DIR}/src/com/ubuntu/content |
627 | + ${UBUNTU_LAUNCH_INCLUDE_DIRS} |
628 | +) |
629 | + |
630 | +set(clipboard_app_HDRS |
631 | + paste-data-provider.h |
632 | + paste-image-provider.h |
633 | + paste-data-model.h |
634 | + paste-data-filter-model.h |
635 | + clipboardapplication.h) |
636 | + |
637 | +set(clipboard_app_SRCS |
638 | + paste-data-provider.cpp |
639 | + paste-image-provider.cpp |
640 | + paste-data-model.cpp |
641 | + paste-data-filter-model.cpp |
642 | + clipboardapplication.cpp |
643 | + main.cpp) |
644 | + |
645 | +qt5_add_resources(RESOURCES qml.qrc) |
646 | + |
647 | +add_executable(${CLIPBOARD_APP} |
648 | + ${clipboard_app_SRCS} |
649 | + ${RESOURCES} |
650 | +) |
651 | + |
652 | +qt5_use_modules(${CLIPBOARD_APP} Core Gui Quick Qml Widgets DBus) |
653 | +find_package(Qt5Core 5.4 REQUIRED) |
654 | +include_directories( |
655 | + ${Qt5Gui_PRIVATE_INCLUDE_DIRS} |
656 | + ) |
657 | + |
658 | +set_target_properties(${CLIPBOARD_APP} |
659 | + PROPERTIES |
660 | + AUTOMOC TRUE |
661 | +) |
662 | + |
663 | +target_link_libraries(${CLIPBOARD_APP} |
664 | + content-hub |
665 | + ${UBUNTU_LAUNCH_LDFLAGS} |
666 | +) |
667 | + |
668 | +install( |
669 | + TARGETS ${CLIPBOARD_APP} |
670 | + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} |
671 | +) |
672 | + |
673 | +install( |
674 | + FILES content-hub-clipboard.desktop |
675 | + DESTINATION ${CMAKE_INSTALL_DATADIR}/applications |
676 | +) |
677 | |
678 | === added file 'tools/clipboard/ClipboardItemDelegate.qml' |
679 | --- tools/clipboard/ClipboardItemDelegate.qml 1970-01-01 00:00:00 +0000 |
680 | +++ tools/clipboard/ClipboardItemDelegate.qml 2017-03-06 18:20:31 +0000 |
681 | @@ -0,0 +1,82 @@ |
682 | +/* |
683 | + * Copyright (C) 2016 Canonical, Ltd. |
684 | + * |
685 | + * This program is free software; you can redistribute it and/or modify |
686 | + * it under the terms of the GNU General Public License as published by |
687 | + * the Free Software Foundation; version 3. |
688 | + * |
689 | + * This program is distributed in the hope that it will be useful, |
690 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
691 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
692 | + * GNU General Public License for more details. |
693 | + * |
694 | + * You should have received a copy of the GNU General Public License |
695 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
696 | + * |
697 | + * Authored by: Arthur Mello <arthur.mello@canonical.com> |
698 | + */ |
699 | + |
700 | +import QtQuick 2.4 |
701 | +import Ubuntu.Components 1.3 |
702 | + |
703 | +ListItem { |
704 | + id: clipboardItem |
705 | + |
706 | + property string title: "" |
707 | + property string summary: "" |
708 | + property url imageSource: "" |
709 | + |
710 | + signal deleteClicked() |
711 | + signal previewClicked() |
712 | + |
713 | + onTitleChanged: title = title.replace("\n", " ") |
714 | + |
715 | + height: clipboardItemLayout.height + (divider.visible ? divider.height : 0) |
716 | + |
717 | + leadingActions: ListItemActions { |
718 | + actions: [ |
719 | + Action { |
720 | + iconName: "delete" |
721 | + text: i18n.tr("Delete") |
722 | + onTriggered: clipboardItem.deleteClicked() |
723 | + } |
724 | + ] |
725 | + } |
726 | + |
727 | + trailingActions: ListItemActions { |
728 | + actions: [ |
729 | + Action { |
730 | + iconName: "find" |
731 | + text: i18n.tr("Preview") |
732 | + onTriggered: clipboardItem.previewClicked() |
733 | + } |
734 | + ] |
735 | + } |
736 | + |
737 | + ListItemLayout { |
738 | + id: clipboardItemLayout |
739 | + |
740 | + title.text: { |
741 | + if (clipboardItem.title) { |
742 | + return clipboardItem.title |
743 | + } else if (clipboardItem.imageSource != "") { |
744 | + return i18n.tr("Image") |
745 | + } |
746 | + return "" |
747 | + } |
748 | + title.textFormat: Text.PlainText |
749 | + summary.text: clipboardItem.summary |
750 | + |
751 | + UbuntuShape { |
752 | + width: units.gu(4) |
753 | + height: width |
754 | + |
755 | + visible: clipboardItem.imageSource != "" |
756 | + |
757 | + SlotsLayout.position: SlotsLayout.Leading |
758 | + source: Image { |
759 | + source: clipboardItem.imageSource |
760 | + } |
761 | + } |
762 | + } |
763 | +} |
764 | |
765 | === added file 'tools/clipboard/PreviewImagePage.qml' |
766 | --- tools/clipboard/PreviewImagePage.qml 1970-01-01 00:00:00 +0000 |
767 | +++ tools/clipboard/PreviewImagePage.qml 2017-03-06 18:20:31 +0000 |
768 | @@ -0,0 +1,54 @@ |
769 | +/* |
770 | + * Copyright (C) 2016 Canonical, Ltd. |
771 | + * |
772 | + * This program is free software; you can redistribute it and/or modify |
773 | + * it under the terms of the GNU General Public License as published by |
774 | + * the Free Software Foundation; version 3. |
775 | + * |
776 | + * This program is distributed in the hope that it will be useful, |
777 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
778 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
779 | + * GNU General Public License for more details. |
780 | + * |
781 | + * You should have received a copy of the GNU General Public License |
782 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
783 | + * |
784 | + * Authored by: Arthur Mello <arthur.mello@canonical.com> |
785 | + */ |
786 | + |
787 | +import QtQuick 2.4 |
788 | +import Ubuntu.Components 1.3 |
789 | + |
790 | +Page { |
791 | + id: previewImagePage |
792 | + |
793 | + property alias imageSource: imagePreview.source |
794 | + |
795 | + signal pasteClicked() |
796 | + |
797 | + header: PageHeader { |
798 | + id: pageHeader |
799 | + title: i18n.tr("Preview") |
800 | + trailingActionBar.actions: [ |
801 | + Action { |
802 | + iconName: "edit-paste" |
803 | + text: i18n.tr("Paste") |
804 | + onTriggered: previewImagePage.pasteClicked() |
805 | + } |
806 | + ] |
807 | + } |
808 | + |
809 | + Image { |
810 | + id: imagePreview |
811 | + |
812 | + anchors { |
813 | + top: pageHeader.bottom |
814 | + bottom: parent.bottom |
815 | + left: parent.left |
816 | + right: parent.right |
817 | + margins: units.gu(2) |
818 | + } |
819 | + |
820 | + fillMode: Image.PreserveAspectFit |
821 | + } |
822 | +} |
823 | |
824 | === added file 'tools/clipboard/PreviewTextPage.qml' |
825 | --- tools/clipboard/PreviewTextPage.qml 1970-01-01 00:00:00 +0000 |
826 | +++ tools/clipboard/PreviewTextPage.qml 2017-03-06 18:20:31 +0000 |
827 | @@ -0,0 +1,182 @@ |
828 | +/* |
829 | + * Copyright (C) 2016 Canonical, Ltd. |
830 | + * |
831 | + * This program is free software; you can redistribute it and/or modify |
832 | + * it under the terms of the GNU General Public License as published by |
833 | + * the Free Software Foundation; version 3. |
834 | + * |
835 | + * This program is distributed in the hope that it will be useful, |
836 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
837 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
838 | + * GNU General Public License for more details. |
839 | + * |
840 | + * You should have received a copy of the GNU General Public License |
841 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
842 | + * |
843 | + * Authored by: Arthur Mello <arthur.mello@canonical.com> |
844 | + */ |
845 | + |
846 | +import QtQuick 2.4 |
847 | +import Ubuntu.Components 1.3 |
848 | +import Ubuntu.Components.ListItems 1.3 as ListItem |
849 | +import Ubuntu.Web 0.2 |
850 | +import com.canonical.Oxide 1.15 |
851 | +import clipboardapp.private 0.1 |
852 | + |
853 | +Page { |
854 | + id: previewTextPage |
855 | + |
856 | + property alias text: textPreview.text |
857 | + property string richText: "" |
858 | + property int outputOption |
859 | + |
860 | + onRichTextChanged: { |
861 | + if (outputOption == PasteDataModel.RichText) { |
862 | + webView.loadHtml(previewTextPage.richText) |
863 | + } |
864 | + } |
865 | + |
866 | + onOutputOptionChanged: { |
867 | + if (outputOption == PasteDataModel.RichText) { |
868 | + webView.loadHtml(previewTextPage.richText) |
869 | + } |
870 | + } |
871 | + |
872 | + signal pasteClicked() |
873 | + |
874 | + header: PageHeader { |
875 | + id: pageHeader |
876 | + title: i18n.tr("Preview") |
877 | + trailingActionBar.actions: [ |
878 | + Action { |
879 | + iconName: "edit-paste" |
880 | + text: i18n.tr("Paste") |
881 | + onTriggered: previewTextPage.pasteClicked() |
882 | + } |
883 | + ] |
884 | + } |
885 | + |
886 | + WebView { |
887 | + id: webView |
888 | + anchors { |
889 | + top: optionsLoader.bottom |
890 | + bottom: parent.bottom |
891 | + left: parent.left |
892 | + right: parent.right |
893 | + margins: units.gu(2) |
894 | + } |
895 | + |
896 | + visible: outputOption == PasteDataModel.RichText |
897 | + |
898 | + onNavigationRequested: request.action = NavigationRequest.ActionReject |
899 | + } |
900 | + |
901 | + Flickable { |
902 | + id: flickable |
903 | + anchors { |
904 | + top: optionsLoader.bottom |
905 | + bottom: parent.bottom |
906 | + left: parent.left |
907 | + right: parent.right |
908 | + margins: units.gu(2) |
909 | + } |
910 | + |
911 | + visible: outputOption == PasteDataModel.PlainText |
912 | + |
913 | + TextArea { |
914 | + id: textPreview |
915 | + |
916 | + anchors.fill: parent |
917 | + |
918 | + textFormat: TextEdit.PlainText |
919 | + wrapMode: Text.WordWrap |
920 | + cursorVisible: false |
921 | + readOnly: true |
922 | + selectByMouse: false |
923 | + } |
924 | + } |
925 | + |
926 | + Loader { |
927 | + id: optionsLoader |
928 | + anchors { |
929 | + top: pageHeader.bottom |
930 | + left: parent.left |
931 | + right: parent.right |
932 | + } |
933 | + |
934 | + height: status == Loader.Ready ? item.height : 0 |
935 | + |
936 | + active: previewTextPage.active && previewTextPage.richText != "" |
937 | + sourceComponent: optionsComp |
938 | + } |
939 | + |
940 | + Component { |
941 | + id: optionsComp |
942 | + Item { |
943 | + anchors { |
944 | + top: parent ? parent.top : undefined |
945 | + left: parent ? parent.left : undefined |
946 | + right: parent ? parent.right : undefined |
947 | + } |
948 | + |
949 | + height: optionsLabelItem.height + optionsDivider.height + units.gu(4) |
950 | + |
951 | + Item { |
952 | + id: optionsLabelItem |
953 | + |
954 | + anchors { |
955 | + top: parent.top |
956 | + left: parent.left |
957 | + margins: units.gu(2) |
958 | + } |
959 | + |
960 | + width: optionsLabel.width |
961 | + height: optionSelector.itemHeight |
962 | + |
963 | + Label { |
964 | + id: optionsLabel |
965 | + |
966 | + anchors.centerIn: parent |
967 | + text: i18n.tr("Paste options:") |
968 | + } |
969 | + } |
970 | + |
971 | + ListItem.ThinDivider { |
972 | + id: optionsDivider |
973 | + |
974 | + anchors { |
975 | + top: optionsLabelItem.bottom |
976 | + topMargin: units.gu(2) |
977 | + } |
978 | + |
979 | + width: parent.width |
980 | + height: units.gu(0.5) |
981 | + } |
982 | + |
983 | + OptionSelector { |
984 | + id: optionSelector |
985 | + |
986 | + Component.onCompleted: selectedIndex = outputOption == PasteDataModel.PlainText ? 0 : 1 |
987 | + |
988 | + anchors { |
989 | + top: parent.top |
990 | + left: optionsLabelItem.right |
991 | + right: parent.right |
992 | + margins: units.gu(2) |
993 | + } |
994 | + |
995 | + expanded: false |
996 | + model: [ i18n.tr("Plain text"), |
997 | + i18n.tr("Rich text")] |
998 | + |
999 | + onSelectedIndexChanged: { |
1000 | + if (selectedIndex == 0) { |
1001 | + outputOption = PasteDataModel.PlainText |
1002 | + } else { |
1003 | + outputOption = PasteDataModel.RichText |
1004 | + } |
1005 | + } |
1006 | + } |
1007 | + } |
1008 | + } |
1009 | +} |
1010 | |
1011 | === added file 'tools/clipboard/clipboardapplication.cpp' |
1012 | --- tools/clipboard/clipboardapplication.cpp 1970-01-01 00:00:00 +0000 |
1013 | +++ tools/clipboard/clipboardapplication.cpp 2017-03-06 18:20:31 +0000 |
1014 | @@ -0,0 +1,121 @@ |
1015 | +/* |
1016 | + * Copyright (C) 2016 Canonical, Ltd. |
1017 | + * |
1018 | + * This program is free software; you can redistribute it and/or modify |
1019 | + * it under the terms of the GNU General Public License as published by |
1020 | + * the Free Software Foundation; version 3. |
1021 | + * |
1022 | + * This program is distributed in the hope that it will be useful, |
1023 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1024 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1025 | + * GNU General Public License for more details. |
1026 | + * |
1027 | + * You should have received a copy of the GNU General Public License |
1028 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1029 | + * |
1030 | + * Authored by: Arthur Mello <arthur.mello@canonical.com> |
1031 | + */ |
1032 | + |
1033 | +#include "clipboardapplication.h" |
1034 | + |
1035 | +#include <iostream> |
1036 | + |
1037 | +#include <QtQml/QQmlContext> |
1038 | +#include <QtQml/QQmlEngine> |
1039 | + |
1040 | +#include <qpa/qplatformnativeinterface.h> |
1041 | +#include <mir_toolkit/mir_window.h> |
1042 | +#include <mir_toolkit/mir_persistent_id.h> |
1043 | + |
1044 | +#include "debug.h" |
1045 | +#include "paste-data-model.h" |
1046 | +#include "paste-data-filter-model.h" |
1047 | +#include "paste-image-provider.h" |
1048 | + |
1049 | +ClipboardApplication::ClipboardApplication(int &argc, char **argv) |
1050 | + : QApplication(argc, argv), |
1051 | + m_surfaceId(), |
1052 | + m_view(new QQuickView()) |
1053 | +{ |
1054 | + connect(this, SIGNAL(applicationStateChanged(Qt::ApplicationState)), SLOT(onApplicationStateChanged(Qt::ApplicationState))); |
1055 | + |
1056 | + bool fullScreen = false; |
1057 | + QString requesterId; |
1058 | + |
1059 | + QStringList args = arguments(); |
1060 | + if (args.contains("--fullscreen")) { |
1061 | + args.removeAll("--fullscreen"); |
1062 | + fullScreen = true; |
1063 | + } |
1064 | + |
1065 | + if (args.count() < 2) { |
1066 | + std::cout << "Usage: content-hub-peer-clipboard app_id\n"; |
1067 | + QApplication::exit(1); |
1068 | + } else { |
1069 | + requesterId = args.at(1); |
1070 | + } |
1071 | + |
1072 | + const char* uri = "clipboardapp.private"; |
1073 | + qmlRegisterType<PasteDataModel>(uri, 0, 1, "PasteDataModel"); |
1074 | + qmlRegisterType<PasteDataFilterModel>(uri, 0, 1, "PasteDataFilterModel"); |
1075 | + |
1076 | + QObject::connect(m_view->engine(), SIGNAL(quit()), SLOT(quit())); |
1077 | + m_view->setResizeMode(QQuickView::SizeRootObjectToView); |
1078 | + m_view->engine()->addImageProvider(QLatin1String("pastedImage"), new PasteImageProvider); |
1079 | + m_view->rootContext()->setContextProperty("application", this); |
1080 | + m_view->rootContext()->setContextProperty("requesterId", requesterId); |
1081 | + m_view->setSource(QUrl(QStringLiteral("qrc:/main.qml"))); |
1082 | + if (fullScreen) { |
1083 | + m_view->showFullScreen(); |
1084 | + } else { |
1085 | + m_view->show(); |
1086 | + } |
1087 | + m_view->requestActivate(); |
1088 | +} |
1089 | + |
1090 | +ClipboardApplication::~ClipboardApplication() |
1091 | +{ |
1092 | + delete m_view; |
1093 | +} |
1094 | + |
1095 | +int ClipboardApplication::exec() |
1096 | +{ |
1097 | + return QApplication::exec(); |
1098 | +} |
1099 | + |
1100 | +const QString& ClipboardApplication::surfaceId() const |
1101 | +{ |
1102 | + return m_surfaceId; |
1103 | +} |
1104 | + |
1105 | +int ClipboardApplication::appState() const |
1106 | +{ |
1107 | + return applicationState(); |
1108 | +} |
1109 | + |
1110 | +void ClipboardApplication::onApplicationStateChanged(Qt::ApplicationState state) |
1111 | +{ |
1112 | + Q_EMIT(appStateChanged()); |
1113 | + |
1114 | + if (m_surfaceId.isEmpty() && state == Qt::ApplicationActive) { |
1115 | + m_surfaceId = requestSurfaceId(); |
1116 | + if (m_surfaceId.isEmpty()) { |
1117 | + TRACE() << Q_FUNC_INFO << "Unable to request MIR surfaceId. Clipboard will not be able to get any data from content-hub"; |
1118 | + } else { |
1119 | + Q_EMIT(surfaceIdChanged()); |
1120 | + } |
1121 | + } |
1122 | +} |
1123 | + |
1124 | +QString ClipboardApplication::requestSurfaceId() |
1125 | +{ |
1126 | + auto mirWindow = static_cast<MirWindow*>(platformNativeInterface()->nativeResourceForWindow("mirwindow", m_view)); |
1127 | + if (!mirWindow) |
1128 | + return QString(); |
1129 | + |
1130 | + MirPersistentId* mirPermaId = mir_window_request_persistent_id_sync(mirWindow); |
1131 | + QString surfaceId(mir_persistent_id_as_string(mirPermaId)); |
1132 | + mir_persistent_id_release(mirPermaId); |
1133 | + |
1134 | + return surfaceId; |
1135 | +} |
1136 | |
1137 | === added file 'tools/clipboard/clipboardapplication.h' |
1138 | --- tools/clipboard/clipboardapplication.h 1970-01-01 00:00:00 +0000 |
1139 | +++ tools/clipboard/clipboardapplication.h 2017-03-06 18:20:31 +0000 |
1140 | @@ -0,0 +1,54 @@ |
1141 | +/* |
1142 | + * Copyright (C) 2016 Canonical, Ltd. |
1143 | + * |
1144 | + * This program is free software; you can redistribute it and/or modify |
1145 | + * it under the terms of the GNU General Public License as published by |
1146 | + * the Free Software Foundation; version 3. |
1147 | + * |
1148 | + * This program is distributed in the hope that it will be useful, |
1149 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1150 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1151 | + * GNU General Public License for more details. |
1152 | + * |
1153 | + * You should have received a copy of the GNU General Public License |
1154 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1155 | + * |
1156 | + * Authored by: Arthur Mello <arthur.mello@canonical.com> |
1157 | + */ |
1158 | + |
1159 | +#ifndef CLIPBOARDAPPLICATION_H |
1160 | +#define CLIPBOARDAPPLICATION_H |
1161 | + |
1162 | +#include <QApplication> |
1163 | +#include <QQuickView> |
1164 | + |
1165 | +class ClipboardApplication : public QApplication |
1166 | +{ |
1167 | + Q_OBJECT |
1168 | + Q_PROPERTY(QString surfaceId READ surfaceId NOTIFY surfaceIdChanged) |
1169 | + Q_PROPERTY(int appState READ appState NOTIFY appStateChanged) |
1170 | + |
1171 | +public: |
1172 | + ClipboardApplication(int &argc, char **argv); |
1173 | + virtual ~ClipboardApplication(); |
1174 | + |
1175 | + int exec(); |
1176 | + |
1177 | + const QString& surfaceId() const; |
1178 | + int appState() const; |
1179 | + |
1180 | +Q_SIGNALS: |
1181 | + void surfaceIdChanged(); |
1182 | + void appStateChanged(); |
1183 | + |
1184 | +protected Q_SLOTS: |
1185 | + void onApplicationStateChanged(Qt::ApplicationState state); |
1186 | + |
1187 | +private: |
1188 | + QString requestSurfaceId(); |
1189 | + |
1190 | + QString m_surfaceId; |
1191 | + QQuickView *m_view; |
1192 | +}; |
1193 | + |
1194 | +#endif // CLIPBOARDAPPLICATION_H |
1195 | |
1196 | === added file 'tools/clipboard/content-hub-clipboard.desktop' |
1197 | --- tools/clipboard/content-hub-clipboard.desktop 1970-01-01 00:00:00 +0000 |
1198 | +++ tools/clipboard/content-hub-clipboard.desktop 2017-03-06 18:20:31 +0000 |
1199 | @@ -0,0 +1,9 @@ |
1200 | +[Desktop Entry] |
1201 | +Name=Content Hub Clipboard |
1202 | +Comment=Content Hub Clipboard |
1203 | +Exec=content-hub-clipboard %U |
1204 | +Icon= |
1205 | +Terminal=false |
1206 | +Type=Application |
1207 | +OnlyShowIn=Old |
1208 | +X-Ubuntu-Touch=true |
1209 | |
1210 | === added file 'tools/clipboard/main.cpp' |
1211 | --- tools/clipboard/main.cpp 1970-01-01 00:00:00 +0000 |
1212 | +++ tools/clipboard/main.cpp 2017-03-06 18:20:31 +0000 |
1213 | @@ -0,0 +1,45 @@ |
1214 | +/* |
1215 | + * Copyright (C) 2016 Canonical, Ltd. |
1216 | + * |
1217 | + * This program is free software; you can redistribute it and/or modify |
1218 | + * it under the terms of the GNU General Public License as published by |
1219 | + * the Free Software Foundation; version 3. |
1220 | + * |
1221 | + * This program is distributed in the hope that it will be useful, |
1222 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1223 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1224 | + * GNU General Public License for more details. |
1225 | + * |
1226 | + * You should have received a copy of the GNU General Public License |
1227 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1228 | + * |
1229 | + * Authored by: Arthur Mello <arthur.mello@canonical.com> |
1230 | + */ |
1231 | + |
1232 | +#include <signal.h> |
1233 | +#include <unistd.h> |
1234 | + |
1235 | +#include "clipboardapplication.h" |
1236 | + |
1237 | +void catchUnixSignals(const std::vector<int>& quitSignals, |
1238 | + const std::vector<int>& ignoreSignals = std::vector<int>()) { |
1239 | + |
1240 | + auto handler = [](int sig) ->void { |
1241 | + QGuiApplication::quit(); |
1242 | + }; |
1243 | + |
1244 | + for ( int sig : ignoreSignals ) |
1245 | + signal(sig, SIG_IGN); |
1246 | + |
1247 | + for ( int sig : quitSignals ) |
1248 | + signal(sig, handler); |
1249 | +} |
1250 | + |
1251 | +int main(int argc, char** argv) |
1252 | +{ |
1253 | + // Set this to make Ubuntu WebView QML component pass AppArmor checks |
1254 | + qputenv("OXIDE_NO_SANDBOX", "1"); |
1255 | + ClipboardApplication app(argc, argv); |
1256 | + catchUnixSignals({SIGQUIT, SIGINT, SIGTERM}); |
1257 | + return app.exec(); |
1258 | +} |
1259 | |
1260 | === added file 'tools/clipboard/main.qml' |
1261 | --- tools/clipboard/main.qml 1970-01-01 00:00:00 +0000 |
1262 | +++ tools/clipboard/main.qml 2017-03-06 18:20:31 +0000 |
1263 | @@ -0,0 +1,308 @@ |
1264 | +/* |
1265 | + * Copyright (C) 2016 Canonical, Ltd. |
1266 | + * |
1267 | + * This program is free software; you can redistribute it and/or modify |
1268 | + * it under the terms of the GNU General Public License as published by |
1269 | + * the Free Software Foundation; version 3. |
1270 | + * |
1271 | + * This program is distributed in the hope that it will be useful, |
1272 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1273 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1274 | + * GNU General Public License for more details. |
1275 | + * |
1276 | + * You should have received a copy of the GNU General Public License |
1277 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1278 | + * |
1279 | + * Authored by: Arthur Mello <arthur.mello@canonical.com> |
1280 | + */ |
1281 | + |
1282 | +import QtQuick 2.4 |
1283 | +import Ubuntu.Components 1.3 |
1284 | +import Ubuntu.Content 1.3 |
1285 | +import clipboardapp.private 0.1 |
1286 | + |
1287 | +MainView { |
1288 | + id: mainView |
1289 | + applicationName: "content-hub-clipboard" |
1290 | + width: units.gu(48) |
1291 | + height: units.gu(60) |
1292 | + |
1293 | + PageStack { |
1294 | + id: pageStack |
1295 | + Component.onCompleted: push(mainPage) |
1296 | + } |
1297 | + |
1298 | + Page { |
1299 | + id: mainPage |
1300 | + |
1301 | + property bool editMode: false |
1302 | + |
1303 | + Binding { |
1304 | + target: pasteDataModel |
1305 | + property: "surfaceId" |
1306 | + value: application.surfaceId |
1307 | + } |
1308 | + |
1309 | + Binding { |
1310 | + target: pasteDataModel |
1311 | + property: "appState" |
1312 | + value: application.appState |
1313 | + } |
1314 | + |
1315 | + PasteDataFilterModel { |
1316 | + id: pasteDataFilterModel |
1317 | + sourceModel: PasteDataModel { |
1318 | + id: pasteDataModel |
1319 | + } |
1320 | + } |
1321 | + |
1322 | + header: PageHeader { |
1323 | + id: pageHeader |
1324 | + |
1325 | + property alias leadingAnchors: leadingBar.anchors |
1326 | + property alias leadingDelegate: leadingBar.delegate |
1327 | + property alias leadingActions: leadingBar.actions |
1328 | + property alias trailingAnchors: trailingBar.anchors |
1329 | + property alias trailingDelegate: trailingBar.delegate |
1330 | + property alias trailingActions: trailingBar.actions |
1331 | + |
1332 | + leadingActionBar { id: leadingBar } |
1333 | + trailingActionBar { id: trailingBar } |
1334 | + } |
1335 | + |
1336 | + states: [ |
1337 | + State { |
1338 | + id: defaultState |
1339 | + name: "default" |
1340 | + when: !mainPage.editMode |
1341 | + |
1342 | + property list<QtObject> leadingActions: [ |
1343 | + Action { |
1344 | + iconName: "close" |
1345 | + text: i18n.tr("Close") |
1346 | + onTriggered: { |
1347 | + ContentHub.selectPasteForAppIdCancelled(requesterId) |
1348 | + Qt.quit() |
1349 | + } |
1350 | + } |
1351 | + ] |
1352 | + |
1353 | + property list<QtObject> trailingActions: [ |
1354 | + Action { |
1355 | + iconName: "edit" |
1356 | + text: i18n.tr("Edit") |
1357 | + enabled: pasteDataFilterModel.count != 0 |
1358 | + onTriggered: mainPage.editMode = true |
1359 | + } |
1360 | + ] |
1361 | + |
1362 | + PropertyChanges { |
1363 | + target: pageHeader |
1364 | + title: i18n.tr("Clipboard") |
1365 | + leadingActions: defaultState.leadingActions |
1366 | + trailingActions: defaultState.trailingActions |
1367 | + } |
1368 | + }, |
1369 | + |
1370 | + State { |
1371 | + id: editState |
1372 | + name: "edit" |
1373 | + when: mainPage.editMode |
1374 | + |
1375 | + property bool entriesEdited: false |
1376 | + |
1377 | + property Component delegate: Component { |
1378 | + AbstractButton { |
1379 | + id: button |
1380 | + |
1381 | + width: label.width + units.gu(4) |
1382 | + height: parent.height |
1383 | + |
1384 | + action: modelData |
1385 | + |
1386 | + Rectangle { |
1387 | + color: UbuntuColors.slate |
1388 | + opacity: 0.1 |
1389 | + anchors.fill: parent |
1390 | + visible: button.pressed |
1391 | + } |
1392 | + |
1393 | + Label { |
1394 | + anchors.centerIn: parent |
1395 | + id: label |
1396 | + text: action.text |
1397 | + font.weight: action.iconName === "tick" ? Font.Normal : Font.Light |
1398 | + } |
1399 | + } |
1400 | + } |
1401 | + |
1402 | + property list<QtObject> leadingActions: [ |
1403 | + Action { |
1404 | + text: i18n.tr("Cancel") |
1405 | + iconName: "close" |
1406 | + onTriggered: { |
1407 | + pasteDataModel.cancelDeletion() |
1408 | + mainPage.editMode = false |
1409 | + editState.entriesEdited = false |
1410 | + } |
1411 | + } |
1412 | + ] |
1413 | + |
1414 | + property list<QtObject> trailingActions: [ |
1415 | + Action { |
1416 | + text: i18n.tr("Save") |
1417 | + iconName: "tick" |
1418 | + enabled: editState.entriesEdited |
1419 | + onTriggered: { |
1420 | + pasteDataModel.deleteEntries() |
1421 | + mainPage.editMode = false |
1422 | + editState.entriesEdited = false |
1423 | + } |
1424 | + } |
1425 | + ] |
1426 | + |
1427 | + property Toolbar extensionToolbar: Toolbar { |
1428 | + anchors { |
1429 | + left: parent ? parent.left : undefined |
1430 | + right: parent ? parent.right : undefined |
1431 | + bottom: parent ? parent.bottom : undefined |
1432 | + } |
1433 | + |
1434 | + leadingActionBar.actions: Action { |
1435 | + iconName: "delete" |
1436 | + text: i18n.tr("Delete") |
1437 | + enabled: pasteDataModel.anyEntrySelected |
1438 | + onTriggered: { |
1439 | + editState.entriesEdited = true |
1440 | + pasteDataModel.markSelectedForDeletion() |
1441 | + } |
1442 | + } |
1443 | + |
1444 | + trailingActionBar.actions: Action { |
1445 | + iconName: pasteDataModel.allEntriesSelected ? "select-none" : "select" |
1446 | + text: i18n.tr("Select All") |
1447 | + onTriggered: pasteDataModel.selectAll(!pasteDataModel.allEntriesSelected) |
1448 | + } |
1449 | + } |
1450 | + |
1451 | + PropertyChanges { |
1452 | + target: pageHeader |
1453 | + leadingAnchors.leftMargin: 0 |
1454 | + leadingDelegate: editState.delegate |
1455 | + leadingActions: editState.leadingActions |
1456 | + trailingAnchors.rightMargin: 0 |
1457 | + trailingDelegate: editState.delegate |
1458 | + trailingActions: editState.trailingActions |
1459 | + extension: editState.extensionToolbar |
1460 | + } |
1461 | + } |
1462 | + ] |
1463 | + |
1464 | + ListView { |
1465 | + id: clipboardListView |
1466 | + |
1467 | + anchors { |
1468 | + top: pageHeader.bottom |
1469 | + bottom: parent.bottom |
1470 | + } |
1471 | + |
1472 | + width: parent.width |
1473 | + |
1474 | + model: pasteDataFilterModel |
1475 | + |
1476 | + delegate: ClipboardItemDelegate { |
1477 | + id: delegate |
1478 | + |
1479 | + title: dataType === PasteDataModel.Image ? i18n.tr("Image") : textData |
1480 | + summary: source |
1481 | + imageSource: { |
1482 | + if (dataType === PasteDataModel.ImageUrl) { |
1483 | + return imageData |
1484 | + } else if (dataType === PasteDataModel.Image) { |
1485 | + return "image://pastedImage/" + application.surfaceId + "/" + id |
1486 | + } |
1487 | + return "" |
1488 | + } |
1489 | + |
1490 | + Binding { |
1491 | + target: delegate |
1492 | + property: "selected" |
1493 | + value: entrySelected |
1494 | + } |
1495 | + |
1496 | + Component.onCompleted: { |
1497 | + selectMode = Qt.binding(function() { return mainPage.editMode }) |
1498 | + } |
1499 | + |
1500 | + onSelectedChanged: { |
1501 | + pasteDataModel.selectByIndex(index, selected) |
1502 | + } |
1503 | + onPressAndHold: { |
1504 | + if (!mainPage.editMode) { |
1505 | + mainPage.editMode = true |
1506 | + } |
1507 | + } |
1508 | + onClicked: { |
1509 | + if (!selectMode) { |
1510 | + ContentHub.selectPasteForAppId(requesterId, application.surfaceId, id, outputType == PasteDataModel.RichText) |
1511 | + Qt.quit() |
1512 | + } |
1513 | + } |
1514 | + onDeleteClicked: { |
1515 | + pasteDataModel.deleteByIndex(index) |
1516 | + } |
1517 | + onPreviewClicked: { |
1518 | + if (dataType === PasteDataModel.ImageUrl) { |
1519 | + previewImagePage.pasteId = id |
1520 | + previewImagePage.imageSource = imageData |
1521 | + pageStack.push(previewImagePage) |
1522 | + |
1523 | + } else if (dataType === PasteDataModel.Image) { |
1524 | + previewImagePage.pasteId = id |
1525 | + previewImagePage.imageSource = "image://pastedImage/" + application.surfaceId + "/" + id |
1526 | + pageStack.push(previewImagePage) |
1527 | + |
1528 | + } else { |
1529 | + previewTextPage.index = index |
1530 | + previewTextPage.pasteId = id |
1531 | + previewTextPage.text = textData |
1532 | + previewTextPage.richText = htmlData |
1533 | + previewTextPage.outputOption = outputType |
1534 | + pageStack.push(previewTextPage) |
1535 | + } |
1536 | + } |
1537 | + } |
1538 | + } |
1539 | + } |
1540 | + |
1541 | + PreviewTextPage { |
1542 | + id: previewTextPage |
1543 | + |
1544 | + property int index |
1545 | + property int pasteId |
1546 | + |
1547 | + visible: false |
1548 | + |
1549 | + onOutputOptionChanged: pasteDataModel.setOutputTypeByIndex(index, outputOption) |
1550 | + |
1551 | + onPasteClicked: { |
1552 | + pageStack.pop() |
1553 | + ContentHub.selectPasteForAppId(requesterId, application.surfaceId, pasteId, outputOption == PasteDataModel.RichText) |
1554 | + Qt.quit() |
1555 | + } |
1556 | + } |
1557 | + |
1558 | + PreviewImagePage { |
1559 | + id: previewImagePage |
1560 | + |
1561 | + property int pasteId |
1562 | + |
1563 | + visible: false |
1564 | + |
1565 | + onPasteClicked: { |
1566 | + pageStack.pop() |
1567 | + ContentHub.selectPasteForAppId(requesterId, application.surfaceId, pasteId, false) |
1568 | + Qt.quit() |
1569 | + } |
1570 | + } |
1571 | +} |
1572 | |
1573 | === added file 'tools/clipboard/paste-data-filter-model.cpp' |
1574 | --- tools/clipboard/paste-data-filter-model.cpp 1970-01-01 00:00:00 +0000 |
1575 | +++ tools/clipboard/paste-data-filter-model.cpp 2017-03-06 18:20:31 +0000 |
1576 | @@ -0,0 +1,60 @@ |
1577 | +/* |
1578 | + * Copyright (C) 2016 Canonical, Ltd. |
1579 | + * |
1580 | + * This program is free software; you can redistribute it and/or modify |
1581 | + * it under the terms of the GNU General Public License as published by |
1582 | + * the Free Software Foundation; version 3. |
1583 | + * |
1584 | + * This program is distributed in the hope that it will be useful, |
1585 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1586 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1587 | + * GNU General Public License for more details. |
1588 | + * |
1589 | + * You should have received a copy of the GNU General Public License |
1590 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1591 | + * |
1592 | + * Authored by: Arthur Mello <arthur.mello@canonical.com> |
1593 | + */ |
1594 | + |
1595 | +#include "paste-data-filter-model.h" |
1596 | + |
1597 | +#include "paste-data-model.h" |
1598 | + |
1599 | +PasteDataFilterModel::PasteDataFilterModel(QObject* parent) |
1600 | + : QSortFilterProxyModel(parent) |
1601 | +{ |
1602 | + setDynamicSortFilter(true); |
1603 | + |
1604 | + connect(this, SIGNAL(rowsInserted(QModelIndex, int, int)), SLOT(onModelChanged())); |
1605 | + connect(this, SIGNAL(rowsRemoved(QModelIndex, int, int)), SLOT(onModelChanged())); |
1606 | +} |
1607 | + |
1608 | +PasteDataModel* PasteDataFilterModel::sourceModel() const |
1609 | +{ |
1610 | + return qobject_cast<PasteDataModel*>(QSortFilterProxyModel::sourceModel()); |
1611 | +} |
1612 | + |
1613 | +void PasteDataFilterModel::setSourceModel(PasteDataModel* sourceModel) |
1614 | +{ |
1615 | + if (sourceModel != this->sourceModel()) { |
1616 | + QSortFilterProxyModel::setSourceModel(sourceModel); |
1617 | + Q_EMIT sourceModelChanged(); |
1618 | + Q_EMIT countChanged(); |
1619 | + } |
1620 | +} |
1621 | + |
1622 | +int PasteDataFilterModel::count() const |
1623 | +{ |
1624 | + return rowCount(); |
1625 | +} |
1626 | + |
1627 | +bool PasteDataFilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const |
1628 | +{ |
1629 | + QModelIndex index = sourceModel()->index(source_row, 0, source_parent); |
1630 | + return !sourceModel()->data(index, PasteDataModel::Deleted).toBool(); |
1631 | +} |
1632 | + |
1633 | +void PasteDataFilterModel::onModelChanged() |
1634 | +{ |
1635 | + Q_EMIT countChanged(); |
1636 | +} |
1637 | |
1638 | === added file 'tools/clipboard/paste-data-filter-model.h' |
1639 | --- tools/clipboard/paste-data-filter-model.h 1970-01-01 00:00:00 +0000 |
1640 | +++ tools/clipboard/paste-data-filter-model.h 2017-03-06 18:20:31 +0000 |
1641 | @@ -0,0 +1,54 @@ |
1642 | +/* |
1643 | + * Copyright (C) 2016 Canonical, Ltd. |
1644 | + * |
1645 | + * This program is free software; you can redistribute it and/or modify |
1646 | + * it under the terms of the GNU General Public License as published by |
1647 | + * the Free Software Foundation; version 3. |
1648 | + * |
1649 | + * This program is distributed in the hope that it will be useful, |
1650 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1651 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1652 | + * GNU General Public License for more details. |
1653 | + * |
1654 | + * You should have received a copy of the GNU General Public License |
1655 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1656 | + * |
1657 | + * Authored by: Arthur Mello <arthur.mello@canonical.com> |
1658 | + */ |
1659 | + |
1660 | +#ifndef PASTEDATAFILTERMODEL_H |
1661 | +#define PASTEDATAFILTERMODEL_H |
1662 | + |
1663 | +#include <QSortFilterProxyModel> |
1664 | + |
1665 | +class PasteDataModel; |
1666 | +class PasteDataEntry; |
1667 | + |
1668 | +class PasteDataFilterModel : public QSortFilterProxyModel |
1669 | +{ |
1670 | + Q_OBJECT |
1671 | + |
1672 | + Q_PROPERTY(PasteDataModel* sourceModel READ sourceModel WRITE setSourceModel NOTIFY sourceModelChanged) |
1673 | + Q_PROPERTY(int count READ count NOTIFY countChanged) |
1674 | + |
1675 | +public: |
1676 | + PasteDataFilterModel(QObject* parent=0); |
1677 | + |
1678 | + PasteDataModel* sourceModel() const; |
1679 | + void setSourceModel(PasteDataModel* sourceModel); |
1680 | + |
1681 | + int count() const; |
1682 | + |
1683 | +Q_SIGNALS: |
1684 | + void sourceModelChanged() const; |
1685 | + void countChanged() const; |
1686 | + |
1687 | +protected: |
1688 | + // reimplemented from QSortFilterProxyModel |
1689 | + bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const; |
1690 | + |
1691 | +private Q_SLOTS: |
1692 | + void onModelChanged(); |
1693 | +}; |
1694 | + |
1695 | +#endif // PASTEDATAFILTERMODEL_H |
1696 | |
1697 | === added file 'tools/clipboard/paste-data-model.cpp' |
1698 | --- tools/clipboard/paste-data-model.cpp 1970-01-01 00:00:00 +0000 |
1699 | +++ tools/clipboard/paste-data-model.cpp 2017-03-06 18:20:31 +0000 |
1700 | @@ -0,0 +1,350 @@ |
1701 | +/* |
1702 | + * Copyright (C) 2016 Canonical Ltd |
1703 | + * |
1704 | + * This program is free software: you can redistribute it and/or modify |
1705 | + * it under the terms of the GNU General Public License version 3 as |
1706 | + * published by the Free Software Foundation. |
1707 | + * |
1708 | + * This program is distributed in the hope that it will be useful, |
1709 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1710 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1711 | + * GNU General Public License for more details. |
1712 | + * |
1713 | + * You should have received a copy of the GNU General Public License |
1714 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1715 | + * |
1716 | +*/ |
1717 | + |
1718 | +#include "paste-data-model.h" |
1719 | + |
1720 | +#include <QDebug> |
1721 | +#include <QImage> |
1722 | +#include <QTimer> |
1723 | + |
1724 | +#include "paste-data-provider.h" |
1725 | + |
1726 | +PasteDataModel::PasteDataModel(QObject* parent) |
1727 | + : QAbstractListModel(parent), |
1728 | + m_provider(new PasteDataProvider()), |
1729 | + m_surfaceId(), |
1730 | + m_appState(-1), |
1731 | + m_selectedEntries(0), |
1732 | + m_shouldUpdateModel(true) |
1733 | +{ |
1734 | + connect(m_provider, SIGNAL(PasteboardChanged()), this, SLOT(onPasteboardChanged())); |
1735 | +} |
1736 | + |
1737 | +PasteDataModel::~PasteDataModel() |
1738 | +{ |
1739 | +} |
1740 | + |
1741 | +QHash<int, QByteArray> PasteDataModel::roleNames() const |
1742 | +{ |
1743 | + static QHash<int, QByteArray> roles; |
1744 | + if (roles.isEmpty()) { |
1745 | + roles[Id] = "id"; |
1746 | + roles[Source] = "source"; |
1747 | + roles[DataType] = "dataType"; |
1748 | + roles[TextData] = "textData"; |
1749 | + roles[HtmlData] = "htmlData"; |
1750 | + roles[ImageData] = "imageData"; |
1751 | + roles[EntrySelected] = "entrySelected"; |
1752 | + roles[Deleted] = "deleted"; |
1753 | + roles[OutputType] = "outputType"; |
1754 | + } |
1755 | + return roles; |
1756 | +} |
1757 | + |
1758 | +int PasteDataModel::rowCount(const QModelIndex& parent) const |
1759 | +{ |
1760 | + Q_UNUSED(parent); |
1761 | + return m_entries.count(); |
1762 | +} |
1763 | + |
1764 | +QVariant PasteDataModel::data(const QModelIndex& index, int role) const |
1765 | +{ |
1766 | + if (!index.isValid()) { |
1767 | + return QVariant(); |
1768 | + } |
1769 | + |
1770 | + const PasteEntry& entry = m_entries.at(index.row()); |
1771 | + switch (role) { |
1772 | + case Id: |
1773 | + return entry.id; |
1774 | + case Source: |
1775 | + return entry.source; |
1776 | + case DataType: |
1777 | + return entry.dataType; |
1778 | + case TextData: |
1779 | + return entry.textData; |
1780 | + case HtmlData: |
1781 | + return entry.htmlData; |
1782 | + case ImageData: |
1783 | + return entry.imageData; |
1784 | + case EntrySelected: |
1785 | + return entry.entrySelected; |
1786 | + case Deleted: |
1787 | + return entry.deleted; |
1788 | + case OutputType: |
1789 | + return entry.outputType; |
1790 | + default: |
1791 | + return QVariant(); |
1792 | + } |
1793 | +} |
1794 | + |
1795 | +QString PasteDataModel::surfaceId() const |
1796 | +{ |
1797 | + return m_surfaceId; |
1798 | +} |
1799 | + |
1800 | +void PasteDataModel::setSurfaceId(QString surfaceId) |
1801 | +{ |
1802 | + if (m_surfaceId != surfaceId) { |
1803 | + m_surfaceId = surfaceId; |
1804 | + Q_EMIT(surfaceIdChanged()); |
1805 | + |
1806 | + if (!m_surfaceId.isEmpty()) { |
1807 | + if (m_shouldUpdateModel && m_appState == Qt::ApplicationActive) { |
1808 | + updateModel(); |
1809 | + } |
1810 | + } |
1811 | + } |
1812 | +} |
1813 | + |
1814 | +int PasteDataModel::appState() const |
1815 | +{ |
1816 | + return m_appState; |
1817 | +} |
1818 | + |
1819 | +void PasteDataModel::setAppState(int state) |
1820 | +{ |
1821 | + if (m_appState != state) { |
1822 | + m_appState = state; |
1823 | + Q_EMIT(appStateChanged()); |
1824 | + |
1825 | + if (m_appState == Qt::ApplicationActive) { |
1826 | + if (m_shouldUpdateModel && !m_surfaceId.isEmpty()) { |
1827 | + updateModel(); |
1828 | + } |
1829 | + } |
1830 | + } |
1831 | +} |
1832 | + |
1833 | +bool PasteDataModel::anyEntrySelected() const |
1834 | +{ |
1835 | + return m_selectedEntries > 0; |
1836 | +} |
1837 | + |
1838 | +bool PasteDataModel::allEntriesSelected() const |
1839 | +{ |
1840 | + return m_selectedEntries == rowCount(); |
1841 | +} |
1842 | + |
1843 | +void PasteDataModel::selectAll(bool selected) |
1844 | +{ |
1845 | + for (int i = 0; i < m_entries.size(); ++i) { |
1846 | + selectByIndex(i, selected); |
1847 | + } |
1848 | +} |
1849 | + |
1850 | +void PasteDataModel::selectByIndex(int index, bool selected) |
1851 | +{ |
1852 | + if (index < 0 || index >= m_entries.size()) { |
1853 | + return; |
1854 | + } |
1855 | + |
1856 | + if (m_entries[index].entrySelected != selected) { |
1857 | + QVector<int> roles; |
1858 | + roles << EntrySelected; |
1859 | + |
1860 | + m_entries[index].entrySelected = selected; |
1861 | + |
1862 | + Q_EMIT dataChanged(this->index(index, 0), this->index(index, 0), roles); |
1863 | + |
1864 | + // Keep count of how many entries are selected |
1865 | + if (selected) { |
1866 | + if (m_selectedEntries == 0) { |
1867 | + m_selectedEntries++; |
1868 | + Q_EMIT anyEntrySelectedChanged(); |
1869 | + } else { |
1870 | + m_selectedEntries++; |
1871 | + } |
1872 | + |
1873 | + if (m_selectedEntries == rowCount()) { |
1874 | + Q_EMIT allEntriesSelectedChanged(); |
1875 | + } |
1876 | + } else { |
1877 | + if (m_selectedEntries == rowCount()) { |
1878 | + m_selectedEntries--; |
1879 | + Q_EMIT allEntriesSelectedChanged(); |
1880 | + } else { |
1881 | + m_selectedEntries--; |
1882 | + } |
1883 | + |
1884 | + if (m_selectedEntries == 0) { |
1885 | + Q_EMIT anyEntrySelectedChanged(); |
1886 | + } |
1887 | + } |
1888 | + } |
1889 | +} |
1890 | + |
1891 | +void PasteDataModel::markSelectedForDeletion() |
1892 | +{ |
1893 | + QList<int> idxs; |
1894 | + for (int i = 0; i < m_entries.size(); ++i) { |
1895 | + if (m_entries[i].entrySelected) { |
1896 | + idxs << i; |
1897 | + selectByIndex(i, false); |
1898 | + } |
1899 | + } |
1900 | + |
1901 | + for (int i = 0; i < idxs.size(); ++i) { |
1902 | + markForDeletionByIndex(idxs[i], true); |
1903 | + } |
1904 | +} |
1905 | + |
1906 | +void PasteDataModel::markForDeletionByIndex(int index, bool deleted) |
1907 | +{ |
1908 | + if (index < 0 || index >= m_entries.size()) { |
1909 | + return; |
1910 | + } |
1911 | + |
1912 | + if (m_entries[index].deleted != deleted) { |
1913 | + QVector<int> roles; |
1914 | + roles << Deleted; |
1915 | + |
1916 | + m_entries[index].deleted = deleted; |
1917 | + |
1918 | + Q_EMIT dataChanged(this->index(index, 0), this->index(index, 0), roles); |
1919 | + } |
1920 | +} |
1921 | + |
1922 | +void PasteDataModel::cancelDeletion() |
1923 | +{ |
1924 | + for (int i = 0; i < m_entries.size(); ++i) { |
1925 | + if (m_entries[i].deleted) { |
1926 | + markForDeletionByIndex(i, false); |
1927 | + } |
1928 | + } |
1929 | +} |
1930 | + |
1931 | +void PasteDataModel::deleteEntries() |
1932 | +{ |
1933 | + for (int i = m_entries.size() - 1; i >= 0; --i) { |
1934 | + if (m_entries[i].deleted) { |
1935 | + deleteByIndex(i); |
1936 | + } |
1937 | + } |
1938 | +} |
1939 | + |
1940 | +void PasteDataModel::deleteByIndex(int index) |
1941 | +{ |
1942 | + if (index < 0 || index >= m_entries.size()) |
1943 | + return; |
1944 | + |
1945 | + if (!m_provider->removePaste(m_surfaceId, m_entries[index].id.toInt())) |
1946 | + return; |
1947 | + |
1948 | + removeFromModel(index); |
1949 | +} |
1950 | + |
1951 | +void PasteDataModel::setOutputTypeByIndex(int index, PasteOutputType output) |
1952 | +{ |
1953 | + if (index < 0 || index >= m_entries.size()) { |
1954 | + return; |
1955 | + } |
1956 | + |
1957 | + if (m_entries[index].outputType != output) { |
1958 | + QVector<int> roles; |
1959 | + roles << OutputType; |
1960 | + |
1961 | + m_entries[index].outputType = output; |
1962 | + |
1963 | + Q_EMIT dataChanged(this->index(index, 0), this->index(index, 0), roles); |
1964 | + } |
1965 | +} |
1966 | + |
1967 | +void PasteDataModel::onPasteboardChanged() |
1968 | +{ |
1969 | + m_shouldUpdateModel = true; |
1970 | +} |
1971 | + |
1972 | +void PasteDataModel::addToModelByPasteId(const QString& pasteId) |
1973 | +{ |
1974 | + PasteEntry entry; |
1975 | + |
1976 | + int id = pasteId.toInt(); |
1977 | + |
1978 | + entry.id = QString::number(id); |
1979 | + entry.source = m_provider->pasteSourceById(m_surfaceId, id); |
1980 | + |
1981 | + QMimeData *pasteMimeData = m_provider->pasteDataById(m_surfaceId, id); |
1982 | + if (pasteMimeData->hasImage()) { |
1983 | + if (pasteMimeData->imageData().toByteArray().isEmpty()) { |
1984 | + // Images copied from webborwser-app do not have imageData but in fact an url |
1985 | + entry.dataType = ImageUrl; |
1986 | + entry.htmlData = pasteMimeData->html(); |
1987 | + |
1988 | + QRegularExpression srcRe("src=\"([^\"]*)\""); |
1989 | + QRegularExpressionMatch srcMatch = srcRe.match(entry.htmlData); |
1990 | + if (srcMatch.hasMatch()) { |
1991 | + entry.imageData = srcMatch.captured(1); |
1992 | + } |
1993 | + |
1994 | + QRegularExpression altRe("alt=\"([^\"]*)\""); |
1995 | + QRegularExpressionMatch altMatch = altRe.match(entry.htmlData); |
1996 | + if (altMatch.hasMatch()) { |
1997 | + entry.textData = altMatch.captured(1); |
1998 | + } |
1999 | + } else { |
2000 | + entry.dataType = Image; |
2001 | + } |
2002 | + |
2003 | + } else { |
2004 | + entry.dataType = Text; |
2005 | + entry.textData = pasteMimeData->text(); |
2006 | + if (pasteMimeData->hasHtml()) { |
2007 | + entry.htmlData = pasteMimeData->html(); |
2008 | + } |
2009 | + } |
2010 | + |
2011 | + entry.entrySelected = false; |
2012 | + entry.deleted = false; |
2013 | + entry.outputType = PlainText; |
2014 | + |
2015 | + addToModel(entry); |
2016 | +} |
2017 | + |
2018 | +void PasteDataModel::addToModel(PasteEntry& entry) |
2019 | +{ |
2020 | + beginInsertRows(QModelIndex(), 0, 0); |
2021 | + m_entries.prepend(entry); |
2022 | + endInsertRows(); |
2023 | + Q_EMIT rowCountChanged(); |
2024 | +} |
2025 | + |
2026 | +void PasteDataModel::removeFromModel(int index) |
2027 | +{ |
2028 | + beginRemoveRows(QModelIndex(), index, index); |
2029 | + m_entries.removeAt(index); |
2030 | + endRemoveRows(); |
2031 | + Q_EMIT rowCountChanged(); |
2032 | +} |
2033 | + |
2034 | +void PasteDataModel::updateModel() |
2035 | +{ |
2036 | + QStringList dataList = m_provider->allPasteIds(m_surfaceId); |
2037 | + |
2038 | + for (int i = m_entries.size() - 1; i >= 0; i--) { |
2039 | + if (dataList.removeAll(m_entries[i].id) == 0) { |
2040 | + // Paste id was removed from current pasteboard |
2041 | + removeFromModel(i); |
2042 | + } |
2043 | + } |
2044 | + |
2045 | + for (int i = 0; i < dataList.size(); ++i) { |
2046 | + addToModelByPasteId(dataList.at(i)); |
2047 | + } |
2048 | + |
2049 | + m_shouldUpdateModel = false; |
2050 | +} |
2051 | |
2052 | === added file 'tools/clipboard/paste-data-model.h' |
2053 | --- tools/clipboard/paste-data-model.h 1970-01-01 00:00:00 +0000 |
2054 | +++ tools/clipboard/paste-data-model.h 2017-03-06 18:20:31 +0000 |
2055 | @@ -0,0 +1,128 @@ |
2056 | +/* |
2057 | + * Copyright (C) 2016 Canonical, Ltd. |
2058 | + * |
2059 | + * This program is free software; you can redistribute it and/or modify |
2060 | + * it under the terms of the GNU General Public License as published by |
2061 | + * the Free Software Foundation; version 3. |
2062 | + * |
2063 | + * This program is distributed in the hope that it will be useful, |
2064 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2065 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2066 | + * GNU General Public License for more details. |
2067 | + * |
2068 | + * You should have received a copy of the GNU General Public License |
2069 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2070 | + * |
2071 | + * Authored by: Arthur Mello <arthur.mello@canonical.com> |
2072 | + */ |
2073 | + |
2074 | +#ifndef PASTEDATAMODEL_H |
2075 | +#define PASTEDATAMODEL_H |
2076 | + |
2077 | +#include <QAbstractListModel> |
2078 | + |
2079 | +class PasteDataProvider; |
2080 | + |
2081 | +class PasteDataModel : public QAbstractListModel |
2082 | +{ |
2083 | + Q_OBJECT |
2084 | + |
2085 | + Q_PROPERTY(int count READ rowCount NOTIFY rowCountChanged) |
2086 | + Q_PROPERTY(QString surfaceId READ surfaceId WRITE setSurfaceId NOTIFY surfaceIdChanged) |
2087 | + Q_PROPERTY(int appState READ appState WRITE setAppState NOTIFY appStateChanged) |
2088 | + Q_PROPERTY(bool anyEntrySelected READ anyEntrySelected NOTIFY anyEntrySelectedChanged) |
2089 | + Q_PROPERTY(bool allEntriesSelected READ allEntriesSelected NOTIFY allEntriesSelectedChanged) |
2090 | + |
2091 | + Q_ENUMS(Roles) |
2092 | + Q_ENUMS(PasteDataType) |
2093 | + Q_ENUMS(PasteOutputType) |
2094 | + |
2095 | +public: |
2096 | + PasteDataModel(QObject* parent=0); |
2097 | + ~PasteDataModel(); |
2098 | + |
2099 | + enum Roles { |
2100 | + Id = Qt::UserRole + 1, |
2101 | + Source, |
2102 | + DataType, |
2103 | + TextData, |
2104 | + HtmlData, |
2105 | + ImageData, |
2106 | + EntrySelected, |
2107 | + Deleted, |
2108 | + OutputType |
2109 | + }; |
2110 | + |
2111 | + enum PasteDataType { |
2112 | + Text, |
2113 | + Image, |
2114 | + ImageUrl |
2115 | + }; |
2116 | + |
2117 | + enum PasteOutputType { |
2118 | + PlainText, |
2119 | + RichText |
2120 | + }; |
2121 | + |
2122 | + // reimplemented from QAbstractListModel |
2123 | + QHash<int, QByteArray> roleNames() const; |
2124 | + int rowCount(const QModelIndex& parent=QModelIndex()) const; |
2125 | + QVariant data(const QModelIndex& index, int role) const; |
2126 | + |
2127 | + QString surfaceId() const; |
2128 | + void setSurfaceId(QString surfaceId); |
2129 | + |
2130 | + int appState() const; |
2131 | + void setAppState(int state); |
2132 | + |
2133 | + bool anyEntrySelected() const; |
2134 | + bool allEntriesSelected() const; |
2135 | + |
2136 | + Q_INVOKABLE void selectAll(bool selected); |
2137 | + Q_INVOKABLE void selectByIndex(int index, bool selected); |
2138 | + Q_INVOKABLE void markSelectedForDeletion(); |
2139 | + Q_INVOKABLE void markForDeletionByIndex(int index, bool deleted); |
2140 | + Q_INVOKABLE void cancelDeletion(); |
2141 | + Q_INVOKABLE void deleteEntries(); |
2142 | + Q_INVOKABLE void deleteByIndex(int index); |
2143 | + Q_INVOKABLE void setOutputTypeByIndex(int index, PasteOutputType outputType); |
2144 | + |
2145 | +protected: |
2146 | + struct PasteEntry { |
2147 | + QString id; |
2148 | + QString source; |
2149 | + PasteDataType dataType; |
2150 | + QString textData; |
2151 | + QString htmlData; |
2152 | + QString imageData; |
2153 | + bool entrySelected; |
2154 | + bool deleted; |
2155 | + PasteOutputType outputType; |
2156 | + }; |
2157 | + QList<PasteEntry> m_entries; |
2158 | + |
2159 | + |
2160 | +Q_SIGNALS: |
2161 | + void rowCountChanged(); |
2162 | + void surfaceIdChanged(); |
2163 | + void appStateChanged(); |
2164 | + void anyEntrySelectedChanged(); |
2165 | + void allEntriesSelectedChanged(); |
2166 | + |
2167 | +private Q_SLOTS: |
2168 | + void onPasteboardChanged(); |
2169 | + |
2170 | +private: |
2171 | + void addToModelByPasteId(const QString& pasteId); |
2172 | + void addToModel(PasteEntry& entry); |
2173 | + void removeFromModel(int index); |
2174 | + void updateModel(); |
2175 | + |
2176 | + PasteDataProvider* m_provider; |
2177 | + QString m_surfaceId; |
2178 | + int m_appState; |
2179 | + int m_selectedEntries; |
2180 | + bool m_shouldUpdateModel; |
2181 | +}; |
2182 | + |
2183 | +#endif // PASTEDATAMODEL_H |
2184 | |
2185 | === added file 'tools/clipboard/paste-data-provider.cpp' |
2186 | --- tools/clipboard/paste-data-provider.cpp 1970-01-01 00:00:00 +0000 |
2187 | +++ tools/clipboard/paste-data-provider.cpp 2017-03-06 18:20:31 +0000 |
2188 | @@ -0,0 +1,105 @@ |
2189 | +/* |
2190 | + * Copyright (C) 2016 Canonical Ltd |
2191 | + * |
2192 | + * This program is free software: you can redistribute it and/or modify |
2193 | + * it under the terms of the GNU General Public License version 3 as |
2194 | + * published by the Free Software Foundation. |
2195 | + * |
2196 | + * This program is distributed in the hope that it will be useful, |
2197 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2198 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2199 | + * GNU General Public License for more details. |
2200 | + * |
2201 | + * You should have received a copy of the GNU General Public License |
2202 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2203 | + * |
2204 | +*/ |
2205 | + |
2206 | +#include "paste-data-provider.h" |
2207 | + |
2208 | +#include "debug.h" |
2209 | +#include "utils.cpp" |
2210 | + |
2211 | +PasteDataProvider::PasteDataProvider(QObject* parent) |
2212 | + : QObject(parent), |
2213 | + d{new PasteDataProviderPrivate{this}} |
2214 | +{ |
2215 | + connect(d->service, SIGNAL(PasteboardChanged()), this, SIGNAL(PasteboardChanged())); |
2216 | +} |
2217 | + |
2218 | +PasteDataProvider::~PasteDataProvider() |
2219 | +{ |
2220 | +} |
2221 | + |
2222 | +QDBusPendingCall PasteDataProvider::requestAllPasteIds(const QString &surfaceId) |
2223 | +{ |
2224 | + TRACE() << Q_FUNC_INFO; |
2225 | + return d->service->GetAllPasteIds(surfaceId); |
2226 | +} |
2227 | + |
2228 | +QDBusPendingCall PasteDataProvider::requestPasteDataById(const QString &surfaceId, int pasteId) |
2229 | +{ |
2230 | + TRACE() << Q_FUNC_INFO; |
2231 | + return d->service->GetPasteData(surfaceId, QString::number(pasteId)); |
2232 | +} |
2233 | + |
2234 | +QDBusPendingCall PasteDataProvider::requestPasteSourceById(const QString &surfaceId, int pasteId) |
2235 | +{ |
2236 | + TRACE() << Q_FUNC_INFO; |
2237 | + return d->service->GetPasteSource(surfaceId, QString::number(pasteId)); |
2238 | +} |
2239 | + |
2240 | +QDBusPendingCall PasteDataProvider::requestRemovePaste(const QString &surfaceId, int pasteId) |
2241 | +{ |
2242 | + TRACE() << Q_FUNC_INFO; |
2243 | + return d->service->RemovePaste(surfaceId, QString::number(pasteId)); |
2244 | +} |
2245 | + |
2246 | +QStringList PasteDataProvider::allPasteIds(const QString &surfaceId) |
2247 | +{ |
2248 | + QDBusPendingCall pendingCall = requestAllPasteIds(surfaceId); |
2249 | + auto reply = QDBusPendingReply<QStringList>(pendingCall); |
2250 | + reply.waitForFinished(); |
2251 | + |
2252 | + if (reply.isError()) |
2253 | + return QStringList(); |
2254 | + |
2255 | + return qdbus_cast<QStringList>(reply.value()); |
2256 | +} |
2257 | + |
2258 | +QMimeData* PasteDataProvider::pasteDataById(const QString &surfaceId, int pasteId) |
2259 | +{ |
2260 | + QDBusPendingCall pendingCall = requestPasteDataById(surfaceId, pasteId); |
2261 | + auto reply = QDBusPendingReply<QByteArray>(pendingCall); |
2262 | + reply.waitForFinished(); |
2263 | + |
2264 | + if (reply.isError()) |
2265 | + return nullptr; |
2266 | + |
2267 | + QByteArray serializedMimeData = qdbus_cast<QByteArray>(reply.value()); |
2268 | + return deserializeMimeData(serializedMimeData); |
2269 | +} |
2270 | + |
2271 | +QString PasteDataProvider::pasteSourceById(const QString &surfaceId, int pasteId) |
2272 | +{ |
2273 | + QDBusPendingCall pendingCall = requestPasteSourceById(surfaceId, pasteId); |
2274 | + auto reply = QDBusPendingReply<QString>(pendingCall); |
2275 | + reply.waitForFinished(); |
2276 | + |
2277 | + if (reply.isError()) |
2278 | + return QString(); |
2279 | + |
2280 | + return qdbus_cast<QString>(reply.value()); |
2281 | +} |
2282 | + |
2283 | +bool PasteDataProvider::removePaste(const QString &surfaceId, int pasteId) |
2284 | +{ |
2285 | + QDBusPendingCall pendingCall = requestRemovePaste(surfaceId, pasteId); |
2286 | + auto reply = QDBusPendingReply<bool>(pendingCall); |
2287 | + reply.waitForFinished(); |
2288 | + |
2289 | + if (reply.isError()) |
2290 | + return false; |
2291 | + |
2292 | + return qdbus_cast<bool>(reply.value()); |
2293 | +} |
2294 | |
2295 | === added file 'tools/clipboard/paste-data-provider.h' |
2296 | --- tools/clipboard/paste-data-provider.h 1970-01-01 00:00:00 +0000 |
2297 | +++ tools/clipboard/paste-data-provider.h 2017-03-06 18:20:31 +0000 |
2298 | @@ -0,0 +1,75 @@ |
2299 | +/* |
2300 | + * Copyright (C) 2016 Canonical, Ltd. |
2301 | + * |
2302 | + * This program is free software; you can redistribute it and/or modify |
2303 | + * it under the terms of the GNU General Public License as published by |
2304 | + * the Free Software Foundation; version 3. |
2305 | + * |
2306 | + * This program is distributed in the hope that it will be useful, |
2307 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2308 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2309 | + * GNU General Public License for more details. |
2310 | + * |
2311 | + * You should have received a copy of the GNU General Public License |
2312 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2313 | + * |
2314 | + * Authored by: Arthur Mello <arthur.mello@canonical.com> |
2315 | + */ |
2316 | + |
2317 | +#ifndef PASTEDATAPROVIDER_H |
2318 | +#define PASTEDATAPROVIDER_H |
2319 | + |
2320 | +#include <QObject> |
2321 | + |
2322 | +#include "ContentServiceInterface.h" |
2323 | + |
2324 | +const QLatin1String SERVICE_NAME = QLatin1String("com.ubuntu.content.dbus.Service"); |
2325 | +const QLatin1String SERVICE_PATH = QLatin1String("/"); |
2326 | + |
2327 | +struct PasteDataProviderPrivate |
2328 | +{ |
2329 | + PasteDataProviderPrivate(QObject* parent) : service( |
2330 | + new com::ubuntu::content::dbus::Service( |
2331 | + SERVICE_NAME, |
2332 | + SERVICE_PATH, |
2333 | + QDBusConnection::sessionBus(), |
2334 | + parent)) |
2335 | + { |
2336 | + } |
2337 | + |
2338 | + com::ubuntu::content::dbus::Service* service; |
2339 | +}; |
2340 | + |
2341 | +class PasteDataProvider : public QObject |
2342 | +{ |
2343 | + Q_OBJECT |
2344 | + |
2345 | +public: |
2346 | + PasteDataProvider(QObject* parent=0); |
2347 | + ~PasteDataProvider(); |
2348 | + |
2349 | + struct PasteData |
2350 | + { |
2351 | + QString pasteId; |
2352 | + QString source; |
2353 | + QString pasteData; |
2354 | + }; |
2355 | + |
2356 | + QStringList allPasteIds(const QString &surfaceId); |
2357 | + QMimeData* pasteDataById(const QString &surfaceId, int pasteId); |
2358 | + QString pasteSourceById(const QString &surfaceId, int pasteId); |
2359 | + bool removePaste(const QString &surfaceId, int pasteId); |
2360 | + |
2361 | +Q_SIGNALS: |
2362 | + void PasteboardChanged(); |
2363 | + |
2364 | +private: |
2365 | + QDBusPendingCall requestAllPasteIds(const QString &surfaceId); |
2366 | + QDBusPendingCall requestPasteDataById(const QString &surfaceId, int pasteId); |
2367 | + QDBusPendingCall requestPasteSourceById(const QString &surfaceId, int pasteId); |
2368 | + QDBusPendingCall requestRemovePaste(const QString &surfaceId, int pasteId); |
2369 | + |
2370 | + PasteDataProviderPrivate* d; |
2371 | +}; |
2372 | + |
2373 | +#endif // PASTEDATAPROVIDER_H |
2374 | |
2375 | === added file 'tools/clipboard/paste-image-provider.cpp' |
2376 | --- tools/clipboard/paste-image-provider.cpp 1970-01-01 00:00:00 +0000 |
2377 | +++ tools/clipboard/paste-image-provider.cpp 2017-03-06 18:20:31 +0000 |
2378 | @@ -0,0 +1,53 @@ |
2379 | +/* |
2380 | + * Copyright (C) 2016 Canonical Ltd |
2381 | + * |
2382 | + * This program is free software: you can redistribute it and/or modify |
2383 | + * it under the terms of the GNU General Public License version 3 as |
2384 | + * published by the Free Software Foundation. |
2385 | + * |
2386 | + * This program is distributed in the hope that it will be useful, |
2387 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2388 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2389 | + * GNU General Public License for more details. |
2390 | + * |
2391 | + * You should have received a copy of the GNU General Public License |
2392 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2393 | + * |
2394 | +*/ |
2395 | + |
2396 | +#include "paste-image-provider.h" |
2397 | + |
2398 | +#include <QDebug> |
2399 | +#include <QMimeData> |
2400 | + |
2401 | +#include "paste-data-provider.h" |
2402 | + |
2403 | +PasteImageProvider::PasteImageProvider() |
2404 | + : QQuickImageProvider(QQuickImageProvider::Image), |
2405 | + m_provider(new PasteDataProvider()) |
2406 | +{ |
2407 | +} |
2408 | + |
2409 | +PasteImageProvider::~PasteImageProvider() |
2410 | +{ |
2411 | +} |
2412 | + |
2413 | +QImage PasteImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize) |
2414 | +{ |
2415 | + QStringList ids = id.split("/"); |
2416 | + if (ids.count() != 2) { |
2417 | + return QImage(); |
2418 | + } |
2419 | + QString surfaceId = ids[0]; |
2420 | + QMimeData *mimeData = m_provider->pasteDataById(surfaceId, ids[1].toInt()); |
2421 | + if (!mimeData || !mimeData->hasImage()) { |
2422 | + return QImage(); |
2423 | + } |
2424 | + |
2425 | + QImage image = QImage::fromData(mimeData->imageData().toByteArray()); |
2426 | + if (requestedSize.width() > 0 && requestedSize.height() > 0) { |
2427 | + return image.scaled(requestedSize.width(), requestedSize.height(), Qt::IgnoreAspectRatio); |
2428 | + } |
2429 | + |
2430 | + return image; |
2431 | +} |
2432 | |
2433 | === added file 'tools/clipboard/paste-image-provider.h' |
2434 | --- tools/clipboard/paste-image-provider.h 1970-01-01 00:00:00 +0000 |
2435 | +++ tools/clipboard/paste-image-provider.h 2017-03-06 18:20:31 +0000 |
2436 | @@ -0,0 +1,39 @@ |
2437 | +/* |
2438 | + * Copyright (C) 2016 Canonical, Ltd. |
2439 | + * |
2440 | + * This program is free software; you can redistribute it and/or modify |
2441 | + * it under the terms of the GNU General Public License as published by |
2442 | + * the Free Software Foundation; version 3. |
2443 | + * |
2444 | + * This program is distributed in the hope that it will be useful, |
2445 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2446 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2447 | + * GNU General Public License for more details. |
2448 | + * |
2449 | + * You should have received a copy of the GNU General Public License |
2450 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2451 | + * |
2452 | + * Authored by: Arthur Mello <arthur.mello@canonical.com> |
2453 | + */ |
2454 | + |
2455 | +#ifndef PASTEIMAGEPROVIDER_H |
2456 | +#define PASTEIMAGEPROVIDER_H |
2457 | + |
2458 | +#include <QQuickImageProvider> |
2459 | + |
2460 | +class PasteDataProvider; |
2461 | + |
2462 | +class PasteImageProvider : public QQuickImageProvider |
2463 | +{ |
2464 | + |
2465 | +public: |
2466 | + PasteImageProvider(); |
2467 | + ~PasteImageProvider(); |
2468 | + |
2469 | + QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize); |
2470 | + |
2471 | +private: |
2472 | + PasteDataProvider* m_provider; |
2473 | +}; |
2474 | + |
2475 | +#endif // PASTEIMAGEPROVIDER_H |
2476 | |
2477 | === added file 'tools/clipboard/qml.qrc' |
2478 | --- tools/clipboard/qml.qrc 1970-01-01 00:00:00 +0000 |
2479 | +++ tools/clipboard/qml.qrc 2017-03-06 18:20:31 +0000 |
2480 | @@ -0,0 +1,8 @@ |
2481 | +<RCC> |
2482 | + <qresource prefix="/"> |
2483 | + <file>main.qml</file> |
2484 | + <file>ClipboardItemDelegate.qml</file> |
2485 | + <file>PreviewImagePage.qml</file> |
2486 | + <file>PreviewTextPage.qml</file> |
2487 | + </qresource> |
2488 | +</RCC> |
FAILED: Continuous integration, rev:325 /jenkins. canonical. com/system- apps/job/ lp-content- hub-ci/ 96/ /jenkins. canonical. com/system- apps/job/ build/1996/ console /jenkins. canonical. com/system- apps/job/ build-0- fetch/1999 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= vivid+overlay/ 1829/console /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 1829 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 1829/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= zesty/1829 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= zesty/1829/ artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= vivid+overlay/ 1829 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= vivid+overlay/ 1829/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 1829 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 1829/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= zesty/1829 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= zesty/1829/ artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= vivid+overlay/ 1829 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= vivid+overlay/ 1829/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 1829 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 1829/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= zesty/1829 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= zesty/1829/ artifact/ output/ *zip*/output. zip
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/system- apps/job/ lp-content- hub-ci/ 96/rebuild
https:/