Merge lp:~michael-sheldon/content-hub/peer_picker_ui into lp:content-hub

Proposed by Michael Sheldon
Status: Merged
Merged at revision: 77
Proposed branch: lp:~michael-sheldon/content-hub/peer_picker_ui
Merge into: lp:content-hub
Prerequisite: lp:~ken-vandine/content-hub/peer_details
Diff against target: 5637 lines (+3115/-715)
82 files modified
CMakeLists.txt (+3/-0)
doc/qml/pages/mainpage.qdoc (+41/-20)
examples/export-qml/app-exporter.qml (+216/-0)
examples/export-qml/export.qml (+10/-27)
examples/exporter/CMakeLists.txt (+1/-1)
examples/exporter/exampleexporter.cpp (+7/-1)
examples/exporter/exampleexporter.h (+1/-1)
examples/exporter/exporter.cpp (+18/-0)
examples/import-qml/import.qml (+36/-28)
examples/importer/CMakeLists.txt (+1/-1)
examples/importer/example.cpp (+3/-4)
examples/importer/exampleimporter.cpp (+12/-5)
examples/importer/exampleimporter.h (+1/-0)
examples/importer/importer.cpp (+18/-1)
examples/picker-qml/picker.qml (+127/-0)
import/Ubuntu/Content/CMakeLists.txt (+23/-3)
import/Ubuntu/Content/ContentPeerPicker.qml (+260/-0)
import/Ubuntu/Content/ContentTransferHint.qml (+11/-4)
import/Ubuntu/Content/ResponsiveGridView.qml (+94/-0)
import/Ubuntu/Content/contenthandler.cpp (+45/-0)
import/Ubuntu/Content/contenthandler.h (+37/-0)
import/Ubuntu/Content/contenthub.cpp (+155/-157)
import/Ubuntu/Content/contenthub.h (+20/-17)
import/Ubuntu/Content/contenthubplugin.cpp (+23/-2)
import/Ubuntu/Content/contenthubplugin.h (+2/-0)
import/Ubuntu/Content/contenticonprovider.cpp (+63/-0)
import/Ubuntu/Content/contenticonprovider.h (+40/-0)
import/Ubuntu/Content/contentpeer.cpp (+168/-6)
import/Ubuntu/Content/contentpeer.h (+40/-2)
import/Ubuntu/Content/contentpeermodel.cpp (+182/-0)
import/Ubuntu/Content/contentpeermodel.h (+67/-0)
import/Ubuntu/Content/contentscope.cpp (+68/-0)
import/Ubuntu/Content/contentscope.h (+43/-0)
import/Ubuntu/Content/contentstore.cpp (+52/-5)
import/Ubuntu/Content/contentstore.h (+12/-0)
import/Ubuntu/Content/contenttransfer.cpp (+39/-21)
import/Ubuntu/Content/contenttransfer.h (+4/-3)
import/Ubuntu/Content/contenttype.cpp (+4/-1)
import/Ubuntu/Content/contenttype.h (+1/-0)
import/Ubuntu/Content/qmldir (+2/-1)
import/Ubuntu/Content/qmlimportexporthandler.cpp (+8/-0)
import/Ubuntu/Content/qmlimportexporthandler.h (+2/-0)
include/com/ubuntu/content/hub.h (+8/-3)
include/com/ubuntu/content/import_export_handler.h (+1/-0)
include/com/ubuntu/content/peer.h (+24/-5)
include/com/ubuntu/content/transfer.h (+10/-0)
include/com/ubuntu/content/type.h (+2/-0)
libcontent-hub.pc.in (+3/-0)
src/com/ubuntu/content/CMakeLists.txt (+2/-1)
src/com/ubuntu/content/detail/app_manager.cpp (+5/-0)
src/com/ubuntu/content/detail/com.ubuntu.content.Handler.xml (+3/-0)
src/com/ubuntu/content/detail/com.ubuntu.content.Service.xml (+27/-12)
src/com/ubuntu/content/detail/com.ubuntu.content.Transfer.xml (+3/-0)
src/com/ubuntu/content/detail/handler.cpp (+18/-3)
src/com/ubuntu/content/detail/handler.h (+1/-0)
src/com/ubuntu/content/detail/peer_registry.h (+8/-5)
src/com/ubuntu/content/detail/service.cpp (+356/-138)
src/com/ubuntu/content/detail/service.h (+15/-8)
src/com/ubuntu/content/detail/transfer.cpp (+12/-2)
src/com/ubuntu/content/detail/transfer.h (+3/-1)
src/com/ubuntu/content/hub.cpp (+101/-27)
src/com/ubuntu/content/peer.cpp (+101/-8)
src/com/ubuntu/content/service/CMakeLists.txt (+2/-3)
src/com/ubuntu/content/service/com.ubuntu.content.hub.gschema.xml (+32/-4)
src/com/ubuntu/content/service/helper.cpp (+1/-1)
src/com/ubuntu/content/service/hook.cpp (+42/-30)
src/com/ubuntu/content/service/hook.h (+12/-0)
src/com/ubuntu/content/service/main.cpp (+1/-1)
src/com/ubuntu/content/service/registry.cpp (+178/-59)
src/com/ubuntu/content/service/registry.h (+12/-6)
src/com/ubuntu/content/transfer.cpp (+5/-0)
src/com/ubuntu/content/transfer_p.h (+12/-0)
src/com/ubuntu/content/utils.cpp (+13/-0)
tests/acceptance-tests/CMakeLists.txt (+14/-14)
tests/acceptance-tests/app_hub_communication_default_source.cpp (+13/-9)
tests/acceptance-tests/app_hub_communication_handler.cpp (+13/-10)
tests/acceptance-tests/app_hub_communication_known_sources.cpp (+15/-11)
tests/acceptance-tests/app_hub_communication_stores.cpp (+11/-7)
tests/acceptance-tests/app_hub_communication_transfer.cpp (+34/-12)
tests/acceptance-tests/app_manager_mock.h (+1/-1)
tests/acceptance-tests/test_hook.cpp (+13/-10)
tests/qml-tests/tst_ContentHub.qml (+28/-13)
To merge this branch: bzr merge lp:~michael-sheldon/content-hub/peer_picker_ui
Reviewer Review Type Date Requested Status
Ken VanDine Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+211092@code.launchpad.net

Commit message

Implements the new QML API for content hub, including the addition of the Peer Picker UI element. These changes are still in progress, the merge request is currently for tracking purposes.

Description of the change

Implements the new QML API for content hub, including the addition of the Peer Picker UI element. These changes are still in progress, the merge request is currently for tracking purposes.

To post a comment you must log in.
Revision history for this message
Bill Filler (bfiller) wrote :

set status to Needs Review in hopes to get CI to build it

151. By Michael Sheldon

Make it possible to use an external ContentPeerModel in the ContentPeerPicker via a Loader

152. By Michael Sheldon

Merge changes from trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
153. By Michael Sheldon

Add documentation to ContentTransferHint and ContentPeerPicker elements

154. By Michael Sheldon

Update documentation

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

Are there any related MPs required for this MP to build/function as expected? Please list.

 The following MRs are required to make the Gallery, Address Book and System Settings apps compatible with the new API:

 * https://code.launchpad.net/~ken-vandine/gallery-app/content_hub/+merge/211091
 * https://code.launchpad.net/~michael-sheldon/address-book-app/new-content-hub-api/+merge/211093
 * https://code.launchpad.net/~ken-vandine/ubuntu-system-settings/content_hub_qml_api_changes/+merge/211094

Is your branch in sync with latest trunk (e.g. bzr pull lp:trunk -> no changes)

 * Yes

Did you perform an exploratory manual test run of your code change and any related functionality on device or emulator?

 * Yes

Did you successfully run all tests found in your component's Test Plan (https://wiki.ubuntu.com/Process/Merges/TestPlan/content-hub) on device or emulator?

 * Yes

If you changed the UI, was the change specified/approved by design?

 * Yes, Peer Picker UI component implemented based upon specification here: https://docs.google.com/a/canonical.com/document/d/1trse15NokU8IJ5lm3BnUi7oMNTCkUnYNHeAHZdtzFoQ

If you changed the packaging (debian), did you subscribe a core-dev to this MP?

 * No packaging changes.

Revision history for this message
Ken VanDine (ken-vandine) wrote :

Did you perform an exploratory manual test run of the code change and any related functionality on device or emulator?

 * Yes, as per: https://wiki.ubuntu.com/Process/Merges/TestPlan/content-hub with
   - gallery-app from lp:~ken-vandine/gallery-app/content_hub/ (r926)
   - address-book-app from lp:~michael-sheldon/address-book-app/new-content-hub-api (r149)
   - ubuntu-system-settings from lp:~ken-vandine/ubuntu-system-settings/content_hub_qml_api_changes (r639)

Did CI run pass? If not, please explain why.

 * Yes

Have you checked that submitter has accurately filled out the submitter checklist and has taken no shortcut?

 * Yes

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2013-12-06 12:33:14 +0000
3+++ CMakeLists.txt 2014-03-20 13:33:31 +0000
4@@ -34,6 +34,8 @@
5 set(CMAKE_INSTALL_FULL_LIBEXECDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBEXECDIR}")
6 endif()
7
8+set(pkglibexecdir "${CMAKE_INSTALL_FULL_LIBEXECDIR}")
9+
10
11 #####################################################################
12 # Enable code coverage calculation with gcov/gcovr/lcov
13@@ -63,6 +65,7 @@
14 pkg_check_modules(GSETTINGS REQUIRED gsettings-qt)
15 pkg_check_modules(NIH REQUIRED libnih)
16 pkg_check_modules(NIH_DBUS REQUIRED libnih-dbus)
17+pkg_check_modules(DBUS REQUIRED dbus-1)
18
19 set(CONTENT_HUB_VERSION_MAJOR 0)
20 set(CONTENT_HUB_VERSION_MINOR 0)
21
22=== modified file 'doc/qml/pages/mainpage.qdoc'
23--- doc/qml/pages/mainpage.qdoc 2013-10-22 20:06:33 +0000
24+++ doc/qml/pages/mainpage.qdoc 2014-03-20 13:33:31 +0000
25@@ -72,28 +72,45 @@
26
27 Rectangle {
28 id: root
29- Button {
30- text: "Import from default"
31- onClicked: {
32- var peer = ContentHub.defaultSourceForType(ContentType.Pictures);
33- activeTransfer = ContentHub.importContent(ContentType.Pictures, peer);
34- }
35- }
36- Button {
37- text: "Import from a selectable list"
38- onClicked: {
39- activeTransfer = ContentHub.importContent(ContentType.Pictures);
40- activeTransfer.selectionType =ContentTransfer.Multiple;
41- activeTransfer.start();
42- }
43- }
44- ContentImportHint {
45- id: importHint
46+ property list<ContentItem> importItems
47+ property var activeTransfer
48+
49+ ContentPeer {
50+ id: picSourceSingle
51+ contentType: ContentType.Pictures
52+ handler: ContentHandler.Source
53+ selectionType: ContentTransfer.Single
54+ }
55+
56+ ContentPeer {
57+ id: picSourceMulti
58+ contentType: ContentType.Pictures
59+ handler: ContentHandler.Source
60+ selectionType: ContentTransfer.Multiple
61+ }
62+
63+ Row {
64+ Button {
65+ text: "Import single item"
66+ onClicked: {
67+ activeTransfer = picSourceSingle.request()
68+ }
69+ }
70+
71+ Button {
72+ text: "Import multiple items"
73+ onClicked: {
74+ activeTransfer = picSourceMulti.request()
75+ }
76+ }
77+ }
78+
79+ ContentTransferHint {
80+ id: transferHint
81 anchors.fill: parent
82 activeTransfer: root.activeTransfer
83 }
84- property list<ContentItem> importItems
85- property var activeTransfer
86+
87 Connections {
88 target: root.activeTransfer
89 onStateChanged: {
90@@ -107,8 +124,12 @@
91 \part General Topics
92 \list
93 \li \l {ContentHub}
94+ \li \l {ContentPeer}
95+ \li \l {ContentPeerModel}
96+ \li \l {ContentPeerPicker}
97+ \li \l {ContentStore}
98 \li \l {ContentTransfer}
99- \li \l {ContentImportHint}
100+ \li \l {ContentTransferHint}
101 \li \l {ContentType}
102 \endlist
103
104
105=== added file 'examples/export-qml/app-exporter.qml'
106--- examples/export-qml/app-exporter.qml 1970-01-01 00:00:00 +0000
107+++ examples/export-qml/app-exporter.qml 2014-03-20 13:33:31 +0000
108@@ -0,0 +1,216 @@
109+import QtQuick 2.0
110+import Ubuntu.Components 0.1
111+import Ubuntu.Components.Popups 0.1
112+import Ubuntu.Components.ListItems 0.1 as ListItem
113+import Ubuntu.Content 0.1
114+
115+MainView {
116+ id: root
117+ applicationName: "app-exporter"
118+ width: units.gu(50)
119+ height: units.gu(60)
120+
121+ property bool pickMode: activeTransfer.state === ContentTransfer.InProgress
122+ property var selectedItems: []
123+ property var activeTransfer
124+
125+ ListModel {
126+ id: images
127+
128+ ListElement {
129+ src: "file:///usr/share/icons/hicolor/128x128/apps/ubuntuone-music.png"
130+ }
131+
132+ ListElement {
133+ src: "file:///usr/share/icons/hicolor/128x128/apps/ubuntuone-music.png"
134+ }
135+
136+ ListElement {
137+ src: "file:///usr/share/icons/hicolor/128x128/apps/ubuntuone-music.png"
138+ }
139+
140+ ListElement {
141+ src: "file:///usr/share/icons/hicolor/128x128/apps/ubuntuone-music.png"
142+ }
143+ }
144+
145+ GridView {
146+ anchors.fill: parent
147+ model: images
148+ cellWidth: 128
149+ cellHeight: 128
150+ delegate: itemDelegate
151+ }
152+
153+ Component {
154+ id: resultComponent
155+ ContentItem {}
156+ }
157+
158+ Component {
159+ id: itemDelegate
160+ Item {
161+ width: 128
162+ height: 128
163+
164+ property bool isSelected: false
165+
166+ UbuntuShape {
167+ width: parent.width
168+ height: width
169+ image: Image {
170+ id: image
171+ source: src
172+ height: parent.width
173+ width: height
174+ fillMode: Image.PreserveAspectFit
175+ smooth: true
176+ }
177+
178+ MouseArea {
179+ anchors.fill: parent
180+ enabled: pickMode
181+ onClicked: {
182+ var shouldAdd = true;
183+ for (var i = 0; i < selectedItems.length; i++)
184+ {
185+ console.log("item: ", selectedItems[i]);
186+ if (selectedItems[i] === src)
187+ {
188+ selectedItems.pop(i);
189+ shouldAdd = false;
190+ isSelected = false;
191+ }
192+ }
193+ if (shouldAdd)
194+ {
195+ selectedItems.push(src);
196+ isSelected = true;
197+ }
198+ }
199+ }
200+
201+ Image {
202+ id: selectionTick
203+ anchors.right: parent.right
204+ anchors.top: parent.top
205+ width: units.gu(5)
206+ height: units.gu(5)
207+ visible: isSelected
208+ source: "photo-preview-selected-overlay.png"
209+ }
210+
211+ MouseArea {
212+ anchors.fill: parent
213+ enabled: !pickMode
214+ onClicked: {
215+ actPop.show();
216+ }
217+ }
218+
219+ ActionSelectionPopover {
220+ id: actPop
221+ delegate: ListItem.Standard {
222+ text: action.text
223+ }
224+
225+ contentWidth: childrenRect.width
226+
227+ actions: ActionList {
228+ Action {
229+ text: "Open with..."
230+ onTriggered: {
231+ print(text + ": " + src);
232+ activeTransfer = picDest.request();
233+ activeTransfer.items = [ resultComponent.createObject(root, {"url": src}) ];
234+ activeTransfer.state = ContentTransfer.Charged;
235+ actPop.hide();
236+ }
237+ }
238+ Action {
239+ text: "Share"
240+ onTriggered: {
241+ print(text + ": " + src);
242+ activeTransfer = picShare.request();
243+ activeTransfer.items = [ resultComponent.createObject(root, {"url": src}) ];
244+ activeTransfer.state = ContentTransfer.Charged;
245+ actPop.hide();
246+ }
247+ }
248+ }
249+ }
250+ }
251+ }
252+ }
253+
254+ ContentPeer {
255+ id: picDest
256+ // well know content type
257+ contentType: ContentType.Pictures
258+ // Type of handler: Source, Destination, or Share
259+ handler: ContentHandler.Destination
260+ // Optional appId, if this isn't specified the hub will use the default
261+ //appId: ""
262+ }
263+
264+ ContentPeer {
265+ id: picShare
266+ // well know content type
267+ contentType: ContentType.Pictures
268+ // Type of handler: Source, Destination, or Share
269+ handler: ContentHandler.Share
270+ // Optional appId, if this isn't specified the hub will use the default
271+ appId: "pkg_app_version"
272+ }
273+
274+ // Provides overlay showing another app is being used to complete the request
275+ // formerly named ContentImportHint
276+ ContentTransferHint {
277+ anchors.fill: parent
278+ activeTransfer: activeTransfer
279+ }
280+
281+ Connections {
282+ target: ContentHub
283+ onExportRequested: {
284+ activeTransfer = transfer
285+ }
286+ }
287+
288+ ListItem.Empty {
289+ id: pickerButtons
290+ anchors {
291+ left: parent.left
292+ right: parent.right
293+ bottom: parent.bottom
294+ margins: units.gu(2)
295+ }
296+ visible: pickMode
297+ Button {
298+ anchors {
299+ left: parent.left
300+ bottom: parent.bottom
301+ margins: units.gu(2)
302+ }
303+ text: "Cancel"
304+ onClicked: activeTransfer.state = ContentTransfer.Aborted;
305+ }
306+
307+ Button {
308+ anchors {
309+ right: parent.right
310+ bottom: parent.bottom
311+ margins: units.gu(2)
312+ }
313+ text: "Select"
314+ onClicked: {
315+ var results = [];
316+ for (var i = 0; i < selectedItems.length; i++)
317+ results.push(resultComponent.createObject(root, {"url": selectedItems[i]}));
318+
319+ if (results.length > 0)
320+ activeTransfer.items = results;
321+ }
322+ }
323+ }
324+}
325
326=== modified file 'examples/export-qml/export.qml'
327--- examples/export-qml/export.qml 2013-08-26 17:36:58 +0000
328+++ examples/export-qml/export.qml 2014-03-20 13:33:31 +0000
329@@ -2,20 +2,15 @@
330 import Ubuntu.Components 0.1
331 import Ubuntu.Content 0.1
332
333-Rectangle {
334+MainView {
335 id: root
336 width: 300
337 height: 200
338
339- property bool pickMode: false
340+ property bool pickMode: activeTransfer.state === ContentTransfer.InProgress
341 property list<ContentItem> selectedItems
342 property var activeTransfer
343
344- function __returnResult() {
345- activeTransfer.items = selectedItems;
346- activeTransfer.state = ContentTransfer.Charged;
347- }
348-
349 Button {
350 id: button1
351 anchors.top: parent.top
352@@ -23,12 +18,11 @@
353 enabled: pickMode
354 text: "Return URL1"
355 onClicked: {
356- var result = resultComponent.createObject(root);
357- result.url = "file:///picture_1.jpg";
358- selectedItems = [ result ];
359- root.__returnResult();
360+ selectedItems = [ resultComponent.createObject(root, {"url": "file:///picture_1.jpg"}) ];
361+ activeTransfer.items = selectedItems;
362 }
363 }
364+
365 Button {
366 id: button2
367 anchors.top: parent.top
368@@ -36,19 +30,10 @@
369 enabled: pickMode
370 text: "Return Url2"
371 onClicked: {
372- var results = [];
373-
374- var result = resultComponent.createObject(root);
375- result.url = "file:///picture_1.jpg";
376- results.push(result);
377-
378- result = resultComponent.createObject(root);
379- result.url = "file:///picture_2.jpg";
380- results.push(result);
381-
382- selectedItems = results;
383+ selectedItems.push(resultComponent.createObject(root, {"url": "file:///picture_1.jpg"}));
384+ selectedItems.push(resultComponent.createObject(root, {"url": "file:///picture_2.jpg"}));
385 console.log(selectedItems[0].url + "/" + selectedItems[1].url)
386- root.__returnResult();
387+ activeTransfer.items = selectedItems;
388 }
389 }
390
391@@ -59,8 +44,7 @@
392 enabled: pickMode
393 text: "Cancel"
394 onClicked: {
395- root.activeTransfer.state = ContentTransfer.Aborted;
396- root.pickMode = false;
397+ activeTransfer.state = ContentTransfer.Aborted;
398 }
399 }
400
401@@ -72,8 +56,7 @@
402 Connections {
403 target: ContentHub
404 onExportRequested: {
405- root.activeTransfer = transfer
406- root.pickMode = true;
407+ activeTransfer = transfer
408 }
409 }
410 }
411
412=== added file 'examples/export-qml/photo-preview-selected-overlay.png'
413Binary files examples/export-qml/photo-preview-selected-overlay.png 1970-01-01 00:00:00 +0000 and examples/export-qml/photo-preview-selected-overlay.png 2014-03-20 13:33:31 +0000 differ
414=== modified file 'examples/exporter/CMakeLists.txt'
415--- examples/exporter/CMakeLists.txt 2013-08-28 18:22:37 +0000
416+++ examples/exporter/CMakeLists.txt 2014-03-20 13:33:31 +0000
417@@ -23,7 +23,7 @@
418 exampleexporter.cpp
419 )
420
421-qt5_use_modules(exporter Core)
422+qt5_use_modules(exporter Core Gui DBus)
423
424 set_target_properties(
425 exporter
426
427=== modified file 'examples/exporter/exampleexporter.cpp'
428--- examples/exporter/exampleexporter.cpp 2013-09-05 18:49:34 +0000
429+++ examples/exporter/exampleexporter.cpp 2014-03-20 13:33:31 +0000
430@@ -24,6 +24,12 @@
431 hub->register_import_export_handler(this);
432 }
433
434+void ExampleExporter::handle_import(cuc::Transfer *transfer)
435+{
436+ qDebug() << Q_FUNC_INFO << "not implemented";
437+ Q_UNUSED(transfer);
438+}
439+
440 void ExampleExporter::handle_export(cuc::Transfer *transfer)
441 {
442 qDebug() << Q_FUNC_INFO;
443@@ -45,7 +51,7 @@
444 qDebug() << Q_FUNC_INFO << "Items:" << items.count();
445 }
446
447-void ExampleExporter::handle_import(cuc::Transfer *transfer)
448+void ExampleExporter::handle_share(cuc::Transfer *transfer)
449 {
450 qDebug() << Q_FUNC_INFO << "not implemented";
451 Q_UNUSED(transfer);
452
453=== modified file 'examples/exporter/exampleexporter.h'
454--- examples/exporter/exampleexporter.h 2013-08-29 15:51:28 +0000
455+++ examples/exporter/exampleexporter.h 2014-03-20 13:33:31 +0000
456@@ -37,7 +37,7 @@
457 public slots:
458 Q_INVOKABLE void handle_import(cuc::Transfer*);
459 Q_INVOKABLE void handle_export(cuc::Transfer*);
460-
461+ Q_INVOKABLE void handle_share(cuc::Transfer*);
462 };
463
464 #endif // EXAMPLEEXPORTER_H
465
466=== modified file 'examples/exporter/exporter.cpp'
467--- examples/exporter/exporter.cpp 2013-08-29 15:51:28 +0000
468+++ examples/exporter/exporter.cpp 2014-03-20 13:33:31 +0000
469@@ -17,6 +17,8 @@
470 */
471
472 #include <QCoreApplication>
473+#include <QStringList>
474+
475
476 #include "exampleexporter.h"
477
478@@ -31,5 +33,21 @@
479
480 ExampleExporter exporter;
481
482+ QString peerName;
483+
484+ if (a.arguments().size() > 1)
485+ peerName = a.arguments().at(1);
486+
487+ if (!peerName.isEmpty())
488+ {
489+ qDebug() << peerName;
490+ auto hub = cuc::Hub::Client::instance();
491+
492+ auto peer = cuc::Peer{peerName};
493+ qDebug() << Q_FUNC_INFO << "PEER: " << peer.id();
494+ auto transfer = hub->create_export_to_peer(peer);
495+ exporter.handle_export(transfer);
496+ }
497+
498 return a.exec();
499 }
500
501=== modified file 'examples/import-qml/import.qml'
502--- examples/import-qml/import.qml 2013-11-08 21:04:52 +0000
503+++ examples/import-qml/import.qml 2014-03-20 13:33:31 +0000
504@@ -1,7 +1,6 @@
505 import QtQuick 2.0
506 import Ubuntu.Components 0.1
507 import Ubuntu.Components.ListItems 0.1 as ListItem
508-
509 import Ubuntu.Content 0.1
510
511 MainView {
512@@ -12,26 +11,31 @@
513
514 property list<ContentItem> importItems
515 property var activeTransfer
516- property list<ContentPeer> peers
517-
518-
519- function _importFromPeer(peer) {
520- /* if peer is null, choose default */
521- if (peer === null)
522- peer = ContentHub.defaultSourceForType(ContentType.Pictures);
523- var transfer = ContentHub.importContent(ContentType.Pictures, peer);
524- var store = ContentHub.defaultStoreForType(ContentType.Pictures);
525- console.log("Store is: " + store.uri);
526- if (transfer !== null) {
527- transfer.selectionType = ContentTransfer.Multiple;
528- transfer.setStore(store);
529- activeTransfer = transfer;
530- activeTransfer.start();
531- }
532- }
533-
534- Component.onCompleted: {
535- peers = ContentHub.knownSourcesForType(ContentType.Pictures);
536+
537+
538+ ContentPeer {
539+ id: picSource
540+ // well know content type
541+ contentType: ContentType.Pictures
542+ // Type of handler: Source, Destination, or Share
543+ handler: ContentHandler.Source
544+ // Optional appId, if this isn't specified the hub will use the default
545+ //appId: ""
546+ }
547+
548+ // Optional store to use for persistent storage of content
549+ ContentStore {
550+ id: appStore
551+ scope: ContentScope.App
552+ }
553+
554+ // Provides a list<ContentPeer> suitable for use as a model
555+ ContentPeerModel {
556+ id: picSources
557+ // Type of handler: Source, Destination, or Share
558+ handler: ContentHandler.Source
559+ // well know content type
560+ contentType: ContentType.Pictures
561 }
562
563 ListView {
564@@ -42,14 +46,15 @@
565 top: importButtons.bottom
566 }
567 height: childrenRect.height
568- model: peers
569+ model: picSources.peers
570
571 delegate: ListItem.Standard {
572 text: modelData.name
573 control: Button {
574 text: "Import"
575 onClicked: {
576- _importFromPeer(modelData);
577+ // Request the transfer, it needs to be created and dispatched from the hub
578+ activeTransfer = modelData.request();
579 }
580 }
581 }
582@@ -64,7 +69,9 @@
583 }
584 text: "Import from default"
585 onClicked: {
586- _importFromPeer(null);
587+ // Request the transfer, it needs to be created and dispatched from the hub
588+ // Specify a location to use for permanent storage
589+ activeTransfer = picSource.request(appStore);
590 }
591 }
592
593@@ -79,7 +86,6 @@
594 }
595 }
596
597-
598 ListView {
599 id: resultList
600 anchors {
601@@ -108,13 +114,15 @@
602 }
603 }
604
605- ContentImportHint {
606+ // Provides overlay showing another app is being used to complete the request
607+ // formerly named ContentImportHint
608+ ContentTransferHint {
609 anchors.fill: parent
610- activeTransfer: root.activeTransfer
611+ activeTransfer: activeTransfer
612 }
613
614 Connections {
615- target: root.activeTransfer
616+ target: activeTransfer
617 onStateChanged: {
618 console.log("StateChanged: " + activeTransfer.state);
619 if (activeTransfer.state === ContentTransfer.Charged)
620
621=== modified file 'examples/importer/CMakeLists.txt'
622--- examples/importer/CMakeLists.txt 2013-08-28 18:22:37 +0000
623+++ examples/importer/CMakeLists.txt 2014-03-20 13:33:31 +0000
624@@ -24,7 +24,7 @@
625 example.cpp
626 )
627
628-qt5_use_modules(importer Core)
629+qt5_use_modules(importer Core Gui DBus)
630
631 set_target_properties(
632 importer
633
634=== modified file 'examples/importer/example.cpp'
635--- examples/importer/example.cpp 2013-10-01 16:55:39 +0000
636+++ examples/importer/example.cpp 2014-03-20 13:33:31 +0000
637@@ -30,12 +30,11 @@
638 {
639 auto hub = cuc::Hub::Client::instance();
640
641- auto peer = hub->default_peer_for_type(cuc::Type::Known::pictures());
642+ auto peer = hub->default_source_for_type(cuc::Type::Known::pictures());
643+
644 qDebug() << Q_FUNC_INFO << "PEER: " << peer.name();
645
646- m_transfer = hub->create_import_for_type_from_peer(
647- cuc::Type::Known::pictures(),
648- peer);
649+ m_transfer = hub->create_import_from_peer(peer);
650
651 /* Uncommit this for persistent storage
652 auto store = hub->store_for_scope_and_type(cuc::Scope::app, cuc::Type::Known::pictures());
653
654=== modified file 'examples/importer/exampleimporter.cpp'
655--- examples/importer/exampleimporter.cpp 2013-10-01 16:55:39 +0000
656+++ examples/importer/exampleimporter.cpp 2014-03-20 13:33:31 +0000
657@@ -25,11 +25,6 @@
658 hub->register_import_export_handler(this);
659 }
660
661-void ExampleImporter::handle_export(cuc::Transfer *transfer)
662-{
663- qDebug() << Q_FUNC_INFO << "not implemented";
664- Q_UNUSED(transfer);
665-}
666
667 void ExampleImporter::handle_import(cuc::Transfer *transfer)
668 {
669@@ -40,3 +35,15 @@
670 qDebug() << Q_FUNC_INFO << "Item:" << item.url();
671 transfer->finalize();
672 }
673+
674+void ExampleImporter::handle_export(cuc::Transfer *transfer)
675+{
676+ qDebug() << Q_FUNC_INFO << "not implemented";
677+ Q_UNUSED(transfer);
678+}
679+
680+void ExampleImporter::handle_share(cuc::Transfer *transfer)
681+{
682+ qDebug() << Q_FUNC_INFO << "not implemented";
683+ Q_UNUSED(transfer);
684+}
685
686=== modified file 'examples/importer/exampleimporter.h'
687--- examples/importer/exampleimporter.h 2013-08-28 18:22:37 +0000
688+++ examples/importer/exampleimporter.h 2014-03-20 13:33:31 +0000
689@@ -34,6 +34,7 @@
690 ExampleImporter();
691 Q_INVOKABLE void handle_import(cuc::Transfer*);
692 Q_INVOKABLE void handle_export(cuc::Transfer*);
693+ Q_INVOKABLE void handle_share(cuc::Transfer*);
694 };
695
696 #endif // EXAMPLEIMPORTER_H
697
698=== modified file 'examples/importer/importer.cpp'
699--- examples/importer/importer.cpp 2013-08-20 16:21:15 +0000
700+++ examples/importer/importer.cpp 2014-03-20 13:33:31 +0000
701@@ -17,6 +17,7 @@
702 */
703
704 #include <QCoreApplication>
705+#include <QStringList>
706 #include "example.h"
707
708 namespace cuc = com::ubuntu::content;
709@@ -27,7 +28,23 @@
710
711 Example *e = new Example();
712
713- e->create_import();
714+ QString peerName;
715+
716+ if (a.arguments().size() > 1)
717+ peerName = a.arguments().at(1);
718+
719+ if (!peerName.isEmpty())
720+ {
721+ qDebug() << peerName;
722+ auto hub = cuc::Hub::Client::instance();
723+
724+ auto peer = cuc::Peer{peerName};
725+ qDebug() << Q_FUNC_INFO << "PEER: " << peer.id();
726+ auto transfer = hub->create_import_from_peer(peer);
727+ transfer->start();
728+ }
729+
730+ Q_UNUSED(e);
731
732 return a.exec();
733 }
734
735=== added directory 'examples/picker-qml'
736=== added file 'examples/picker-qml/picker.qml'
737--- examples/picker-qml/picker.qml 1970-01-01 00:00:00 +0000
738+++ examples/picker-qml/picker.qml 2014-03-20 13:33:31 +0000
739@@ -0,0 +1,127 @@
740+import QtQuick 2.0
741+import Ubuntu.Components 0.1
742+import Ubuntu.Components.ListItems 0.1 as ListItem
743+import Ubuntu.Components.Popups 0.1
744+
745+import Ubuntu.Content 0.1
746+
747+MainView {
748+ id: mainView
749+ applicationName: "picker-qml"
750+
751+ width: units.gu(100)
752+ height: units.gu(75)
753+
754+ PageStack {
755+ id: pageStack
756+ Component.onCompleted: pageStack.push(root)
757+
758+ Page {
759+ id: root
760+ title: i18n.tr("Peer Picker Example")
761+ visible: false
762+
763+ property list<ContentItem> importItems
764+ property var activeTransfer
765+ property list<ContentPeer> peers
766+
767+ Column {
768+ anchors.fill: parent
769+
770+ ListItem.Standard {
771+ id: peerListHeader
772+ anchors {
773+ left: parent.left
774+ right: parent.right
775+ }
776+ text: i18n.tr("Sources")
777+ control: Button {
778+ text: i18n.tr("Select source")
779+ onClicked: {
780+ pageStack.push(picker);
781+ }
782+ }
783+ }
784+
785+ ListItem.Header {
786+ id: titleItem
787+ anchors {
788+ left: parent.left
789+ right: parent.right
790+ }
791+ text: i18n.tr("Results")
792+ }
793+
794+ GridView {
795+ id: resultList
796+ anchors {
797+ left: parent.left
798+ right: parent.right
799+ }
800+ height: childrenRect.height
801+ cellWidth: units.gu(20)
802+ cellHeight: cellWidth
803+
804+ model: root.importItems
805+ delegate: Item {
806+ id: result
807+ height: units.gu(19)
808+ width: height
809+ UbuntuShape {
810+ width: parent.width
811+ height: width
812+ image: Image {
813+ id: image
814+ source: url
815+ sourceSize.width: width
816+ sourceSize.height: height
817+ height: parent.height
818+ width: height
819+ fillMode: Image.PreserveAspectFit
820+ smooth: true
821+ }
822+ }
823+ }
824+ }
825+ }
826+
827+ ContentTransferHint {
828+ anchors.fill: root
829+ activeTransfer: root.activeTransfer
830+ }
831+
832+ Connections {
833+ target: root.activeTransfer
834+ onStateChanged: {
835+ console.log("StateChanged: " + root.activeTransfer.state);
836+ if (root.activeTransfer.state === ContentTransfer.Charged)
837+ root.importItems = root.activeTransfer.items;
838+ }
839+ }
840+
841+ }
842+
843+ Page {
844+ id: picker
845+ visible: false
846+
847+ ContentPeerPicker {
848+ visible: parent.visible
849+
850+ // Type of handler: Source, Destination, or Share
851+ handler: ContentHandler.Source
852+ // well know content type
853+ contentType: ContentType.Pictures
854+
855+ onPeerSelected: {
856+ root.activeTransfer = peer.request();
857+ pageStack.pop();
858+ }
859+
860+ onCancelPressed: {
861+ pageStack.pop();
862+ }
863+ }
864+ }
865+ }
866+}
867
868=== modified file 'import/Ubuntu/Content/CMakeLists.txt'
869--- import/Ubuntu/Content/CMakeLists.txt 2013-10-01 16:55:39 +0000
870+++ import/Ubuntu/Content/CMakeLists.txt 2014-03-20 13:33:31 +0000
871@@ -26,13 +26,24 @@
872
873 set(PLUGIN ubuntu-content-hub-plugin)
874
875-include_directories(${CMAKE_SOURCE_DIR})
876+add_definitions(-DQT_NO_KEYWORDS)
877+
878+include_directories(
879+ ${CMAKE_SOURCE_DIR}
880+ ${NIH_INCLUDE_DIRS}
881+ ${NIH_DBUS_INCLUDE_DIRS}
882+ ${DBUS_INCLUDE_DIRS}
883+)
884
885 set(PLUGIN_HDRS
886+ contenthandler.h
887 contenthub.h
888 contenthubplugin.h
889+ contenticonprovider.h
890 contentitem.h
891 contentpeer.h
892+ contentpeermodel.h
893+ contentscope.h
894 contentstore.h
895 contenttransfer.h
896 contenttype.h
897@@ -40,10 +51,14 @@
898 )
899
900 set(PLUGIN_SRC
901+ contenthandler.cpp
902 contenthub.cpp
903 contenthubplugin.cpp
904+ contenticonprovider.cpp
905 contentitem.cpp
906 contentpeer.cpp
907+ contentpeermodel.cpp
908+ contentscope.cpp
909 contentstore.cpp
910 contenttransfer.cpp
911 contenttype.cpp
912@@ -52,8 +67,13 @@
913
914 add_library(${PLUGIN} MODULE ${PLUGIN_SRC} ${PLUGIN_HDRS})
915
916-qt5_use_modules(${PLUGIN} Core Qml Quick)
917-target_link_libraries(${PLUGIN} content-hub)
918+qt5_use_modules(${PLUGIN} Core Qml Quick DBus)
919+target_link_libraries(
920+ ${PLUGIN}
921+ content-hub
922+ ${NIH_LIBRARIES}
923+ ${NIH_DBUS_LIBRARIES}
924+)
925
926 install(TARGETS ${PLUGIN} DESTINATION ${CONTENT_HUB_IMPORTS_DIR})
927 install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/qmldir DESTINATION ${CONTENT_HUB_IMPORTS_DIR})
928
929=== added file 'import/Ubuntu/Content/ContentPeerPicker.qml'
930--- import/Ubuntu/Content/ContentPeerPicker.qml 1970-01-01 00:00:00 +0000
931+++ import/Ubuntu/Content/ContentPeerPicker.qml 2014-03-20 13:33:31 +0000
932@@ -0,0 +1,260 @@
933+/*
934+ * Copyright 2013 Canonical Ltd.
935+ *
936+ * This program is free software; you can redistribute it and/or modify
937+ * it under the terms of the GNU Lesser General Public License as published by
938+ * the Free Software Foundation; version 3.
939+ *
940+ * This program is distributed in the hope that it will be useful,
941+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
942+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
943+ * GNU Lesser General Public License for more details.
944+ *
945+ * You should have received a copy of the GNU Lesser General Public License
946+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
947+ */
948+
949+import QtQuick 2.0
950+import Ubuntu.Components 0.1
951+import Ubuntu.Components.Popups 0.1
952+import Ubuntu.Components.ListItems 0.1 as ListItem
953+import Ubuntu.Content 0.1
954+
955+/*!
956+ \qmltype ContentPeerPicker
957+ \inqmlmodule Ubuntu.Content 0.1
958+ \brief Component that allows users to select a source/destination for content transfer
959+
960+ This component displays a list of applications, devices and services which
961+ are appropriate for transferring a given content type with.
962+*/
963+Item {
964+ id: root
965+ anchors.fill: parent
966+ visible: false
967+
968+ /*!
969+ \qmlproperty ContentHandler handler
970+ \brief The ContentHandler to use when finding peers.
971+ */
972+ property var handler
973+
974+ /*! \qmlproperty ContentType contentType
975+ \brief The ContentType to use when finding peers.
976+ */
977+ property var contentType
978+
979+ /*! \qmlproperty bool showTitle
980+ \brief Determines whether the header should be displayed.
981+
982+ This makes it possible to hide the header, which can be useful
983+ if embedding the picker within another page or popup.
984+ */
985+ property alias showTitle: header.visible
986+
987+ /*! \qmlproperty ContentPeer peer
988+ \brief The peer selected by the user.
989+
990+ Once the peerSelected signal has been sent, this provides the
991+ ContentPeer which the user has selected.
992+ */
993+ property var peer
994+
995+ /*! \qmlproperty Loader customerPeerModelLoader
996+ \brief A Loader containing a ContentPeerModel.
997+
998+ This can optionally be used to provide a pre-populated ContentPeerModel
999+ to this ContentPeerPicker.
1000+ */
1001+ property var customPeerModelLoader
1002+
1003+ /*! \qmlsignal peerSelected
1004+ \brief Emitted when a user selects a peer.
1005+
1006+ Once this signal has been emitted the selected peer can be accessed via
1007+ the peer property.
1008+ \c onPeerSelected
1009+ */
1010+ signal peerSelected
1011+
1012+ /*! \qmlsignal cancelPressed
1013+ \brief Emitted when the user clicks the cancel button.
1014+
1015+ The ContentPeerPicker will be hidden automatically when the user cancels
1016+ the operations and the active ContentTransfer will be set to Aborted.
1017+ \c onCancelPressed
1018+ */
1019+ signal cancelPressed
1020+
1021+ Header {
1022+ id: header
1023+ title: (handler === ContentHandler.Source) ? i18n.tr("Choose from") : i18n.tr("Share to")
1024+ }
1025+
1026+ Loader {
1027+ id: peerModelLoader
1028+ active: false
1029+ sourceComponent: ContentPeerModel {
1030+ id: peerModel
1031+ }
1032+ onLoaded: {
1033+ item.handler = root.handler
1034+ item.contentType = root.contentType
1035+ }
1036+ }
1037+
1038+ Component.onCompleted: {
1039+ if(customPeerModelLoader) {
1040+ customPeerModelLoader.active = true;
1041+ } else {
1042+ peerModelLoader.active = true;
1043+ }
1044+ }
1045+
1046+ Component {
1047+ id: peerDelegate
1048+ Item {
1049+ width: units.gu(13.5)
1050+ height: units.gu(16)
1051+ AbstractButton {
1052+ width: parent.width
1053+ height: icon.height + label.height
1054+ UbuntuShape {
1055+ id: icon
1056+ anchors {
1057+ top: parent.top
1058+ horizontalCenter: parent.horizontalCenter
1059+ }
1060+ radius: "medium"
1061+ width: units.gu(8)
1062+ height: units.gu(7.5)
1063+ image: Image {
1064+ id: image
1065+ objectName: "image"
1066+ sourceSize { width: icon.width; height: icon.height }
1067+ asynchronous: true
1068+ cache: false
1069+ source: "image://content-hub/" + modelData.appId
1070+ horizontalAlignment: Image.AlignHCenter
1071+ verticalAlignment: Image.AlignVCenter
1072+ }
1073+ }
1074+
1075+ Label {
1076+ id: label
1077+ objectName: "label"
1078+ anchors {
1079+ baseline: icon.bottom
1080+ baselineOffset: units.gu(2)
1081+ left: parent.left
1082+ right: parent.right
1083+ leftMargin: units.gu(1)
1084+ rightMargin: units.gu(1)
1085+ }
1086+
1087+ opacity: 0.9
1088+ fontSize: "small"
1089+ elide: Text.ElideMiddle
1090+ horizontalAlignment: Text.AlignHCenter
1091+ text: modelData.name || modelData.appId
1092+ }
1093+
1094+ onClicked: {
1095+ peer = modelData
1096+ peerSelected()
1097+ }
1098+ }
1099+
1100+ }
1101+ }
1102+
1103+ ListItem.Header {
1104+ id: appTitle
1105+ anchors.top: header.visible ? header.bottom : parent.top
1106+ text: "Apps"
1107+ }
1108+
1109+ Rectangle {
1110+ id: apps
1111+ color: "#FFFFFF"
1112+ height: (parent.height / 2.4)
1113+ width: parent.width
1114+ clip: true
1115+ anchors {
1116+ left: parent.left
1117+ right: parent.right
1118+ top: appTitle.bottom
1119+ }
1120+
1121+ Flickable {
1122+ anchors.fill: parent
1123+
1124+ ResponsiveGridView {
1125+ id: appPeers
1126+ anchors.fill: parent
1127+ minimumHorizontalSpacing: units.gu(0.5)
1128+ maximumNumberOfColumns: 6
1129+ delegateWidth: units.gu(11)
1130+ delegateHeight: units.gu(9.5)
1131+ verticalSpacing: units.gu(2)
1132+ model: customPeerModelLoader ? customPeerModelLoader.item.peers : peerModelLoader.item.peers
1133+ delegate: peerDelegate
1134+ }
1135+
1136+ }
1137+ }
1138+
1139+ ListItem.Header {
1140+ id: devTitle
1141+ anchors {
1142+ left: parent.left
1143+ right: parent.right
1144+ top: apps.bottom
1145+ }
1146+ text: "Devices"
1147+ }
1148+
1149+ Rectangle {
1150+ id: devices
1151+ color: "#FFFFFF"
1152+ width: parent.width
1153+ radius: 0
1154+ anchors {
1155+ left: parent.left
1156+ right: parent.right
1157+ top: devTitle.bottom
1158+ bottom: cancelButton.top
1159+ bottomMargin: units.gu(1)
1160+ }
1161+
1162+ Flickable {
1163+ anchors.fill: parent
1164+
1165+ GridView {
1166+ id: devPeers
1167+ header: Item { height: units.gu(2) }
1168+ cellWidth: units.gu(13.5)
1169+ cellHeight: units.gu(16)
1170+ delegate: peerDelegate
1171+ }
1172+
1173+ }
1174+ }
1175+
1176+ Button {
1177+ id: cancelButton
1178+ text: "Cancel"
1179+ anchors {
1180+ left: parent.left
1181+ bottom: parent.bottom
1182+ margins: units.gu(1)
1183+ }
1184+ onClicked: {
1185+ if(root.activeTransfer) {
1186+ root.activeTransfer.state = ContentTransfer.Aborted;
1187+ }
1188+ cancelPressed();
1189+ }
1190+ }
1191+
1192+}
1193
1194=== renamed file 'import/Ubuntu/Content/ContentImportHint.qml' => 'import/Ubuntu/Content/ContentTransferHint.qml'
1195--- import/Ubuntu/Content/ContentImportHint.qml 2013-10-21 16:36:02 +0000
1196+++ import/Ubuntu/Content/ContentTransferHint.qml 2014-03-20 13:33:31 +0000
1197@@ -20,11 +20,11 @@
1198 import Ubuntu.Content 0.1
1199
1200 /*!
1201- \qmltype ContentImportHint
1202+ \qmltype ContentTransferHint
1203 \inqmlmodule Ubuntu.Content 0.1
1204- \brief Component that indicates that a trasnfer is active
1205+ \brief Component that indicates that a transfer is active
1206
1207- This component shows, that the transfer is currently running, and the source
1208+ This component shows that the transfer is currently running, and the source
1209 application is active. It blocks all input during that time.
1210 Place this component on top of your view.
1211
1212@@ -33,7 +33,14 @@
1213 Item {
1214 id: root
1215
1216- /// The current running transfer
1217+ /*!
1218+ \qmlproperty ContentTransfer ContentTransferHint::activeTransfer
1219+ \brief The ContentTransfer to monitor the status of.
1220+
1221+ This should be set to the currently active ContentTransfer, which
1222+ will then cause the ContentTransferHint to become visible while
1223+ the transfer is in progress.
1224+ */
1225 property var activeTransfer
1226
1227 opacity: internal.isTransferRunning ? 1.0 : 0.0
1228
1229=== added file 'import/Ubuntu/Content/ResponsiveGridView.qml'
1230--- import/Ubuntu/Content/ResponsiveGridView.qml 1970-01-01 00:00:00 +0000
1231+++ import/Ubuntu/Content/ResponsiveGridView.qml 2014-03-20 13:33:31 +0000
1232@@ -0,0 +1,94 @@
1233+/*
1234+ * Copyright (C) 2013 Canonical, Ltd.
1235+ *
1236+ * This program is free software; you can redistribute it and/or modify
1237+ * it under the terms of the GNU General Public License as published by
1238+ * the Free Software Foundation; version 3.
1239+ *
1240+ * This program is distributed in the hope that it will be useful,
1241+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1242+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1243+ * GNU General Public License for more details.
1244+ *
1245+ * You should have received a copy of the GNU General Public License
1246+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1247+ */
1248+
1249+import QtQuick 2.0
1250+import Ubuntu.Components 0.1
1251+
1252+/*
1253+ Essentially a GridView where you can specify the maximum number of columns it can have.
1254+ */
1255+Item {
1256+ property int minimumHorizontalSpacing: units.gu(0.5)
1257+ // property int minimumNumberOfColumns: 2 // FIXME: not implemented
1258+ property int maximumNumberOfColumns: 6
1259+ readonly property int columns: gridView.columns
1260+ property alias verticalSpacing: gridView.verticalSpacing
1261+ readonly property alias margins: gridView.margin
1262+ property int delegateWidth
1263+ property int delegateHeight
1264+ property alias model: gridView.model
1265+ property alias delegate: gridView.delegate
1266+ readonly property int cellWidth: gridView.cellWidth
1267+ readonly property int cellHeight: gridView.cellHeight
1268+ readonly property int totalContentHeight: {
1269+ return contentHeightForRows(Math.ceil(gridView.model.count / columns))
1270+ }
1271+ property alias interactive: gridView.interactive
1272+ readonly property alias flicking: gridView.flicking
1273+ readonly property alias moving: gridView.moving
1274+ readonly property alias pressDelay: gridView.pressDelay
1275+ property alias delegateCreationBegin: gridView.delegateCreationBegin
1276+ property alias delegateCreationEnd: gridView.delegateCreationEnd
1277+ property alias highlightIndex: gridView.highlightIndex
1278+ readonly property alias currentItem: gridView.currentItem
1279+
1280+ function contentHeightForRows(rows) {
1281+ return rows * cellHeight + verticalSpacing
1282+ }
1283+
1284+ GridView {
1285+ id: gridView
1286+ objectName: "responsiveGridViewGrid"
1287+ anchors {
1288+ fill: parent
1289+ leftMargin: margin/2
1290+ rightMargin: margin/2
1291+ topMargin: verticalSpacing
1292+ }
1293+ clip: parent.height != totalContentHeight
1294+
1295+ function pixelToGU(value) {
1296+ return Math.floor(value / units.gu(1));
1297+ }
1298+
1299+ function spacingForColumns(columns) {
1300+ // spacing between columns as an integer number of GU, the remainder goes in the margins
1301+ var spacingGU = pixelToGU(allocatableHorizontalSpace / columns);
1302+ return units.gu(spacingGU);
1303+ }
1304+
1305+ function columnsForSpacing(spacing) {
1306+ // minimum margin is half of the spacing
1307+ return Math.max(1, Math.floor(parent.width / (delegateWidth + spacing)));
1308+ }
1309+
1310+ property real allocatableHorizontalSpace: parent.width - columns * delegateWidth
1311+ property int columns: Math.min(columnsForSpacing(minimumHorizontalSpacing), maximumNumberOfColumns)
1312+ property real horizontalSpacing: spacingForColumns(columns)
1313+ property real verticalSpacing: horizontalSpacing
1314+ property int margin: allocatableHorizontalSpace - columns * horizontalSpacing
1315+ property int highlightIndex: -1
1316+
1317+ cellWidth: delegateWidth + horizontalSpacing
1318+ cellHeight: delegateHeight + verticalSpacing
1319+
1320+ onHighlightIndexChanged: {
1321+ if (highlightIndex != -1) {
1322+ currentIndex = highlightIndex
1323+ }
1324+ }
1325+ }
1326+}
1327
1328=== added file 'import/Ubuntu/Content/contenthandler.cpp'
1329--- import/Ubuntu/Content/contenthandler.cpp 1970-01-01 00:00:00 +0000
1330+++ import/Ubuntu/Content/contenthandler.cpp 2014-03-20 13:33:31 +0000
1331@@ -0,0 +1,45 @@
1332+/*
1333+ * Copyright 2013 Canonical Ltd.
1334+ *
1335+ * This program is free software; you can redistribute it and/or modify
1336+ * it under the terms of the GNU Lesser General Public License as published by
1337+ * the Free Software Foundation; version 3.
1338+ *
1339+ * This program is distributed in the hope that it will be useful,
1340+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1341+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1342+ * GNU Lesser General Public License for more details.
1343+ *
1344+ * You should have received a copy of the GNU Lesser General Public License
1345+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1346+ */
1347+
1348+#include "contenthandler.h"
1349+
1350+#include <QDebug>
1351+
1352+/*!
1353+ \qmltype ContentHandler
1354+ \instantiates ContentHandler
1355+ \inqmlmodule Ubuntu.Content 0.1
1356+
1357+ \sa ContentHub
1358+
1359+ \e {ContentHandler} is an enumeration of handler types:
1360+ \table
1361+ \header
1362+ \li Handler
1363+ \row
1364+ \li ContentHandler.Source
1365+ \row
1366+ \li ContentHandler.Destination
1367+ \row
1368+ \li ContentHandler.Share
1369+ \endtable
1370+ */
1371+
1372+ContentHandler::ContentHandler(QObject *parent)
1373+ : QObject(parent)
1374+{
1375+ qDebug() << Q_FUNC_INFO;
1376+}
1377
1378=== added file 'import/Ubuntu/Content/contenthandler.h'
1379--- import/Ubuntu/Content/contenthandler.h 1970-01-01 00:00:00 +0000
1380+++ import/Ubuntu/Content/contenthandler.h 2014-03-20 13:33:31 +0000
1381@@ -0,0 +1,37 @@
1382+/*
1383+ * Copyright 2013 Canonical Ltd.
1384+ *
1385+ * This program is free software; you can redistribute it and/or modify
1386+ * it under the terms of the GNU Lesser General Public License as published by
1387+ * the Free Software Foundation; version 3.
1388+ *
1389+ * This program is distributed in the hope that it will be useful,
1390+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1391+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1392+ * GNU Lesser General Public License for more details.
1393+ *
1394+ * You should have received a copy of the GNU Lesser General Public License
1395+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1396+ */
1397+
1398+#ifndef COM_UBUNTU_CONTENTHANDLER_H_
1399+#define COM_UBUNTU_CONTENTHANDLER_H_
1400+
1401+#include <QObject>
1402+
1403+class ContentHandler : public QObject
1404+{
1405+ Q_OBJECT
1406+ Q_ENUMS(Handler)
1407+
1408+public:
1409+ enum Handler {
1410+ Source = 0,
1411+ Destination = 1,
1412+ Share = 2
1413+ };
1414+
1415+ ContentHandler(QObject *parent = nullptr);
1416+};
1417+
1418+#endif // COM_UBUNTU_CONTENTHANDLER_H_
1419
1420=== modified file 'import/Ubuntu/Content/contenthub.cpp'
1421--- import/Ubuntu/Content/contenthub.cpp 2013-11-18 22:16:50 +0000
1422+++ import/Ubuntu/Content/contenthub.cpp 2014-03-20 13:33:31 +0000
1423@@ -25,6 +25,7 @@
1424 #include <com/ubuntu/content/peer.h>
1425 #include <com/ubuntu/content/type.h>
1426
1427+#include <QStringList>
1428 #include <QDebug>
1429
1430 /*!
1431@@ -42,36 +43,45 @@
1432 * id: root
1433 * width: units.gu(60)
1434 * height: units.gu(90)
1435- * Button {
1436- * anchors {
1437- * left: parent.left
1438- * margins: units.gu(2)
1439- * }
1440- * text: "Import from default"
1441- * onClicked: {
1442- * var peer = ContentHub.defaultSourceForType(ContentType.Pictures);
1443- * activeTransfer = ContentHub.importContent(ContentType.Pictures, peer);
1444- * }
1445- * }
1446- * Button {
1447- * anchors {
1448- * right: parent.right
1449- * margins: units.gu(2)
1450- * }
1451- * text: "Import from a selectable list"
1452- * onClicked: {
1453- * activeTransfer = ContentHub.importContent(ContentType.Pictures);
1454- * activeTransfer.selectionType =ContentTransfer.Multiple;
1455- * activeTransfer.start();
1456- * }
1457- * }
1458- * ContentImportHint {
1459+ * property list<ContentItem> importItems
1460+ * property var activeTransfer
1461+ *
1462+ * ContentPeer {
1463+ * id: picSourceSingle
1464+ * contentType: ContentType.Pictures
1465+ * handler: ContentHandler.Source
1466+ * selectionType: ContentTransfer.Single
1467+ * }
1468+ *
1469+ * ContentPeer {
1470+ * id: picSourceMulti
1471+ * contentType: ContentType.Pictures
1472+ * handler: ContentHandler.Source
1473+ * selectionType: ContentTransfer.Multiple
1474+ * }
1475+ *
1476+ * Row {
1477+ * Button {
1478+ * text: "Import single item"
1479+ * onClicked: {
1480+ * activeTransfer = picSourceSingle.request()
1481+ * }
1482+ * }
1483+ *
1484+ * Button {
1485+ * text: "Import multiple items"
1486+ * onClicked: {
1487+ * activeTransfer = picSourceMulti.request()
1488+ * }
1489+ * }
1490+ * }
1491+ *
1492+ * ContentTransferHint {
1493 * id: importHint
1494 * anchors.fill: parent
1495 * activeTransfer: root.activeTransfer
1496 * }
1497- * property list<ContentItem> importItems
1498- * property var activeTransfer
1499+ *
1500 * Connections {
1501 * target: root.activeTransfer
1502 * onStateChanged: {
1503@@ -107,6 +117,7 @@
1504 : QObject(parent),
1505 m_hub(0)
1506 {
1507+ qDebug() << Q_FUNC_INFO;
1508 m_hub = cuc::Hub::Client::instance();
1509 m_handler = new QmlImportExportHandler(this);
1510 m_hub->register_import_export_handler(m_handler);
1511@@ -115,121 +126,15 @@
1512 this, SLOT(handleImport(com::ubuntu::content::Transfer*)));
1513 connect(m_handler, SIGNAL(exportRequested(com::ubuntu::content::Transfer*)),
1514 this, SLOT(handleExport(com::ubuntu::content::Transfer*)));
1515-}
1516-
1517-/*!
1518- * \qmlmethod ContentHub::defaultSourceForType(ContentType)
1519- *
1520- * Returns the default \a ContentPeer for the given \a ContentType
1521- */
1522-ContentPeer *ContentHub::defaultSourceForType(int type)
1523-{
1524- qDebug() << Q_FUNC_INFO;
1525-
1526- const cuc::Type &hubType = ContentType::contentType2HubType(type);
1527- cuc::Peer hubPeer = m_hub->default_peer_for_type(hubType);
1528-
1529- ContentPeer *qmlPeer = new ContentPeer(this);
1530- qmlPeer->setPeer(hubPeer);
1531-
1532- return qmlPeer;
1533-}
1534-
1535-/*!
1536- * \qmlmethod ContentHub::defaultStoreForType(ContentType)
1537- *
1538- * Returns the default \a ContentStore for the given \a ContentType
1539- */
1540-ContentStore *ContentHub::defaultStoreForType(int type)
1541-{
1542- qDebug() << Q_FUNC_INFO;
1543-
1544- const cuc::Type &hubType = ContentType::contentType2HubType(type);
1545- const cuc::Store *hubStore = m_hub->store_for_scope_and_type(cuc::app, hubType);
1546-
1547- qDebug() << Q_FUNC_INFO << "STORE:" << hubStore->uri();
1548-
1549- ContentStore *qmlStore = new ContentStore(this);
1550- qmlStore->setStore(hubStore);
1551-
1552- return qmlStore;
1553-}
1554-
1555-/*!
1556- * \qmlmethod ContentHub::knownSourcesForType(ContentType)
1557- *
1558- * Returns all possible peers for the given ContentType
1559- *
1560- * \qml
1561- * import QtQuick 2.0
1562- * import Ubuntu.Components 0.1
1563- * import Ubuntu.Components.ListItems 0.1 as ListItem
1564- * import Ubuntu.Content 0.1
1565- *
1566- * MainView {
1567- * property list<ContentPeer> peers
1568- *
1569- * Component.onCompleted: {
1570- * peers = ContentHub.knownSourcesForType(ContentType.Pictures);
1571- * }
1572- * ListView {
1573- * anchors.fill: parent
1574- * height: childrenRect.height
1575- * model: peers
1576- * delegate: ListItem.Standard {
1577- * text: modelData.name
1578- * }
1579- * }
1580- * }
1581- * \endqml
1582- */
1583-QVariantList ContentHub::knownSourcesForType(int type)
1584-{
1585- qDebug() << Q_FUNC_INFO;
1586-
1587- const cuc::Type &hubType = ContentType::contentType2HubType(type);
1588- QVector<cuc::Peer> hubPeers = m_hub->known_peers_for_type(hubType);
1589-
1590- QVariantList qmlPeers;
1591- foreach (const cuc::Peer &hubPeer, hubPeers) {
1592- ContentPeer *qmlPeer = new ContentPeer(this);
1593- qmlPeer->setPeer(hubPeer);
1594- qmlPeers.append(QVariant::fromValue(qmlPeer));
1595- }
1596- return qmlPeers;
1597-}
1598-
1599-/*!
1600- * \qmlmethod ContentHub::importContent(ContentType)
1601- * \overload ContentHub::importContent(ContentType, ContentPeer)
1602- *
1603- * \brief Request to import data of \a ContentType from the default
1604- * ContentPeer
1605- */
1606-ContentTransfer *ContentHub::importContent(int type)
1607-{
1608- qDebug() << Q_FUNC_INFO << static_cast<ContentType::Type>(type);
1609-
1610- const cuc::Type &hubType = ContentType::contentType2HubType(type);
1611-// FIXME show user a selection of possible peers instead
1612- cuc::Peer hubPeer = m_hub->default_peer_for_type(hubType);
1613-
1614- return importContent(hubType, hubPeer);
1615-}
1616-
1617-/*!
1618- * \qmlmethod ContentHub::importContent(ContentType, ContentPeer)
1619- * \overload ContentHub::importContent(ContentType)
1620- *
1621- * \brief Request to import data of \a ContentType from the
1622- * specified \a ContentPeer
1623- */
1624-ContentTransfer *ContentHub::importContent(int type, ContentPeer *peer)
1625-{
1626- qDebug() << Q_FUNC_INFO << static_cast<ContentType::Type>(type) << peer;
1627-
1628- const cuc::Type &hubType = ContentType::contentType2HubType(type);
1629- return importContent(hubType, peer->peer());
1630+ connect(m_handler, SIGNAL(shareRequested(com::ubuntu::content::Transfer*)),
1631+ this, SLOT(handleShare(com::ubuntu::content::Transfer*)));
1632+}
1633+
1634+ContentHub *ContentHub::instance()
1635+{
1636+ qDebug() << Q_FUNC_INFO;
1637+ static ContentHub *contentHub = new ContentHub(nullptr);
1638+ return contentHub;
1639 }
1640
1641 /*!
1642@@ -238,16 +143,47 @@
1643 * \a peer
1644 * \internal
1645 */
1646-ContentTransfer* ContentHub::importContent(const com::ubuntu::content::Type &hubType,
1647- const com::ubuntu::content::Peer &hubPeer)
1648-{
1649- cuc::Transfer *hubTransfer = m_hub->create_import_for_type_from_peer(hubType, hubPeer);
1650-// FIXME update tests so this can be enabled
1651-// if (!hubTransfer)
1652-// return nullptr;
1653-
1654- ContentTransfer *qmlTransfer = new ContentTransfer(this);
1655- qmlTransfer->setTransfer(hubTransfer, ContentTransfer::Import);
1656+ContentTransfer* ContentHub::importContent(cuc::Peer peer)
1657+{
1658+ qDebug() << Q_FUNC_INFO;
1659+
1660+ cuc::Transfer *hubTransfer = m_hub->create_import_from_peer(peer);
1661+ ContentTransfer *qmlTransfer = new ContentTransfer(this);
1662+ qmlTransfer->setTransfer(hubTransfer);
1663+ m_activeImports.insert(hubTransfer, qmlTransfer);
1664+ return qmlTransfer;
1665+}
1666+
1667+/*!
1668+ * \brief ContentHub::exportContent creates a ContentTransfer object
1669+ * \a type
1670+ * \a peer
1671+ * \internal
1672+ */
1673+ContentTransfer* ContentHub::exportContent(cuc::Peer peer)
1674+{
1675+ qDebug() << Q_FUNC_INFO;
1676+
1677+ cuc::Transfer *hubTransfer = m_hub->create_export_to_peer(peer);
1678+ ContentTransfer *qmlTransfer = new ContentTransfer(this);
1679+ qmlTransfer->setTransfer(hubTransfer);
1680+ m_activeImports.insert(hubTransfer, qmlTransfer);
1681+ return qmlTransfer;
1682+}
1683+
1684+/*!
1685+ * \brief ContentHub::shareContent creates a ContentTransfer object
1686+ * \a type
1687+ * \a peer
1688+ * \internal
1689+ */
1690+ContentTransfer* ContentHub::shareContent(cuc::Peer peer)
1691+{
1692+ qDebug() << Q_FUNC_INFO;
1693+
1694+ cuc::Transfer *hubTransfer = m_hub->create_share_to_peer(peer);
1695+ ContentTransfer *qmlTransfer = new ContentTransfer(this);
1696+ qmlTransfer->setTransfer(hubTransfer);
1697 m_activeImports.insert(hubTransfer, qmlTransfer);
1698 return qmlTransfer;
1699 }
1700@@ -283,8 +219,14 @@
1701 qmlTransfer = m_activeImports.take(transfer);
1702 qmlTransfer->collectItems();
1703 } else {
1704+ // If we don't have a reference to the transfer, it was created
1705+ // by another handler so this would be an Import
1706 qmlTransfer = new ContentTransfer(this);
1707- qmlTransfer->setTransfer(transfer, ContentTransfer::Import);
1708+ qmlTransfer->setTransfer(transfer);
1709+ connect(qmlTransfer, SIGNAL(stateChanged()),
1710+ this, SLOT(updateState()));
1711+ qmlTransfer->collectItems();
1712+ Q_EMIT importRequested(qmlTransfer);
1713 }
1714
1715 m_finishedImports.append(qmlTransfer);
1716@@ -298,11 +240,61 @@
1717 void ContentHub::handleExport(com::ubuntu::content::Transfer *transfer)
1718 {
1719 qDebug() << Q_FUNC_INFO;
1720- ContentTransfer *qmlTransfer = new ContentTransfer(this);
1721- qmlTransfer->setTransfer(transfer, ContentTransfer::Export);
1722-
1723- Q_EMIT exportRequested(qmlTransfer);
1724-}
1725+ ContentTransfer *qmlTransfer = nullptr;
1726+ if (m_activeImports.contains(transfer))
1727+ qmlTransfer = m_activeImports.take(transfer);
1728+ else {
1729+ // If we don't have a reference to the transfer, it was created
1730+ // by another handler so this would be an Import
1731+ qmlTransfer = new ContentTransfer(this);
1732+ qmlTransfer->setTransfer(transfer);
1733+ m_activeImports.insert(transfer, qmlTransfer);
1734+ connect(qmlTransfer, SIGNAL(stateChanged()),
1735+ this, SLOT(updateState()));
1736+ Q_EMIT exportRequested(qmlTransfer);
1737+ }
1738+
1739+ m_finishedImports.append(qmlTransfer);
1740+ Q_EMIT finishedImportsChanged();
1741+}
1742+
1743+/*!
1744+ * \brief ContentHub::handleExport handles an incoming request for sharing content
1745+ * \internal
1746+ */
1747+void ContentHub::handleShare(com::ubuntu::content::Transfer *transfer)
1748+{
1749+ qDebug() << Q_FUNC_INFO;
1750+ ContentTransfer *qmlTransfer = nullptr;
1751+ if (m_activeImports.contains(transfer))
1752+ {
1753+ qmlTransfer = m_activeImports.take(transfer);
1754+ qmlTransfer->collectItems();
1755+ } else {
1756+ // If we don't have a reference to the transfer, it was created
1757+ // by another handler so this would be an Import
1758+ qmlTransfer = new ContentTransfer(this);
1759+ qmlTransfer->setTransfer(transfer);
1760+ connect(qmlTransfer, SIGNAL(stateChanged()),
1761+ this, SLOT(updateState()));
1762+ qmlTransfer->collectItems();
1763+ Q_EMIT shareRequested(qmlTransfer);
1764+ }
1765+
1766+ m_finishedImports.append(qmlTransfer);
1767+ Q_EMIT finishedImportsChanged();
1768+}
1769+
1770+void ContentHub::updateState()
1771+{
1772+ qDebug() << Q_FUNC_INFO;
1773+}
1774+
1775+/*!
1776+ * \qmlsignal ContentHub::importRequested(ContentTransfer transfer)
1777+ *
1778+ * The signal is triggered when an import is requested.
1779+ */
1780
1781 /*!
1782 * \qmlsignal ContentHub::exportRequested(ContentTransfer transfer)
1783@@ -310,3 +302,9 @@
1784 * The signal is triggered when an export is requested.
1785 */
1786
1787+/*!
1788+ * \qmlsignal ContentHub::shareRequested(ContentTransfer transfer)
1789+ *
1790+ * The signal is triggered when a share is requested.
1791+ */
1792+
1793
1794=== modified file 'import/Ubuntu/Content/contenthub.h'
1795--- import/Ubuntu/Content/contenthub.h 2013-11-07 20:12:56 +0000
1796+++ import/Ubuntu/Content/contenthub.h 2014-03-20 13:33:31 +0000
1797@@ -21,10 +21,10 @@
1798 #include <QList>
1799 #include <QObject>
1800 #include <QQmlListProperty>
1801+#include "contentpeer.h"
1802+#include "contenttransfer.h"
1803
1804-class ContentPeer;
1805 class ContentStore;
1806-class ContentTransfer;
1807 class QmlImportExportHandler;
1808
1809 namespace com {
1810@@ -45,37 +45,40 @@
1811 Q_PROPERTY(QQmlListProperty<ContentTransfer> finishedImports READ finishedImports NOTIFY finishedImportsChanged)
1812
1813 public:
1814- ContentHub(QObject *parent = nullptr);
1815-
1816- Q_INVOKABLE ContentPeer *defaultSourceForType(int type);
1817- Q_INVOKABLE QVariantList knownSourcesForType(int type);
1818-
1819- Q_INVOKABLE ContentStore *defaultStoreForType(int type);
1820-
1821- Q_INVOKABLE ContentTransfer* importContent(int type);
1822- Q_INVOKABLE ContentTransfer* importContent(int type, ContentPeer *peer);
1823+ ContentHub(const ContentHub&) = delete;
1824+
1825+ static ContentHub *instance();
1826
1827 Q_INVOKABLE void restoreImports();
1828
1829 QQmlListProperty<ContentTransfer> finishedImports();
1830
1831+ Q_INVOKABLE ContentTransfer* importContent(com::ubuntu::content::Peer peer);
1832+ Q_INVOKABLE ContentTransfer* exportContent(com::ubuntu::content::Peer peer);
1833+ Q_INVOKABLE ContentTransfer* shareContent(com::ubuntu::content::Peer peer);
1834+
1835 Q_SIGNALS:
1836+ void importRequested(ContentTransfer *transfer);
1837 void exportRequested(ContentTransfer *transfer);
1838+ void shareRequested(ContentTransfer *transfer);
1839+
1840 void finishedImportsChanged();
1841
1842 private Q_SLOTS:
1843- void handleImport(com::ubuntu::content::Transfer * transfer);
1844- void handleExport(com::ubuntu::content::Transfer * transfer);
1845+ void handleImport(com::ubuntu::content::Transfer* transfer);
1846+ void handleExport(com::ubuntu::content::Transfer* transfer);
1847+ void handleShare(com::ubuntu::content::Transfer* transfer);
1848+ void updateState();
1849
1850 private:
1851- ContentTransfer* importContent(const com::ubuntu::content::Type &hubType,
1852- const com::ubuntu::content::Peer &hubPeer);
1853-
1854 QList<ContentTransfer *> m_finishedImports;
1855 QHash<com::ubuntu::content::Transfer *, ContentTransfer *> m_activeImports;
1856-
1857 com::ubuntu::content::Hub *m_hub;
1858 QmlImportExportHandler *m_handler;
1859+
1860+protected:
1861+ ContentHub(QObject* = nullptr);
1862+
1863 };
1864
1865 #endif // COM_UBUNTU_CONTENTHUB_H_
1866
1867=== modified file 'import/Ubuntu/Content/contenthubplugin.cpp'
1868--- import/Ubuntu/Content/contenthubplugin.cpp 2013-11-08 21:04:52 +0000
1869+++ import/Ubuntu/Content/contenthubplugin.cpp 2014-03-20 13:33:31 +0000
1870@@ -16,9 +16,13 @@
1871
1872 #include "contenthubplugin.h"
1873
1874+#include "contenthandler.h"
1875 #include "contenthub.h"
1876+#include "contenticonprovider.h"
1877 #include "contentitem.h"
1878 #include "contentpeer.h"
1879+#include "contentpeermodel.h"
1880+#include "contentscope.h"
1881 #include "contentstore.h"
1882 #include "contenttransfer.h"
1883 #include "contenttype.h"
1884@@ -27,6 +31,7 @@
1885 #include <QQmlContext>
1886 #include <QQmlEngine>
1887 #include <QDebug>
1888+#include <QIcon>
1889
1890 /*!
1891 * \brief qml_content_hub function to unstatinate the ContentHub as a singleton in QML
1892@@ -36,7 +41,20 @@
1893 Q_UNUSED(engine)
1894 Q_UNUSED(scriptEngine)
1895 qDebug() << Q_FUNC_INFO;
1896- return new ContentHub();
1897+ return ContentHub::instance();
1898+}
1899+
1900+/*!
1901+ * \reimp
1902+ */
1903+void ContentHubPlugin::initializeEngine(QQmlEngine * engine, const char * uri)
1904+{
1905+ Q_UNUSED(uri)
1906+ qDebug() << Q_FUNC_INFO;
1907+ QIcon::setThemeName("ubuntu-mobile");
1908+ QIcon::setThemeSearchPaths(QStringList() << ("/usr/share/icons/"));
1909+ ContentIconProvider *iconProvider = ContentIconProvider::instance();
1910+ engine->addImageProvider("content-hub", iconProvider);
1911 }
1912
1913 /*!
1914@@ -50,10 +68,13 @@
1915 const int versionMajor = 0;
1916 const int versionMinor = 1;
1917
1918+ qmlRegisterUncreatableType<ContentHandler>(uri, versionMajor, versionMinor, "ContentHandler", "Not creatable as an object, use only to retrieve handler enums (e.g. ContentHandler.Source)");
1919 qmlRegisterSingletonType<ContentHub>(uri, versionMajor, versionMinor, "ContentHub", qml_content_hub);
1920 qmlRegisterType<ContentItem>(uri, versionMajor, versionMinor, "ContentItem");
1921 qmlRegisterType<ContentPeer>(uri, versionMajor, versionMinor, "ContentPeer");
1922- qmlRegisterUncreatableType<ContentStore>(uri, versionMajor, versionMinor, "ContentStore", "created by hub");
1923+ qmlRegisterType<ContentPeerModel>(uri, versionMajor, versionMinor, "ContentPeerModel");
1924+ qmlRegisterType<ContentScope>(uri, versionMajor, versionMinor, "ContentScope");
1925+ qmlRegisterType<ContentStore>(uri, versionMajor, versionMinor, "ContentStore");
1926 qmlRegisterUncreatableType<ContentTransfer>(uri, versionMajor, versionMinor, "ContentTransfer", "created by hub");
1927 qmlRegisterUncreatableType<ContentType>(uri, versionMajor, versionMinor, "ContentType", "Use only the type");
1928 }
1929
1930=== modified file 'import/Ubuntu/Content/contenthubplugin.h'
1931--- import/Ubuntu/Content/contenthubplugin.h 2013-08-27 07:49:26 +0000
1932+++ import/Ubuntu/Content/contenthubplugin.h 2014-03-20 13:33:31 +0000
1933@@ -18,6 +18,7 @@
1934 #define COM_UBUNTU_CONTENT_PLUGIN_H_
1935
1936 #include <QQmlExtensionPlugin>
1937+#include <QQmlEngine>
1938
1939 class ContentHub;
1940
1941@@ -27,6 +28,7 @@
1942 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
1943
1944 public:
1945+ void initializeEngine(QQmlEngine * engine, const char * uri);
1946 void registerTypes(const char *uri);
1947
1948 private:
1949
1950=== added file 'import/Ubuntu/Content/contenticonprovider.cpp'
1951--- import/Ubuntu/Content/contenticonprovider.cpp 1970-01-01 00:00:00 +0000
1952+++ import/Ubuntu/Content/contenticonprovider.cpp 2014-03-20 13:33:31 +0000
1953@@ -0,0 +1,63 @@
1954+/*
1955+ * Copyright 2013 Canonical Ltd.
1956+ *
1957+ * This program is free software; you can redistribute it and/or modify
1958+ * it under the terms of the GNU Lesser General Public License as published by
1959+ * the Free Software Foundation; version 3.
1960+ *
1961+ * This program is distributed in the hope that it will be useful,
1962+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1963+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1964+ * GNU Lesser General Public License for more details.
1965+ *
1966+ * You should have received a copy of the GNU Lesser General Public License
1967+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1968+ */
1969+
1970+#include "contenticonprovider.h"
1971+
1972+#include <QDebug>
1973+
1974+ContentIconProvider::ContentIconProvider()
1975+ : QQuickImageProvider(QQuickImageProvider::Image)
1976+{
1977+ qDebug() << Q_FUNC_INFO;
1978+
1979+ appIdImageMap = new QMap<QString, QImage>();
1980+}
1981+
1982+ContentIconProvider *ContentIconProvider::instance()
1983+{
1984+ static ContentIconProvider *contentIconProvider = new ContentIconProvider();
1985+ return contentIconProvider;
1986+}
1987+
1988+/*!
1989+ * \brief void ContentIconProvider::addImage
1990+ *
1991+ * Add an app's icon to the provider
1992+ */
1993+void ContentIconProvider::addImage(QString appId, QImage image)
1994+{
1995+ qDebug() << Q_FUNC_INFO;
1996+ appIdImageMap->insert(appId, image);
1997+}
1998+
1999+/*!
2000+ * \brief QImage ContentIconProvider::requestImage
2001+ *
2002+ * Returns the QImage for a given appId at the requested size
2003+ */
2004+QImage ContentIconProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
2005+{
2006+ Q_UNUSED(requestedSize)
2007+ qDebug() << Q_FUNC_INFO;
2008+
2009+ QImage image = appIdImageMap->value(id);
2010+ if(size) {
2011+ *size = image.size();
2012+ }
2013+
2014+ return image;
2015+}
2016+
2017
2018=== added file 'import/Ubuntu/Content/contenticonprovider.h'
2019--- import/Ubuntu/Content/contenticonprovider.h 1970-01-01 00:00:00 +0000
2020+++ import/Ubuntu/Content/contenticonprovider.h 2014-03-20 13:33:31 +0000
2021@@ -0,0 +1,40 @@
2022+/*
2023+ * Copyright 2013 Canonical Ltd.
2024+ *
2025+ * This program is free software; you can redistribute it and/or modify
2026+ * it under the terms of the GNU Lesser General Public License as published by
2027+ * the Free Software Foundation; version 3.
2028+ *
2029+ * This program is distributed in the hope that it will be useful,
2030+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2031+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2032+ * GNU Lesser General Public License for more details.
2033+ *
2034+ * You should have received a copy of the GNU Lesser General Public License
2035+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2036+ */
2037+
2038+#ifndef COM_UBUNTU_CONTENTICONPROVIDER_H_
2039+#define COM_UBUNTU_CONTENTICONPROVIDER_H_
2040+
2041+#include <QMap>
2042+#include <QQuickImageProvider>
2043+#include <QString>
2044+#include <QImage>
2045+
2046+class ContentIconProvider : public QQuickImageProvider
2047+{
2048+
2049+public:
2050+ ContentIconProvider();
2051+
2052+ static ContentIconProvider *instance();
2053+
2054+ QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize);
2055+ void addImage(QString appId, QImage image);
2056+
2057+private:
2058+ QMap<QString, QImage> *appIdImageMap;
2059+};
2060+
2061+#endif // COM_UBUNTU_CONTENTICONPROVIDER_H_
2062
2063=== modified file 'import/Ubuntu/Content/contentpeer.cpp'
2064--- import/Ubuntu/Content/contentpeer.cpp 2013-11-07 20:12:56 +0000
2065+++ import/Ubuntu/Content/contentpeer.cpp 2014-03-20 13:33:31 +0000
2066@@ -14,11 +14,15 @@
2067 * along with this program. If not, see <http://www.gnu.org/licenses/>.
2068 */
2069
2070+#include "contenthandler.h"
2071+#include "contenthub.h"
2072+#include "contenticonprovider.h"
2073 #include "contentpeer.h"
2074+#include "contenttype.h"
2075
2076 #include <com/ubuntu/content/peer.h>
2077-
2078 #include <QDebug>
2079+#include <QIcon>
2080
2081 /*!
2082 * \qmltype ContentPeer
2083@@ -36,15 +40,21 @@
2084
2085 ContentPeer::ContentPeer(QObject *parent)
2086 : QObject(parent),
2087- m_peer(0)
2088+ m_peer(0),
2089+ m_handler(ContentHandler::Source),
2090+ m_contentType(ContentType::Unknown),
2091+ m_selectionType(ContentTransfer::Single),
2092+ m_explicit_peer(false)
2093 {
2094 qDebug() << Q_FUNC_INFO;
2095+
2096+ m_hub = cuc::Hub::Client::instance();
2097 }
2098
2099 /*!
2100 * \qmlproperty string ContentPeer::name
2101 *
2102- * Returns user friendly name of the peer
2103+ * Returns user friendly name of the peer.
2104 */
2105 QString ContentPeer::name()
2106 {
2107@@ -54,8 +64,7 @@
2108
2109 /*!
2110 * \qmlproperty string ContentPeer::appId
2111- *
2112- * Returns the Application id
2113+ * When set, this property allows for a specific application to be used as a peer.
2114 */
2115 const QString &ContentPeer::appId() const
2116 {
2117@@ -64,6 +73,23 @@
2118 }
2119
2120 /*!
2121+ * \brief ContentPeer::setAppId
2122+ * \internal
2123+ * Sets the Application id
2124+ */
2125+void ContentPeer::setAppId(const QString& appId)
2126+{
2127+ qDebug() << Q_FUNC_INFO << appId;
2128+ this->setPeer(cuc::Peer{appId});
2129+}
2130+
2131+QImage &ContentPeer::icon()
2132+{
2133+ qDebug() << Q_FUNC_INFO;
2134+ return m_icon;
2135+}
2136+
2137+/*!
2138 * \brief ContentPeer::peer
2139 * \internal
2140 */
2141@@ -76,9 +102,145 @@
2142 * \brief ContentPeer::setPeer
2143 * \internal
2144 */
2145-void ContentPeer::setPeer(const cuc::Peer &peer)
2146+void ContentPeer::setPeer(const cuc::Peer &peer, bool explicitPeer)
2147 {
2148+ qDebug() << Q_FUNC_INFO;
2149 m_peer = peer;
2150+ m_explicit_peer = explicitPeer;
2151+ if (peer.iconData().isEmpty())
2152+ {
2153+ if (QIcon::hasThemeIcon(peer.iconName().toUtf8()))
2154+ m_icon = QIcon::fromTheme(peer.iconName().toUtf8()).pixmap(256).toImage();
2155+ } else
2156+ m_icon.loadFromData(peer.iconData());
2157+ ContentIconProvider *iconProvider = ContentIconProvider::instance();
2158+ iconProvider->addImage(appId(), m_icon);
2159+
2160 Q_EMIT nameChanged();
2161 Q_EMIT appIdChanged();
2162 }
2163+
2164+/*!
2165+ * \qmlproperty ContentHandler ContentPeer::handler
2166+ * Specifies which ContentHandler this peer should support (e.g. Source, Destination, Share).
2167+ */
2168+ContentHandler::Handler ContentPeer::handler()
2169+{
2170+ qDebug() << Q_FUNC_INFO;
2171+ return m_handler;
2172+}
2173+
2174+/*!
2175+ * \brief ContentPeer::setHandler
2176+ * \internal
2177+ */
2178+void ContentPeer::setHandler(ContentHandler::Handler handler)
2179+{
2180+ qDebug() << Q_FUNC_INFO;
2181+ m_handler = handler;
2182+
2183+ Q_EMIT handlerChanged();
2184+}
2185+
2186+/*!
2187+ * \qmlproperty ContentType ContentPeer::contentType
2188+ * Specifies the ContentType this peer should support.
2189+ */
2190+ContentType::Type ContentPeer::contentType()
2191+{
2192+ qDebug() << Q_FUNC_INFO;
2193+ return m_contentType;
2194+}
2195+
2196+/*!
2197+ * \brief ContentPeer::setContentType
2198+ * \internal
2199+ */
2200+void ContentPeer::setContentType(ContentType::Type contentType)
2201+{
2202+ qDebug() << Q_FUNC_INFO;
2203+ m_contentType = contentType;
2204+
2205+ if(!m_explicit_peer) {
2206+ const cuc::Type &hubType = ContentType::contentType2HubType(m_contentType);
2207+ setPeer(m_hub->default_source_for_type(hubType), false);
2208+ }
2209+
2210+ Q_EMIT contentTypeChanged();
2211+}
2212+
2213+/*!
2214+ * \qmlproperty ContentTransfer.SelectionType ContentPeer::selectionType
2215+ * Specifies whether this peer is allowed to return multiple items.
2216+ */
2217+ContentTransfer::SelectionType ContentPeer::selectionType()
2218+{
2219+ qDebug() << Q_FUNC_INFO;
2220+ return m_selectionType;
2221+}
2222+
2223+/*!
2224+ * \brief ContentPeer::setSelectionType
2225+ * \internal
2226+ */
2227+void ContentPeer::setSelectionType(ContentTransfer::SelectionType selectionType)
2228+{
2229+ qDebug() << Q_FUNC_INFO;
2230+ m_selectionType = selectionType;
2231+
2232+ Q_EMIT selectionTypeChanged();
2233+}
2234+
2235+/*!
2236+ * \brief ContentPeer::isDefaultPeer
2237+ * \internal
2238+ */
2239+bool ContentPeer::isDefaultPeer()
2240+{
2241+ qDebug() << Q_FUNC_INFO;
2242+ return m_peer.isDefaultPeer();
2243+}
2244+
2245+/*!
2246+ * \qmlmethod ContentPeer::request()
2247+ *
2248+ * \brief Request an active transfer from this ContentPeer.
2249+ */
2250+ContentTransfer *ContentPeer::request()
2251+{
2252+ qDebug() << Q_FUNC_INFO;
2253+ return request(nullptr);
2254+}
2255+
2256+/*!
2257+ * \qmlmethod ContentPeer::request(ContentStore)
2258+ *
2259+ * \brief Request to an active transfer from this ContentPeer and use
2260+ * a ContentStore for permanent storage.
2261+ */
2262+ContentTransfer *ContentPeer::request(ContentStore *store)
2263+{
2264+ qDebug() << Q_FUNC_INFO;
2265+
2266+ ContentHub *contentHub = ContentHub::instance();
2267+ ContentTransfer *qmlTransfer = NULL;
2268+ if(m_handler == ContentHandler::Source) {
2269+ qmlTransfer = contentHub->importContent(m_peer);
2270+ } else if (m_handler == ContentHandler::Destination) {
2271+ qmlTransfer = contentHub->exportContent(m_peer);
2272+ } else if (m_handler == ContentHandler::Share) {
2273+ qmlTransfer = contentHub->shareContent(m_peer);
2274+ }
2275+
2276+ qmlTransfer->setSelectionType(m_selectionType);
2277+ if(store) {
2278+ store->updateStore(m_contentType);
2279+ qmlTransfer->setStore(store);
2280+ }
2281+
2282+ /* We only need to start it for import requests */
2283+ if (m_handler == ContentHandler::Source)
2284+ qmlTransfer->start();
2285+
2286+ return qmlTransfer;
2287+}
2288
2289=== modified file 'import/Ubuntu/Content/contentpeer.h'
2290--- import/Ubuntu/Content/contentpeer.h 2013-10-23 12:06:13 +0000
2291+++ import/Ubuntu/Content/contentpeer.h 2014-03-20 13:33:31 +0000
2292@@ -17,32 +17,70 @@
2293 #ifndef COM_UBUNTU_CONTENTPEER_H_
2294 #define COM_UBUNTU_CONTENTPEER_H_
2295
2296+#include "contenthandler.h"
2297+#include "contenttransfer.h"
2298+#include "contenttype.h"
2299+#include <com/ubuntu/content/hub.h>
2300 #include <com/ubuntu/content/peer.h>
2301
2302 #include <QObject>
2303 #include <QString>
2304+#include <QImage>
2305
2306 class ContentPeer : public QObject
2307 {
2308 Q_OBJECT
2309 Q_PROPERTY(QString name READ name NOTIFY nameChanged)
2310- Q_PROPERTY(QString appId READ appId NOTIFY appIdChanged)
2311+ Q_PROPERTY(QString appId READ appId WRITE setAppId NOTIFY appIdChanged)
2312+ Q_PROPERTY(ContentHandler::Handler handler READ handler WRITE setHandler NOTIFY handlerChanged)
2313+ Q_PROPERTY(ContentType::Type contentType READ contentType WRITE setContentType NOTIFY contentTypeChanged)
2314+ Q_PROPERTY(ContentTransfer::SelectionType selectionType READ selectionType WRITE setSelectionType NOTIFY selectionTypeChanged)
2315+ Q_PROPERTY(QImage icon READ icon)
2316+ Q_PROPERTY(bool isDefaultPeer READ isDefaultPeer)
2317
2318 public:
2319 ContentPeer(QObject *parent = nullptr);
2320+ ContentPeer(ContentType::Type type, QObject *parent);
2321+
2322+ Q_INVOKABLE ContentTransfer* request();
2323+ Q_INVOKABLE ContentTransfer* request(ContentStore *store);
2324
2325 QString name();
2326 const QString &appId() const;
2327+ void setAppId(const QString&);
2328+ QImage &icon();
2329
2330 const com::ubuntu::content::Peer &peer() const;
2331- void setPeer(const com::ubuntu::content::Peer &peer);
2332+ void setPeer(const com::ubuntu::content::Peer &peer, bool explicitPeer = true);
2333+
2334+ ContentHandler::Handler handler();
2335+ void setHandler(ContentHandler::Handler handler);
2336+
2337+ ContentType::Type contentType();
2338+ void setContentType(ContentType::Type contentType);
2339+
2340+ ContentTransfer::SelectionType selectionType();
2341+ void setSelectionType(ContentTransfer::SelectionType selectionType);
2342+
2343+ bool isDefaultPeer();
2344
2345 Q_SIGNALS:
2346 void nameChanged();
2347 void appIdChanged();
2348+ void handlerChanged();
2349+ void contentTypeChanged();
2350+ void selectionTypeChanged();
2351
2352 private:
2353+ void init();
2354+
2355+ com::ubuntu::content::Hub *m_hub;
2356 com::ubuntu::content::Peer m_peer;
2357+ ContentHandler::Handler m_handler;
2358+ ContentType::Type m_contentType;
2359+ ContentTransfer::SelectionType m_selectionType;
2360+ bool m_explicit_peer;
2361+ QImage m_icon;
2362 };
2363
2364 #endif // COM_UBUNTU_CONTENTPEER_H_
2365
2366=== added file 'import/Ubuntu/Content/contentpeermodel.cpp'
2367--- import/Ubuntu/Content/contentpeermodel.cpp 1970-01-01 00:00:00 +0000
2368+++ import/Ubuntu/Content/contentpeermodel.cpp 2014-03-20 13:33:31 +0000
2369@@ -0,0 +1,182 @@
2370+/*
2371+ * Copyright 2013 Canonical Ltd.
2372+ *
2373+ * This program is free software; you can redistribute it and/or modify
2374+ * it under the terms of the GNU Lesser General Public License as published by
2375+ * the Free Software Foundation; version 3.
2376+ *
2377+ * This program is distributed in the hope that it will be useful,
2378+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2379+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2380+ * GNU Lesser General Public License for more details.
2381+ *
2382+ * You should have received a copy of the GNU Lesser General Public License
2383+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2384+ */
2385+
2386+#include "contentpeermodel.h"
2387+#include <stdio.h>
2388+
2389+#include <QDebug>
2390+
2391+namespace cuc = com::ubuntu::content;
2392+
2393+/*!
2394+ * \qmltype ContentPeerModel
2395+ * \instantiates ContentPeerModel
2396+ * \inqmlmodule Ubuntu.Content 0.1
2397+ * \brief A list of applications that can export or import a ContentType
2398+ *
2399+ * A ContentPeerModel provides a list of all applications that are registered
2400+ * in the ContentHub as a source or destination of a ContentType
2401+ *
2402+ * See documentation for ContentPeer
2403+ */
2404+
2405+ContentPeerModel::ContentPeerModel(QObject *parent)
2406+ : QObject(parent),
2407+ m_contentType(ContentType::Unknown),
2408+ m_handler(ContentHandler::Source),
2409+ m_complete(false)
2410+{
2411+ qDebug() << Q_FUNC_INFO;
2412+ m_hub = cuc::Hub::Client::instance();
2413+}
2414+
2415+/*!
2416+ * \brief \reimp
2417+ * \internal
2418+ */
2419+void ContentPeerModel::classBegin()
2420+{
2421+
2422+}
2423+
2424+/*!
2425+ * \brief \reimp
2426+ * \internal
2427+ */
2428+void ContentPeerModel::componentComplete()
2429+{
2430+ m_complete = true;
2431+ QTimer::singleShot(0, this, SLOT(findPeers()));
2432+}
2433+
2434+/*!
2435+ * \qmlproperty ContentType ContentPeerModel::contentType
2436+ *
2437+ * Specifies which ContentType discovered peers should support.
2438+ */
2439+ContentType::Type ContentPeerModel::contentType()
2440+{
2441+ qDebug() << Q_FUNC_INFO;
2442+ return m_contentType;
2443+}
2444+
2445+/*!
2446+ * \brief ContentPeerModel::setContentType
2447+ * \internal
2448+ */
2449+void ContentPeerModel::setContentType(ContentType::Type contentType)
2450+{
2451+ qDebug() << Q_FUNC_INFO;
2452+ m_contentType = contentType;
2453+ if (m_complete) {
2454+ findPeers();
2455+ }
2456+ Q_EMIT contentTypeChanged();
2457+}
2458+
2459+/*!
2460+ * \brief ContentPeerModel::findPeers
2461+ * \internal
2462+ */
2463+void ContentPeerModel::findPeers() {
2464+ qDebug() << Q_FUNC_INFO;
2465+ m_peers.clear();
2466+ QCoreApplication::processEvents();
2467+ if(m_contentType == ContentType::All) {
2468+ appendPeersForContentType(ContentType::Unknown);
2469+ appendPeersForContentType(ContentType::Documents);
2470+ appendPeersForContentType(ContentType::Pictures);
2471+ appendPeersForContentType(ContentType::Music);
2472+ appendPeersForContentType(ContentType::Contacts);
2473+ } else {
2474+ appendPeersForContentType(m_contentType);
2475+ }
2476+ Q_EMIT findPeersCompleted();
2477+}
2478+
2479+/*!
2480+ * \brief ContentPeerModel::appendPeersForContentType
2481+ * \internal
2482+ */
2483+void ContentPeerModel::appendPeersForContentType(ContentType::Type contentType)
2484+{
2485+ qDebug() << Q_FUNC_INFO;
2486+ const cuc::Type &hubType = ContentType::contentType2HubType(contentType);
2487+ QVector<cuc::Peer> hubPeers;
2488+ if (m_handler == ContentHandler::Destination) {
2489+ hubPeers = m_hub->known_destinations_for_type(hubType);
2490+ } else if (m_handler == ContentHandler::Share) {
2491+ hubPeers = m_hub->known_shares_for_type(hubType);
2492+ } else {
2493+ hubPeers = m_hub->known_sources_for_type(hubType);
2494+ }
2495+
2496+ Q_FOREACH (const cuc::Peer &hubPeer, hubPeers)
2497+ {
2498+ if(!hubPeer.id().isEmpty())
2499+ {
2500+ ContentPeer *qmlPeer = new ContentPeer();
2501+ qmlPeer->setPeer(hubPeer);
2502+ qmlPeer->setContentType(contentType);
2503+ qmlPeer->setHandler(m_handler);
2504+ if(qmlPeer->isDefaultPeer())
2505+ {
2506+ m_peers.prepend(qmlPeer);
2507+ } else {
2508+ m_peers.append(qmlPeer);
2509+ }
2510+ Q_EMIT peersChanged();
2511+ }
2512+ QCoreApplication::processEvents();
2513+ }
2514+}
2515+
2516+/*!
2517+ * \qmlproperty ContentHandler ContentPeerModel::handler
2518+ *
2519+ * Specifies which ContentHandler discovered peers should support.
2520+ */
2521+ContentHandler::Handler ContentPeerModel::handler()
2522+{
2523+ qDebug() << Q_FUNC_INFO;
2524+ return m_handler;
2525+}
2526+
2527+/*!
2528+ * \brief ContentPeerModel::setHandler
2529+ * \internal
2530+ */
2531+void ContentPeerModel::setHandler(ContentHandler::Handler handler)
2532+{
2533+ qDebug() << Q_FUNC_INFO;
2534+ m_handler = handler;
2535+ if (m_complete) {
2536+ findPeers();
2537+ }
2538+ Q_EMIT handlerChanged();
2539+}
2540+
2541+/*!
2542+ * \qmlproperty list<ContentPeer> ContentPeerModel::peers
2543+ *
2544+ * Provides a list of discovered peers matching the requested ContentType and ContentHandler.
2545+ */
2546+QQmlListProperty<ContentPeer> ContentPeerModel::peers()
2547+{
2548+ qDebug() << Q_FUNC_INFO;
2549+ return QQmlListProperty<ContentPeer>(this, m_peers);
2550+}
2551+
2552
2553=== added file 'import/Ubuntu/Content/contentpeermodel.h'
2554--- import/Ubuntu/Content/contentpeermodel.h 1970-01-01 00:00:00 +0000
2555+++ import/Ubuntu/Content/contentpeermodel.h 2014-03-20 13:33:31 +0000
2556@@ -0,0 +1,67 @@
2557+/*
2558+ * Copyright 2013 Canonical Ltd.
2559+ *
2560+ * This program is free software; you can redistribute it and/or modify
2561+ * it under the terms of the GNU Lesser General Public License as published by
2562+ * the Free Software Foundation; version 3.
2563+ *
2564+ * This program is distributed in the hope that it will be useful,
2565+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2566+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2567+ * GNU Lesser General Public License for more details.
2568+ *
2569+ * You should have received a copy of the GNU Lesser General Public License
2570+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2571+ */
2572+
2573+#ifndef COM_UBUNTU_CONTENTPEERMODEL_H_
2574+#define COM_UBUNTU_CONTENTPEERMODEL_H_
2575+
2576+#include "contentpeer.h"
2577+#include "contenttype.h"
2578+#include "contenthandler.h"
2579+#include <com/ubuntu/content/hub.h>
2580+
2581+#include <QObject>
2582+#include <QVariant>
2583+#include <QQmlListProperty>
2584+#include <QQmlParserStatus>
2585+
2586+class ContentPeerModel : public QObject, public QQmlParserStatus
2587+{
2588+ Q_OBJECT
2589+ Q_INTERFACES(QQmlParserStatus)
2590+ Q_PROPERTY(ContentType::Type contentType READ contentType WRITE setContentType NOTIFY contentTypeChanged)
2591+ Q_PROPERTY(ContentHandler::Handler handler READ handler WRITE setHandler NOTIFY handlerChanged)
2592+ Q_PROPERTY(QQmlListProperty<ContentPeer> peers READ peers NOTIFY peersChanged)
2593+
2594+public:
2595+ ContentPeerModel(QObject *parent = nullptr);
2596+
2597+ void classBegin();
2598+ void componentComplete();
2599+ ContentType::Type contentType();
2600+ void setContentType(ContentType::Type contentType);
2601+ void appendPeersForContentType(ContentType::Type contentType);
2602+ ContentHandler::Handler handler();
2603+ void setHandler(ContentHandler::Handler handler);
2604+ QQmlListProperty<ContentPeer> peers();
2605+
2606+Q_SIGNALS:
2607+ void contentTypeChanged();
2608+ void handlerChanged();
2609+ void peersChanged();
2610+ void findPeersCompleted();
2611+
2612+public Q_SLOTS:
2613+ void findPeers();
2614+
2615+private:
2616+ com::ubuntu::content::Hub *m_hub;
2617+ ContentType::Type m_contentType;
2618+ ContentHandler::Handler m_handler;
2619+ QList<ContentPeer *> m_peers;
2620+ bool m_complete;
2621+};
2622+
2623+#endif // COM_UBUNTU_CONTENTPEERMODEL_H_
2624
2625=== added file 'import/Ubuntu/Content/contentscope.cpp'
2626--- import/Ubuntu/Content/contentscope.cpp 1970-01-01 00:00:00 +0000
2627+++ import/Ubuntu/Content/contentscope.cpp 2014-03-20 13:33:31 +0000
2628@@ -0,0 +1,68 @@
2629+/*
2630+ * Copyright 2013 Canonical Ltd.
2631+ *
2632+ * This program is free software; you can redistribute it and/or modify
2633+ * it under the terms of the GNU Lesser General Public License as published by
2634+ * the Free Software Foundation; version 3.
2635+ *
2636+ * This program is distributed in the hope that it will be useful,
2637+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2638+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2639+ * GNU Lesser General Public License for more details.
2640+ *
2641+ * You should have received a copy of the GNU Lesser General Public License
2642+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2643+ */
2644+
2645+#include "contentscope.h"
2646+
2647+#include <QDebug>
2648+
2649+/*!
2650+ \qmltype ContentScope
2651+ \instantiates ContentScope
2652+ \inqmlmodule Ubuntu.Content 0.1
2653+
2654+ \sa ContentStore
2655+
2656+ \e {ContentScope} is an enumeration of scope types:
2657+ \table
2658+ \header
2659+ \li Scope
2660+ \row
2661+ \li ContentScope.System
2662+ \row
2663+ \li ContentScope.User
2664+ \row
2665+ \li ContentScope.App
2666+ \endtable
2667+ */
2668+
2669+ContentScope::ContentScope(QObject *parent)
2670+ : QObject(parent)
2671+{
2672+ qDebug() << Q_FUNC_INFO;
2673+}
2674+
2675+/*!
2676+ * \brief ContentScope::contentScope2HubScope converts a ContentScope::Scope to a
2677+ * com::ubuntu::content::Scope
2678+ * \internal
2679+ */
2680+com::ubuntu::content::Scope ContentScope::contentScope2HubScope(int scope)
2681+{
2682+ Scope cscope = static_cast<Scope>(scope);
2683+ qDebug() << Q_FUNC_INFO << cscope;
2684+ return contentScope2HubScope(cscope);
2685+}
2686+
2687+/*!
2688+ * \brief ContentScope::contentScope2HubScope converts a ContentScope::Scope to a
2689+ * com::ubuntu::content::Scope
2690+ * \internal
2691+ */
2692+com::ubuntu::content::Scope ContentScope::contentScope2HubScope(Scope scope)
2693+{
2694+ return static_cast<com::ubuntu::content::Scope>(scope);
2695+}
2696+
2697
2698=== added file 'import/Ubuntu/Content/contentscope.h'
2699--- import/Ubuntu/Content/contentscope.h 1970-01-01 00:00:00 +0000
2700+++ import/Ubuntu/Content/contentscope.h 2014-03-20 13:33:31 +0000
2701@@ -0,0 +1,43 @@
2702+/*
2703+ * Copyright 2013 Canonical Ltd.
2704+ *
2705+ * This program is free software; you can redistribute it and/or modify
2706+ * it under the terms of the GNU Lesser General Public License as published by
2707+ * the Free Software Foundation; version 3.
2708+ *
2709+ * This program is distributed in the hope that it will be useful,
2710+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2711+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2712+ * GNU Lesser General Public License for more details.
2713+ *
2714+ * You should have received a copy of the GNU Lesser General Public License
2715+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2716+ */
2717+
2718+#ifndef COM_UBUNTU_CONTENTSCOPE_H_
2719+#define COM_UBUNTU_CONTENTSCOPE_H_
2720+
2721+#include <com/ubuntu/content/scope.h>
2722+
2723+#include <QObject>
2724+
2725+class ContentScope : public QObject
2726+{
2727+ Q_OBJECT
2728+ Q_ENUMS(Scope)
2729+
2730+public:
2731+ enum Scope {
2732+ System = 0,
2733+ User = 1,
2734+ App = 2
2735+ };
2736+
2737+ ContentScope(QObject *parent = nullptr);
2738+
2739+ static com::ubuntu::content::Scope contentScope2HubScope(int scope);
2740+ static com::ubuntu::content::Scope contentScope2HubScope(Scope scope);
2741+
2742+};
2743+
2744+#endif // COM_UBUNTU_CONTENTSCOPE_H_
2745
2746=== modified file 'import/Ubuntu/Content/contentstore.cpp'
2747--- import/Ubuntu/Content/contentstore.cpp 2013-10-22 20:44:52 +0000
2748+++ import/Ubuntu/Content/contentstore.cpp 2014-03-20 13:33:31 +0000
2749@@ -14,7 +14,9 @@
2750 * along with this program. If not, see <http://www.gnu.org/licenses/>.
2751 */
2752
2753+#include "contentpeer.h"
2754 #include "contentstore.h"
2755+#include "contenttype.h"
2756
2757 #include <QDebug>
2758
2759@@ -23,16 +25,20 @@
2760 * \instantiates ContentStore
2761 * \inqmlmodule Ubuntu.Content 0.1
2762 *
2763- * See documentation for ContentHub
2764+ * A ContentStore allows for the permanent storage of a transfered item.
2765+ *
2766+ * See documentation for ContentHub and ContentScope
2767 */
2768
2769 namespace cuc = com::ubuntu::content;
2770
2771 ContentStore::ContentStore(QObject *parent)
2772 : QObject(parent),
2773- m_store(0)
2774+ m_store(0),
2775+ m_scope(ContentScope::System)
2776 {
2777 qDebug() << Q_FUNC_INFO;
2778+ m_hub = cuc::Hub::Client::instance();
2779 }
2780
2781 /*!
2782@@ -42,7 +48,14 @@
2783 */
2784 const QString &ContentStore::uri() const
2785 {
2786+ static const QString __empty;
2787+
2788 qDebug() << Q_FUNC_INFO;
2789+
2790+ if ( ! m_store) {
2791+ qWarning() << "Accessing ContentStore uri with NULL internal store";
2792+ return __empty;
2793+ }
2794 return m_store->uri();
2795 }
2796
2797@@ -63,9 +76,43 @@
2798 void ContentStore::setStore(const com::ubuntu::content::Store *store)
2799 {
2800 qDebug() << Q_FUNC_INFO;
2801- //if (store == m_store)
2802- // return;
2803-
2804 m_store = store;
2805 Q_EMIT uriChanged();
2806 }
2807+
2808+/*!
2809+ * \qmlproperty ContentScope ContentStore::scope
2810+ *
2811+ * Specifies the ContentScope for this store.
2812+ */
2813+ContentScope::Scope ContentStore::scope()
2814+{
2815+ qDebug() << Q_FUNC_INFO;
2816+ return m_scope;
2817+}
2818+
2819+/*!
2820+ * \brief ContentStore::setScope
2821+ * \internal
2822+ */
2823+void ContentStore::setScope(ContentScope::Scope scope)
2824+{
2825+ qDebug() << Q_FUNC_INFO;
2826+ m_scope = scope;
2827+
2828+ Q_EMIT scopeChanged();
2829+}
2830+
2831+/*!
2832+ * \brief ContentStore::updateStore
2833+ * \internal
2834+ */
2835+void ContentStore::updateStore(ContentType::Type contentType)
2836+{
2837+ qDebug() << Q_FUNC_INFO;
2838+
2839+ com::ubuntu::content::Scope hubScope = ContentScope::contentScope2HubScope(m_scope);
2840+ const com::ubuntu::content::Type &hubType = ContentType::contentType2HubType(contentType);
2841+ setStore(m_hub->store_for_scope_and_type(hubScope, hubType));
2842+}
2843+
2844
2845=== modified file 'import/Ubuntu/Content/contentstore.h'
2846--- import/Ubuntu/Content/contentstore.h 2013-09-30 13:30:45 +0000
2847+++ import/Ubuntu/Content/contentstore.h 2014-03-20 13:33:31 +0000
2848@@ -17,6 +17,9 @@
2849 #ifndef COM_UBUNTU_CONTENTSTORE_H_
2850 #define COM_UBUNTU_CONTENTSTORE_H_
2851
2852+#include "contentscope.h"
2853+#include "contenttype.h"
2854+#include <com/ubuntu/content/hub.h>
2855 #include <com/ubuntu/content/store.h>
2856
2857 #include <QObject>
2858@@ -26,6 +29,7 @@
2859 {
2860 Q_OBJECT
2861 Q_PROPERTY(QString uri READ uri NOTIFY uriChanged)
2862+ Q_PROPERTY(ContentScope::Scope scope READ scope WRITE setScope NOTIFY scopeChanged)
2863
2864 public:
2865 ContentStore(QObject *parent = nullptr);
2866@@ -35,11 +39,19 @@
2867 const com::ubuntu::content::Store *store() const;
2868 void setStore(const com::ubuntu::content::Store *store);
2869
2870+ ContentScope::Scope scope();
2871+ void setScope(ContentScope::Scope scope);
2872+
2873+ void updateStore(ContentType::Type type);
2874+
2875 Q_SIGNALS:
2876 void uriChanged();
2877+ void scopeChanged();
2878
2879 private:
2880+ com::ubuntu::content::Hub *m_hub;
2881 const com::ubuntu::content::Store *m_store;
2882+ ContentScope::Scope m_scope;
2883 };
2884
2885 #endif // COM_UBUNTU_CONTENTSTORE_H_
2886
2887=== modified file 'import/Ubuntu/Content/contenttransfer.cpp'
2888--- import/Ubuntu/Content/contenttransfer.cpp 2013-10-22 20:44:52 +0000
2889+++ import/Ubuntu/Content/contenttransfer.cpp 2014-03-20 13:33:31 +0000
2890@@ -82,18 +82,24 @@
2891
2892 void ContentTransfer::setState(ContentTransfer::State state)
2893 {
2894- qDebug() << Q_FUNC_INFO;
2895+ qDebug() << Q_FUNC_INFO << state;
2896 if (!m_transfer)
2897 return;
2898
2899- if (state == Charged && m_state == InProgress && m_direction == Export) {
2900+ if (state == Charged && m_state == InProgress) {
2901+ qDebug() << Q_FUNC_INFO << "Charged";
2902 QVector<cuc::Item> hubItems;
2903 hubItems.reserve(m_items.size());
2904- foreach (const ContentItem *citem, m_items) {
2905+ Q_FOREACH (const ContentItem *citem, m_items) {
2906 hubItems.append(citem->item());
2907 }
2908 m_transfer->charge(hubItems);
2909- }
2910+ return;
2911+ } else if (state == Aborted) {
2912+ qDebug() << Q_FUNC_INFO << "Aborted";
2913+ m_transfer->abort();
2914+ } else
2915+ updateState();
2916 }
2917
2918 /*!
2919@@ -112,6 +118,9 @@
2920 \row
2921 \li ContentTransfer.Export
2922 \li Transfer is a request to export content.
2923+ \row
2924+ \li ContentTransfer.Share
2925+ \li Transfer is a request to share content.
2926 \endtable
2927 */
2928 ContentTransfer::Direction ContentTransfer::direction() const
2929@@ -161,7 +170,7 @@
2930 QQmlListProperty<ContentItem> ContentTransfer::items()
2931 {
2932 qDebug() << Q_FUNC_INFO;
2933- if (m_state == Charged && m_direction == Import) {
2934+ if (m_state == Charged) {
2935 collectItems();
2936 }
2937 return QQmlListProperty<ContentItem>(this, m_items);
2938@@ -174,7 +183,7 @@
2939 */
2940 bool ContentTransfer::start()
2941 {
2942- qDebug() << Q_FUNC_INFO;
2943+ qDebug() << Q_FUNC_INFO << m_transfer->id() << ":" << m_state;
2944 if (m_state == Created) {
2945 return m_transfer->start();
2946 } else {
2947@@ -213,7 +222,10 @@
2948 qWarning() << Q_FUNC_INFO << "invalid transfer";
2949 return;
2950 }
2951- m_transfer->setStore(contentStore->store());
2952+
2953+ if(contentStore->store() != nullptr) {
2954+ m_transfer->setStore(contentStore->store());
2955+ }
2956 }
2957
2958 /*!
2959@@ -230,7 +242,7 @@
2960 * \brief ContentTransfer::setTransfer
2961 * \internal
2962 */
2963-void ContentTransfer::setTransfer(com::ubuntu::content::Transfer *transfer, Direction direction)
2964+void ContentTransfer::setTransfer(com::ubuntu::content::Transfer *transfer)
2965 {
2966 if (m_transfer) {
2967 qWarning() << Q_FUNC_INFO << "the transfer object was already set";
2968@@ -242,21 +254,17 @@
2969 return;
2970 }
2971
2972- qDebug() << Q_FUNC_INFO;
2973-
2974- m_direction = direction;
2975 m_transfer = transfer;
2976+ m_direction = static_cast<ContentTransfer::Direction>(transfer->direction());
2977+ qDebug() << Q_FUNC_INFO << "Direction:" << m_direction;
2978+
2979+ connect(m_transfer, SIGNAL(selectionTypeChanged()), this, SLOT(updateSelectionType()));
2980+ connect(m_transfer, SIGNAL(storeChanged()), this, SLOT(updateStore()));
2981+ connect(m_transfer, SIGNAL(stateChanged()), this, SLOT(updateState()));
2982
2983 updateSelectionType();
2984 updateStore();
2985 updateState();
2986-
2987- if (m_state == Charged && m_direction == Import)
2988- collectItems();
2989-
2990- connect(m_transfer, SIGNAL(selectionTypeChanged()), this, SLOT(updateSelectionType()));
2991- connect(m_transfer, SIGNAL(storeChanged()), this, SLOT(updateStore()));
2992- connect(m_transfer, SIGNAL(stateChanged()), this, SLOT(updateState()));
2993 }
2994
2995 /*!
2996@@ -266,14 +274,14 @@
2997 void ContentTransfer::collectItems()
2998 {
2999 qDebug() << Q_FUNC_INFO;
3000- if (m_state != Charged || m_direction != Import)
3001+ if (m_state != Charged)
3002 return;
3003
3004 qDeleteAll(m_items);
3005 m_items.clear();
3006
3007 QVector<cuc::Item> transfereditems = m_transfer->collect();
3008- foreach (const cuc::Item &hubItem, transfereditems) {
3009+ Q_FOREACH (const cuc::Item &hubItem, transfereditems) {
3010 ContentItem *qmlItem = new ContentItem(this);
3011 qmlItem->setItem(hubItem);
3012 m_items.append(qmlItem);
3013@@ -287,9 +295,13 @@
3014 */
3015 void ContentTransfer::updateState()
3016 {
3017- qDebug() << Q_FUNC_INFO;
3018+ qDebug() << Q_FUNC_INFO << m_transfer->state();
3019+
3020 if (!m_transfer)
3021+ {
3022+ qWarning() << Q_FUNC_INFO << "Invalid transfer";
3023 return;
3024+ }
3025
3026 m_state = static_cast<ContentTransfer::State>(m_transfer->state());
3027 Q_EMIT stateChanged();
3028@@ -303,7 +315,10 @@
3029 {
3030 qDebug() << Q_FUNC_INFO;
3031 if (!m_transfer)
3032+ {
3033+ qWarning() << Q_FUNC_INFO << "Invalid transfer";
3034 return;
3035+ }
3036
3037 m_selectionType = static_cast<ContentTransfer::SelectionType>(m_transfer->selectionType());
3038 Q_EMIT selectionTypeChanged();
3039@@ -318,7 +333,10 @@
3040 {
3041 qDebug() << Q_FUNC_INFO;
3042 if (!m_transfer)
3043+ {
3044+ qWarning() << Q_FUNC_INFO << "Invalid transfer";
3045 return;
3046+ }
3047
3048 m_store = m_transfer->store();
3049 Q_EMIT storeChanged();
3050
3051=== modified file 'import/Ubuntu/Content/contenttransfer.h'
3052--- import/Ubuntu/Content/contenttransfer.h 2013-10-21 17:16:57 +0000
3053+++ import/Ubuntu/Content/contenttransfer.h 2014-03-20 13:33:31 +0000
3054@@ -51,8 +51,9 @@
3055 Finalized = com::ubuntu::content::Transfer::finalized
3056 };
3057 enum Direction {
3058- Import,
3059- Export
3060+ Import = com::ubuntu::content::Transfer::Import,
3061+ Export = com::ubuntu::content::Transfer::Export,
3062+ Share = com::ubuntu::content::Transfer::Share
3063 };
3064 enum SelectionType {
3065 Single = com::ubuntu::content::Transfer::SelectionType::single,
3066@@ -78,7 +79,7 @@
3067 Q_INVOKABLE void setStore(ContentStore *contentStore);
3068
3069 com::ubuntu::content::Transfer *transfer() const;
3070- void setTransfer(com::ubuntu::content::Transfer *transfer, Direction direction);
3071+ void setTransfer(com::ubuntu::content::Transfer *transfer);
3072
3073 void collectItems();
3074
3075
3076=== modified file 'import/Ubuntu/Content/contenttype.cpp'
3077--- import/Ubuntu/Content/contenttype.cpp 2013-12-10 15:59:15 +0000
3078+++ import/Ubuntu/Content/contenttype.cpp 2014-03-20 13:33:31 +0000
3079@@ -44,7 +44,10 @@
3080 \li Music
3081 \row
3082 \li ContentType.Contacts
3083- \li Music
3084+ \li Contacts
3085+ \row
3086+ \li ContentType.All
3087+ \li Any of the above content types
3088 \endtable
3089 */
3090
3091
3092=== modified file 'import/Ubuntu/Content/contenttype.h'
3093--- import/Ubuntu/Content/contenttype.h 2013-12-10 15:59:15 +0000
3094+++ import/Ubuntu/Content/contenttype.h 2014-03-20 13:33:31 +0000
3095@@ -29,6 +29,7 @@
3096
3097 public:
3098 enum Type {
3099+ All = -1,
3100 Unknown = 0,
3101 Documents = 1,
3102 Pictures = 2,
3103
3104=== modified file 'import/Ubuntu/Content/qmldir'
3105--- import/Ubuntu/Content/qmldir 2013-09-27 13:11:45 +0000
3106+++ import/Ubuntu/Content/qmldir 2014-03-20 13:33:31 +0000
3107@@ -1,4 +1,5 @@
3108 module Ubuntu.Content
3109 plugin ubuntu-content-hub-plugin
3110
3111-ContentImportHint 0.1 ContentImportHint.qml
3112+ContentTransferHint 0.1 ContentTransferHint.qml
3113+ContentPeerPicker 0.1 ContentPeerPicker.qml
3114
3115=== modified file 'import/Ubuntu/Content/qmlimportexporthandler.cpp'
3116--- import/Ubuntu/Content/qmlimportexporthandler.cpp 2013-08-23 15:51:35 +0000
3117+++ import/Ubuntu/Content/qmlimportexporthandler.cpp 2014-03-20 13:33:31 +0000
3118@@ -50,3 +50,11 @@
3119 Q_EMIT exportRequested(transfer);
3120 }
3121
3122+/*!
3123+ * \reimp
3124+ */
3125+void QmlImportExportHandler::handle_share(com::ubuntu::content::Transfer *transfer)
3126+{
3127+ qDebug() << Q_FUNC_INFO;
3128+ Q_EMIT shareRequested(transfer);
3129+}
3130
3131=== modified file 'import/Ubuntu/Content/qmlimportexporthandler.h'
3132--- import/Ubuntu/Content/qmlimportexporthandler.h 2013-08-23 15:51:35 +0000
3133+++ import/Ubuntu/Content/qmlimportexporthandler.h 2014-03-20 13:33:31 +0000
3134@@ -36,10 +36,12 @@
3135
3136 Q_INVOKABLE virtual void handle_import(com::ubuntu::content::Transfer *transfer);
3137 Q_INVOKABLE virtual void handle_export(com::ubuntu::content::Transfer *transfer);
3138+ Q_INVOKABLE virtual void handle_share(com::ubuntu::content::Transfer *transfer);
3139
3140 Q_SIGNALS:
3141 void importRequested(com::ubuntu::content::Transfer*);
3142 void exportRequested(com::ubuntu::content::Transfer*);
3143+ void shareRequested(com::ubuntu::content::Transfer*);
3144 };
3145
3146 #endif // COM_UBUNTU_QMLIMPORTEXPORTHANDLER_H_
3147
3148=== modified file 'include/com/ubuntu/content/hub.h'
3149--- include/com/ubuntu/content/hub.h 2013-09-10 14:11:37 +0000
3150+++ include/com/ubuntu/content/hub.h 2014-03-20 13:33:31 +0000
3151@@ -51,9 +51,14 @@
3152
3153 Q_INVOKABLE virtual void register_import_export_handler(ImportExportHandler* handler);
3154 Q_INVOKABLE virtual const Store* store_for_scope_and_type(Scope scope, Type type);
3155- Q_INVOKABLE virtual Peer default_peer_for_type(Type type);
3156- Q_INVOKABLE virtual QVector<Peer> known_peers_for_type(Type type);
3157- Q_INVOKABLE virtual Transfer* create_import_for_type_from_peer(Type type, Peer peer);
3158+ Q_INVOKABLE virtual Peer default_source_for_type(Type type);
3159+ Q_INVOKABLE virtual QVector<Peer> known_sources_for_type(Type type);
3160+ Q_INVOKABLE virtual QVector<Peer> known_destinations_for_type(Type type);
3161+ Q_INVOKABLE virtual QVector<Peer> known_shares_for_type(Type type);
3162+ Q_INVOKABLE virtual Transfer* create_import_from_peer(Peer peer);
3163+ Q_INVOKABLE virtual Transfer* create_export_to_peer(Peer peer);
3164+ Q_INVOKABLE virtual Transfer* create_share_to_peer(Peer peer);
3165+
3166
3167 Q_INVOKABLE virtual void quit();
3168
3169
3170=== modified file 'include/com/ubuntu/content/import_export_handler.h'
3171--- include/com/ubuntu/content/import_export_handler.h 2013-08-15 13:01:40 +0000
3172+++ include/com/ubuntu/content/import_export_handler.h 2014-03-20 13:33:31 +0000
3173@@ -38,6 +38,7 @@
3174
3175 Q_INVOKABLE virtual void handle_import(Transfer*) = 0;
3176 Q_INVOKABLE virtual void handle_export(Transfer*) = 0;
3177+ Q_INVOKABLE virtual void handle_share(Transfer*) = 0;
3178
3179 protected:
3180 ImportExportHandler(QObject* parent = nullptr);
3181
3182=== modified file 'include/com/ubuntu/content/peer.h'
3183--- include/com/ubuntu/content/peer.h 2013-10-01 16:55:39 +0000
3184+++ include/com/ubuntu/content/peer.h 2014-03-20 13:33:31 +0000
3185@@ -18,8 +18,10 @@
3186 #ifndef COM_UBUNTU_CONTENT_PEER_H_
3187 #define COM_UBUNTU_CONTENT_PEER_H_
3188
3189+#include <QtDBus>
3190 #include <QObject>
3191 #include <QSharedPointer>
3192+#include <QImage>
3193
3194 namespace com
3195 {
3196@@ -30,13 +32,14 @@
3197 class Peer : public QObject
3198 {
3199 Q_OBJECT
3200- Q_PROPERTY(QString id READ id())
3201- Q_PROPERTY(QString name READ name())
3202+ Q_PROPERTY(QString id READ id)
3203+ Q_PROPERTY(QString name READ name WRITE setName)
3204+ Q_PROPERTY(QString iconName READ iconName WRITE setIconName)
3205+ Q_PROPERTY(bool isDefaultPeer READ isDefaultPeer)
3206
3207 public:
3208 static const Peer& unknown();
3209-
3210- Peer(const QString& id = QString(), QObject* parent = nullptr);
3211+ Peer(const QString& id = QString(), bool isDefaultPeer = false, QObject* parent = nullptr);
3212 Peer(const Peer& rhs);
3213 virtual ~Peer();
3214
3215@@ -44,7 +47,13 @@
3216 bool operator==(const Peer& rhs) const;
3217
3218 Q_INVOKABLE virtual const QString& id() const;
3219- Q_INVOKABLE virtual QString name();
3220+ Q_INVOKABLE virtual QString name() const;
3221+ Q_INVOKABLE void setName(const QString&);
3222+ Q_INVOKABLE virtual QByteArray iconData() const;
3223+ Q_INVOKABLE void setIconData(const QByteArray&);
3224+ Q_INVOKABLE virtual QString iconName() const;
3225+ Q_INVOKABLE void setIconName(const QString&);
3226+ Q_INVOKABLE virtual bool isDefaultPeer() const;
3227
3228 private:
3229 struct Private;
3230@@ -54,4 +63,14 @@
3231 }
3232 }
3233
3234+Q_DECL_EXPORT
3235+QDBusArgument &operator<<(QDBusArgument &argument,
3236+ const com::ubuntu::content::Peer &peer);
3237+
3238+Q_DECL_EXPORT
3239+const QDBusArgument &operator>>(const QDBusArgument &argument,
3240+ com::ubuntu::content::Peer &peer);
3241+
3242+Q_DECLARE_METATYPE(com::ubuntu::content::Peer)
3243+
3244 #endif // COM_UBUNTU_CONTENT_PEER_H_
3245
3246=== modified file 'include/com/ubuntu/content/transfer.h'
3247--- include/com/ubuntu/content/transfer.h 2013-10-01 16:55:39 +0000
3248+++ include/com/ubuntu/content/transfer.h 2014-03-20 13:33:31 +0000
3249@@ -52,11 +52,13 @@
3250 Q_OBJECT
3251 Q_ENUMS(State)
3252 Q_ENUMS(SelectionType)
3253+ Q_ENUMS(Direction)
3254 Q_PROPERTY(int id READ id)
3255 Q_PROPERTY(State state READ state NOTIFY stateChanged)
3256 Q_PROPERTY(QVector<Item> items READ collect WRITE charge)
3257 Q_PROPERTY(Store store READ store NOTIFY storeChanged)
3258 Q_PROPERTY(SelectionType selectionType READ selectionType WRITE setSelectionType NOTIFY selectionTypeChanged)
3259+ Q_PROPERTY(Direction direction READ direction)
3260
3261 public:
3262 enum State
3263@@ -76,6 +78,13 @@
3264 multiple
3265 };
3266
3267+ enum Direction
3268+ {
3269+ Import,
3270+ Export,
3271+ Share
3272+ };
3273+
3274 Transfer(const Transfer&) = delete;
3275 virtual ~Transfer();
3276
3277@@ -84,6 +93,7 @@
3278 Q_INVOKABLE virtual int id() const;
3279 Q_INVOKABLE virtual State state() const;
3280 Q_INVOKABLE virtual SelectionType selectionType() const;
3281+ Q_INVOKABLE virtual Direction direction() const;
3282 Q_INVOKABLE virtual bool start();
3283 Q_INVOKABLE virtual bool abort();
3284 Q_INVOKABLE virtual bool finalize();
3285
3286=== modified file 'include/com/ubuntu/content/type.h'
3287--- include/com/ubuntu/content/type.h 2013-12-10 15:59:15 +0000
3288+++ include/com/ubuntu/content/type.h 2014-03-20 13:33:31 +0000
3289@@ -30,6 +30,7 @@
3290 namespace detail
3291 {
3292 class Service;
3293+class Hook;
3294 }
3295 class Type : public QObject
3296 {
3297@@ -59,6 +60,7 @@
3298 protected:
3299 friend struct Known;
3300 friend class detail::Service;
3301+ friend class detail::Hook;
3302
3303 explicit Type(const QString&, QObject* = nullptr);
3304
3305
3306=== modified file 'libcontent-hub.pc.in'
3307--- libcontent-hub.pc.in 2013-09-30 21:28:46 +0000
3308+++ libcontent-hub.pc.in 2014-03-20 13:33:31 +0000
3309@@ -1,8 +1,11 @@
3310 prefix=@prefix@
3311 exec_prefix=@exec_prefix@
3312 libdir=@libdir@
3313+includedir=${prefix}/include
3314
3315 Name: @pkg-name@
3316 Description: content sharing/picking library
3317 Version: @CONTENT_HUB_VERSION@
3318 Libs: -L${libdir} -lcontent-hub
3319+Cflags: -I${includedir}
3320+Requires: Qt5DBus
3321
3322=== modified file 'src/com/ubuntu/content/CMakeLists.txt'
3323--- src/com/ubuntu/content/CMakeLists.txt 2013-12-06 12:38:33 +0000
3324+++ src/com/ubuntu/content/CMakeLists.txt 2014-03-20 13:33:31 +0000
3325@@ -20,6 +20,7 @@
3326 ${CMAKE_CURRENT_BINARY_DIR}
3327 ${CMAKE_SOURCE_DIR}/src
3328 ${CMAKE_SOURCE_DIR}
3329+ ${CMAKE_SOURCE_DIR}/include
3330 ${GLIB_INCLUDE_DIRS}
3331 ${GIO_INCLUDE_DIRS}
3332 ${NIH_INCLUDE_DIRS}
3333@@ -91,7 +92,7 @@
3334 AUTOMOC TRUE
3335 )
3336
3337-qt5_use_modules(content-hub Core DBus)
3338+qt5_use_modules(content-hub Core DBus Gui)
3339
3340 target_link_libraries(content-hub
3341 ${UPSTART_LAUNCH_LDFLAGS}
3342
3343=== modified file 'src/com/ubuntu/content/detail/app_manager.cpp'
3344--- src/com/ubuntu/content/detail/app_manager.cpp 2013-12-06 12:36:31 +0000
3345+++ src/com/ubuntu/content/detail/app_manager.cpp 2014-03-20 13:33:31 +0000
3346@@ -17,14 +17,17 @@
3347 #include "app_manager.h"
3348
3349 #include <upstart-app-launch.h>
3350+#include <QDebug>
3351
3352 namespace cucd = com::ubuntu::content::detail;
3353
3354 /*!
3355 * \reimp
3356 */
3357+
3358 bool cucd::AppManager::invoke_application(const std::string &app_id)
3359 {
3360+ qDebug() << Q_FUNC_INFO << "APP_ID:" << app_id.c_str();
3361 gchar ** uris = NULL;
3362 gboolean ok = upstart_app_launch_start_application(app_id.c_str(), (const gchar * const *)uris);
3363 return static_cast<bool>(ok);
3364@@ -35,6 +38,8 @@
3365 */
3366 bool cucd::AppManager::stop_application(const std::string &app_id)
3367 {
3368+ qDebug() << Q_FUNC_INFO << "APP_ID:" << app_id.c_str();
3369+
3370 gboolean ok = upstart_app_launch_stop_application(app_id.c_str());
3371 return static_cast<bool>(ok);
3372 }
3373
3374=== modified file 'src/com/ubuntu/content/detail/com.ubuntu.content.Handler.xml'
3375--- src/com/ubuntu/content/detail/com.ubuntu.content.Handler.xml 2013-08-22 12:48:30 +0000
3376+++ src/com/ubuntu/content/detail/com.ubuntu.content.Handler.xml 2014-03-20 13:33:31 +0000
3377@@ -6,5 +6,8 @@
3378 <method name="HandleExport">
3379 <arg name="transfer" type="o" direction="in"/>
3380 </method>
3381+ <method name="HandleShare">
3382+ <arg name="transfer" type="o" direction="in"/>
3383+ </method>
3384 </interface>
3385 </node>
3386
3387=== modified file 'src/com/ubuntu/content/detail/com.ubuntu.content.Service.xml'
3388--- src/com/ubuntu/content/detail/com.ubuntu.content.Service.xml 2013-09-10 14:11:37 +0000
3389+++ src/com/ubuntu/content/detail/com.ubuntu.content.Service.xml 2014-03-20 13:33:31 +0000
3390@@ -2,23 +2,38 @@
3391 <interface name="com.ubuntu.content.dbus.Service">
3392 <method name="Quit">
3393 </method>
3394- <method name="DefaultPeerForType">
3395- <annotation name="com.trolltech.QtDBus.QtTypeName.In1" value="QVariantMap"/>
3396- <arg name="type_id" type="s" direction="in" />
3397- <arg name="peer_id" type="s" direction="out" />
3398- </method>
3399- <method name="KnownPeersForType">
3400- <arg name="type_id" type="s" direction="in" />
3401- <arg name="peer_ids" type="as" direction="out" />
3402- </method>
3403- <method name="CreateImportForTypeFromPeer">
3404- <arg name="type_id" type="s" direction="in" />
3405+ <method name="DefaultSourceForType">
3406+ <arg name="type_id" type="s" direction="in" />
3407+ <arg name="peer" type="v" direction="out" />
3408+ </method>
3409+ <method name="KnownSourcesForType">
3410+ <arg name="type_id" type="s" direction="in" />
3411+ <arg name="peers" type="av" direction="out" />
3412+ </method>
3413+ <method name="KnownDestinationsForType">
3414+ <arg name="type_id" type="s" direction="in" />
3415+ <arg name="peers" type="av" direction="out" />
3416+ </method>
3417+ <method name="KnownSharesForType">
3418+ <arg name="type_id" type="s" direction="in" />
3419+ <arg name="peers" type="av" direction="out" />
3420+ </method>
3421+ <method name="CreateImportFromPeer">
3422+ <arg name="peer_id" type="s" direction="in" />
3423+ <arg name="app_id" type="s" direction="in" />
3424+ <arg name="transfer_object" type="o" direction="out" />
3425+ </method>
3426+ <method name="CreateExportToPeer">
3427+ <arg name="peer_id" type="s" direction="in" />
3428+ <arg name="app_id" type="s" direction="in" />
3429+ <arg name="transfer_object" type="o" direction="out" />
3430+ </method>
3431+ <method name="CreateShareToPeer">
3432 <arg name="peer_id" type="s" direction="in" />
3433 <arg name="app_id" type="s" direction="in" />
3434 <arg name="transfer_object" type="o" direction="out" />
3435 </method>
3436 <method name="RegisterImportExportHandler">
3437- <arg name="type_id" type="s" direction="in" />
3438 <arg name="peer_id" type="s" direction="in" />
3439 <arg name="handler_object" type="o" direction="in" />
3440 </method>
3441
3442=== modified file 'src/com/ubuntu/content/detail/com.ubuntu.content.Transfer.xml'
3443--- src/com/ubuntu/content/detail/com.ubuntu.content.Transfer.xml 2013-10-01 16:55:39 +0000
3444+++ src/com/ubuntu/content/detail/com.ubuntu.content.Transfer.xml 2014-03-20 13:33:31 +0000
3445@@ -41,5 +41,8 @@
3446 <signal name="SelectionTypeChanged">
3447 <arg name="selection_type" type="i"/>
3448 </signal>
3449+ <method name="Direction">
3450+ <arg name="direction" type="i" direction="out" />
3451+ </method>
3452 </interface>
3453 </node>
3454
3455=== modified file 'src/com/ubuntu/content/detail/handler.cpp'
3456--- src/com/ubuntu/content/detail/handler.cpp 2013-09-09 18:07:14 +0000
3457+++ src/com/ubuntu/content/detail/handler.cpp 2014-03-20 13:33:31 +0000
3458@@ -21,6 +21,7 @@
3459 #include "utils.cpp"
3460
3461 #include <QObject>
3462+#include <QDebug>
3463
3464 namespace cucd = com::ubuntu::content::detail;
3465 namespace cuc = com::ubuntu::content;
3466@@ -48,11 +49,13 @@
3467 m_handler = handler;
3468 }
3469
3470-cucd::Handler::~Handler() {}
3471+cucd::Handler::~Handler() {
3472+ delete m_handler;
3473+}
3474
3475 void cucd::Handler::HandleImport(const QDBusObjectPath& transfer)
3476 {
3477- qDebug() << Q_FUNC_INFO;
3478+ qDebug() << Q_FUNC_INFO << transfer.path();
3479 cuc::Transfer* t = cuc::Transfer::Private::make_transfer(transfer, this);
3480
3481 qDebug() << Q_FUNC_INFO << "State:" << t->state();
3482@@ -62,7 +65,7 @@
3483
3484 void cucd::Handler::HandleExport(const QDBusObjectPath& transfer)
3485 {
3486- qDebug() << Q_FUNC_INFO;
3487+ qDebug() << Q_FUNC_INFO << transfer.path();
3488 cuc::Transfer* t = cuc::Transfer::Private::make_transfer(transfer, this);
3489
3490 qDebug() << Q_FUNC_INFO << "State:" << t->state();
3491@@ -72,3 +75,15 @@
3492 m_handler->handle_export(t);
3493 }
3494 }
3495+
3496+void cucd::Handler::HandleShare(const QDBusObjectPath& transfer)
3497+{
3498+ qDebug() << Q_FUNC_INFO;
3499+ cuc::Transfer* t = cuc::Transfer::Private::make_transfer(transfer, this);
3500+
3501+ qDebug() << Q_FUNC_INFO << "State:" << t->state();
3502+ if (t->state() == cuc::Transfer::charged)
3503+ {
3504+ m_handler->handle_share(t);
3505+ }
3506+}
3507
3508=== modified file 'src/com/ubuntu/content/detail/handler.h'
3509--- src/com/ubuntu/content/detail/handler.h 2013-09-06 13:18:05 +0000
3510+++ src/com/ubuntu/content/detail/handler.h 2014-03-20 13:33:31 +0000
3511@@ -48,6 +48,7 @@
3512 public Q_SLOTS:
3513 void HandleImport(const QDBusObjectPath &transfer);
3514 void HandleExport(const QDBusObjectPath &transfer);
3515+ void HandleShare(const QDBusObjectPath &transfer);
3516
3517 private:
3518 struct Private;
3519
3520=== modified file 'src/com/ubuntu/content/detail/peer_registry.h'
3521--- src/com/ubuntu/content/detail/peer_registry.h 2013-09-25 03:14:53 +0000
3522+++ src/com/ubuntu/content/detail/peer_registry.h 2014-03-20 13:33:31 +0000
3523@@ -40,12 +40,15 @@
3524
3525 PeerRegistry& operator=(const PeerRegistry&) = delete;
3526
3527- virtual Peer default_peer_for_type(Type) = 0;
3528- virtual void enumerate_known_peers_for_type(Type, const std::function<void(const Peer&)>& for_each) = 0;
3529+ virtual Peer default_source_for_type(Type) = 0;
3530 virtual void enumerate_known_peers(const std::function<void(const Peer&)>& for_each) = 0;
3531-
3532- virtual bool install_default_peer_for_type(Type, Peer) = 0;
3533- virtual bool install_peer_for_type(Type, Peer) = 0;
3534+ virtual void enumerate_known_sources_for_type(Type, const std::function<void(const Peer&)>& for_each) = 0;
3535+ virtual void enumerate_known_destinations_for_type(Type, const std::function<void(const Peer&)>& for_each) = 0;
3536+ virtual void enumerate_known_shares_for_type(Type, const std::function<void(const Peer&)>& for_each) = 0;
3537+ virtual bool install_default_source_for_type(Type, Peer) = 0;
3538+ virtual bool install_source_for_type(Type, Peer) = 0;
3539+ virtual bool install_destination_for_type(Type, Peer) = 0;
3540+ virtual bool install_share_for_type(Type, Peer) = 0;
3541 virtual bool remove_peer(Peer peer) = 0;
3542
3543
3544
3545=== modified file 'src/com/ubuntu/content/detail/service.cpp'
3546--- src/com/ubuntu/content/detail/service.cpp 2013-10-10 15:00:36 +0000
3547+++ src/com/ubuntu/content/detail/service.cpp 2014-03-20 13:33:31 +0000
3548@@ -22,14 +22,13 @@
3549 #include "transfer.h"
3550 #include "transferadaptor.h"
3551 #include "utils.cpp"
3552-
3553-#include "handler.h"
3554 #include "ContentHandlerInterface.h"
3555
3556 #include <com/ubuntu/content/peer.h>
3557 #include <com/ubuntu/content/type.h>
3558 #include <com/ubuntu/content/transfer.h>
3559
3560+#include <QDBusMetaType>
3561 #include <QCache>
3562 #include <QCoreApplication>
3563 #include <QDebug>
3564@@ -42,6 +41,19 @@
3565 namespace cucd = com::ubuntu::content::detail;
3566 namespace cuc = com::ubuntu::content;
3567
3568+struct cucd::Service::RegHandler
3569+{
3570+ RegHandler(QString id, QString service, cuc::dbus::Handler* handler) : id(id),
3571+ service(service),
3572+ handler(handler)
3573+ {
3574+ }
3575+
3576+ QString id;
3577+ QString service;
3578+ cuc::dbus::Handler* handler;
3579+};
3580+
3581 struct cucd::Service::Private : public QObject
3582 {
3583 Private(QDBusConnection connection,
3584@@ -58,7 +70,9 @@
3585 QDBusConnection connection;
3586 QSharedPointer<cucd::PeerRegistry> registry;
3587 QSet<cucd::Transfer*> active_transfers;
3588+ QSet<RegHandler*> handlers;
3589 QSharedPointer<cua::ApplicationManager> app_manager;
3590+
3591 };
3592
3593 cucd::Service::Service(QDBusConnection connection, const QSharedPointer<cucd::PeerRegistry>& peer_registry,
3594@@ -69,11 +83,13 @@
3595 {
3596 assert(!peer_registry.isNull());
3597
3598- m_watcher->setWatchMode(QDBusServiceWatcher::WatchForRegistration);
3599+ qDBusRegisterMetaType<cuc::Peer>();
3600+
3601+ m_watcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
3602 m_watcher->setConnection(d->connection);
3603- QObject::connect(m_watcher, SIGNAL(serviceRegistered(const QString&)),
3604+ QObject::connect(m_watcher, SIGNAL(serviceUnregistered(const QString&)),
3605 this,
3606- SLOT(handler_registered(const QString&)));
3607+ SLOT(handler_unregistered(const QString&)));
3608 }
3609
3610 cucd::Service::~Service()
3611@@ -86,172 +102,374 @@
3612 }
3613 }
3614
3615-void cucd::Service::handler_registered(const QString& name)
3616-{
3617- qDebug() << Q_FUNC_INFO << name;
3618- Q_FOREACH (cucd::Transfer *t, d->active_transfers)
3619- {
3620- if (handler_address(t->source()) == name)
3621- {
3622- qDebug() << Q_FUNC_INFO << "Found source:" << name;
3623- cuc::dbus::Handler *h = new cuc::dbus::Handler(
3624- name,
3625- handler_path(t->source()),
3626- QDBusConnection::sessionBus(),
3627- 0);
3628- if (h->isValid())
3629- h->HandleExport(QDBusObjectPath{t->export_path()});
3630- }
3631- else if (handler_address(t->destination()) == name)
3632- {
3633- qDebug() << Q_FUNC_INFO << "Found destination:" << name;
3634- cuc::dbus::Handler *h = new cuc::dbus::Handler(
3635- name,
3636- handler_path(t->destination()),
3637- QDBusConnection::sessionBus(),
3638- 0);
3639- if (h->isValid())
3640- h->HandleImport(QDBusObjectPath{t->import_path()});
3641- }
3642- }
3643-}
3644-
3645 void cucd::Service::Quit()
3646 {
3647 QCoreApplication::instance()->quit();
3648 }
3649
3650-QStringList cucd::Service::KnownPeersForType(const QString& type_id)
3651-{
3652- QStringList result;
3653-
3654- d->registry->enumerate_known_peers_for_type(
3655- Type(type_id),
3656- [&result](const Peer& peer)
3657- {
3658- result.append(peer.id());
3659- });
3660-
3661- return result;
3662-}
3663-
3664-QString cucd::Service::DefaultPeerForType(const QString& type_id)
3665-{
3666- auto peer = d->registry->default_peer_for_type(Type(type_id));
3667-
3668- return peer.id();
3669-}
3670-
3671-void cucd::Service::connect_export_handler(const QString& peer_id, const QString& transfer)
3672-{
3673- qDebug() << Q_FUNC_INFO;
3674-
3675- cuc::dbus::Handler *h = new cuc::dbus::Handler(
3676- handler_address(peer_id),
3677- handler_path(peer_id),
3678- QDBusConnection::sessionBus(),
3679- 0);
3680-
3681- qDebug() << Q_FUNC_INFO << "h->isValid:" << h->isValid();
3682- if (h->isValid() && (not transfer.isEmpty()))
3683- h->HandleExport(QDBusObjectPath{transfer});
3684-}
3685-
3686-void cucd::Service::connect_import_handler(const QString& peer_id, const QString& transfer)
3687-{
3688- qDebug() << Q_FUNC_INFO;
3689-
3690- cuc::dbus::Handler *h = new cuc::dbus::Handler(
3691- handler_address(peer_id),
3692- handler_path(peer_id),
3693- QDBusConnection::sessionBus(),
3694- 0);
3695-
3696- qDebug() << Q_FUNC_INFO << "h->isValid:" << h->isValid();
3697- if (h->isValid() && (not transfer.isEmpty()))
3698- h->HandleImport(QDBusObjectPath{transfer});
3699-}
3700-
3701-QDBusObjectPath cucd::Service::CreateImportForTypeFromPeer(const QString& type_id, const QString& peer_id, const QString& dest_id)
3702-{
3703- qDebug() << Q_FUNC_INFO;
3704+QVariantList cucd::Service::KnownSourcesForType(const QString& type_id)
3705+{
3706+ QVariantList result;
3707+
3708+ d->registry->enumerate_known_sources_for_type(
3709+ Type(type_id),
3710+ [&result](const Peer& peer)
3711+ {
3712+ result.append(QVariant::fromValue(peer));
3713+ });
3714+
3715+ return result;
3716+}
3717+
3718+QVariantList cucd::Service::KnownDestinationsForType(const QString& type_id)
3719+{
3720+ QVariantList result;
3721+
3722+ d->registry->enumerate_known_destinations_for_type(
3723+ Type(type_id),
3724+ [&result](const Peer& peer)
3725+ {
3726+ result.append(QVariant::fromValue(peer));
3727+ });
3728+
3729+ return result;
3730+}
3731+
3732+QVariantList cucd::Service::KnownSharesForType(const QString& type_id)
3733+{
3734+ QVariantList result;
3735+
3736+ d->registry->enumerate_known_shares_for_type(
3737+ Type(type_id),
3738+ [&result](const Peer& peer)
3739+ {
3740+ result.append(QVariant::fromValue(peer));
3741+ });
3742+
3743+ return result;
3744+}
3745+
3746+QDBusVariant cucd::Service::DefaultSourceForType(const QString& type_id)
3747+{
3748+ cuc::Peer peer = d->registry->default_source_for_type(Type(type_id));
3749+
3750+ return QDBusVariant(QVariant::fromValue(peer));
3751+}
3752+
3753+QDBusObjectPath cucd::Service::CreateImportFromPeer(const QString& peer_id, const QString& app_id)
3754+{
3755+ qDebug() << Q_FUNC_INFO;
3756+ QString dest_id = app_id;
3757+ if (dest_id.isEmpty())
3758+ {
3759+ qDebug() << Q_FUNC_INFO << "APP_ID isnt' set, attempting to get it from AppArmor";
3760+ dest_id = aa_profile(this->message().service());
3761+ }
3762+ return CreateTransfer(dest_id, peer_id, cuc::Transfer::Import);
3763+}
3764+
3765+bool cucd::Service::should_cancel (int st)
3766+{
3767+ qDebug() << Q_FUNC_INFO << "State:" << st;
3768+
3769+ return (st != cuc::Transfer::finalized
3770+ && st != cuc::Transfer::collected
3771+ && st != cuc::Transfer::aborted);
3772+}
3773+
3774+QDBusObjectPath cucd::Service::CreateExportToPeer(const QString& peer_id, const QString& app_id)
3775+{
3776+ qDebug() << Q_FUNC_INFO;
3777+ QString src_id = app_id;
3778+ if (src_id.isEmpty())
3779+ {
3780+ qDebug() << Q_FUNC_INFO << "APP_ID isnt' set, attempting to get it from AppArmor";
3781+ src_id = aa_profile(this->message().service());
3782+ }
3783+ return CreateTransfer(peer_id, src_id, cuc::Transfer::Export);
3784+}
3785+
3786+QDBusObjectPath cucd::Service::CreateShareToPeer(const QString& peer_id, const QString& app_id)
3787+{
3788+ qDebug() << Q_FUNC_INFO;
3789+ QString src_id = app_id;
3790+ if (src_id.isEmpty())
3791+ {
3792+ qDebug() << Q_FUNC_INFO << "APP_ID isnt' set, attempting to get it from AppArmor";
3793+ src_id = aa_profile(this->message().service());
3794+ }
3795+ return CreateTransfer(peer_id, src_id, cuc::Transfer::Share);
3796+}
3797+
3798+QDBusObjectPath cucd::Service::CreateTransfer(const QString& dest_id, const QString& src_id, int dir)
3799+{
3800+ qDebug() << Q_FUNC_INFO << "DEST:" << dest_id << "SRC:" << src_id << "DIRECTION:" << dir;
3801
3802 static size_t import_counter{0}; import_counter++;
3803
3804- QString app_id = dest_id;
3805- if (app_id.isEmpty())
3806- {
3807- qDebug() << Q_FUNC_INFO << "APP_ID isnt' set, attempting to get it from AppArmor";
3808- app_id = aa_profile(this->message().service());
3809- }
3810-
3811- qDebug() << Q_FUNC_INFO << "APP_ID:" << app_id;
3812-
3813 QUuid uuid{QUuid::createUuid()};
3814
3815- auto transfer = new cucd::Transfer(import_counter, peer_id, app_id, this);
3816+ Q_FOREACH (cucd::Transfer *t, d->active_transfers)
3817+ {
3818+ if (t->destination() == dest_id || t->source() == src_id)
3819+ {
3820+ qDebug() << Q_FUNC_INFO << "Found transfer for peer_id:" << src_id;
3821+ if (should_cancel(t->State()))
3822+ {
3823+ qDebug() << Q_FUNC_INFO << "Aborting active transfer:" << t->Id();
3824+ t->Abort();
3825+ }
3826+ }
3827+ }
3828+
3829+ auto transfer = new cucd::Transfer(import_counter, src_id, dest_id, dir, this);
3830 new TransferAdaptor(transfer);
3831 d->active_transfers.insert(transfer);
3832
3833 auto destination = transfer->import_path();
3834 auto source = transfer->export_path();
3835- if (not d->connection.registerObject(destination, transfer))
3836- qDebug() << "Problem registering object for path: " << destination;
3837- d->connection.registerObject(source, transfer);
3838+ if (not d->connection.registerObject(source, transfer))
3839+ qDebug() << "Problem registering object for path: " << source;
3840+ d->connection.registerObject(destination, transfer);
3841
3842 qDebug() << "Created transfer " << source << " -> " << destination;
3843
3844- connect(transfer, SIGNAL(StateChanged(int)), this, SLOT(handle_transfer(int)));
3845-
3846- /* watch for handlers */
3847- m_watcher->addWatchedService(handler_address(peer_id));
3848- qDebug() << Q_FUNC_INFO << "Watches:" << m_watcher->watchedServices();
3849- this->connect_export_handler(peer_id, source);
3850- this->connect_import_handler(app_id, destination);
3851-
3852- Q_UNUSED(type_id);
3853-
3854- return QDBusObjectPath{destination};
3855-}
3856-
3857-void cucd::Service::handle_transfer(int state)
3858+ // Content flow is different for import
3859+ if (dir == cuc::Transfer::Import)
3860+ {
3861+ connect(transfer, SIGNAL(StateChanged(int)), this, SLOT(handle_imports(int)));
3862+ return QDBusObjectPath{destination};
3863+ }
3864+
3865+ connect(transfer, SIGNAL(StateChanged(int)), this, SLOT(handle_exports(int)));
3866+ return QDBusObjectPath{source};
3867+}
3868+
3869+void cucd::Service::handle_imports(int state)
3870+{
3871+ qDebug() << Q_FUNC_INFO << state;
3872+ cucd::Transfer *transfer = static_cast<cucd::Transfer*>(sender());
3873+ qDebug() << Q_FUNC_INFO << "State: " << transfer->State() << "Id:" << transfer->Id();
3874+
3875+ if (state == cuc::Transfer::initiated)
3876+ {
3877+ qDebug() << Q_FUNC_INFO << "initiated";
3878+ if (d->app_manager->is_application_started(transfer->source().toStdString()))
3879+ transfer->SetSourceStartedByContentHub(false);
3880+ else
3881+ transfer->SetSourceStartedByContentHub(true);
3882+
3883+ Q_FOREACH (RegHandler *r, d->handlers)
3884+ {
3885+ qDebug() << Q_FUNC_INFO << "ID:" << r->id << "Handler: " << r->service << "Transfer: " << transfer->source();
3886+ if (r->id == transfer->source())
3887+ {
3888+ qDebug() << Q_FUNC_INFO << "Found handler for initiated transfer" << r->id;
3889+ if (r->handler->isValid())
3890+ r->handler->HandleExport(QDBusObjectPath{transfer->export_path()});
3891+ else
3892+ qDebug() << Q_FUNC_INFO << "Handler invalid";
3893+ }
3894+ }
3895+
3896+ d->app_manager->invoke_application(transfer->source().toStdString());
3897+ }
3898+
3899+ if (state == cuc::Transfer::charged)
3900+ {
3901+ qDebug() << Q_FUNC_INFO << "Charged";
3902+ if (transfer->WasSourceStartedByContentHub())
3903+ d->app_manager->stop_application(transfer->source().toStdString());
3904+
3905+ d->app_manager->invoke_application(transfer->destination().toStdString());
3906+
3907+ Q_FOREACH (RegHandler *r, d->handlers)
3908+ {
3909+ qDebug() << Q_FUNC_INFO << "ID:" << r->id << "Handler: " << r->service << "Transfer: " << transfer->destination();
3910+ if (r->id == transfer->destination())
3911+ {
3912+ qDebug() << Q_FUNC_INFO << "Found handler for charged transfer" << r->id;
3913+ if (r->handler->isValid())
3914+ r->handler->HandleImport(QDBusObjectPath{transfer->import_path()});
3915+ }
3916+ }
3917+ }
3918+
3919+ if (state == cuc::Transfer::aborted)
3920+ {
3921+ if (transfer->WasSourceStartedByContentHub())
3922+ {
3923+ bool shouldStop = true;
3924+ Q_FOREACH (cucd::Transfer *t, d->active_transfers)
3925+ {
3926+ if (t->Id() != transfer->Id())
3927+ {
3928+ if ((t->source() == transfer->source()) || (t->destination() == transfer->destination()))
3929+ {
3930+ qDebug() << Q_FUNC_INFO << "Peer has pending transfers:" << t->Id();
3931+ shouldStop = false;
3932+ }
3933+ }
3934+ }
3935+ if (shouldStop)
3936+ {
3937+ d->app_manager->stop_application(transfer->source().toStdString());
3938+ d->app_manager->invoke_application(transfer->destination().toStdString());
3939+ }
3940+ }
3941+ }
3942+}
3943+
3944+void cucd::Service::handle_exports(int state)
3945 {
3946 qDebug() << Q_FUNC_INFO;
3947 cucd::Transfer *transfer = static_cast<cucd::Transfer*>(sender());
3948
3949+ qDebug() << Q_FUNC_INFO << "STATE:" << transfer->State();
3950+
3951+
3952 if (state == cuc::Transfer::initiated)
3953 {
3954 qDebug() << Q_FUNC_INFO << "Initiated";
3955- if (d->app_manager->is_application_started(transfer->source().toStdString()))
3956+ transfer->Handled();
3957+ }
3958+
3959+ if (state == cuc::Transfer::charged)
3960+ {
3961+ qDebug() << Q_FUNC_INFO << "Charged";
3962+ if (d->app_manager->is_application_started(transfer->destination().toStdString()))
3963 transfer->SetSourceStartedByContentHub(false);
3964 else
3965 transfer->SetSourceStartedByContentHub(true);
3966
3967+ d->app_manager->invoke_application(transfer->destination().toStdString());
3968+
3969+ Q_FOREACH (RegHandler *r, d->handlers)
3970+ {
3971+ qDebug() << "Handler: " << r->service << "Transfer: " << transfer->destination();
3972+ if (r->id == transfer->destination())
3973+ {
3974+ qDebug() << "Found handler for charged transfer" << r->id;
3975+ if (transfer->Direction() == cuc::Transfer::Share && r->handler->isValid())
3976+ r->handler->HandleShare(QDBusObjectPath{transfer->import_path()});
3977+ else if (r->handler->isValid())
3978+ r->handler->HandleImport(QDBusObjectPath{transfer->import_path()});
3979+ }
3980+ }
3981+ }
3982+
3983+ if (state == cuc::Transfer::finalized)
3984+ {
3985+ qDebug() << Q_FUNC_INFO << "Finalized";
3986+ if (transfer->WasSourceStartedByContentHub())
3987+ d->app_manager->stop_application(transfer->destination().toStdString());
3988+
3989 d->app_manager->invoke_application(transfer->source().toStdString());
3990- this->connect_export_handler(transfer->source(), transfer->export_path());
3991- }
3992-
3993- if (state == cuc::Transfer::charged)
3994- {
3995- qDebug() << Q_FUNC_INFO << "Charged";
3996- d->app_manager->invoke_application(transfer->destination().toStdString());
3997-
3998- if (transfer->WasSourceStartedByContentHub())
3999- d->app_manager->stop_application(transfer->source().toStdString());
4000-
4001- this->connect_import_handler(transfer->destination(), transfer->import_path());
4002 }
4003
4004 if (state == cuc::Transfer::aborted)
4005 {
4006- d->app_manager->invoke_application(transfer->destination().toStdString());
4007-
4008+ qDebug() << Q_FUNC_INFO << "Aborted";
4009 if (transfer->WasSourceStartedByContentHub())
4010- d->app_manager->stop_application(transfer->source().toStdString());
4011- }
4012-}
4013-
4014-void cucd::Service::RegisterImportExportHandler(const QString& /*type_id*/, const QString& peer_id, const QDBusObjectPath& handler)
4015-{
4016- qDebug() << Q_FUNC_INFO << peer_id << ":" << handler.path();
4017+ {
4018+ bool shouldStop = true;
4019+ Q_FOREACH (cucd::Transfer *t, d->active_transfers)
4020+ {
4021+ if (t->Id() != transfer->Id())
4022+ {
4023+ if ((t->source() == transfer->source()) || (t->destination() == transfer->destination()))
4024+ {
4025+ qDebug() << Q_FUNC_INFO << "Peer has pending transfers:" << t->Id();
4026+ shouldStop = false;
4027+ }
4028+ }
4029+ }
4030+ if (shouldStop)
4031+ {
4032+ d->app_manager->stop_application(transfer->destination().toStdString());
4033+ d->app_manager->invoke_application(transfer->source().toStdString());
4034+ }
4035+ }
4036+ }
4037+}
4038+
4039+void cucd::Service::handler_unregistered(const QString& s)
4040+{
4041+ qDebug() << Q_FUNC_INFO << s;
4042+
4043+ if (d->handlers.isEmpty())
4044+ return;
4045+
4046+ Q_FOREACH (RegHandler *r, d->handlers)
4047+ {
4048+ qDebug() << "Handler: " << r->id;
4049+ if (r->service == s)
4050+ {
4051+ qDebug() << "Found match for " << r->id;
4052+ d->handlers.remove(r);
4053+ m_watcher->removeWatchedService(s);
4054+ delete r;
4055+ }
4056+ }
4057+}
4058+
4059+void cucd::Service::RegisterImportExportHandler(const QString& peer_id, const QDBusObjectPath& handler)
4060+{
4061+ qDebug() << Q_FUNC_INFO << peer_id;
4062+ bool exists = false;
4063+ RegHandler* r;
4064+ Q_FOREACH (RegHandler *rh, d->handlers)
4065+ {
4066+ qDebug() << "Handler: " << rh->id;
4067+ if (rh->id == peer_id)
4068+ {
4069+ qDebug() << "Found existing handler for " << rh->id;
4070+ exists = true;
4071+ r = rh;
4072+ }
4073+ }
4074+
4075+ if (!exists)
4076+ {
4077+ r = new RegHandler{peer_id,
4078+ this->message().service(),
4079+ new cuc::dbus::Handler(
4080+ this->message().service(),
4081+ handler.path(),
4082+ QDBusConnection::sessionBus(),
4083+ 0)};
4084+ d->handlers.insert(r);
4085+ m_watcher->addWatchedService(r->service);
4086+ }
4087+
4088+ qDebug() << Q_FUNC_INFO << r->id;
4089+
4090+ Q_FOREACH (cucd::Transfer *t, d->active_transfers)
4091+ {
4092+ qDebug() << Q_FUNC_INFO << "SOURCE: " << t->source() << "DEST:" << t->destination() << "STATE:" << t->State();
4093+ if ((t->source() == peer_id) && (t->State() == cuc::Transfer::initiated))
4094+ {
4095+ qDebug() << Q_FUNC_INFO << "Found source:" << peer_id << "Direction:" << t->Direction();
4096+ if (t->Direction() == cuc::Transfer::Import)
4097+ {
4098+ if (r->handler->isValid())
4099+ r->handler->HandleExport(QDBusObjectPath{t->export_path()});
4100+ }
4101+ }
4102+ else if ((t->destination() == peer_id) && (t->State() == cuc::Transfer::charged))
4103+ {
4104+ qDebug() << Q_FUNC_INFO << "Found destination:" << peer_id << "Direction:" << t->Direction();
4105+ if (t->Direction() == cuc::Transfer::Export)
4106+ {
4107+ qDebug() << Q_FUNC_INFO << "Found import, calling HandleImport";
4108+ if (r->handler->isValid())
4109+ r->handler->HandleImport(QDBusObjectPath{t->import_path()});
4110+ } else if (t->Direction() == cuc::Transfer::Share)
4111+ {
4112+ qDebug() << Q_FUNC_INFO << "Found share, calling HandleShare";
4113+ if (r->handler->isValid())
4114+ r->handler->HandleShare(QDBusObjectPath{t->import_path()});
4115+ }
4116+ }
4117+ }
4118 }
4119
4120=== modified file 'src/com/ubuntu/content/detail/service.h'
4121--- src/com/ubuntu/content/detail/service.h 2013-09-13 16:02:49 +0000
4122+++ src/com/ubuntu/content/detail/service.h 2014-03-20 13:33:31 +0000
4123@@ -53,22 +53,29 @@
4124 Service& operator=(const Service&) = delete;
4125
4126 public Q_SLOTS:
4127- QString DefaultPeerForType(const QString &type_id);
4128- QStringList KnownPeersForType(const QString &type_id);
4129- QDBusObjectPath CreateImportForTypeFromPeer(const QString&, const QString&, const QString&);
4130- void RegisterImportExportHandler(const QString&, const QString&, const QDBusObjectPath& handler);
4131+ QDBusVariant DefaultSourceForType(const QString &type_id);
4132+ QVariantList KnownSourcesForType(const QString &type_id);
4133+ QVariantList KnownDestinationsForType(const QString &type_id);
4134+ QVariantList KnownSharesForType(const QString &type_id);
4135+ QDBusObjectPath CreateImportFromPeer(const QString&, const QString&);
4136+ QDBusObjectPath CreateExportToPeer(const QString&, const QString&);
4137+ QDBusObjectPath CreateShareToPeer(const QString&, const QString&);
4138+
4139+ void RegisterImportExportHandler(const QString&, const QDBusObjectPath& handler);
4140 void Quit();
4141
4142 private:
4143+ bool should_cancel(int);
4144 struct Private;
4145+ struct RegHandler;
4146 QDBusServiceWatcher* m_watcher;
4147 QScopedPointer<Private> d;
4148- void connect_export_handler(const QString&, const QString&);
4149- void connect_import_handler(const QString&, const QString&);
4150
4151 private Q_SLOTS:
4152- void handle_transfer(int);
4153- void handler_registered(const QString&);
4154+ void handle_imports(int);
4155+ void handle_exports(int);
4156+ void handler_unregistered(const QString&);
4157+ QDBusObjectPath CreateTransfer(const QString&, const QString&, int);
4158
4159 };
4160 }
4161
4162=== modified file 'src/com/ubuntu/content/detail/transfer.cpp'
4163--- src/com/ubuntu/content/detail/transfer.cpp 2013-10-10 15:00:36 +0000
4164+++ src/com/ubuntu/content/detail/transfer.cpp 2014-03-20 13:33:31 +0000
4165@@ -32,11 +32,13 @@
4166 {
4167 Private(const int id,
4168 const QString& source,
4169- const QString& destination) :
4170+ const QString& destination,
4171+ const int direction) :
4172 state(cuc::Transfer::created),
4173 id(id),
4174 source(source),
4175 destination(destination),
4176+ direction(direction),
4177 selection_type(cuc::Transfer::single),
4178 source_started_by_content_hub(false)
4179 {
4180@@ -46,6 +48,7 @@
4181 const int id;
4182 const QString source;
4183 const QString destination;
4184+ int direction;
4185 QString store;
4186 int selection_type;
4187 QStringList items;
4188@@ -55,8 +58,9 @@
4189 cucd::Transfer::Transfer(const int id,
4190 const QString& source,
4191 const QString& destination,
4192+ const int direction,
4193 QObject* parent) :
4194- QObject(parent), d(new Private(id, source, destination))
4195+ QObject(parent), d(new Private(id, source, destination, direction))
4196 {
4197 qDebug() << __PRETTY_FUNCTION__;
4198 }
4199@@ -88,6 +92,12 @@
4200 return d->destination;
4201 }
4202
4203+int cucd::Transfer::Direction()
4204+{
4205+ qDebug() << __PRETTY_FUNCTION__;
4206+ return d->direction;
4207+}
4208+
4209 int cucd::Transfer::State()
4210 {
4211 qDebug() << __PRETTY_FUNCTION__;
4212
4213=== modified file 'src/com/ubuntu/content/detail/transfer.h'
4214--- src/com/ubuntu/content/detail/transfer.h 2013-10-10 15:00:36 +0000
4215+++ src/com/ubuntu/content/detail/transfer.h 2014-03-20 13:33:31 +0000
4216@@ -38,9 +38,10 @@
4217 Q_PROPERTY(int id READ Id)
4218 Q_PROPERTY(QString source READ source)
4219 Q_PROPERTY(QString destination READ destination)
4220+ Q_PROPERTY(int direction READ Direction)
4221
4222 public:
4223- Transfer(const int, const QString&, const QString&, QObject* parent = nullptr);
4224+ Transfer(const int, const QString&, const QString&, const int, QObject* parent = nullptr);
4225 Transfer(const Transfer&) = delete;
4226 virtual ~Transfer();
4227
4228@@ -67,6 +68,7 @@
4229 int SelectionType();
4230 void SetSelectionType(int);
4231 int Id();
4232+ int Direction();
4233 QString source();
4234 QString destination();
4235 QString export_path();
4236
4237=== modified file 'src/com/ubuntu/content/hub.cpp'
4238--- src/com/ubuntu/content/hub.cpp 2013-10-01 16:55:39 +0000
4239+++ src/com/ubuntu/content/hub.cpp 2014-03-20 13:33:31 +0000
4240@@ -74,27 +74,19 @@
4241 return;
4242 }
4243
4244- QString bus_name = handler_address(id);
4245- qDebug() << Q_FUNC_INFO << "BUS_NAME:" << bus_name;
4246-
4247 auto c = QDBusConnection::sessionBus();
4248 auto h = new cuc::detail::Handler(c, id, handler);
4249
4250 new HandlerAdaptor(h);
4251- if (not c.registerService(bus_name))
4252- {
4253- qWarning() << Q_FUNC_INFO << "Failed to register name:" << bus_name;
4254- return;
4255- }
4256+
4257
4258 if (not c.registerObject(handler_path(id), h))
4259 {
4260- qWarning() << Q_FUNC_INFO << "Failed to register object for:" << bus_name;
4261+ qWarning() << Q_FUNC_INFO << "Failed to register object for:" << id;
4262 return;
4263 }
4264
4265 d->service->RegisterImportExportHandler(
4266- QString(""),
4267 id,
4268 QDBusObjectPath{handler_path(id)});
4269 }
4270@@ -122,43 +114,82 @@
4271 return it->second;
4272 }
4273
4274-cuc::Peer cuc::Hub::default_peer_for_type(cuc::Type t)
4275+cuc::Peer cuc::Hub::default_source_for_type(cuc::Type t)
4276 {
4277- auto reply = d->service->DefaultPeerForType(t.id());
4278+ qDebug() << Q_FUNC_INFO;
4279+ auto reply = d->service->DefaultSourceForType(t.id());
4280 reply.waitForFinished();
4281
4282 if (reply.isError())
4283 return cuc::Peer::unknown();
4284
4285- return cuc::Peer(reply.value(), this);
4286+ auto peer = reply.value();
4287+ return qdbus_cast<cuc::Peer>(peer.variant());
4288 }
4289
4290-QVector<cuc::Peer> cuc::Hub::known_peers_for_type(cuc::Type t)
4291+QVector<cuc::Peer> cuc::Hub::known_sources_for_type(cuc::Type t)
4292 {
4293 QVector<cuc::Peer> result;
4294
4295- auto reply = d->service->KnownPeersForType(t.id());
4296+ auto reply = d->service->KnownSourcesForType(t.id());
4297 reply.waitForFinished();
4298
4299 if (reply.isError())
4300 return result;
4301
4302- auto ids = reply.value();
4303-
4304- Q_FOREACH(const QString& id, ids)
4305- {
4306- result << cuc::Peer(id, this);
4307- }
4308-
4309- return result;
4310-}
4311-
4312-cuc::Transfer* cuc::Hub::create_import_for_type_from_peer(cuc::Type type, cuc::Peer peer)
4313+ auto peers = reply.value();
4314+
4315+ Q_FOREACH(const QVariant& p, peers)
4316+ {
4317+ result << qdbus_cast<cuc::Peer>(p);
4318+ }
4319+ return result;
4320+}
4321+
4322+QVector<cuc::Peer> cuc::Hub::known_destinations_for_type(cuc::Type t)
4323+{
4324+ QVector<cuc::Peer> result;
4325+
4326+ auto reply = d->service->KnownDestinationsForType(t.id());
4327+ reply.waitForFinished();
4328+
4329+ if (reply.isError())
4330+ return result;
4331+
4332+ auto peers = reply.value();
4333+
4334+ Q_FOREACH(const QVariant& p, peers)
4335+ {
4336+ result << qdbus_cast<cuc::Peer>(p);
4337+ }
4338+ return result;
4339+}
4340+
4341+QVector<cuc::Peer> cuc::Hub::known_shares_for_type(cuc::Type t)
4342+{
4343+ QVector<cuc::Peer> result;
4344+
4345+ auto reply = d->service->KnownSharesForType(t.id());
4346+ reply.waitForFinished();
4347+
4348+ if (reply.isError())
4349+ return result;
4350+
4351+ auto peers = reply.value();
4352+
4353+ Q_FOREACH(const QVariant& p, peers)
4354+ {
4355+ result << qdbus_cast<cuc::Peer>(p);
4356+ }
4357+ return result;
4358+}
4359+
4360+cuc::Transfer* cuc::Hub::create_import_from_peer(cuc::Peer peer)
4361 {
4362 /* This needs to be replaced with a better way to get the APP_ID */
4363 QString id = app_id();
4364
4365- auto reply = d->service->CreateImportForTypeFromPeer(type.id(), peer.id(), id);
4366+ auto reply = d->service->CreateImportFromPeer(peer.id(), id);
4367 reply.waitForFinished();
4368
4369 if (reply.isError())
4370@@ -170,6 +201,49 @@
4371 return transfer;
4372 }
4373
4374+cuc::Transfer* cuc::Hub::create_export_to_peer(cuc::Peer peer)
4375+{
4376+ /* This needs to be replaced with a better way to get the APP_ID */
4377+ QString id = app_id();
4378+
4379+ auto reply = d->service->CreateExportToPeer(peer.id(), id);
4380+ reply.waitForFinished();
4381+
4382+ if (reply.isError())
4383+ return nullptr;
4384+
4385+ cuc::Transfer *transfer = cuc::Transfer::Private::make_transfer(reply.value(), this);
4386+
4387+ QString peerName = peer.id().split("_")[0];
4388+ qDebug() << Q_FUNC_INFO << "peerName: " << peerName;
4389+ const cuc::Store *store = new cuc::Store{QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/" + peerName + "/HubIncoming/" + QString::number(transfer->id()), this};
4390+ qDebug() << Q_FUNC_INFO << "STORE:" << store->uri();
4391+ transfer->setStore(store);
4392+ transfer->start();
4393+ return transfer;
4394+}
4395+
4396+cuc::Transfer* cuc::Hub::create_share_to_peer(cuc::Peer peer)
4397+{
4398+ /* This needs to be replaced with a better way to get the APP_ID */
4399+ QString id = app_id();
4400+
4401+ auto reply = d->service->CreateShareToPeer(peer.id(), id);
4402+ reply.waitForFinished();
4403+
4404+ if (reply.isError())
4405+ return nullptr;
4406+
4407+ cuc::Transfer *transfer = cuc::Transfer::Private::make_transfer(reply.value(), this);
4408+ QString peerName = peer.id().split("_")[0];
4409+ qDebug() << Q_FUNC_INFO << "peerName: " << peerName;
4410+ const cuc::Store *store = new cuc::Store{QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/" + peerName + "/HubIncoming/" + QString::number(transfer->id()), this};
4411+ qDebug() << Q_FUNC_INFO << "STORE:" << store->uri();
4412+ transfer->setStore(store);
4413+ transfer->start();
4414+ return transfer;
4415+}
4416+
4417 void cuc::Hub::quit()
4418 {
4419 d->service->Quit();
4420
4421=== modified file 'src/com/ubuntu/content/peer.cpp'
4422--- src/com/ubuntu/content/peer.cpp 2013-10-01 16:55:39 +0000
4423+++ src/com/ubuntu/content/peer.cpp 2014-03-20 13:33:31 +0000
4424@@ -16,14 +16,49 @@
4425 * Authored by: Thomas Voß <thomas.voss@canonical.com>
4426 */
4427
4428+
4429 #include <gio/gdesktopappinfo.h>
4430 #include <com/ubuntu/content/peer.h>
4431+#include <QMetaType>
4432
4433 namespace cuc = com::ubuntu::content;
4434
4435 struct cuc::Peer::Private
4436 {
4437+ Private (QString id, bool isDefaultPeer) : id(id), isDefaultPeer(isDefaultPeer)
4438+ {
4439+ qDebug() << Q_FUNC_INFO << id;
4440+ if (name.isEmpty())
4441+ {
4442+ QString desktop_id(id + ".desktop");
4443+ GDesktopAppInfo* app = g_desktop_app_info_new(desktop_id.toLocal8Bit().data());
4444+ if (G_IS_APP_INFO(app))
4445+ {
4446+ name = QString::fromLatin1(g_app_info_get_display_name(G_APP_INFO(app)));
4447+ GIcon* ic = g_app_info_get_icon(G_APP_INFO(app));
4448+ if (G_IS_ICON(ic))
4449+ {
4450+ iconName = QString::fromUtf8(g_icon_to_string(ic));
4451+ if (QFile::exists(iconName)) {
4452+ QFile iconFile(iconName);
4453+ if(iconFile.open(QIODevice::ReadOnly)) {
4454+ iconData = iconFile.readAll();
4455+ iconFile.close();
4456+ }
4457+ }
4458+ g_object_unref(ic);
4459+ }
4460+
4461+ g_object_unref(app);
4462+ }
4463+ }
4464+ }
4465+
4466 QString id;
4467+ QString name;
4468+ QByteArray iconData;
4469+ QString iconName;
4470+ bool isDefaultPeer;
4471 };
4472
4473 const cuc::Peer& cuc::Peer::unknown()
4474@@ -32,8 +67,9 @@
4475 return peer;
4476 }
4477
4478-cuc::Peer::Peer(const QString& id, QObject* parent) : QObject(parent), d(new cuc::Peer::Private{id})
4479+cuc::Peer::Peer(const QString& id, bool isDefaultPeer, QObject* parent) : QObject(parent), d(new cuc::Peer::Private{id, isDefaultPeer})
4480 {
4481+ qDebug() << Q_FUNC_INFO;
4482 }
4483
4484 cuc::Peer::Peer(const cuc::Peer& rhs) : QObject(rhs.parent()), d(rhs.d)
4485@@ -63,11 +99,68 @@
4486 return d->id;
4487 }
4488
4489-QString cuc::Peer::name()
4490-{
4491- QString desktop_id(d->id + ".desktop");
4492- GDesktopAppInfo* app = g_desktop_app_info_new(desktop_id.toLocal8Bit().data());
4493- QString display_name = QString::fromLatin1(g_app_info_get_display_name(G_APP_INFO(app)));
4494- g_object_unref(app);
4495- return display_name;
4496+QString cuc::Peer::name() const
4497+{
4498+ return d->name;
4499+}
4500+
4501+void cuc::Peer::setName(const QString& name)
4502+{
4503+ if (name != d->name)
4504+ d->name = name;
4505+}
4506+
4507+QByteArray cuc::Peer::iconData() const
4508+{
4509+ return d->iconData;
4510+}
4511+
4512+void cuc::Peer::setIconData(const QByteArray& iconData)
4513+{
4514+ if (iconData != d->iconData)
4515+ d->iconData = iconData;
4516+}
4517+
4518+QString cuc::Peer::iconName() const
4519+{
4520+ return d->iconName;
4521+}
4522+
4523+void cuc::Peer::setIconName(const QString& iconName)
4524+{
4525+ if (iconName != d->iconName)
4526+ d->iconName = iconName;
4527+}
4528+
4529+bool cuc::Peer::isDefaultPeer() const
4530+{
4531+ return d->isDefaultPeer;
4532+}
4533+
4534+QDBusArgument &operator<<(QDBusArgument &argument, const cuc::Peer& peer)
4535+{
4536+ argument.beginStructure();
4537+ argument << peer.id() << peer.name() << peer.iconData() << peer.iconName() << peer.isDefaultPeer();
4538+ argument.endStructure();
4539+ return argument;
4540+}
4541+
4542+const QDBusArgument &operator>>(const QDBusArgument &argument, cuc::Peer &peer)
4543+{
4544+ qDebug() << Q_FUNC_INFO;
4545+ QString id;
4546+ QString name;
4547+ QByteArray ic;
4548+ QString iconName;
4549+ bool isDefaultPeer;
4550+
4551+ argument.beginStructure();
4552+ argument >> id >> name >> ic >> iconName >> isDefaultPeer;
4553+ argument.endStructure();
4554+
4555+ peer = cuc::Peer{id, isDefaultPeer};
4556+ peer.setName(name);
4557+ peer.setIconData(ic);
4558+ peer.setIconName(iconName);
4559+ return argument;
4560 }
4561
4562=== modified file 'src/com/ubuntu/content/service/CMakeLists.txt'
4563--- src/com/ubuntu/content/service/CMakeLists.txt 2014-01-29 19:39:49 +0000
4564+++ src/com/ubuntu/content/service/CMakeLists.txt 2014-03-20 13:33:31 +0000
4565@@ -35,7 +35,7 @@
4566 ${CONTENT_SERVICE_SKELETON}
4567 )
4568
4569-qt5_use_modules(content-hub-service Core DBus)
4570+qt5_use_modules(content-hub-service Core DBus Gui)
4571
4572 target_link_libraries(
4573 content-hub-service
4574@@ -69,7 +69,7 @@
4575 hook.cpp
4576 )
4577
4578-qt5_use_modules(content-hub-peer-hook Core)
4579+qt5_use_modules(content-hub-peer-hook Core Gui DBus)
4580
4581 target_link_libraries(
4582 content-hub-peer-hook
4583@@ -94,7 +94,6 @@
4584 "${CMAKE_CURRENT_BINARY_DIR}/content-hub.hook"
4585 )
4586
4587-set(pkglibexecdir "${CMAKE_INSTALL_FULL_LIBEXECDIR}")
4588 configure_file("content-hub.hook.in"
4589 "${CLICK_HOOK}"
4590 @ONLY
4591
4592=== modified file 'src/com/ubuntu/content/service/com.ubuntu.content.hub.gschema.xml'
4593--- src/com/ubuntu/content/service/com.ubuntu.content.hub.gschema.xml 2014-01-29 19:24:02 +0000
4594+++ src/com/ubuntu/content/service/com.ubuntu.content.hub.gschema.xml 2014-03-20 13:33:31 +0000
4595@@ -11,10 +11,38 @@
4596 <default>[]</default>
4597 </key>
4598 <key name="contacts" type="as">
4599- <default>[]</default>
4600- </key>
4601- </schema>
4602- <schema id="com.ubuntu.content.hub.all" path="/com/ubuntu/content/hub/peers/">
4603+ <default>["com.ubuntu.address-book", "address-book", "current-user-version"]</default>
4604+ </key>
4605+ </schema>
4606+ <schema id="com.ubuntu.content.hub.source" path="/com/ubuntu/content/hub/source/">
4607+ <key name="pictures" type="as">
4608+ <default>[]</default>
4609+ </key>
4610+ <key name="music" type="as">
4611+ <default>[]</default>
4612+ </key>
4613+ <key name="documents" type="as">
4614+ <default>[]</default>
4615+ </key>
4616+ <key name="contacts" type="as">
4617+ <default>[]</default>
4618+ </key>
4619+ </schema>
4620+ <schema id="com.ubuntu.content.hub.destination" path="/com/ubuntu/content/hub/destination/">
4621+ <key name="pictures" type="as">
4622+ <default>[]</default>
4623+ </key>
4624+ <key name="music" type="as">
4625+ <default>[]</default>
4626+ </key>
4627+ <key name="documents" type="as">
4628+ <default>[]</default>
4629+ </key>
4630+ <key name="contacts" type="as">
4631+ <default>[]</default>
4632+ </key>
4633+ </schema>
4634+ <schema id="com.ubuntu.content.hub.share" path="/com/ubuntu/content/hub/share/">
4635 <key name="pictures" type="as">
4636 <default>[]</default>
4637 </key>
4638
4639=== modified file 'src/com/ubuntu/content/service/helper.cpp'
4640--- src/com/ubuntu/content/service/helper.cpp 2013-09-23 20:30:18 +0000
4641+++ src/com/ubuntu/content/service/helper.cpp 2014-03-20 13:33:31 +0000
4642@@ -34,7 +34,7 @@
4643 return 1;
4644 }
4645
4646- new Hook();
4647+ new cuc::detail::Hook();
4648
4649 app.exec();
4650
4651
4652=== modified file 'src/com/ubuntu/content/service/hook.cpp'
4653--- src/com/ubuntu/content/service/hook.cpp 2013-12-10 15:59:15 +0000
4654+++ src/com/ubuntu/content/service/hook.cpp 2014-03-20 13:33:31 +0000
4655@@ -28,21 +28,22 @@
4656
4657 #include "hook.h"
4658
4659-Hook::Hook(QObject *parent) :
4660+namespace cucd = com::ubuntu::content::detail;
4661+
4662+cucd::Hook::Hook(QObject *parent) :
4663 QObject(parent),
4664 registry(new Registry())
4665 {
4666 QTimer::singleShot(200, this, SLOT(run()));
4667 }
4668
4669-
4670-Hook::Hook(com::ubuntu::content::detail::PeerRegistry *registry, QObject *parent) :
4671+cucd::Hook::Hook(com::ubuntu::content::detail::PeerRegistry *registry, QObject *parent) :
4672 QObject(parent),
4673 registry(registry)
4674 {
4675 }
4676
4677-void Hook::run()
4678+void cucd::Hook::run()
4679 {
4680 qDebug() << Q_FUNC_INFO;
4681 /* Looks for files in ${HOME}/.local/share/content-hub/${id} installed
4682@@ -87,10 +88,12 @@
4683 QCoreApplication::instance()->quit();
4684 }
4685
4686-bool Hook::add_peer(QFileInfo result)
4687+bool cucd::Hook::add_peer(QFileInfo result)
4688 {
4689 qDebug() << Q_FUNC_INFO << "Hook:" << result.filePath();
4690
4691+ QStringList knownTypes;
4692+ knownTypes << "pictures" << "music" << "contacts" << "documents";
4693 QString app_id = result.fileName();
4694 auto peer = cuc::Peer(app_id);
4695
4696@@ -109,35 +112,44 @@
4697
4698 QJsonObject contentObj = contentDoc.object();
4699 QVariant sources = contentObj.toVariantMap()["source"];
4700- Q_FOREACH(QString source, sources.toStringList())
4701- {
4702- /* FIXME: we should iterate known types, but there isn't
4703- * really a good way to do that right now */
4704- if (source == "pictures")
4705- {
4706- if (not registry->install_peer_for_type(cuc::Type::Known::pictures(), peer))
4707- qWarning() << "Failed to install peer for" << source;
4708- }
4709- else if (source == "music")
4710- {
4711- if (not registry->install_peer_for_type(cuc::Type::Known::music(), peer))
4712- qWarning() << "Failed to install peer for" << source;
4713- }
4714- else if (source == "documents")
4715- {
4716- if (not registry->install_peer_for_type(cuc::Type::Known::documents(), peer))
4717- qWarning() << "Failed to install peer for" << source;
4718- }
4719- else if (source == "contacts")
4720- {
4721- if (not registry->install_peer_for_type(cuc::Type::Known::contacts(), peer))
4722- qWarning() << "Failed to install peer for" << source;
4723- }
4724+ Q_FOREACH(QString k, sources.toStringList())
4725+ {
4726+ if (knownTypes.contains(k))
4727+ {
4728+ if (registry->install_source_for_type(cuc::Type{k}, peer))
4729+ qDebug() << "Installed source:" << peer.id() << "for type:" << k;
4730+ }
4731+ else
4732+ qWarning() << "Failed to install" << peer.id() << "unknown type:" << k;
4733+ }
4734+
4735+ QVariant dests = contentObj.toVariantMap()["destination"];
4736+ Q_FOREACH(QString k, dests.toStringList())
4737+ {
4738+ if (knownTypes.contains(k))
4739+ {
4740+ if (registry->install_destination_for_type(cuc::Type{k}, peer))
4741+ qDebug() << "Installed destination:" << peer.id() << "for type:" << k;
4742+ }
4743+ else
4744+ qWarning() << "Failed to install" << peer.id() << "unknown type:" << k;
4745+ }
4746+
4747+ QVariant shares = contentObj.toVariantMap()["share"];
4748+ Q_FOREACH(QString k, shares.toStringList())
4749+ {
4750+ if (knownTypes.contains(k))
4751+ {
4752+ if (registry->install_share_for_type(cuc::Type{k}, peer))
4753+ qDebug() << "Installed share:" << peer.id() << "for type:" << k;
4754+ }
4755+ else
4756+ qWarning() << "Failed to install" << peer.id() << "unknown type:" << k;
4757 }
4758 return true;
4759 }
4760
4761-bool Hook::return_error(QString err)
4762+bool cucd::Hook::return_error(QString err)
4763 {
4764 qWarning() << "Failed to install peer" << err;
4765 return false;
4766
4767=== modified file 'src/com/ubuntu/content/service/hook.h'
4768--- src/com/ubuntu/content/service/hook.h 2013-09-25 03:14:53 +0000
4769+++ src/com/ubuntu/content/service/hook.h 2014-03-20 13:33:31 +0000
4770@@ -25,6 +25,14 @@
4771
4772 #include "registry.h"
4773
4774+namespace com
4775+{
4776+namespace ubuntu
4777+{
4778+namespace content
4779+{
4780+namespace detail
4781+{
4782 class Hook : public QObject
4783 {
4784 Q_OBJECT
4785@@ -41,5 +49,9 @@
4786 com::ubuntu::content::detail::PeerRegistry* registry;
4787
4788 };
4789+}
4790+}
4791+}
4792+}
4793
4794 #endif // HOOK_H
4795
4796=== modified file 'src/com/ubuntu/content/service/main.cpp'
4797--- src/com/ubuntu/content/service/main.cpp 2013-10-01 16:55:39 +0000
4798+++ src/com/ubuntu/content/service/main.cpp 2014-03-20 13:33:31 +0000
4799@@ -36,7 +36,7 @@
4800 {
4801 /* list known peers for pictures */
4802 QStringList result;
4803- registry->enumerate_known_peers_for_type(
4804+ registry->enumerate_known_sources_for_type(
4805 cuc::Type::Known::pictures(),
4806 [&result](const cuc::Peer& peer)
4807 {
4808
4809=== modified file 'src/com/ubuntu/content/service/registry.cpp'
4810--- src/com/ubuntu/content/service/registry.cpp 2014-01-29 19:24:02 +0000
4811+++ src/com/ubuntu/content/service/registry.cpp 2014-03-20 13:33:31 +0000
4812@@ -17,80 +17,181 @@
4813 */
4814
4815 #include "registry.h"
4816+#include "utils.cpp"
4817 #include <upstart-app-launch.h>
4818
4819 Registry::Registry() :
4820- m_defaultPeers(new QGSettings("com.ubuntu.content.hub.default",
4821+ m_defaultSources(new QGSettings("com.ubuntu.content.hub.default",
4822 "/com/ubuntu/content/hub/peers/")),
4823- m_peers(new QGSettings("com.ubuntu.content.hub.all",
4824- "/com/ubuntu/content/hub/peers/"))
4825+ m_sources(new QGSettings("com.ubuntu.content.hub.source",
4826+ "/com/ubuntu/content/hub/source/")),
4827+ m_dests(new QGSettings("com.ubuntu.content.hub.destination",
4828+ "/com/ubuntu/content/hub/destination/")),
4829+ m_shares(new QGSettings("com.ubuntu.content.hub.share",
4830+ "/com/ubuntu/content/hub/share/"))
4831 {
4832+ /* ensure all default sources are registered as available sources */
4833+ QList<cuc::Type> types = known_types();
4834+ Q_FOREACH (cuc::Type type, types)
4835+ {
4836+ if (m_defaultSources->keys().contains(type.id()))
4837+ {
4838+ QString peer_id = m_defaultSources->get(type.id()).toString();
4839+ QStringList as(m_defaultSources->get(type.id()).toStringList());
4840+ if (!as.isEmpty())
4841+ {
4842+ std::string pkg = as[0].toStdString();
4843+ std::string app = as[1].toStdString();
4844+ std::string ver = as[2].toStdString();
4845+ cuc::Peer peer(QString::fromLocal8Bit(upstart_app_launch_triplet_to_app_id(pkg.c_str(), app.c_str(), ver.c_str())));
4846+ install_source_for_type(type, cuc::Peer{peer.id(), true});
4847+ }
4848+ }
4849+ }
4850 }
4851
4852 Registry::~Registry() {}
4853
4854-cuc::Peer Registry::default_peer_for_type(cuc::Type type)
4855-{
4856- qDebug() << Q_FUNC_INFO << type.id();
4857- if (m_defaultPeers->keys().contains(type.id()))
4858- {
4859- QStringList as(m_defaultPeers->get(type.id()).toStringList());
4860- std::string pkg = as[0].toStdString();
4861- std::string app = as[1].toStdString();
4862- std::string ver = as[2].toStdString();
4863- return cuc::Peer(QString::fromLocal8Bit(upstart_app_launch_triplet_to_app_id(pkg.c_str(), app.c_str(), ver.c_str())));
4864- }
4865- else
4866- return cuc::Peer();
4867-}
4868-
4869-void Registry::enumerate_known_peers_for_type(cuc::Type type, const std::function<void(const cuc::Peer&)>&for_each)
4870-{
4871- qDebug() << Q_FUNC_INFO << type.id();
4872-
4873- Q_FOREACH (QString k, m_peers->get(type.id()).toStringList())
4874- {
4875- qDebug() << Q_FUNC_INFO << k;
4876- for_each(k);
4877- }
4878+cuc::Peer Registry::default_source_for_type(cuc::Type type)
4879+{
4880+ qDebug() << Q_FUNC_INFO << type.id();
4881+ if (m_defaultSources->keys().contains(type.id()))
4882+ {
4883+ QStringList as(m_defaultSources->get(type.id()).toStringList());
4884+ if (!as.isEmpty())
4885+ {
4886+ std::string pkg = as[0].toStdString();
4887+ std::string app = as[1].toStdString();
4888+ std::string ver = as[2].toStdString();
4889+ return cuc::Peer(QString::fromLocal8Bit(upstart_app_launch_triplet_to_app_id(pkg.c_str(), app.c_str(), ver.c_str())), true);
4890+ }
4891+ }
4892+
4893+ return cuc::Peer();
4894 }
4895
4896 void Registry::enumerate_known_peers(const std::function<void(const cuc::Peer&)>&for_each)
4897 {
4898 qDebug() << Q_FUNC_INFO;
4899
4900- Q_FOREACH (QString type_id, m_peers->keys())
4901- {
4902- qDebug() << Q_FUNC_INFO << type_id;
4903- Q_FOREACH (QString k, m_peers->get(type_id).toStringList())
4904- {
4905- qDebug() << Q_FUNC_INFO << k;
4906- for_each(k);
4907- }
4908- }
4909-}
4910-
4911-bool Registry::install_default_peer_for_type(cuc::Type type, cuc::Peer peer)
4912+ Q_FOREACH (QString type_id, m_sources->keys())
4913+ {
4914+ qDebug() << Q_FUNC_INFO << type_id;
4915+ Q_FOREACH (QString k, m_sources->get(type_id).toStringList())
4916+ {
4917+ qDebug() << Q_FUNC_INFO << k;
4918+ for_each(cuc::Peer{k});
4919+ }
4920+ }
4921+ Q_FOREACH (QString type_id, m_dests->keys())
4922+ {
4923+ qDebug() << Q_FUNC_INFO << type_id;
4924+ Q_FOREACH (QString k, m_dests->get(type_id).toStringList())
4925+ {
4926+ qDebug() << Q_FUNC_INFO << k;
4927+ for_each(cuc::Peer{k});
4928+ }
4929+ }
4930+ Q_FOREACH (QString type_id, m_shares->keys())
4931+ {
4932+ qDebug() << Q_FUNC_INFO << type_id;
4933+ Q_FOREACH (QString k, m_shares->get(type_id).toStringList())
4934+ {
4935+ qDebug() << Q_FUNC_INFO << k;
4936+ for_each(cuc::Peer{k});
4937+ }
4938+ }
4939+}
4940+
4941+void Registry::enumerate_known_sources_for_type(cuc::Type type, const std::function<void(const cuc::Peer&)>&for_each)
4942+{
4943+ qDebug() << Q_FUNC_INFO << type.id();
4944+
4945+ if (type == cuc::Type::unknown())
4946+ return;
4947+
4948+ Q_FOREACH (QString k, m_sources->get(type.id()).toStringList())
4949+ {
4950+ qDebug() << Q_FUNC_INFO << k;
4951+ bool defaultPeer = false;
4952+ QStringList as(m_defaultSources->get(type.id()).toStringList());
4953+ if (!as.isEmpty())
4954+ {
4955+ std::string pkg = as[0].toStdString();
4956+ std::string app = as[1].toStdString();
4957+ std::string ver = as[2].toStdString();
4958+ defaultPeer = QString::fromLocal8Bit(upstart_app_launch_triplet_to_app_id(pkg.c_str(), app.c_str(), ver.c_str())) == k;
4959+ }
4960+ for_each(cuc::Peer{k, defaultPeer});
4961+ }
4962+}
4963+
4964+void Registry::enumerate_known_destinations_for_type(cuc::Type type, const std::function<void(const cuc::Peer&)>&for_each)
4965+{
4966+ qDebug() << Q_FUNC_INFO << type.id();
4967+ Q_FOREACH (QString k, m_dests->get(type.id()).toStringList())
4968+ {
4969+ qDebug() << Q_FUNC_INFO << k;
4970+ for_each(cuc::Peer{k});
4971+ }
4972+}
4973+
4974+void Registry::enumerate_known_shares_for_type(cuc::Type type, const std::function<void(const cuc::Peer&)>&for_each)
4975+{
4976+ qDebug() << Q_FUNC_INFO << type.id();
4977+
4978+ Q_FOREACH (QString k, m_shares->get(type.id()).toStringList())
4979+ {
4980+ qDebug() << Q_FUNC_INFO << k;
4981+ for_each(cuc::Peer{k});
4982+ }
4983+}
4984+
4985+bool Registry::install_default_source_for_type(cuc::Type type, cuc::Peer peer)
4986 {
4987 qDebug() << Q_FUNC_INFO << "type:" << type.id() << "peer:" << peer.id();
4988- if (m_defaultPeers->keys().contains(type.id()))
4989+ if (m_defaultSources->keys().contains(type.id()))
4990 {
4991 qDebug() << Q_FUNC_INFO << "Default peer for" << type.id() << "already installed.";
4992 return false;
4993 }
4994
4995- this->install_peer_for_type(type, peer);
4996- return m_defaultPeers->trySet(type.id(), QVariant(peer.id()));
4997-}
4998-
4999-bool Registry::install_peer_for_type(cuc::Type type, cuc::Peer peer)
5000-{
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches