From 313d26d9f3f96d81f88ab0d1067daaebb4d0bd49 Mon Sep 17 00:00:00 2001 From: Patrick Franz Date: Sun, 17 Jul 2022 17:13:40 +0100 Subject: [PATCH] Import qt6-remoteobjects_6.3.1.orig.tar.xz [dgit import orig qt6-remoteobjects_6.3.1.orig.tar.xz] --- .QT-ENTERPRISE-LICENSE-AGREEMENT | 1977 +++++ .cmake.conf | 2 + .tag | 1 + CMakeLists.txt | 29 + LICENSE.FDL | 451 ++ LICENSE.GPL2 | 339 + LICENSE.GPL3 | 674 ++ LICENSE.GPL3-EXCEPT | 704 ++ LICENSE.LGPL3 | 165 + coin/module_config.yaml | 12 + conanfile.py | 60 + dependencies.yaml | 7 + dist/changes-5.11.0 | 41 + dist/changes-5.11.1 | 26 + dist/changes-5.11.2 | 24 + dist/changes-5.11.3 | 27 + dist/changes-5.12.0 | 46 + dist/changes-5.12.1 | 30 + dist/changes-5.12.2 | 20 + dist/changes-5.12.3 | 29 + dist/changes-5.12.4 | 71 + dist/changes-5.12.5 | 20 + dist/changes-5.13.0 | 57 + dist/changes-5.13.1 | 21 + dist/changes-5.13.2 | 30 + dist/changes-5.14.0 | 25 + dist/changes-5.14.1 | 27 + dist/changes-5.14.2 | 27 + dist/changes-5.15.0 | 22 + dist/changes-5.15.1 | 20 + examples/CMakeLists.txt | 5 + examples/examples.pro | 3 + examples/remoteobjects/CMakeLists.txt | 18 + .../remoteobjects/clientapp/CMakeLists.txt | 49 + .../remoteobjects/clientapp/clientapp.pro | 11 + .../remoteobjects/clientapp/clientapp.qrc | 8 + examples/remoteobjects/clientapp/main.cpp | 65 + .../remoteobjects/clientapp/qml/plugins.qml | 71 + .../remoteobjects/clientapp/qml/plugins0.qml | 58 + .../remoteobjects/clientapp/qml/plugins1.qml | 70 + .../remoteobjects/clientapp/qml/plugins2.qml | 81 + .../remoteobjects/cppclient/CMakeLists.txt | 37 + .../remoteobjects/cppclient/cppclient.pro | 19 + examples/remoteobjects/cppclient/main.cpp | 99 + .../remoteobjects/cppclient/timemodel.rep | 12 + .../modelviewclient/CMakeLists.txt | 34 + .../doc/src/modelviewclient.qdoc | 56 + .../remoteobjects/modelviewclient/main.cpp | 83 + .../modelviewclient/modelviewclient.pro | 10 + .../modelviewserver/CMakeLists.txt | 34 + .../doc/src/modelviewserver.qdoc | 71 + .../remoteobjects/modelviewserver/main.cpp | 187 + .../modelviewserver/modelviewserver.pro | 11 + examples/remoteobjects/plugins/CMakeLists.txt | 45 + .../plugins/imports/TimeExample/Clock.qml | 98 + .../plugins/imports/TimeExample/center.png | Bin 0 -> 765 bytes .../plugins/imports/TimeExample/clock.png | Bin 0 -> 20653 bytes .../plugins/imports/TimeExample/hour.png | Bin 0 -> 625 bytes .../plugins/imports/TimeExample/minute.png | Bin 0 -> 625 bytes .../plugins/imports/TimeExample/qmldir | 3 + examples/remoteobjects/plugins/plugin.cpp | 139 + examples/remoteobjects/plugins/plugins.pro | 30 + examples/remoteobjects/plugins/plugins.qml | 71 + examples/remoteobjects/plugins/plugins0.qml | 58 + examples/remoteobjects/plugins/plugins1.qml | 70 + examples/remoteobjects/plugins/plugins2.qml | 81 + .../qmlmodelviewclient/CMakeLists.txt | 47 + .../doc/src/qmlmodelviewclient.qdoc | 38 + .../remoteobjects/qmlmodelviewclient/main.cpp | 73 + .../remoteobjects/qmlmodelviewclient/main.qml | 105 + .../remoteobjects/qmlmodelviewclient/qml.qrc | 5 + .../qmlmodelviewclient/qmlmodelviewclient.pro | 11 + examples/remoteobjects/remoteobjects.pro | 23 + .../remoteobjects_server/CMakeLists.txt | 38 + .../remoteobjects_server/main.cpp | 104 + .../remoteobjects_server.pro | 13 + .../remoteobjects_server/timemodel.cpp | 90 + .../remoteobjects_server/timemodel.h | 71 + .../remoteobjects/simpleswitch/CMakeLists.txt | 5 + .../directconnectclient/CMakeLists.txt | 38 + .../directconnectclient/client.cpp | 85 + .../simpleswitch/directconnectclient/client.h | 78 + .../directconnectclient.pro | 23 + .../simpleswitch/directconnectclient/main.cpp | 69 + .../directconnectclient/simpleswitch.rep | 7 + .../directconnectdynamicclient/CMakeLists.txt | 33 + .../directconnectdynamicclient.pro | 18 + .../dynamicclient.cpp | 86 + .../dynamicclient.h | 80 + .../directconnectdynamicclient/main.cpp | 69 + .../directconnectserver/CMakeLists.txt | 38 + .../directconnectserver.pro | 21 + .../simpleswitch/directconnectserver/main.cpp | 64 + .../directconnectserver/simpleswitch.cpp | 83 + .../directconnectserver/simpleswitch.h | 69 + .../directconnectserver/simpleswitch.rep | 7 + .../registryconnectedclient/CMakeLists.txt | 33 + .../registryconnectedclient/dynamicclient.cpp | 86 + .../registryconnectedclient/dynamicclient.h | 80 + .../registryconnectedclient/main.cpp | 67 + .../registryconnectedclient.pro | 24 + .../registryconnectedserver/CMakeLists.txt | 38 + .../registryconnectedserver/main.cpp | 70 + .../registryconnectedserver.pro | 30 + .../registryconnectedserver/simpleswitch.cpp | 83 + .../registryconnectedserver/simpleswitch.h | 69 + .../registryconnectedserver/simpleswitch.rep | 8 + .../simpleswitch/simpleswitch.pro | 8 + examples/remoteobjects/ssl/CMakeLists.txt | 2 + examples/remoteobjects/ssl/doc/src/ssl.qdoc | 35 + examples/remoteobjects/ssl/ssl.pro | 6 + .../ssl/sslcppclient/CMakeLists.txt | 59 + .../remoteobjects/ssl/sslcppclient/main.cpp | 132 + .../ssl/sslcppclient/sslcppclient.pro | 24 + .../ssl/sslcppclient/timemodel.rep | 12 + .../ssl/sslserver/CMakeLists.txt | 60 + .../remoteobjects/ssl/sslserver/cert/cert.qrc | 11 + .../ssl/sslserver/cert/client.crt | 17 + .../ssl/sslserver/cert/client.key | 27 + .../remoteobjects/ssl/sslserver/cert/readme | 2 + .../ssl/sslserver/cert/rootCA.key | 27 + .../ssl/sslserver/cert/rootCA.pem | 19 + .../ssl/sslserver/cert/rootCA.srl | 1 + .../ssl/sslserver/cert/server.crt | 19 + .../ssl/sslserver/cert/server.key | 27 + examples/remoteobjects/ssl/sslserver/main.cpp | 126 + .../remoteobjects/ssl/sslserver/sslserver.cpp | 79 + .../remoteobjects/ssl/sslserver/sslserver.h | 71 + .../remoteobjects/ssl/sslserver/sslserver.pro | 21 + .../remoteobjects/ssl/sslserver/timemodel.cpp | 90 + .../remoteobjects/ssl/sslserver/timemodel.h | 71 + examples/remoteobjects/timemodel.rep | 14 + .../remoteobjects/websockets/CMakeLists.txt | 4 + .../websockets/common/cert/cert.qrc | 11 + .../websockets/common/cert/client.crt | 17 + .../websockets/common/cert/client.key | 27 + .../websockets/common/cert/readme | 2 + .../websockets/common/cert/rootCA.key | 27 + .../websockets/common/cert/rootCA.pem | 19 + .../websockets/common/cert/rootCA.srl | 1 + .../websockets/common/cert/server.crt | 19 + .../websockets/common/cert/server.key | 27 + .../websockets/common/common.pri | 11 + .../websockets/common/websocketiodevice.cpp | 99 + .../websockets/common/websocketiodevice.h | 84 + .../websockets/doc/src/websocket.qdoc | 35 + .../remoteobjects/websockets/websockets.pro | 7 + .../websockets/wsclient/CMakeLists.txt | 60 + .../websockets/wsclient/main.cpp | 107 + .../websockets/wsclient/wsclient.pro | 9 + .../websockets/wsserver/CMakeLists.txt | 60 + .../websockets/wsserver/main.cpp | 207 + .../websockets/wsserver/wsserver.pro | 9 + .../private/qconnection_local_backend_p.h | 1 + .../private/qconnection_qnx_backend_p.h | 1 + .../private/qconnection_qnx_global_p.h | 1 + .../private/qconnection_qnx_qiodevices_p.h | 1 + .../private/qconnection_qnx_server_p.h | 1 + .../private/qconnection_tcpip_backend_p.h | 1 + .../private/qconnectionfactories_p.h | 1 + .../qremoteobjectabstractitemmodeladapter_p.h | 1 + .../qremoteobjectabstractitemmodelreplica_p.h | 1 + .../qremoteobjectabstractitemmodeltypes_p.h | 1 + .../private/qremoteobjectcontainers_p.h | 1 + .../private/qremoteobjectnode_p.h | 1 + .../private/qremoteobjectpacket_p.h | 1 + .../private/qremoteobjectpendingcall_p.h | 1 + .../private/qremoteobjectregistrysource_p.h | 1 + .../private/qremoteobjectreplica_p.h | 1 + .../private/qremoteobjectsource_p.h | 1 + .../private/qremoteobjectsourceio_p.h | 1 + .../QtRemoteObjects/QAbstractItemModelReplica | 1 + .../QtRemoteObjects/QConnectionAbstractServer | 1 + include/QtRemoteObjects/QIOQnxSource | 1 + include/QtRemoteObjects/QIntHash | 1 + include/QtRemoteObjects/QQnxNativeIo | 1 + include/QtRemoteObjects/QQnxNativeServer | 1 + .../QRemoteObjectAbstractPersistedStore | 1 + .../QRemoteObjectDynamicReplica | 1 + include/QtRemoteObjects/QRemoteObjectHost | 1 + include/QtRemoteObjects/QRemoteObjectHostBase | 1 + include/QtRemoteObjects/QRemoteObjectNode | 1 + .../QtRemoteObjects/QRemoteObjectPendingCall | 1 + .../QRemoteObjectPendingCallWatcher | 1 + .../QtRemoteObjects/QRemoteObjectPendingReply | 1 + include/QtRemoteObjects/QRemoteObjectRegistry | 1 + .../QtRemoteObjects/QRemoteObjectRegistryHost | 1 + include/QtRemoteObjects/QRemoteObjectReplica | 1 + .../QRemoteObjectSettingsStore | 1 + .../QRemoteObjectSourceLocation | 1 + .../QRemoteObjectSourceLocationInfo | 1 + .../QRemoteObjectSourceLocations | 1 + include/QtRemoteObjects/QtROClientFactory | 1 + include/QtRemoteObjects/QtROClientIoDevice | 1 + include/QtRemoteObjects/QtROIoDeviceBase | 1 + include/QtRemoteObjects/QtROServerFactory | 1 + include/QtRemoteObjects/QtROServerIoDevice | 1 + include/QtRemoteObjects/QtRemoteObjects | 15 + .../QtRemoteObjects/QtRemoteObjectsVersion | 1 + include/QtRemoteObjects/headers.pri | 6 + .../qconnection_qnx_qiodevices.h | 1 + .../QtRemoteObjects/qconnection_qnx_server.h | 1 + .../QtRemoteObjects/qconnectionfactories.h | 1 + .../qremoteobjectabstractitemmodelreplica.h | 1 + .../qremoteobjectdynamicreplica.h | 1 + include/QtRemoteObjects/qremoteobjectnode.h | 1 + .../qremoteobjectpendingcall.h | 1 + .../QtRemoteObjects/qremoteobjectregistry.h | 1 + .../QtRemoteObjects/qremoteobjectreplica.h | 1 + .../qremoteobjectsettingsstore.h | 1 + include/QtRemoteObjects/qremoteobjectsource.h | 1 + .../QtRemoteObjects/qtremoteobjectglobal.h | 1 + .../QtRemoteObjects/qtremoteobjectsversion.h | 9 + .../private/qremoteobjectsqml_p.h | 1 + include/QtRemoteObjectsQml/QtRemoteObjectsQml | 5 + .../QtRemoteObjectsQmlVersion | 1 + include/QtRemoteObjectsQml/headers.pri | 6 + .../qtremoteobjectsqmlversion.h | 9 + include/QtRepParser/QRegexParser | 1 + include/QtRepParser/QtRepParser | 6 + include/QtRepParser/QtRepParserVersion | 1 + include/QtRepParser/headers.pri | 6 + include/QtRepParser/qregexparser.h | 1 + include/QtRepParser/qtrepparserversion.h | 9 + mkspecs/features/features.pro | 18 + mkspecs/features/remoteobjects_repc.prf | 26 + mkspecs/features/repcclient.pri | 4 + mkspecs/features/repccommon.pri | 75 + mkspecs/features/repcmerged.pri | 4 + mkspecs/features/repcserver.pri | 4 + mkspecs/features/repparser.prf | 9 + mkspecs/mkspecs.pro | 3 + src/CMakeLists.txt | 8 + src/remoteobjects/CMakeLists.txt | 69 + .../Qt5RemoteObjectsConfigExtras.cmake.in | 62 + .../Qt6RemoteObjectsMacros.cmake | 202 + src/remoteobjects/configure.cmake | 26 + .../DirectConnectClientServerOutput.png | Bin 0 -> 34559 bytes .../doc/images/DirectConnectServerOutput.png | Bin 0 -> 16105 bytes src/remoteobjects/doc/images/README | 1 + .../doc/images/RemoteObjectsHighLevel.png | Bin 0 -> 30405 bytes .../doc/qtremoteobjects.qdocconf | 54 + src/remoteobjects/doc/snippets/README | 1 + .../doc/snippets/cmake-macros/CMakeLists.txt | 49 + .../doc/snippets/cmake-macros/main.cpp | 64 + .../snippets/cmake-macros/simpleswitch.cpp | 83 + .../doc/snippets/cmake-macros/simpleswitch.h | 69 + .../snippets/cmake-macros/simpleswitch.rep | 7 + .../doc/snippets/doc_src_remoteobjects.h | 70 + .../doc/snippets/doc_src_simpleswitch.cpp | 363 + src/remoteobjects/doc/src/cmake-macros.qdoc | 157 + src/remoteobjects/doc/src/qt6-changes.qdoc | 101 + .../doc/src/remoteobjects-compatibility.qdoc | 56 + .../doc/src/remoteobjects-cpp.qdoc | 47 + .../src/remoteobjects-custom-transport.qdoc | 64 + ...remoteobjects-example-dynamic-replica.qdoc | 74 + .../src/remoteobjects-example-registry.qdoc | 66 + .../remoteobjects-example-static-source.qdoc | 206 + .../src/remoteobjects-external-schemas.qdoc | 136 + .../doc/src/remoteobjects-gettingstarted.qdoc | 117 + .../doc/src/remoteobjects-index.qdoc | 154 + .../doc/src/remoteobjects-interaction.qdoc | 50 + .../doc/src/remoteobjects-nodes.qdoc | 112 + .../doc/src/remoteobjects-qml.qdoc | 106 + .../doc/src/remoteobjects-registry.qdoc | 57 + .../doc/src/remoteobjects-repc.qdoc | 434 ++ .../doc/src/remoteobjects-replica.qdoc | 113 + .../doc/src/remoteobjects-source.qdoc | 117 + .../src/remoteobjects-troubleshooting.qdoc | 40 + .../qconnection_local_backend.cpp | 231 + .../qconnection_local_backend_p.h | 144 + src/remoteobjects/qconnection_qnx_backend.cpp | 192 + src/remoteobjects/qconnection_qnx_backend_p.h | 155 + src/remoteobjects/qconnection_qnx_global_p.h | 118 + .../qconnection_qnx_qiodevices.cpp | 655 ++ .../qconnection_qnx_qiodevices.h | 158 + .../qconnection_qnx_qiodevices_p.h | 111 + src/remoteobjects/qconnection_qnx_server.cpp | 540 ++ src/remoteobjects/qconnection_qnx_server.h | 82 + src/remoteobjects/qconnection_qnx_server_p.h | 108 + .../qconnection_tcpip_backend.cpp | 213 + .../qconnection_tcpip_backend_p.h | 121 + src/remoteobjects/qconnectionfactories.cpp | 396 + src/remoteobjects/qconnectionfactories.h | 251 + src/remoteobjects/qconnectionfactories_p.h | 122 + .../qremoteobjectabstractitemmodeladapter.cpp | 295 + .../qremoteobjectabstractitemmodeladapter_p.h | 310 + .../qremoteobjectabstractitemmodelreplica.cpp | 1174 +++ .../qremoteobjectabstractitemmodelreplica.h | 91 + .../qremoteobjectabstractitemmodelreplica_p.h | 476 ++ .../qremoteobjectabstractitemmodeltypes_p.h | 266 + src/remoteobjects/qremoteobjectcontainers.cpp | 179 + src/remoteobjects/qremoteobjectcontainers_p.h | 120 + .../qremoteobjectdynamicreplica.cpp | 216 + .../qremoteobjectdynamicreplica.h | 65 + src/remoteobjects/qremoteobjectnode.cpp | 2824 ++++++++ src/remoteobjects/qremoteobjectnode.h | 248 + src/remoteobjects/qremoteobjectnode_p.h | 244 + src/remoteobjects/qremoteobjectpacket.cpp | 1165 +++ src/remoteobjects/qremoteobjectpacket_p.h | 327 + .../qremoteobjectpendingcall.cpp | 271 + src/remoteobjects/qremoteobjectpendingcall.h | 135 + .../qremoteobjectpendingcall_p.h | 96 + src/remoteobjects/qremoteobjectregistry.cpp | 244 + src/remoteobjects/qremoteobjectregistry.h | 88 + .../qremoteobjectregistrysource.cpp | 95 + .../qremoteobjectregistrysource_p.h | 86 + src/remoteobjects/qremoteobjectreplica.cpp | 976 +++ src/remoteobjects/qremoteobjectreplica.h | 111 + src/remoteobjects/qremoteobjectreplica_p.h | 206 + .../qremoteobjectsettingsstore.cpp | 109 + .../qremoteobjectsettingsstore.h | 66 + src/remoteobjects/qremoteobjectsource.cpp | 684 ++ src/remoteobjects/qremoteobjectsource.h | 188 + src/remoteobjects/qremoteobjectsource_p.h | 223 + src/remoteobjects/qremoteobjectsourceio.cpp | 331 + src/remoteobjects/qremoteobjectsourceio_p.h | 115 + src/remoteobjects/qtremoteobjectglobal.cpp | 125 + src/remoteobjects/qtremoteobjectglobal.h | 179 + src/remoteobjectsqml/CMakeLists.txt | 19 + src/remoteobjectsqml/qremoteobjectsqml_p.h | 184 + src/repparser/CMakeLists.txt | 15 + src/repparser/parser.g | 1472 ++++ src/repparser/qregexparser.h | 396 + sync.profile | 5 + tests/CMakeLists.txt | 8 + tests/auto/CMakeLists.txt | 29 + tests/auto/benchmarks/CMakeLists.txt | 25 + tests/auto/benchmarks/tst_benchmarkstest.cpp | 397 + ...QtRemoteObjects.5.13.0.linux-gcc-amd64.txt | 6368 ++++++++++++++++ ...QtRemoteObjects.5.14.0.linux-gcc-amd64.txt | 6412 +++++++++++++++++ tests/auto/cmake/CMakeLists.txt | 46 + .../cmake/test_cmake_macros/CMakeLists.txt | 13 + tests/auto/cmake/test_cmake_macros/main.cpp | 40 + tests/auto/external_IODevice/CMakeLists.txt | 3 + tests/auto/external_IODevice/cert/cert.qrc | 11 + tests/auto/external_IODevice/cert/client.crt | 17 + tests/auto/external_IODevice/cert/client.key | 27 + tests/auto/external_IODevice/cert/generate.sh | 70 + tests/auto/external_IODevice/cert/rootCA.key | 27 + tests/auto/external_IODevice/cert/rootCA.pem | 19 + tests/auto/external_IODevice/cert/rootCA.srl | 1 + .../external_IODevice/cert/server-req.ext | 8 + tests/auto/external_IODevice/cert/server.crt | 19 + tests/auto/external_IODevice/cert/server.key | 27 + tests/auto/external_IODevice/pingpong.rep | 8 + .../sslTestServer/CMakeLists.txt | 44 + .../external_IODevice/sslTestServer/main.cpp | 60 + .../sslTestServer/pingpong.cpp | 47 + .../sslTestServer/pingpong.h | 45 + .../sslTestServer/sslserver.cpp | 57 + .../sslTestServer/sslserver.h | 50 + .../tst_client/CMakeLists.txt | 36 + .../tst_client/tst_client.cpp | 100 + tests/auto/integration/CMakeLists.txt | 31 + tests/auto/integration/engine.cpp | 69 + tests/auto/integration/engine.h | 67 + tests/auto/integration/engine.rep | 21 + tests/auto/integration/enum.rep | 9 + tests/auto/integration/pod.rep | 6 + tests/auto/integration/speedometer.cpp | 38 + tests/auto/integration/speedometer.h | 45 + tests/auto/integration/speedometer.rep | 4 + tests/auto/integration/temperature.h | 101 + tests/auto/integration/tst_integration.cpp | 1537 ++++ .../auto/integration_external/CMakeLists.txt | 4 + .../auto/integration_external/MyInterface.rep | 18 + .../client/CMakeLists.txt | 21 + .../auto/integration_external/client/main.cpp | 202 + .../external/CMakeLists.txt | 12 + .../external/tst_integration_external.cpp | 98 + .../server/CMakeLists.txt | 22 + .../auto/integration_external/server/main.cpp | 128 + .../server/mytestserver.cpp | 74 + .../server/mytestserver.h | 59 + .../integration_multiprocess/CMakeLists.txt | 4 + .../ExtPodInterface.rep | 1 + .../integration_multiprocess/MyInterface.rep | 22 + .../integration_multiprocess/PodInterface.rep | 8 + .../client/CMakeLists.txt | 26 + .../integration_multiprocess/client/main.cpp | 217 + .../server/CMakeLists.txt | 27 + .../integration_multiprocess/server/main.cpp | 97 + .../server/mytestserver.cpp | 74 + .../server/mytestserver.h | 58 + .../tst/CMakeLists.txt | 12 + .../tst/tst_integration_multiprocess.cpp | 98 + .../auto/localsockettestserver/CMakeLists.txt | 16 + tests/auto/localsockettestserver/main.cpp | 43 + tests/auto/modelreplica/CMakeLists.txt | 19 + tests/auto/modelreplica/model.rep | 12 + .../modelreplica/tst_modelreplicatest.cpp | 221 + tests/auto/modelview/CMakeLists.txt | 26 + tests/auto/modelview/tst_modelview.cpp | 1162 +++ tests/auto/pods/CMakeLists.txt | 17 + tests/auto/pods/pods.h | 184 + tests/auto/pods/tst_pods.cpp | 83 + tests/auto/proxy/CMakeLists.txt | 19 + tests/auto/proxy/engine.rep | 8 + tests/auto/proxy/subclass.rep | 13 + tests/auto/proxy/tst_proxy.cpp | 459 ++ tests/auto/proxy_multiprocess/CMakeLists.txt | 5 + .../proxy_multiprocess/client/CMakeLists.txt | 23 + tests/auto/proxy_multiprocess/client/main.cpp | 141 + tests/auto/proxy_multiprocess/namespace.h | 20 + .../proxy_multiprocess/proxy/CMakeLists.txt | 18 + tests/auto/proxy_multiprocess/proxy/main.cpp | 59 + .../proxy_multiprocess/server/CMakeLists.txt | 25 + tests/auto/proxy_multiprocess/server/main.cpp | 127 + .../server/mytestserver.cpp | 67 + .../proxy_multiprocess/server/mytestserver.h | 57 + tests/auto/proxy_multiprocess/shared.h | 6 + tests/auto/proxy_multiprocess/subclass.rep | 50 + .../proxy_multiprocess/tst/CMakeLists.txt | 12 + .../tst/tst_proxy_multiprocess.cpp | 125 + tests/auto/qml/CMakeLists.txt | 3 + tests/auto/qml/integration/CMakeLists.txt | 24 + .../qml/integration/data/tst_integration.qml | 56 + .../auto/qml/integration/tst_integration.cpp | 30 + tests/auto/qml/usertypes/CMakeLists.txt | 40 + tests/auto/qml/usertypes/data/MyType.qml | 5 + tests/auto/qml/usertypes/data/complex.qml | 10 + tests/auto/qml/usertypes/data/composite.qml | 8 + .../qml/usertypes/data/extraPropComplex.qml | 14 + tests/auto/qml/usertypes/data/extraprop.qml | 12 + tests/auto/qml/usertypes/data/extraprop2.qml | 12 + tests/auto/qml/usertypes/data/hosted.qml | 21 + tests/auto/qml/usertypes/data/model.qml | 10 + tests/auto/qml/usertypes/data/subObject.qml | 18 + tests/auto/qml/usertypes/data/twoReplicas.qml | 30 + tests/auto/qml/usertypes/data/watcher.qml | 38 + tests/auto/qml/usertypes/tst_usertypes.cpp | 314 + tests/auto/qml/usertypes/usertypes.rep | 33 + tests/auto/reconnect/CMakeLists.txt | 4 + tests/auto/reconnect/client/CMakeLists.txt | 6 + tests/auto/reconnect/client/main.cpp | 63 + tests/auto/reconnect/server/CMakeLists.txt | 6 + tests/auto/reconnect/server/main.cpp | 79 + tests/auto/reconnect/tst/CMakeLists.txt | 5 + tests/auto/reconnect/tst/tst_reconnect.cpp | 83 + tests/auto/rep_from_header/CMakeLists.txt | 15 + tests/auto/rep_from_header/pods.h | 184 + .../rep_from_header/tst_rep_from_header.cpp | 79 + tests/auto/repc/CMakeLists.txt | 6 + tests/auto/repc/enums/CMakeLists.txt | 17 + tests/auto/repc/enums/enums.rep | 6 + tests/auto/repc/enums/tst_enums.cpp | 79 + tests/auto/repc/pods/CMakeLists.txt | 17 + tests/auto/repc/pods/pods.rep | 12 + tests/auto/repc/pods/tst_pods.cpp | 92 + tests/auto/repc/signature/CMakeLists.txt | 22 + .../differentClassEnum/CMakeLists.txt | 18 + .../signature/differentClassEnum/mismatch.rep | 23 + .../differentGlobalEnum/CMakeLists.txt | 18 + .../differentGlobalEnum/mismatch.rep | 31 + .../differentPropertyCount/CMakeLists.txt | 18 + .../differentPropertyCount/mismatch.rep | 32 + .../CMakeLists.txt | 18 + .../differentPropertyCountChild.pro | 5 + .../differentPropertyCountChild/mismatch.rep | 30 + .../differentPropertyType/CMakeLists.txt | 18 + .../differentPropertyType/mismatch.rep | 31 + .../differentSignalCount/CMakeLists.txt | 18 + .../differentSignalCount/mismatch.rep | 32 + .../differentSignalParamCount/CMakeLists.txt | 18 + .../differentSignalParamCount/mismatch.rep | 31 + .../differentSignalParamType/CMakeLists.txt | 18 + .../differentSignalParamType/mismatch.rep | 31 + .../differentSlotCount/CMakeLists.txt | 18 + .../signature/differentSlotCount/mismatch.rep | 32 + .../differentSlotParamCount/CMakeLists.txt | 18 + .../differentSlotParamCount/mismatch.rep | 31 + .../differentSlotParamType/CMakeLists.txt | 18 + .../differentSlotParamType/mismatch.rep | 31 + .../differentSlotType/CMakeLists.txt | 18 + .../signature/differentSlotType/mismatch.rep | 31 + .../signature/matchAndQuit/CMakeLists.txt | 21 + .../auto/repc/signature/matchAndQuit/main.cpp | 70 + tests/auto/repc/signature/mismatch.cpp | 52 + tests/auto/repc/signature/mismatch.pri | 10 + .../scrambledProperties/CMakeLists.txt | 18 + .../scrambledProperties/mismatch.rep | 31 + .../signature/scrambledSignals/CMakeLists.txt | 18 + .../signature/scrambledSignals/mismatch.rep | 31 + .../signature/scrambledSlots/CMakeLists.txt | 18 + .../signature/scrambledSlots/mismatch.rep | 31 + tests/auto/repc/signature/server.rep | 31 + .../signature/signatureServer/CMakeLists.txt | 22 + .../repc/signature/signatureServer/main.cpp | 81 + .../signature/signatureTests/CMakeLists.txt | 12 + .../signatureTests/tst_signature.cpp | 106 + .../auto/repc/signature/state/CMakeLists.txt | 21 + tests/auto/repc/signature/state/main.cpp | 71 + tests/auto/repc/signature/state/mismatch.rep | 31 + tests/auto/repcodegenerator/CMakeLists.txt | 19 + .../classwithreadonlypropertytest.rep | 4 + .../classwithsignalonlytest.rep | 4 + .../repcodegenerator/preprocessortest.rep | 3 + .../repcodegenerator/tst_repcodegenerator.cpp | 48 + tests/auto/repfiles/localdatacenter.rep | 8 + tests/auto/repfiles/tcpdatacenter.rep | 7 + tests/auto/repparser/CMakeLists.txt | 29 + tests/auto/repparser/tst_parser.cpp | 661 ++ tests/auto/restart/CMakeLists.txt | 4 + tests/auto/restart/client/CMakeLists.txt | 21 + tests/auto/restart/client/main.cpp | 106 + tests/auto/restart/server/CMakeLists.txt | 22 + tests/auto/restart/server/main.cpp | 92 + tests/auto/restart/server/mytestserver.cpp | 55 + tests/auto/restart/server/mytestserver.h | 55 + tests/auto/restart/subclass.rep | 19 + tests/auto/restart/tst/CMakeLists.txt | 12 + tests/auto/restart/tst/tst_restart.cpp | 129 + tests/auto/shared/model_utilities.h | 128 + tests/auto/subclassreplica/CMakeLists.txt | 19 + tests/auto/subclassreplica/class.rep | 14 + .../tst_subclassreplicatest.cpp | 123 + tests/global/global.cfg | 5 + tests/shared/testutils.h | 84 + tools/CMakeLists.txt | 5 + tools/repc/CMakeLists.txt | 49 + tools/repc/cppcodegenerator.cpp | 52 + tools/repc/cppcodegenerator.h | 49 + tools/repc/main.cpp | 267 + tools/repc/repc.pro | 25 + tools/repc/repcodegenerator.cpp | 1523 ++++ tools/repc/repcodegenerator.h | 88 + tools/repc/utils.cpp | 313 + tools/repc/utils.h | 43 + tools/tools.pro | 4 + 530 files changed, 59224 insertions(+) create mode 100644 .QT-ENTERPRISE-LICENSE-AGREEMENT create mode 100644 .cmake.conf create mode 100644 .tag create mode 100644 CMakeLists.txt create mode 100644 LICENSE.FDL create mode 100644 LICENSE.GPL2 create mode 100644 LICENSE.GPL3 create mode 100644 LICENSE.GPL3-EXCEPT create mode 100644 LICENSE.LGPL3 create mode 100644 coin/module_config.yaml create mode 100644 conanfile.py create mode 100644 dependencies.yaml create mode 100644 dist/changes-5.11.0 create mode 100644 dist/changes-5.11.1 create mode 100644 dist/changes-5.11.2 create mode 100644 dist/changes-5.11.3 create mode 100644 dist/changes-5.12.0 create mode 100644 dist/changes-5.12.1 create mode 100644 dist/changes-5.12.2 create mode 100644 dist/changes-5.12.3 create mode 100644 dist/changes-5.12.4 create mode 100644 dist/changes-5.12.5 create mode 100644 dist/changes-5.13.0 create mode 100644 dist/changes-5.13.1 create mode 100644 dist/changes-5.13.2 create mode 100644 dist/changes-5.14.0 create mode 100644 dist/changes-5.14.1 create mode 100644 dist/changes-5.14.2 create mode 100644 dist/changes-5.15.0 create mode 100644 dist/changes-5.15.1 create mode 100644 examples/CMakeLists.txt create mode 100644 examples/examples.pro create mode 100644 examples/remoteobjects/CMakeLists.txt create mode 100644 examples/remoteobjects/clientapp/CMakeLists.txt create mode 100644 examples/remoteobjects/clientapp/clientapp.pro create mode 100644 examples/remoteobjects/clientapp/clientapp.qrc create mode 100644 examples/remoteobjects/clientapp/main.cpp create mode 100644 examples/remoteobjects/clientapp/qml/plugins.qml create mode 100644 examples/remoteobjects/clientapp/qml/plugins0.qml create mode 100644 examples/remoteobjects/clientapp/qml/plugins1.qml create mode 100644 examples/remoteobjects/clientapp/qml/plugins2.qml create mode 100644 examples/remoteobjects/cppclient/CMakeLists.txt create mode 100644 examples/remoteobjects/cppclient/cppclient.pro create mode 100644 examples/remoteobjects/cppclient/main.cpp create mode 100644 examples/remoteobjects/cppclient/timemodel.rep create mode 100644 examples/remoteobjects/modelviewclient/CMakeLists.txt create mode 100644 examples/remoteobjects/modelviewclient/doc/src/modelviewclient.qdoc create mode 100644 examples/remoteobjects/modelviewclient/main.cpp create mode 100644 examples/remoteobjects/modelviewclient/modelviewclient.pro create mode 100644 examples/remoteobjects/modelviewserver/CMakeLists.txt create mode 100644 examples/remoteobjects/modelviewserver/doc/src/modelviewserver.qdoc create mode 100644 examples/remoteobjects/modelviewserver/main.cpp create mode 100644 examples/remoteobjects/modelviewserver/modelviewserver.pro create mode 100644 examples/remoteobjects/plugins/CMakeLists.txt create mode 100644 examples/remoteobjects/plugins/imports/TimeExample/Clock.qml create mode 100644 examples/remoteobjects/plugins/imports/TimeExample/center.png create mode 100644 examples/remoteobjects/plugins/imports/TimeExample/clock.png create mode 100644 examples/remoteobjects/plugins/imports/TimeExample/hour.png create mode 100644 examples/remoteobjects/plugins/imports/TimeExample/minute.png create mode 100644 examples/remoteobjects/plugins/imports/TimeExample/qmldir create mode 100644 examples/remoteobjects/plugins/plugin.cpp create mode 100644 examples/remoteobjects/plugins/plugins.pro create mode 100644 examples/remoteobjects/plugins/plugins.qml create mode 100644 examples/remoteobjects/plugins/plugins0.qml create mode 100644 examples/remoteobjects/plugins/plugins1.qml create mode 100644 examples/remoteobjects/plugins/plugins2.qml create mode 100644 examples/remoteobjects/qmlmodelviewclient/CMakeLists.txt create mode 100644 examples/remoteobjects/qmlmodelviewclient/doc/src/qmlmodelviewclient.qdoc create mode 100644 examples/remoteobjects/qmlmodelviewclient/main.cpp create mode 100644 examples/remoteobjects/qmlmodelviewclient/main.qml create mode 100644 examples/remoteobjects/qmlmodelviewclient/qml.qrc create mode 100644 examples/remoteobjects/qmlmodelviewclient/qmlmodelviewclient.pro create mode 100644 examples/remoteobjects/remoteobjects.pro create mode 100644 examples/remoteobjects/remoteobjects_server/CMakeLists.txt create mode 100644 examples/remoteobjects/remoteobjects_server/main.cpp create mode 100644 examples/remoteobjects/remoteobjects_server/remoteobjects_server.pro create mode 100644 examples/remoteobjects/remoteobjects_server/timemodel.cpp create mode 100644 examples/remoteobjects/remoteobjects_server/timemodel.h create mode 100644 examples/remoteobjects/simpleswitch/CMakeLists.txt create mode 100644 examples/remoteobjects/simpleswitch/directconnectclient/CMakeLists.txt create mode 100644 examples/remoteobjects/simpleswitch/directconnectclient/client.cpp create mode 100644 examples/remoteobjects/simpleswitch/directconnectclient/client.h create mode 100644 examples/remoteobjects/simpleswitch/directconnectclient/directconnectclient.pro create mode 100644 examples/remoteobjects/simpleswitch/directconnectclient/main.cpp create mode 100644 examples/remoteobjects/simpleswitch/directconnectclient/simpleswitch.rep create mode 100644 examples/remoteobjects/simpleswitch/directconnectdynamicclient/CMakeLists.txt create mode 100644 examples/remoteobjects/simpleswitch/directconnectdynamicclient/directconnectdynamicclient.pro create mode 100644 examples/remoteobjects/simpleswitch/directconnectdynamicclient/dynamicclient.cpp create mode 100644 examples/remoteobjects/simpleswitch/directconnectdynamicclient/dynamicclient.h create mode 100644 examples/remoteobjects/simpleswitch/directconnectdynamicclient/main.cpp create mode 100644 examples/remoteobjects/simpleswitch/directconnectserver/CMakeLists.txt create mode 100644 examples/remoteobjects/simpleswitch/directconnectserver/directconnectserver.pro create mode 100644 examples/remoteobjects/simpleswitch/directconnectserver/main.cpp create mode 100644 examples/remoteobjects/simpleswitch/directconnectserver/simpleswitch.cpp create mode 100644 examples/remoteobjects/simpleswitch/directconnectserver/simpleswitch.h create mode 100644 examples/remoteobjects/simpleswitch/directconnectserver/simpleswitch.rep create mode 100644 examples/remoteobjects/simpleswitch/registryconnectedclient/CMakeLists.txt create mode 100644 examples/remoteobjects/simpleswitch/registryconnectedclient/dynamicclient.cpp create mode 100644 examples/remoteobjects/simpleswitch/registryconnectedclient/dynamicclient.h create mode 100644 examples/remoteobjects/simpleswitch/registryconnectedclient/main.cpp create mode 100644 examples/remoteobjects/simpleswitch/registryconnectedclient/registryconnectedclient.pro create mode 100644 examples/remoteobjects/simpleswitch/registryconnectedserver/CMakeLists.txt create mode 100644 examples/remoteobjects/simpleswitch/registryconnectedserver/main.cpp create mode 100644 examples/remoteobjects/simpleswitch/registryconnectedserver/registryconnectedserver.pro create mode 100644 examples/remoteobjects/simpleswitch/registryconnectedserver/simpleswitch.cpp create mode 100644 examples/remoteobjects/simpleswitch/registryconnectedserver/simpleswitch.h create mode 100644 examples/remoteobjects/simpleswitch/registryconnectedserver/simpleswitch.rep create mode 100644 examples/remoteobjects/simpleswitch/simpleswitch.pro create mode 100644 examples/remoteobjects/ssl/CMakeLists.txt create mode 100644 examples/remoteobjects/ssl/doc/src/ssl.qdoc create mode 100644 examples/remoteobjects/ssl/ssl.pro create mode 100644 examples/remoteobjects/ssl/sslcppclient/CMakeLists.txt create mode 100644 examples/remoteobjects/ssl/sslcppclient/main.cpp create mode 100644 examples/remoteobjects/ssl/sslcppclient/sslcppclient.pro create mode 100644 examples/remoteobjects/ssl/sslcppclient/timemodel.rep create mode 100644 examples/remoteobjects/ssl/sslserver/CMakeLists.txt create mode 100644 examples/remoteobjects/ssl/sslserver/cert/cert.qrc create mode 100644 examples/remoteobjects/ssl/sslserver/cert/client.crt create mode 100644 examples/remoteobjects/ssl/sslserver/cert/client.key create mode 100644 examples/remoteobjects/ssl/sslserver/cert/readme create mode 100644 examples/remoteobjects/ssl/sslserver/cert/rootCA.key create mode 100644 examples/remoteobjects/ssl/sslserver/cert/rootCA.pem create mode 100644 examples/remoteobjects/ssl/sslserver/cert/rootCA.srl create mode 100644 examples/remoteobjects/ssl/sslserver/cert/server.crt create mode 100644 examples/remoteobjects/ssl/sslserver/cert/server.key create mode 100644 examples/remoteobjects/ssl/sslserver/main.cpp create mode 100644 examples/remoteobjects/ssl/sslserver/sslserver.cpp create mode 100644 examples/remoteobjects/ssl/sslserver/sslserver.h create mode 100644 examples/remoteobjects/ssl/sslserver/sslserver.pro create mode 100644 examples/remoteobjects/ssl/sslserver/timemodel.cpp create mode 100644 examples/remoteobjects/ssl/sslserver/timemodel.h create mode 100644 examples/remoteobjects/timemodel.rep create mode 100644 examples/remoteobjects/websockets/CMakeLists.txt create mode 100644 examples/remoteobjects/websockets/common/cert/cert.qrc create mode 100644 examples/remoteobjects/websockets/common/cert/client.crt create mode 100644 examples/remoteobjects/websockets/common/cert/client.key create mode 100644 examples/remoteobjects/websockets/common/cert/readme create mode 100644 examples/remoteobjects/websockets/common/cert/rootCA.key create mode 100644 examples/remoteobjects/websockets/common/cert/rootCA.pem create mode 100644 examples/remoteobjects/websockets/common/cert/rootCA.srl create mode 100644 examples/remoteobjects/websockets/common/cert/server.crt create mode 100644 examples/remoteobjects/websockets/common/cert/server.key create mode 100644 examples/remoteobjects/websockets/common/common.pri create mode 100644 examples/remoteobjects/websockets/common/websocketiodevice.cpp create mode 100644 examples/remoteobjects/websockets/common/websocketiodevice.h create mode 100644 examples/remoteobjects/websockets/doc/src/websocket.qdoc create mode 100644 examples/remoteobjects/websockets/websockets.pro create mode 100644 examples/remoteobjects/websockets/wsclient/CMakeLists.txt create mode 100644 examples/remoteobjects/websockets/wsclient/main.cpp create mode 100644 examples/remoteobjects/websockets/wsclient/wsclient.pro create mode 100644 examples/remoteobjects/websockets/wsserver/CMakeLists.txt create mode 100644 examples/remoteobjects/websockets/wsserver/main.cpp create mode 100644 examples/remoteobjects/websockets/wsserver/wsserver.pro create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_local_backend_p.h create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_qnx_backend_p.h create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_qnx_global_p.h create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_qnx_qiodevices_p.h create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_qnx_server_p.h create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_tcpip_backend_p.h create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnectionfactories_p.h create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectabstractitemmodeladapter_p.h create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectabstractitemmodelreplica_p.h create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectabstractitemmodeltypes_p.h create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectcontainers_p.h create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectnode_p.h create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectpacket_p.h create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectpendingcall_p.h create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectregistrysource_p.h create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectreplica_p.h create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectsource_p.h create mode 100644 include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectsourceio_p.h create mode 100644 include/QtRemoteObjects/QAbstractItemModelReplica create mode 100644 include/QtRemoteObjects/QConnectionAbstractServer create mode 100644 include/QtRemoteObjects/QIOQnxSource create mode 100644 include/QtRemoteObjects/QIntHash create mode 100644 include/QtRemoteObjects/QQnxNativeIo create mode 100644 include/QtRemoteObjects/QQnxNativeServer create mode 100644 include/QtRemoteObjects/QRemoteObjectAbstractPersistedStore create mode 100644 include/QtRemoteObjects/QRemoteObjectDynamicReplica create mode 100644 include/QtRemoteObjects/QRemoteObjectHost create mode 100644 include/QtRemoteObjects/QRemoteObjectHostBase create mode 100644 include/QtRemoteObjects/QRemoteObjectNode create mode 100644 include/QtRemoteObjects/QRemoteObjectPendingCall create mode 100644 include/QtRemoteObjects/QRemoteObjectPendingCallWatcher create mode 100644 include/QtRemoteObjects/QRemoteObjectPendingReply create mode 100644 include/QtRemoteObjects/QRemoteObjectRegistry create mode 100644 include/QtRemoteObjects/QRemoteObjectRegistryHost create mode 100644 include/QtRemoteObjects/QRemoteObjectReplica create mode 100644 include/QtRemoteObjects/QRemoteObjectSettingsStore create mode 100644 include/QtRemoteObjects/QRemoteObjectSourceLocation create mode 100644 include/QtRemoteObjects/QRemoteObjectSourceLocationInfo create mode 100644 include/QtRemoteObjects/QRemoteObjectSourceLocations create mode 100644 include/QtRemoteObjects/QtROClientFactory create mode 100644 include/QtRemoteObjects/QtROClientIoDevice create mode 100644 include/QtRemoteObjects/QtROIoDeviceBase create mode 100644 include/QtRemoteObjects/QtROServerFactory create mode 100644 include/QtRemoteObjects/QtROServerIoDevice create mode 100644 include/QtRemoteObjects/QtRemoteObjects create mode 100644 include/QtRemoteObjects/QtRemoteObjectsVersion create mode 100644 include/QtRemoteObjects/headers.pri create mode 100644 include/QtRemoteObjects/qconnection_qnx_qiodevices.h create mode 100644 include/QtRemoteObjects/qconnection_qnx_server.h create mode 100644 include/QtRemoteObjects/qconnectionfactories.h create mode 100644 include/QtRemoteObjects/qremoteobjectabstractitemmodelreplica.h create mode 100644 include/QtRemoteObjects/qremoteobjectdynamicreplica.h create mode 100644 include/QtRemoteObjects/qremoteobjectnode.h create mode 100644 include/QtRemoteObjects/qremoteobjectpendingcall.h create mode 100644 include/QtRemoteObjects/qremoteobjectregistry.h create mode 100644 include/QtRemoteObjects/qremoteobjectreplica.h create mode 100644 include/QtRemoteObjects/qremoteobjectsettingsstore.h create mode 100644 include/QtRemoteObjects/qremoteobjectsource.h create mode 100644 include/QtRemoteObjects/qtremoteobjectglobal.h create mode 100644 include/QtRemoteObjects/qtremoteobjectsversion.h create mode 100644 include/QtRemoteObjectsQml/6.3.1/QtRemoteObjectsQml/private/qremoteobjectsqml_p.h create mode 100644 include/QtRemoteObjectsQml/QtRemoteObjectsQml create mode 100644 include/QtRemoteObjectsQml/QtRemoteObjectsQmlVersion create mode 100644 include/QtRemoteObjectsQml/headers.pri create mode 100644 include/QtRemoteObjectsQml/qtremoteobjectsqmlversion.h create mode 100644 include/QtRepParser/QRegexParser create mode 100644 include/QtRepParser/QtRepParser create mode 100644 include/QtRepParser/QtRepParserVersion create mode 100644 include/QtRepParser/headers.pri create mode 100644 include/QtRepParser/qregexparser.h create mode 100644 include/QtRepParser/qtrepparserversion.h create mode 100644 mkspecs/features/features.pro create mode 100644 mkspecs/features/remoteobjects_repc.prf create mode 100644 mkspecs/features/repcclient.pri create mode 100644 mkspecs/features/repccommon.pri create mode 100644 mkspecs/features/repcmerged.pri create mode 100644 mkspecs/features/repcserver.pri create mode 100644 mkspecs/features/repparser.prf create mode 100644 mkspecs/mkspecs.pro create mode 100644 src/CMakeLists.txt create mode 100644 src/remoteobjects/CMakeLists.txt create mode 100644 src/remoteobjects/Qt5RemoteObjectsConfigExtras.cmake.in create mode 100644 src/remoteobjects/Qt6RemoteObjectsMacros.cmake create mode 100644 src/remoteobjects/configure.cmake create mode 100644 src/remoteobjects/doc/images/DirectConnectClientServerOutput.png create mode 100644 src/remoteobjects/doc/images/DirectConnectServerOutput.png create mode 100644 src/remoteobjects/doc/images/README create mode 100644 src/remoteobjects/doc/images/RemoteObjectsHighLevel.png create mode 100644 src/remoteobjects/doc/qtremoteobjects.qdocconf create mode 100644 src/remoteobjects/doc/snippets/README create mode 100644 src/remoteobjects/doc/snippets/cmake-macros/CMakeLists.txt create mode 100644 src/remoteobjects/doc/snippets/cmake-macros/main.cpp create mode 100644 src/remoteobjects/doc/snippets/cmake-macros/simpleswitch.cpp create mode 100644 src/remoteobjects/doc/snippets/cmake-macros/simpleswitch.h create mode 100644 src/remoteobjects/doc/snippets/cmake-macros/simpleswitch.rep create mode 100644 src/remoteobjects/doc/snippets/doc_src_remoteobjects.h create mode 100644 src/remoteobjects/doc/snippets/doc_src_simpleswitch.cpp create mode 100644 src/remoteobjects/doc/src/cmake-macros.qdoc create mode 100644 src/remoteobjects/doc/src/qt6-changes.qdoc create mode 100644 src/remoteobjects/doc/src/remoteobjects-compatibility.qdoc create mode 100644 src/remoteobjects/doc/src/remoteobjects-cpp.qdoc create mode 100644 src/remoteobjects/doc/src/remoteobjects-custom-transport.qdoc create mode 100644 src/remoteobjects/doc/src/remoteobjects-example-dynamic-replica.qdoc create mode 100644 src/remoteobjects/doc/src/remoteobjects-example-registry.qdoc create mode 100644 src/remoteobjects/doc/src/remoteobjects-example-static-source.qdoc create mode 100644 src/remoteobjects/doc/src/remoteobjects-external-schemas.qdoc create mode 100644 src/remoteobjects/doc/src/remoteobjects-gettingstarted.qdoc create mode 100644 src/remoteobjects/doc/src/remoteobjects-index.qdoc create mode 100644 src/remoteobjects/doc/src/remoteobjects-interaction.qdoc create mode 100644 src/remoteobjects/doc/src/remoteobjects-nodes.qdoc create mode 100644 src/remoteobjects/doc/src/remoteobjects-qml.qdoc create mode 100644 src/remoteobjects/doc/src/remoteobjects-registry.qdoc create mode 100644 src/remoteobjects/doc/src/remoteobjects-repc.qdoc create mode 100644 src/remoteobjects/doc/src/remoteobjects-replica.qdoc create mode 100644 src/remoteobjects/doc/src/remoteobjects-source.qdoc create mode 100644 src/remoteobjects/doc/src/remoteobjects-troubleshooting.qdoc create mode 100644 src/remoteobjects/qconnection_local_backend.cpp create mode 100644 src/remoteobjects/qconnection_local_backend_p.h create mode 100644 src/remoteobjects/qconnection_qnx_backend.cpp create mode 100644 src/remoteobjects/qconnection_qnx_backend_p.h create mode 100644 src/remoteobjects/qconnection_qnx_global_p.h create mode 100644 src/remoteobjects/qconnection_qnx_qiodevices.cpp create mode 100644 src/remoteobjects/qconnection_qnx_qiodevices.h create mode 100644 src/remoteobjects/qconnection_qnx_qiodevices_p.h create mode 100644 src/remoteobjects/qconnection_qnx_server.cpp create mode 100644 src/remoteobjects/qconnection_qnx_server.h create mode 100644 src/remoteobjects/qconnection_qnx_server_p.h create mode 100644 src/remoteobjects/qconnection_tcpip_backend.cpp create mode 100644 src/remoteobjects/qconnection_tcpip_backend_p.h create mode 100644 src/remoteobjects/qconnectionfactories.cpp create mode 100644 src/remoteobjects/qconnectionfactories.h create mode 100644 src/remoteobjects/qconnectionfactories_p.h create mode 100644 src/remoteobjects/qremoteobjectabstractitemmodeladapter.cpp create mode 100644 src/remoteobjects/qremoteobjectabstractitemmodeladapter_p.h create mode 100644 src/remoteobjects/qremoteobjectabstractitemmodelreplica.cpp create mode 100644 src/remoteobjects/qremoteobjectabstractitemmodelreplica.h create mode 100644 src/remoteobjects/qremoteobjectabstractitemmodelreplica_p.h create mode 100644 src/remoteobjects/qremoteobjectabstractitemmodeltypes_p.h create mode 100644 src/remoteobjects/qremoteobjectcontainers.cpp create mode 100644 src/remoteobjects/qremoteobjectcontainers_p.h create mode 100644 src/remoteobjects/qremoteobjectdynamicreplica.cpp create mode 100644 src/remoteobjects/qremoteobjectdynamicreplica.h create mode 100644 src/remoteobjects/qremoteobjectnode.cpp create mode 100644 src/remoteobjects/qremoteobjectnode.h create mode 100644 src/remoteobjects/qremoteobjectnode_p.h create mode 100644 src/remoteobjects/qremoteobjectpacket.cpp create mode 100644 src/remoteobjects/qremoteobjectpacket_p.h create mode 100644 src/remoteobjects/qremoteobjectpendingcall.cpp create mode 100644 src/remoteobjects/qremoteobjectpendingcall.h create mode 100644 src/remoteobjects/qremoteobjectpendingcall_p.h create mode 100644 src/remoteobjects/qremoteobjectregistry.cpp create mode 100644 src/remoteobjects/qremoteobjectregistry.h create mode 100644 src/remoteobjects/qremoteobjectregistrysource.cpp create mode 100644 src/remoteobjects/qremoteobjectregistrysource_p.h create mode 100644 src/remoteobjects/qremoteobjectreplica.cpp create mode 100644 src/remoteobjects/qremoteobjectreplica.h create mode 100644 src/remoteobjects/qremoteobjectreplica_p.h create mode 100644 src/remoteobjects/qremoteobjectsettingsstore.cpp create mode 100644 src/remoteobjects/qremoteobjectsettingsstore.h create mode 100644 src/remoteobjects/qremoteobjectsource.cpp create mode 100644 src/remoteobjects/qremoteobjectsource.h create mode 100644 src/remoteobjects/qremoteobjectsource_p.h create mode 100644 src/remoteobjects/qremoteobjectsourceio.cpp create mode 100644 src/remoteobjects/qremoteobjectsourceio_p.h create mode 100644 src/remoteobjects/qtremoteobjectglobal.cpp create mode 100644 src/remoteobjects/qtremoteobjectglobal.h create mode 100644 src/remoteobjectsqml/CMakeLists.txt create mode 100644 src/remoteobjectsqml/qremoteobjectsqml_p.h create mode 100644 src/repparser/CMakeLists.txt create mode 100644 src/repparser/parser.g create mode 100644 src/repparser/qregexparser.h create mode 100644 sync.profile create mode 100644 tests/CMakeLists.txt create mode 100644 tests/auto/CMakeLists.txt create mode 100644 tests/auto/benchmarks/CMakeLists.txt create mode 100644 tests/auto/benchmarks/tst_benchmarkstest.cpp create mode 100644 tests/auto/bic/data/QtRemoteObjects.5.13.0.linux-gcc-amd64.txt create mode 100644 tests/auto/bic/data/QtRemoteObjects.5.14.0.linux-gcc-amd64.txt create mode 100644 tests/auto/cmake/CMakeLists.txt create mode 100644 tests/auto/cmake/test_cmake_macros/CMakeLists.txt create mode 100644 tests/auto/cmake/test_cmake_macros/main.cpp create mode 100644 tests/auto/external_IODevice/CMakeLists.txt create mode 100644 tests/auto/external_IODevice/cert/cert.qrc create mode 100644 tests/auto/external_IODevice/cert/client.crt create mode 100644 tests/auto/external_IODevice/cert/client.key create mode 100644 tests/auto/external_IODevice/cert/generate.sh create mode 100644 tests/auto/external_IODevice/cert/rootCA.key create mode 100644 tests/auto/external_IODevice/cert/rootCA.pem create mode 100644 tests/auto/external_IODevice/cert/rootCA.srl create mode 100644 tests/auto/external_IODevice/cert/server-req.ext create mode 100644 tests/auto/external_IODevice/cert/server.crt create mode 100644 tests/auto/external_IODevice/cert/server.key create mode 100644 tests/auto/external_IODevice/pingpong.rep create mode 100644 tests/auto/external_IODevice/sslTestServer/CMakeLists.txt create mode 100644 tests/auto/external_IODevice/sslTestServer/main.cpp create mode 100644 tests/auto/external_IODevice/sslTestServer/pingpong.cpp create mode 100644 tests/auto/external_IODevice/sslTestServer/pingpong.h create mode 100644 tests/auto/external_IODevice/sslTestServer/sslserver.cpp create mode 100644 tests/auto/external_IODevice/sslTestServer/sslserver.h create mode 100644 tests/auto/external_IODevice/tst_client/CMakeLists.txt create mode 100644 tests/auto/external_IODevice/tst_client/tst_client.cpp create mode 100644 tests/auto/integration/CMakeLists.txt create mode 100644 tests/auto/integration/engine.cpp create mode 100644 tests/auto/integration/engine.h create mode 100644 tests/auto/integration/engine.rep create mode 100644 tests/auto/integration/enum.rep create mode 100644 tests/auto/integration/pod.rep create mode 100644 tests/auto/integration/speedometer.cpp create mode 100644 tests/auto/integration/speedometer.h create mode 100644 tests/auto/integration/speedometer.rep create mode 100644 tests/auto/integration/temperature.h create mode 100644 tests/auto/integration/tst_integration.cpp create mode 100644 tests/auto/integration_external/CMakeLists.txt create mode 100644 tests/auto/integration_external/MyInterface.rep create mode 100644 tests/auto/integration_external/client/CMakeLists.txt create mode 100644 tests/auto/integration_external/client/main.cpp create mode 100644 tests/auto/integration_external/external/CMakeLists.txt create mode 100644 tests/auto/integration_external/external/tst_integration_external.cpp create mode 100644 tests/auto/integration_external/server/CMakeLists.txt create mode 100644 tests/auto/integration_external/server/main.cpp create mode 100644 tests/auto/integration_external/server/mytestserver.cpp create mode 100644 tests/auto/integration_external/server/mytestserver.h create mode 100644 tests/auto/integration_multiprocess/CMakeLists.txt create mode 100644 tests/auto/integration_multiprocess/ExtPodInterface.rep create mode 100644 tests/auto/integration_multiprocess/MyInterface.rep create mode 100644 tests/auto/integration_multiprocess/PodInterface.rep create mode 100644 tests/auto/integration_multiprocess/client/CMakeLists.txt create mode 100644 tests/auto/integration_multiprocess/client/main.cpp create mode 100644 tests/auto/integration_multiprocess/server/CMakeLists.txt create mode 100644 tests/auto/integration_multiprocess/server/main.cpp create mode 100644 tests/auto/integration_multiprocess/server/mytestserver.cpp create mode 100644 tests/auto/integration_multiprocess/server/mytestserver.h create mode 100644 tests/auto/integration_multiprocess/tst/CMakeLists.txt create mode 100644 tests/auto/integration_multiprocess/tst/tst_integration_multiprocess.cpp create mode 100644 tests/auto/localsockettestserver/CMakeLists.txt create mode 100644 tests/auto/localsockettestserver/main.cpp create mode 100644 tests/auto/modelreplica/CMakeLists.txt create mode 100644 tests/auto/modelreplica/model.rep create mode 100644 tests/auto/modelreplica/tst_modelreplicatest.cpp create mode 100644 tests/auto/modelview/CMakeLists.txt create mode 100644 tests/auto/modelview/tst_modelview.cpp create mode 100644 tests/auto/pods/CMakeLists.txt create mode 100644 tests/auto/pods/pods.h create mode 100644 tests/auto/pods/tst_pods.cpp create mode 100644 tests/auto/proxy/CMakeLists.txt create mode 100644 tests/auto/proxy/engine.rep create mode 100644 tests/auto/proxy/subclass.rep create mode 100644 tests/auto/proxy/tst_proxy.cpp create mode 100644 tests/auto/proxy_multiprocess/CMakeLists.txt create mode 100644 tests/auto/proxy_multiprocess/client/CMakeLists.txt create mode 100644 tests/auto/proxy_multiprocess/client/main.cpp create mode 100644 tests/auto/proxy_multiprocess/namespace.h create mode 100644 tests/auto/proxy_multiprocess/proxy/CMakeLists.txt create mode 100644 tests/auto/proxy_multiprocess/proxy/main.cpp create mode 100644 tests/auto/proxy_multiprocess/server/CMakeLists.txt create mode 100644 tests/auto/proxy_multiprocess/server/main.cpp create mode 100644 tests/auto/proxy_multiprocess/server/mytestserver.cpp create mode 100644 tests/auto/proxy_multiprocess/server/mytestserver.h create mode 100644 tests/auto/proxy_multiprocess/shared.h create mode 100644 tests/auto/proxy_multiprocess/subclass.rep create mode 100644 tests/auto/proxy_multiprocess/tst/CMakeLists.txt create mode 100644 tests/auto/proxy_multiprocess/tst/tst_proxy_multiprocess.cpp create mode 100644 tests/auto/qml/CMakeLists.txt create mode 100644 tests/auto/qml/integration/CMakeLists.txt create mode 100644 tests/auto/qml/integration/data/tst_integration.qml create mode 100644 tests/auto/qml/integration/tst_integration.cpp create mode 100644 tests/auto/qml/usertypes/CMakeLists.txt create mode 100644 tests/auto/qml/usertypes/data/MyType.qml create mode 100644 tests/auto/qml/usertypes/data/complex.qml create mode 100644 tests/auto/qml/usertypes/data/composite.qml create mode 100644 tests/auto/qml/usertypes/data/extraPropComplex.qml create mode 100644 tests/auto/qml/usertypes/data/extraprop.qml create mode 100644 tests/auto/qml/usertypes/data/extraprop2.qml create mode 100644 tests/auto/qml/usertypes/data/hosted.qml create mode 100644 tests/auto/qml/usertypes/data/model.qml create mode 100644 tests/auto/qml/usertypes/data/subObject.qml create mode 100644 tests/auto/qml/usertypes/data/twoReplicas.qml create mode 100644 tests/auto/qml/usertypes/data/watcher.qml create mode 100644 tests/auto/qml/usertypes/tst_usertypes.cpp create mode 100644 tests/auto/qml/usertypes/usertypes.rep create mode 100644 tests/auto/reconnect/CMakeLists.txt create mode 100644 tests/auto/reconnect/client/CMakeLists.txt create mode 100644 tests/auto/reconnect/client/main.cpp create mode 100644 tests/auto/reconnect/server/CMakeLists.txt create mode 100644 tests/auto/reconnect/server/main.cpp create mode 100644 tests/auto/reconnect/tst/CMakeLists.txt create mode 100644 tests/auto/reconnect/tst/tst_reconnect.cpp create mode 100644 tests/auto/rep_from_header/CMakeLists.txt create mode 100644 tests/auto/rep_from_header/pods.h create mode 100644 tests/auto/rep_from_header/tst_rep_from_header.cpp create mode 100644 tests/auto/repc/CMakeLists.txt create mode 100644 tests/auto/repc/enums/CMakeLists.txt create mode 100644 tests/auto/repc/enums/enums.rep create mode 100644 tests/auto/repc/enums/tst_enums.cpp create mode 100644 tests/auto/repc/pods/CMakeLists.txt create mode 100644 tests/auto/repc/pods/pods.rep create mode 100644 tests/auto/repc/pods/tst_pods.cpp create mode 100644 tests/auto/repc/signature/CMakeLists.txt create mode 100644 tests/auto/repc/signature/differentClassEnum/CMakeLists.txt create mode 100644 tests/auto/repc/signature/differentClassEnum/mismatch.rep create mode 100644 tests/auto/repc/signature/differentGlobalEnum/CMakeLists.txt create mode 100644 tests/auto/repc/signature/differentGlobalEnum/mismatch.rep create mode 100644 tests/auto/repc/signature/differentPropertyCount/CMakeLists.txt create mode 100644 tests/auto/repc/signature/differentPropertyCount/mismatch.rep create mode 100644 tests/auto/repc/signature/differentPropertyCountChild/CMakeLists.txt create mode 100644 tests/auto/repc/signature/differentPropertyCountChild/differentPropertyCountChild.pro create mode 100644 tests/auto/repc/signature/differentPropertyCountChild/mismatch.rep create mode 100644 tests/auto/repc/signature/differentPropertyType/CMakeLists.txt create mode 100644 tests/auto/repc/signature/differentPropertyType/mismatch.rep create mode 100644 tests/auto/repc/signature/differentSignalCount/CMakeLists.txt create mode 100644 tests/auto/repc/signature/differentSignalCount/mismatch.rep create mode 100644 tests/auto/repc/signature/differentSignalParamCount/CMakeLists.txt create mode 100644 tests/auto/repc/signature/differentSignalParamCount/mismatch.rep create mode 100644 tests/auto/repc/signature/differentSignalParamType/CMakeLists.txt create mode 100644 tests/auto/repc/signature/differentSignalParamType/mismatch.rep create mode 100644 tests/auto/repc/signature/differentSlotCount/CMakeLists.txt create mode 100644 tests/auto/repc/signature/differentSlotCount/mismatch.rep create mode 100644 tests/auto/repc/signature/differentSlotParamCount/CMakeLists.txt create mode 100644 tests/auto/repc/signature/differentSlotParamCount/mismatch.rep create mode 100644 tests/auto/repc/signature/differentSlotParamType/CMakeLists.txt create mode 100644 tests/auto/repc/signature/differentSlotParamType/mismatch.rep create mode 100644 tests/auto/repc/signature/differentSlotType/CMakeLists.txt create mode 100644 tests/auto/repc/signature/differentSlotType/mismatch.rep create mode 100644 tests/auto/repc/signature/matchAndQuit/CMakeLists.txt create mode 100644 tests/auto/repc/signature/matchAndQuit/main.cpp create mode 100644 tests/auto/repc/signature/mismatch.cpp create mode 100644 tests/auto/repc/signature/mismatch.pri create mode 100644 tests/auto/repc/signature/scrambledProperties/CMakeLists.txt create mode 100644 tests/auto/repc/signature/scrambledProperties/mismatch.rep create mode 100644 tests/auto/repc/signature/scrambledSignals/CMakeLists.txt create mode 100644 tests/auto/repc/signature/scrambledSignals/mismatch.rep create mode 100644 tests/auto/repc/signature/scrambledSlots/CMakeLists.txt create mode 100644 tests/auto/repc/signature/scrambledSlots/mismatch.rep create mode 100644 tests/auto/repc/signature/server.rep create mode 100644 tests/auto/repc/signature/signatureServer/CMakeLists.txt create mode 100644 tests/auto/repc/signature/signatureServer/main.cpp create mode 100644 tests/auto/repc/signature/signatureTests/CMakeLists.txt create mode 100644 tests/auto/repc/signature/signatureTests/tst_signature.cpp create mode 100644 tests/auto/repc/signature/state/CMakeLists.txt create mode 100644 tests/auto/repc/signature/state/main.cpp create mode 100644 tests/auto/repc/signature/state/mismatch.rep create mode 100644 tests/auto/repcodegenerator/CMakeLists.txt create mode 100644 tests/auto/repcodegenerator/classwithreadonlypropertytest.rep create mode 100644 tests/auto/repcodegenerator/classwithsignalonlytest.rep create mode 100644 tests/auto/repcodegenerator/preprocessortest.rep create mode 100644 tests/auto/repcodegenerator/tst_repcodegenerator.cpp create mode 100644 tests/auto/repfiles/localdatacenter.rep create mode 100644 tests/auto/repfiles/tcpdatacenter.rep create mode 100644 tests/auto/repparser/CMakeLists.txt create mode 100644 tests/auto/repparser/tst_parser.cpp create mode 100644 tests/auto/restart/CMakeLists.txt create mode 100644 tests/auto/restart/client/CMakeLists.txt create mode 100644 tests/auto/restart/client/main.cpp create mode 100644 tests/auto/restart/server/CMakeLists.txt create mode 100644 tests/auto/restart/server/main.cpp create mode 100644 tests/auto/restart/server/mytestserver.cpp create mode 100644 tests/auto/restart/server/mytestserver.h create mode 100644 tests/auto/restart/subclass.rep create mode 100644 tests/auto/restart/tst/CMakeLists.txt create mode 100644 tests/auto/restart/tst/tst_restart.cpp create mode 100644 tests/auto/shared/model_utilities.h create mode 100644 tests/auto/subclassreplica/CMakeLists.txt create mode 100644 tests/auto/subclassreplica/class.rep create mode 100644 tests/auto/subclassreplica/tst_subclassreplicatest.cpp create mode 100644 tests/global/global.cfg create mode 100644 tests/shared/testutils.h create mode 100644 tools/CMakeLists.txt create mode 100644 tools/repc/CMakeLists.txt create mode 100644 tools/repc/cppcodegenerator.cpp create mode 100644 tools/repc/cppcodegenerator.h create mode 100644 tools/repc/main.cpp create mode 100644 tools/repc/repc.pro create mode 100644 tools/repc/repcodegenerator.cpp create mode 100644 tools/repc/repcodegenerator.h create mode 100644 tools/repc/utils.cpp create mode 100644 tools/repc/utils.h create mode 100644 tools/tools.pro diff --git a/.QT-ENTERPRISE-LICENSE-AGREEMENT b/.QT-ENTERPRISE-LICENSE-AGREEMENT new file mode 100644 index 0000000..8d68b15 --- /dev/null +++ b/.QT-ENTERPRISE-LICENSE-AGREEMENT @@ -0,0 +1,1977 @@ +QT LICENSE AGREEMENT +Agreement version 4.4.1 + +This Qt License Agreement ("Agreement") is a legal agreement for the licensing +of Licensed Software (as defined below) between The Qt Company (as defined +below) and the Licensee who has accepted the terms of this Agreement by signing +this Agreement or by downloading or using the Licensed Software or in any other +appropriate means. + +Capitalized terms used herein are defined in Section 1. + +WHEREAS: + (A) Licensee wishes to use the Licensed Software for the purpose of + developing and distributing Applications and/or Devices (each as defined + below); + (B) The Qt Company is willing to grant the Licensee a right to use Licensed + Software for such a purpose pursuant to term and conditions of this + Agreement; and + (C) Parties wish to enable that their respective Affiliates also can sell + and purchase licenses to serve Licensee Affiliates' needs to use Licensed + Software pursuant to terms of the Agreement. Any such license purchases by + Licensee Affiliates from The Qt Company or its Affiliates will create + contractual relationship directly between the relevant The Qt Company and + the respective ordering Licensee Affiliate "Acceding Agreement"). + Accordingly, Licensee shall not be a party to any such Acceding Agreement, + and no rights or obligations are created to the Licensee thereunder but all + rights and obligations under such Acceding Agreement are vested and borne + solely by the ordering Licensee Affiliate and the relevant The Qt Company + as a contracting parties under such Acceding Agreement. + +NOW, THEREFORE, THE PARTIES HEREBY AGREE AS FOLLOWS: + +1. DEFINITIONS + +"Affiliate" of a Party shall mean an entity + (i) which is directly or indirectly controlling such Party; + (ii) which is under the same direct or indirect ownership or control as + such Party; or + (iii) which is directly or indirectly owned or controlled by such Party. +For these purposes, an entity shall be treated as being controlled by another +if that other entity has fifty percent (50 %) or more of the votes in such +entity, is able to direct its affairs and/or to control the composition of its +board of directors or equivalent body. + +"Add-on Products" shall mean The Qt Company's specific add-on software products +which are not licensed as part of The Qt Company's standard product offering, +but shall be included into the scope of Licensed Software only if so +specifically agreed between the Parties. + +"Agreement Term" shall mean the validity period of this Agreement, as set forth +in Section 12. + +"Applications" shall mean software products created using the Licensed +Software, which include the Redistributables, or part thereof. + +"Contractor(s)" shall mean third party consultants, distributors and +contractors performing services to the Licensee under applicable contractual +arrangement. + +"Customer(s)" shall mean Licensee's customers to whom Licensee, directly or +indirectly, distributes copies of the Redistributables as integrated or +incorporated into Applications or Devices. + +"Data Protection Legislation" shall mean the General Data Protection Regulation +(EU 2016/679) (GDPR) and any national implementing laws, regulations and +secondary legislation, as may be amended or updated from time to time, as well +as any other data protection laws or regulations applicable in relevant +territory. + +"Deployment Platforms" shall mean target operating systems and/or hardware +specified in the License Certificate, on which the Redistributables can be +distributed pursuant to the terms and conditions of this Agreement. + +"Designated User(s)" shall mean the employee(s) of Licensee or Licensee's +Affiliates acting within the scope of their employment or Licensee's +Contractors acting within the scope of their services on behalf of Licensee. + +"Development License" shall mean the license needed by the Licensee for each +Designated User to use the Licensed Software under the license grant described +in Section 3.1 of this Agreement. Development Licenses are available per +respective Licensed Software products, each product having its designated scope +and purpose of use. + +"Development License Term" shall mean the agreed validity period of the +Development License or QA Tools license during which time the relevant Licensed +Software product can be used pursuant to this Agreement. Agreed Development +License Term, as ordered and paid for by the Licensee, shall be memorialized in +the applicable License Certificate. + +"Development Platforms" shall mean those host operating systems specified in +the License Certificate, in which the Licensed Software can be used under the +Development License. + +"Devices" shall mean + (1) hardware devices or products that + i. are manufactured and/or distributed by the Licensee, its Affiliates, + Contractors or Customers, and + ii. incorporate, integrate or link to Applications such that + substantial functionality of such unit, when used by an End User, + is provided by Application(s) or otherwise depends on the Licensed + Software, regardless of whether the Application is developed by + Licensee or its Contractors; or + (2) Applications designed for the hardware devices specified in item (1). + + Devices covered by this Agreement shall be specified in Appendix 2 or in a + quote. + +"Distribution License(s)" shall mean a royalty-bearing license required for any +kind of sale, trade, exchange, loan, lease, rental or other distribution by or +on behalf of Licensee to a third party of Redistributables in connection with +Devices pursuant to license grant described in Section 3.3 of this Agreement. +Distribution Licensed are sold separately for each type of Device respectively +and cannot be used for any type of Devices at Licensee's discretion. + +"Distribution License Packs" shall mean set of prepaid Distribution Licenses +for distribution of Redistributables, as defined in The Qt Company's standard +price list, quote, Purchase Order confirmation or in an Appendix 2 hereto, as +the case may be. + +"End User" shall mean the final end user of the Application or a Device. + +"Evaluation License Term" shall mean a time period specified in the License +Certificate for the Licensee to use the relevant Licensed Software for +evaluation purposes according to Section 3.6 herein. + +"Intellectual Property Rights" shall mean patents (including utility models), +design patents, and designs (whether or not capable of registration), chip +topography rights and other like protection, copyrights, trademarks, service +marks, trade names, logos or other words or symbols and any other form of +statutory protection of any kind and applications for any of the foregoing as +well as any trade secrets. + +"License Certificate" shall mean a certificate generated by The Qt Company for +each Designated User respectively upon them downloading the Licensed Software, +which will be available under respective Designated User's Qt Account at +account.qt.io. License Certificates will specify relevant information +pertaining the Licensed Software purchased by Licensee and Designated User's +license to the Licensed Software. + +"License Fee" shall mean the fee charged to the Licensee for rights granted +under the terms of this Agreement. + +"Licensed Software" shall mean specified product of commercially licensed +version of Qt Software and/or QA Tools defined in Appendix 1 and/or Appendix 3, +which Licensee has purchased and which is provided to Licensee under the terms +of this Agreement. Licensed Software shall include corresponding online or +electronic documentation, associated media and printed materials, including the +source code (where applicable), example programs and the documentation. +Licensed Software does not include Third Party Software (as defined in Section +4) or Open Source Qt. The Qt Company may, in the course of its development +activities, at its free and absolute discretion and without any obligation to +send or publish any notifications to the Licensee or in general, make changes, +additions or deletions in the components and functionalities of the Licensed +Software, provided that no such changes, additions or deletions will affect +the already released version of the Licensed Software, but only upcoming +version(s). + +"Licensee" shall mean the individual or legal entity that is party to this +Agreement. + +"Licensee's Records" shall mean books and records that contain information +bearing on Licensee's compliance with this Agreement, Licensee's use of Open +Source Qt and/or the payments due to The Qt Company under this Agreement, +including, but not limited to user information, assembly logs, sales records +and distribution records. + +"Modified Software" shall have the meaning as set forth in Section 2.3. + +"Online Services" shall mean any services or access to systems made available +by The Qt Company to the Licensee over the Internet relating to the Licensed +Software or for the purpose of use by the Licensee of the Licensed Software or +Support. Use of any such Online Services is discretionary for the Licensee and +some of them may be subject to additional fees. + +"Open Source Qt" shall mean Qt Software available under the terms of the GNU +Lesser General Public License, version 2.1 or later ("LGPL") or the GNU General +Public License, version 2.0 or later ("GPL"). For clarity, Open Source Qt shall +not be provided, governed or used under this Agreement. + +"Party" or "Parties" shall mean Licensee and/or The Qt Company. + +"Permitted Software" shall mean (i) third party open source software products +that are generally available for public in source code form and free of any +charge under any of the licenses approved by Open Source Initiative as listed +on https://opensource.org/licenses, which may include parts of Open Source Qt +or be developed using Open Source Qt; and (ii) software The Qt Company has made +available via its Qt Marketplace online distribution channel. + +"Pre-Release Code" shall have the meaning as set forth in Section 4. + +"Prohibited Combination" shall mean any effort to use, combine, incorporate, +link or integrate Licensed Software with any software created with or +incorporating Open Source Qt, or use Licensed Software for creation of any such +software. + +"Purchase Order" shall have the meaning as set forth in Section 10.2. + +"QA Tools" shall mean software libraries and tools as defined in Appendix 1 +depending on which product(s) the Licensee has purchased under the Agreement. + +"Qt Software" shall mean the software libraries and tools of The Qt Company, +which The Qt Company makes available under commercial and/or open source +licenses. + +"Redistributables" shall mean the portions of the Licensed Software set forth +in Appendix 1 that may be distributed pursuant to the terms of this Agreement +in object code form only, including any relevant documentation. Where relevant, +any reference to Licensed Software in this Agreement shall include and refer +also to Redistributables. + +"Renewal Term" shall mean an extension of previous Development License Term as +agreed between the Parties. + +"Submitted Modified Software" shall have the meaning as set forth in Section +2.3. + +"Support" shall mean standard developer support that is provided by The Qt +Company to assist Designated Users in using the Licensed Software in accordance +with this Agreement and the Support Terms. + +"Support Terms" shall mean The Qt Company's standard support terms specified in +Appendix 9 hereto. + +"Taxes" shall have the meaning set forth in Section 10.5. + +"The Qt Company" shall mean: + (i) in the event Licensee is an individual residing in the United States or + a legal entity incorporated in the United States or having its + headquarters in the United States, The Qt Company Inc., a Delaware + corporation with its office at 3031 Tisch Way, 110 Plaza West, + San Jose, CA 95128, USA.; or + (ii) in the event the Licensee is an individual residing outside of the + United States or a legal entity incorporated outside of the United + States or having its registered office outside of the United States, + The Qt Company Ltd., a Finnish company with its registered office at + Miestentie 7, 02150 Espoo, Finland. + +"Third-Party Software" shall have the meaning set forth in Section 4. + +"Updates" shall mean a release or version of the Licensed Software containing +bug fixes, error corrections and other changes that are generally made +available to users of the Licensed Software that have contracted for Support. +Updates are generally depicted as a change to the digits following the decimal +in the Licensed Software version number. The Qt Company shall make Updates +available to the Licensee under the Support. Updates shall be considered as +part of the Licensed Software hereunder. + +"Upgrades" shall mean a release or version of the Licensed Software containing +enhancements and new features and are generally depicted as a change to the +first digit of the Licensed Software version number. In the event Upgrades are +provided to the Licensee under this Agreement, they shall be considered as part +of the Licensed Software hereunder. + +2. OWNERSHIP + +2.1. Ownership of The Qt Company + +The Licensed Software is protected by copyright laws and international +copyright treaties, as well as other intellectual property laws and treaties. +The Licensed Software is licensed, not sold. + +All of The Qt Company's Intellectual Property Rights are and shall remain the +exclusive property of The Qt Company or its licensors respectively. No rights +to The Qt Company's Intellectual Property Rights are assigned or granted to +Licensee under this Agreement, except when and to the extent expressly +specified herein. + +2.2. Ownership of Licensee + +All the Licensee's Intellectual Property Rights are and shall remain the +exclusive property of the Licensee or its licensors respectively. + +All Intellectual Property Rights to the Modified Software, Applications and +Devices shall remain with the Licensee and no rights thereto shall be granted +by the Licensee to The Qt Company under this Agreement (except as set forth in +Section 2.3 below). + +2.3. Modified Software + +Licensee may create bug-fixes, error corrections, patches or modifications to +the Licensed Software ("Modified Software"). Such Modified Software may break +the source or binary compatibility with the Licensed Software (including +without limitation through changing the application programming interfaces +("API") or by adding, changing or deleting any variable, method, or class +signature in the Licensed Software and/or any inter-process protocols, +services or standards in the Licensed Software libraries). To the extent that +Licensee's Modified Software so breaks source or binary compatibility with the +Licensed Software, Licensee acknowledges that The Qt Company's ability to +provide Support may be prevented or limited and Licensee's ability to make use +of Updates may be restricted. + +Licensee may, at its sole and absolute discretion, choose to submit Modified +Software to The Qt Company ("Submitted Modified Software") in connection with +Licensee's Support request, service request or otherwise. In the event +Licensee does so, then, Licensee hereby grants The Qt Company a sublicensable, +assignable, irrevocable, perpetual, worldwide, non-exclusive, royalty-free and +fully paid-up license, under all of Licensee's Intellectual Property Rights, to +reproduce, adapt, translate, modify, and prepare derivative works of, publicly +display, publicly perform, sublicense, make available and distribute such +Submitted Modified Software as The Qt Company sees fit at its free and absolute +discretion. + +3. LICENSES GRANTED + +3.1. Development with Licensed Software + +Subject to the terms of this Agreement, The Qt Company grants to Licensee a +worldwide, non-exclusive, non-transferable license, valid for each Development +License Term, to use, modify and copy the Licensed Software by Designated +Users on the Development Platforms for the sole purposes of designing, +developing, demonstrating and testing Application(s) and/or Devices, and to +provide thereto related support and other related services to Customers. Each +Application and/or Device can only include, incorporate or integrate +contributions by such Designated Users who are duly licensed for the applicable +Development Platform(s) and Deployment Platform(s) (i.e have a valid license +for the appropriate Licensed Software product). + +Licensee may install copies of the Licensed Software on five (5) computers per +Designated User, provided that only the Designated Users who have a valid +Development License may use the Licensed Software. + +Licensee may at any time designate another Designated User to replace a +then-current Designated User by notifying The Qt Company in writing, where such +replacement is due to termination of employment, change of job duties, long +time absence or other such permanent reason affecting Designated User's need +for Licensed Software. + +Upon expiry of the initially agreed Development License Term, the respective +Development License Term shall be automatically extended to one or more Renewal +Term(s), unless and until either Party notifies the other Party in writing, or +any other method acceptable to The Qt Company (it being specifically +acknowledged and understood that verbal notification is explicitly deemed +inadequate in all circumstances), that it does not wish to continue the +Development License Term, such notification to be provided to the other Party +no less than thirty (30) days before expiry of the respective Development +License Term. The Qt Company shall, in good time before the due date for the +above notification, remind the Licensee on the coming Renewal Term. Unless +otherwise agreed between the Parties, Renewal Term shall be 12 months. + +Any such Renewal Term shall be subject to License Fees agreed between the +Parties or, if no advance agreement exists, subject to The Qt Company's +standard list pricing applicable at the commencement date of any such +Renewal Term. + +The Qt Company may either request the Licensee to place a purchase order +corresponding to a quote by The Qt Company, or use Licensee's stored Credit +Card information in the Qt Account to automatically charge the Licensee for the +relevant Renewal Term. + +3.2. Distribution of Applications + +Subject to the terms of this Agreement, The Qt Company grants to Licensee a +worldwide, non-exclusive, non-transferable, revocable (for cause pursuant to +this Agreement), right and license, valid for the Agreement Term, to + (i) distribute, by itself or through its Contractors, Redistributables as + installed, incorporated or integrated into Applications for execution + on the Deployment Platforms, and + (ii) grant perpetual and irrevocable sublicenses to Redistributables, as + distributed hereunder, for Customers solely to the extent necessary in + order for the Customers to use the Applications for their respective + intended purposes. + +Right to distribute the Redistributables as part of an Application as provided +herein is not royalty-bearing but is conditional upon the Application having +been created, updated and maintained under a valid and duly paid Development +Licenses. + +3.3. Distribution of Devices + +Subject to the terms of this Agreement, The Qt Company grants to Licensee a +worldwide, non-exclusive, non-transferable, revocable (for cause pursuant to +this Agreement), right and license, valid for the Agreement Term, to + (i) distribute, by itself or through one or more tiers of Contractors, + Redistributables as installed, incorporated or integrated, or intended + to be installed, incorporated or integrated into Devices for execution + on the Deployment Platforms, and + (ii) grant perpetual and irrevocable sublicenses to Redistributables, as + distributed hereunder, for Customers solely to the extent necessary in + order for the Customers to use the Devices for their respective + intended purposes. + +Right to distribute the Devices as provided herein is conditional upon + (i) the Devices having been created, updated and maintained under a valid + and duly paid Development Licenses, and + (ii) the Licensee having acquired corresponding Distribution Licenses at + the time of distribution of any Devices to Customers. + +3.4. Further Requirements + +The licenses granted above in this Section 3 by The Qt Company to Licensee are +conditional and subject to Licensee's compliance with the following terms: + (i) Licensee acknowledges that The Qt Company has separate products of + Licensed Software for the purpose of Applications and Devices + respectively, where development and distribution of Devices is only + allowed using the correct designated product. Licensee shall make sure + and bear the burden of proof that Licensee is using a correct product + of Licensed Software entitling Licensee to development and distribution + of Devices; + (ii) Licensee shall not remove or alter any copyright, trademark or other + proprietary rights notice(s) contained in any portion of the Licensed + Software; + (iii) Applications must add primary and substantial functionality to the + Licensed Software so as not to compete with the Licensed Software; + (iv) Applications may not pass on functionality which in any way makes it + possible for others to create software with the Licensed Software; + provided however that Licensee may use the Licensed Software's + scripting and QML ("Qt Quick") functionality solely in order to enable + scripting, themes and styles that augment the functionality and + appearance of the Application(s) without adding primary and substantial + functionality to the Application(s); + (v) Licensee shall not use Licensed Software in any manner or for any + purpose that infringes, misappropriates or otherwise violates any + Intellectual property or right of any third party, or that violates any + applicable law; + (vi) Licensee shall not use The Qt Company's or any of its suppliers' + names, logos, or trademarks to market Applications, except that + Licensee may use "Built with Qt" logo to indicate that Application(s) + or Device(s) was developed using the Licensed Software; + (vii) Licensee shall not distribute, sublicense or disclose source code of + Licensed Software to any third party (provided however that Licensee + may appoint employee(s) of Contractors and Affiliates as Designated + Users to use Licensed Software pursuant to this Agreement). Such right + may be available for the Licensee subject to a separate software + development kit ("SDK") license agreement to be concluded with The Qt + Company; + (viii) Licensee shall not grant the Customers a right to (a) make copies of + the Redistributables except when and to the extent required to use the + Applications and/or Devices for their intended purpose, (b) modify the + Redistributables or create derivative works thereof, (c) decompile, + disassemble or otherwise reverse engineer Redistributables, or (d) + redistribute any copy or portion of the Redistributables to any third + party, except as part of the onward sale of the Application or Device + on which the Redistributables are installed; + (ix) Licensee shall not and shall cause that its Affiliates or Contractors + shall not use Licensed Software in any Prohibited Combination, unless + Licensee has received an advance written permission from The Qt Company + to do so. Absent such written permission, any and all distribution by + the Licensee during the Agreement Term of a hardware device or product + a) which incorporate or integrate any part of Licensed Software or Open + Source Qt; or b) where substantial functionality is provided by + software built with Licensed Software or Open Source Qt or otherwise + depends on the Licensed Software or Open Source Qt, shall be considered + to be Device distribution under this Agreement and shall be dependent + on Licensee's compliance thereof (including but not limited to + obligation to pay applicable License Fees for such distribution). + Notwithstanding what is provided above in this sub-section (ix), + Licensee is entitled to use and combine Licensed Software with any + Permitted Software; + (x) Licensee shall cause all of its Affiliates, Contractors and Customers + entitled to make use of the licenses granted under this Agreement, to + be contractually bound to comply with the relevant terms of this + Agreement and not to use the Licensed Software beyond the terms hereof + and for any purposes other than operating within the scope of their + services for Licensee. Licensee shall be responsible for any and all + actions and omissions of its Affiliates and Contractors relating to the + Licensed Software and use thereof (including but not limited to payment + of all applicable License Fees); + (xi) Except when and to the extent explicitly provided in this Section 3, + Licensee shall not transfer, publish, disclose, display or otherwise + make available the Licensed Software; and + (xii) Licensee shall not attempt or enlist a third party to conduct or + attempt to conduct any of the above. + +Above terms shall not be applicable if and to the extent they conflict with any +mandatory provisions of any applicable laws. + +Any use of Licensed Software beyond the provisions of this Agreement is +strictly prohibited and requires an additional license from The Qt Company. + +3.5 QA Tools License + +Subject to the terms of this Agreement, The Qt Company grants to Licensee a +worldwide, non-exclusive, non-transferable license, valid for the Development +License Term, to use the QA Tools for Licensee's internal business purposes in +the manner provided below and in Appendix 1 hereto. + +Licensee may modify the QA Tools except for altering or removing any details of +ownership, copyright, trademark or other property right connected with the QA +Tools. + +Licensee shall not distribute the QA Tools or any part thereof, modified or +unmodified, separately or as part of any software package, Application or +Device. + +Upon expiry of the initially agreed Development License Term, the respective +Development License Term shall be automatically extended to one or more Renewal +Term(s), unless and until either Party notifies the other Party in writing, or +any other method acceptable to The Qt Company (it being specifically +acknowledged and understood that verbal notification is explicitly deemed +inadequate in all circumstances), that it does not wish to continue the +Development License Term, such notification to be provided to the other Party +no less than thirty (30) days before expiry of the respective Development +License Term. The Qt Company shall, in good time before the due date for the +above notification, remind the Licensee on the coming Renewal Term. Unless +otherwise agreed between the Parties, Renewal Term shall be 12 months. + +Any such Renewal Term shall be subject to License Fees agreed between the +Parties or, if no advance agreement exists, subject to The Qt Company's +standard list pricing applicable at the commencement date of any such +Renewal Term. + +3.6 Evaluation License + +Subject to the terms of this Agreement, The Qt Company grants to Licensee a +worldwide, non-exclusive, non-transferable license, valid for the Evaluation +License Term to use the Licensed Software solely for the Licensee's internal +use to evaluate and determine whether the Licensed Software meets Licensee's +business requirements, specifically excluding any commercial use of the +Licensed Software or any derived work thereof. + +Upon the expiry of the Evaluation License Term, Licensee must either +discontinue use of the relevant Licensed Software or acquire a commercial +Development License or QA Tools License specified herein. + +4. THIRD-PARTY SOFTWARE + +The Licensed Software may provide links or access to third party libraries or +code (collectively "Third-Party Software") to implement various functions. +Third-Party Software does not, however, comprise part of the Licensed Software, +but is provided to Licensee complimentary and use thereof is discretionary for +the Licensee. Third-Party Software will be listed in the ".../src/3rdparty" +source tree delivered with the Licensed Software or documented in the Licensed +Software, as such may be amended from time to time. Licensee acknowledges that +use or distribution of Third-Party Software is in all respects subject to +applicable license terms of applicable third-party right holders. + +5. PRE-RELEASE CODE + +The Licensed Software may contain pre-release code and functionality, or sample +code marked or otherwise stated with appropriate designation such as +"Technology Preview", "Alpha", "Beta", "Sample", "Example" etc. +("Pre-Release Code"). + +Such Pre-Release Code may be present complimentary for the Licensee, in order +to provide experimental support or information for new platforms or +preliminary versions of one or more new functionalities or for other similar +reasons. The Pre-Release Code may not be at the level of performance and +compatibility of a final, generally available, product offering. The +Pre-Release Code may not operate correctly, may contain errors and may be +substantially modified by The Qt Company prior to the first commercial +product release, if any. The Qt Company is under no obligation to make +Pre-Release Code commercially available, or provide any Support or Updates +relating thereto. The Qt Company assumes no liability whatsoever regarding +any Pre-Release Code, but any use thereof is exclusively at Licensee's own risk +and expense. + +For clarity, unless Licensed Software specifies different license terms for the +respective Pre-Release Code, the Licensee is entitled to use such pre-release +code pursuant to Section 3, just like other Licensed Software. + +6. LIMITED WARRANTY AND WARRANTY DISCLAIMER + +The Qt Company hereby represents and warrants that (i) it has the power and +authority to grant the rights and licenses granted to Licensee under this +Agreement, and (ii) Licensed Software will operate materially in accordance +with its specifications. + +Except as set forth above, the Licensed Software is licensed to Licensee "as +is" and Licensee's exclusive remedy and The Qt Company's entire liability for +errors in the Licensed Software shall be limited, at The Qt Company's option, +to correction of the error, replacement of the Licensed Software or return of +the applicable fees paid for the defective Licensed Software for the time +period during which the License is not able to utilize the Licensed Software +under the terms of this Agreement. + +TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE QT COMPANY ON BEHALF OF +ITSELF AND ITS LICENSORS, SUPPLIERS AND AFFILIATES, DISCLAIMS ALL OTHER +WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND +NON-INFRINGEMENT WITH REGARD TO THE LICENSED SOFTWARE. THE QT COMPANY DOES NOT +WARRANT THAT THE LICENSED SOFTWARE WILL SATISFY LICENSEE'S REQUIREMENTS OR THAT +IT WILL OPERATE WITHOUT DEFECT OR ERROR OR THAT THE OPERATION THEREOF WILL BE +UNINTERRUPTED. + +7. LIMITATION OF LIABILITY + +EXCEPT FOR (I) CASES OF GROSS NEGLIGENCE OR INTENTIONAL MISCONDUCT, AND (II) +BREACH OF CONFIDENTIALITY, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, IN NO +EVENT SHALL EITHER PARTY BE LIABLE TO THE OTHER PARTY FOR ANY LOSS OF PROFIT, +LOSS OF DATA, LOSS OF BUSINESS OR GOODWILL OR ANY OTHER INDIRECT, SPECIAL, +CONSEQUENTIAL, INCIDENTAL OR PUNITIVE COST, DAMAGES OR EXPENSE OF ANY KIND, +HOWSOEVER ARISING UNDER OR IN CONNECTION WITH THIS AGREEMENT. + +EXCEPT FOR (I) CASES OF GROSS NEGLIGENCE OR INTENTIONAL MISCONDUCT, AND (II) +BREACH OF CONFIDENTIALITY, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, IN NO +EVENT SHALL EITHER PARTY'S TOTAL AGGREGATE LIABILITY UNDER THIS AGREEMENT +EXCEED THE AGGREGATE LICENSE FEES PAID OR PAYABLE TO THE QT COMPANY BY LICENSEE +DURING THE DEVELOPMENT LICENSE TERM DURING WHICH THE EVENT RESULTING IN SUCH +LIABILITY OCCURRED. + +THE PROVISIONS OF THIS SECTION 7 ALLOCATE THE RISKS UNDER THIS AGREEMENT +BETWEEN THE QT COMPANY AND LICENSEE AND THE PARTIES HAVE RELIED UPON THE +LIMITATIONS SET FORTH HEREIN IN DETERMINING WHETHER TO ENTER INTO THIS +AGREEMENT. + +NOTWITHSTANDING ANYTHING TO THE CONTRARY IN THIS AGREEMENT, LICENSEE SHALL +ALWAYS BE LIABLE TO PAY THE APPLICABLE LICENSE FEES CORRESPONDING TO ITS +ACTUAL USE OF LICENSED SOFTWARE. + +8. SUPPORT, UPDATES AND ONLINE SERVICES + +Upon due payment of the agreed License Fees the Licensee will be eligible to +receive Support and Updates and to use the Online Services during the agreed +Development License Term or other agreed fixed time period. Support is +provided according to agreed support level and subject to applicable +requirements and restrictions, as specified in the Support Terms. + +Unless otherwise decided by The Qt Company at its free and absolute discretion, +Upgrades will not be included in the Support but may be available subject to +additional fees. + +From time to time The Qt Company may change the Support Terms, provided that +during the respective ongoing Support period the level of Support may not be +reduced without the consent of the Licensee. + +Unless otherwise agreed, The Qt Company shall not be responsible for providing +any service or support to Customers. + +9. CONFIDENTIALITY + +Each Party acknowledges that during the Agreement Term each Party may receive +information about the other Party's business, business methods, business plans, +customers, business relations, technology, and other information, including the +terms of this Agreement, that is confidential and of great value to the other +Party, and the value of which would be significantly reduced if disclosed to +third parties ("Confidential Information"). Accordingly, when a Party (the +"Receiving Party") receives Confidential Information from the other Party (the +"Disclosing Party"), the Receiving Party shall only disclose such information +to employees and Contractors on a need to know basis, and shall cause its +employees and employees of its Affiliates to: (i) maintain any and all +Confidential Information in confidence; (ii) not disclose the Confidential +Information to a third party without the Disclosing Party's prior written +approval; and (iii) not, directly or indirectly, use the Confidential +Information for any purpose other than for exercising its rights and +fulfilling its responsibilities pursuant to this Agreement. Each Party shall +take reasonable measures to protect the Confidential Information of the other +Party, which measures shall not be less than the measures taken by such Party +to protect its own confidential and proprietary information. + +Obligation of confidentiality shall not apply to information that (i) is or +becomes generally known to the public through no act or omission of the +Receiving Party; (ii) was in the Receiving Party's lawful possession prior to +the disclosure hereunder and was not subject to limitations on disclosure or +use; (iii) is developed independently by employees or Contractors of the +Receiving Party or other persons working for the Receiving Party who have not +had access to the Confidential Information of the Disclosing Party, as proven +by the written records of the Receiving Party; (iv) is lawfully disclosed to +the Receiving Party without restrictions, by a third party not under an +obligation of confidentiality; or (v) the Receiving Party is legally compelled +to disclose, in which case the Receiving Party shall notify the Disclosing +Party of such compelled disclosure and assert the privileged and confidential +nature of the information and cooperate fully with the Disclosing Party to +limit the scope of disclosure and the dissemination of disclosed Confidential +Information to the minimum extent necessary. + +The obligations under this Section 9 shall continue to remain in force for a +period of five (5) years after the last disclosure, and, with respect to trade +secrets, for so long as such trade secrets are protected under applicable trade +secret laws. + +10. FEES, DELIVERY AND PAYMENT + +10.1. License Fees + +License Fees are described in The Qt Company's standard price list, quote or +Purchase Order confirmation or in an Appendix 2 hereto, as the case may be. + +Unless otherwise expressly provided in this Agreement, the License Fees shall +not be refunded or claimed as a credit in any event or for any reason +whatsoever. + +10.2. Ordering Licenses + +Licensee may purchase Development Licenses, Distribution Licenses and QA Tools +Licenses pursuant to agreed pricing terms or, if no specific pricing terms have +been agreed upon, at The Qt Company's standard pricing terms applicable at the +time of purchase. + +Unless expressly otherwise agreed, any price or other term quoted to the +Licensee or specified herein shall only be valid for the thirty (30) days from +the effective date of this Agreement, Appendix 2 or the date of the quote, as +applicable. + +Licensee shall submit all purchase orders for Development Licenses and +Distribution Licenses to The Qt Company by email or any other method acceptable +to The Qt Company (each such order is referred to herein as a "Purchase Order") +for confirmation, whereupon the Purchase Order shall become binding between the +Parties. + +Licensee acknowledges and agrees that all Purchase Orders for Licensed Software +the Licensee makes during the Agreement Term shall be governed exclusively +under the terms of this Agreement. + +10.3. Distribution License Packs + +Unless otherwise agreed, Distribution Licenses shall be purchased by way of +Distribution License Packs. + +Upon due payment of the ordered Distribution License Pack(s), the Licensee will +have an account of Distribution Licenses available for distributing the +Redistributables in accordance with this Agreement. + +Each time Licensee distributes a copy of Redistributables, then one +Distribution License is used, and Licensee's account of available Distribution +Licenses is decreased accordingly. + +Licensee may distribute copies of the Redistributables so long as Licensee has +Distribution Licenses remaining on its account. + +10.4. Payment Terms + +License Fees and any other charges under this Agreement shall be paid by +Licensee no later than thirty (30) days from the date of the applicable invoice +from The Qt Company. + +The Qt Company will submit an invoice to Licensee after the date of this +Agreement and/or after The Qt Company receives a Purchase Order from Licensee. + +A late payment charge of the lower of (a) one percent per month; or (b) the +interest rate stipulated by applicable law, shall be charged on any unpaid +balances that remain past due and which have not been disputed by the Licensee +in good faith. + +10.5. Taxes + +All License Fees and other charges payable hereunder are gross amounts but +exclusive of any value added tax, use tax, sales tax, withholding tax and other +taxes, duties or tariffs ("Taxes") levied directly for the sale, delivery or +use of Licensed Software hereunder pursuant to any applicable law. Such +applicable Taxes shall be paid by Licensee to The Qt Company, or, where +applicable, in lieu of payment of such Taxes to The Qt Company, Licensee shall +provide an exemption certificate to The Qt Company and any applicable +authority. + +11. RECORD-KEEPING AND REPORTING OBLIGATIONS; AUDIT RIGHTS + +11.1. Licensee's Record-keeping + +Licensee shall at all times during the Agreement Term and for a period of two +(2) years thereafter maintain Licensee's Records in an accurate and up-to-date +form. Licensee's Records shall be adequate to reasonably enable The Qt Company +to determine Licensee's compliance with the provisions of this Agreement. The +records shall conform to general good accounting practices. + +Licensee shall, within thirty (30) days from receiving The Qt Company's request +to that effect, deliver to The Qt Company a report based on Licensee's Records, +such report to contain information, in sufficient detail, on (i) number and +identity of users working with Licensed Software or Open Source Qt, (ii) copies +of Redistributables distributed by Licensee during the most recent calendar +quarter and/or any other term specified by The Qt Company, , and (iii) any +other information pertaining to Licensee's compliance with the terms of this +Agreement (like e.g. information on products and/or projects relating to use of +Distribution Licenses), as The Qt Company may reasonably require from time to +time. + +11.2. The Qt Company's Audit Rights + +The Qt Company or an independent auditor acting on behalf of The Qt Company's, +may, upon at least thirty (30) days' prior written notice and at its expense, +audit Licensee with respect to the Licensee's use of the Licensed Software, but +not more frequently than once during each 6-month period. Such audit may be +conducted by mail, electronic means or through an in-person visit to Licensee's +place of business. Any possible in-person audit shall be conducted during +regular business hours at Licensee's facilities and shall not unreasonably +interfere with Licensee's business activities and shall be limited in scope to +verify Licensee's compliance with the terms of this Agreement. The Qt Company +or the independent auditor acting on behalf of The Qt Company shall be entitled +to inspect Licensee's Records and conduct necessary interviews of Licensee's +relevant employees and Contractors. All such Licensee's Records and use thereof +shall be subject to an obligation of confidentiality under this Agreement. + +If an audit reveals that Licensee is using the Licensed Software beyond scope +of the licenses Licensee has paid for, Licensee shall pay to The Qt Company any +amounts owed for such unauthorized use within 30 days from receipt of the +corresponding invoice from The Qt Company. + +In addition, in the event the audit reveals a material violation of the terms +of this Agreement (without limitation, either (i) underpayment of more than 10 +% of License Fees or 10,000 euros (whichever is more) or (ii) distribution of +products, which include or result from Prohibited Combination, shall be deemed +a material violation for purposes of this section), then the Licensee shall +pay The Qt Company's reasonable cost of conducting such audit. + +12. TERM AND TERMINATION + +12.1. Agreement Term + +This Agreement shall enter into force upon due acceptance by both Parties and +remain in force until terminated pursuant to the terms of this Section 12 +("Agreement Term"). + +12.2. Termination for breach and suspension of rights +Either Party shall have the right to terminate this Agreement upon thirty (30) +days prior written notice if the other Party commits a material breach of any +obligation of this Agreement and fails to remedy such breach within such notice +period. + +Instead of termination, The Qt Company shall have the right to suspend or +withhold grants of all rights to the Licensed Software hereunder, including but +not limited to the Development Licenses, Distribution License, and Support, +should Licensee fail to make payment in timely fashion or otherwise violates or +is reasonably suspected to violate its obligations or terms of this Agreement, +and where such violation or breach is not cured within ten (10) business days +following The Qt Company's written notice thereof. + +12.3. Termination for insolvency + +Either Party shall have the right to terminate this Agreement immediately upon +written notice in the event that the other Party becomes insolvent, files for +any form of bankruptcy, makes any assignment for the benefit of creditors, has +a receiver, administrative receiver or officer appointed over the whole or a +substantial part of its assets, ceases to conduct business, or an act +equivalent to any of the above occurs under the laws of the jurisdiction of the +other Party. + +12.4. Parties' Rights and Duties upon Termination + +Upon expiry or termination of the Agreement, Licensee shall cease and shall +cause all Designated Users (including those of its Affiliates' and +Contractors') to cease using the Licensed Software under this Agreement. For +clarity, a Development License of a Designated User or a QA Tools License, and +all rights relating thereto, shall always terminate at the expiry of the +respective Development License Term, even if the Agreement continues to remain +in force. + +Upon such termination the Licensee shall destroy or return to The Qt Company +all copies of the Licensed Software and all related materials and will certify +the same by Licensee's duly authorized officer to The Qt Company upon its +request, provided however that Licensee may retain and exploit such copies of +the Licensed Software as it may reasonably require in providing continued +support to Customers. + +Except when this Agreement is terminated by The Qt Company due to Licensee's +material breach as set forth in Section 12.2, the Licensee may continue +distribution of Applications and Devices under the terms of this Agreement +despite the termination of this Agreement. In such event the terms hereof will +continue to be applicable and govern any such distribution of Applications and +Devices beyond the expiry or termination of this Agreement. In case of +termination by The Qt Company due to Licensee's material breach, Licensee must +cease any distribution of Applications and Devices at the date of termination +of this Agreement. + +Expiry or termination of this Agreement for any reason whatsoever shall not +relieve Licensee of its obligation to pay any License Fees accrued or payable +to The Qt Company prior to the effective date of termination, and Licensee pay +to The Qt Company all such fees within 30 days from the effective date of +termination of this Agreement. + +Termination of this Agreement shall not affect any rights of Customers to +continue use of Applications and Devices (and therein incorporated +Redistributables). + +12.5. Extension of Rights under Special Circumstances + +In the event of The Qt Company choosing not to renew the Development License(s) +or QA Tools Licenses, as set forth in Section 3.1 and 3.5 respectively, and +where such decision of non-renewal is not due to any ongoing breach or alleged +breach (as reasonably determined by The Qt Company) by Licensee of the terms of +this Agreement or any applicable license terms of Open Source Qt, then all +valid and affected Development Licenses and QA Tools licenses possessed by the +Licensee at such date shall be extended to be valid in perpetuity under the +terms of this Agreement and Licensee is entitled to purchase additional +licenses as set forth in Section 10.2. + +In the event The Qt Company is declared bankrupt under a final, non-cancellable +decision by relevant court of law, and this Agreement is not, at the date of +expiry of the Development License(s) or QA Tools Licenses, assigned to party, +who has assumed The Qt Company's position as a legitimate licensor of Licensed +Software under this Agreement, then all valid Development Licenses and QA Tools +Licenses possessed by the Licensee at such date of expiry, and which the +Licensee has not notified for expiry, shall be extended to be valid in +perpetuity under the terms of this Agreement. + +For clarity, in case of an extension under this Section 12.5, any such +extension shall not apply to The Qt Company's Support obligations, but Support +shall be provided only up until the end of the respective fixed Development +License Term regardless of the extension of relevant Development License or QA +Tools License, unless otherwise agreed between the Parties. + +13. GOVERNING LAW AND LEGAL VENUE + +In the event this Agreement is in the name of The Qt Company Inc., a Delaware +Corporation, then: + (i) this Agreement shall be construed and interpreted in accordance with + the laws of the State of California, USA, excluding its choice of law + provisions; + (ii) the United Nations Convention on Contracts for the International Sale + of Goods will not apply to this Agreement; and + (iii) any dispute, claim or controversy arising out of or relating to this + Agreement or the breach, termination, enforcement, interpretation or + validity thereof, including the determination of the scope or + applicability of this Agreement to arbitrate, shall be determined by + arbitration in San Francisco, USA, before one arbitrator. The + arbitration shall be administered by JAMS pursuant to JAMS' Streamlined + Arbitration Rules and Procedures. Judgment on the Award may be entered + in any court having jurisdiction. This Section shall not preclude + parties from seeking provisional remedies in aid of arbitration from a + court of appropriate jurisdiction. + +In the event this Agreement is in the name of The Qt Company Ltd., a Finnish +Company, then: + (i) this Agreement shall be construed and interpreted in accordance with + the laws of Finland, excluding its choice of law provisions; + (ii) the United Nations Convention on Contracts for the International Sale + of Goods will not apply to this Agreement; and + (iii) any disputes, controversy or claim arising out of or relating to this + Agreement, or the breach, termination or validity thereof shall be + finally settled by arbitration in accordance with the Arbitration Rules + of International Chamber of Commerce. The arbitration tribunal shall + consist of one (1), or if either Party so requires, of three (3), + arbitrators. The award shall be final and binding and enforceable in + any court of competent jurisdiction. The arbitration shall be held in + Helsinki, Finland and the process shall be conducted in the English + language. This Section shall not preclude parties from seeking + provisional remedies in aid of arbitration from a court of appropriate + jurisdiction. + +14. GENERAL PROVISIONS + +14.1. No Assignment + +Except in the case of a merger or sale of substantially all of its corporate +assets, Licensee shall not be entitled to assign or transfer all or any of its +rights, benefits and obligations under this Agreement without the prior written +consent of The Qt Company, which shall not be unreasonably withheld or delayed. +The Qt Company shall be entitled to freely assign or transfer any of its +rights, benefits or obligations under this Agreement. + +14.2. No Third-Party Representations + +Licensee shall make no representations or warranties concerning the Licensed +Software on behalf of The Qt Company. Any representation or warranty Licensee +makes or purports to make on The Qt Company's behalf shall be void as to +The Qt Company. + +14.3. Surviving Sections + +Any terms and conditions that by their nature or otherwise reasonably should +survive termination of this Agreement shall so be deemed to survive. Such +sections include especially the following: 1, 2, 6, 7, 9, 11, 12.4, 13 and 14. + +14.4. Entire Agreement + +This Agreement, the Appendices hereto, the License Certificate and any +applicable quote and Purchase Order accepted by The Qt Company constitute the +complete agreement between the Parties and supersedes all prior or +contemporaneous discussions, representations, and proposals, written or oral, +with respect to the subject matters discussed herein. + +In the event of any conflict or inconsistency between this Agreement and any +Purchase Order, the terms of this Agreement will prevail over the terms of the +Purchase Order with respect to such conflict or inconsistency. + +Parties specifically acknowledge and agree that this Agreement prevails over +any click-to-accept or similar agreements the Designated Users may need to +accept online upon download of the Licensed Software, as may be required by +The Qt Company's applicable processes relating to Licensed Software. + +14.5. Modifications + +No modification of this Agreement shall be effective unless contained in a +writing executed by an authorized representative of each Party. No term or +condition contained in Licensee's Purchase Order ("Deviating Terms") shall +apply unless The Qt Company has expressly agreed such Deviating Terms in +writing. Unless and to the extent expressly agreed by The Qt Company, any such +Deviating Terms shall be deemed void and with no legal effect. For clarity, +delivery of the Licensed Software following the receipt of the Purchase Order +including Deviating Terms shall not constitute acceptance of such Deviating +Terms. + +14.6. Force Majeure + +Except for the payment obligations hereunder, neither Party shall be liable to +the other for any delay or non-performance of its obligations hereunder in the +event and to the extent that such delay or non-performance is due to an event +of act of God, terrorist attack or other similar unforeseeable catastrophic +event that prevents either Party for fulfilling its obligations under this +Agreement and which such Party cannot avoid or circumvent ("Force Majeure +Event"). If the Force Majeure Event results in a delay or non-performance of a +Party for a period of three (3) months or longer, then either Party shall have +the right to terminate this Agreement with immediate effect without any +liability (except for the obligations of payment arising prior to the event of +Force Majeure) towards the other Party. + +14.7. Notices + +Any notice given by one Party to the other shall be deemed properly given and +deemed received if specifically acknowledged by the receiving Party in writing +or when successfully delivered to the recipient by hand, fax, or special +courier during normal business hours on a business day to the addresses +specified for each Party on the signature page. Each communication and document +made or delivered by one Party to the other Party pursuant to this Agreement +shall be in the English language. + +14.8. Export Control + +Licensee acknowledges that the Redistributables, as incorporated in +Applications or Devices, may be subject to export control restrictions under +the applicable laws of respective countries. Licensee shall fully comply with +all applicable export license restrictions and requirements as well as with all +laws and regulations relating to the Redistributables and exercise of licenses +hereunder and shall procure all necessary governmental authorizations, +including without limitation, all necessary licenses, approvals, permissions or +consents, where necessary for the re-exportation of the Redistributables, +Applications and/or Devices. + +14.9. No Implied License + +There are no implied licenses or other implied rights granted under this +Agreement, and all rights, save for those expressly granted hereunder, shall +remain with The Qt Company and its licensors. In addition, no licenses or +immunities are granted to the combination of the Licensed Software with any +other software or hardware not delivered by The Qt Company under this +Agreement. + +14.10. Attorney Fees + +The prevailing Party in any action to enforce this Agreement shall be entitled +to recover its attorney's fees and costs in connection with such action, as to +be ordered by the relevant dispute resolution body. + +14.11. Privacy + +Licensee acknowledges and agrees that for the purpose of this Agreement, +The Qt Company may collect, use, transfer and disclose personal data pertaining +to Designated Users as well as any other employees and directors of the +Licensee and its Contractors relevant for carrying out the intent of this +Agreement. Such personal data will be primarily collected from the relevant +individuals but may be collected also from Licensee (e.g. in the course of +Licensee's reporting obligations). The Parties acknowledge that as +The Qt Company determines the purpose and means for such collection and +processing of the applicable personal data, The Qt Company shall be regarded as +the Data Controller under the applicable Data Protection Legislation. +The Qt Company shall process any such personal data in accordance with its +privacy and security policies and practices, which will comply with all +applicable requirements of the Data Protection Legislation. + +14.12. Severability + +If any provision of this Agreement shall be adjudged by any court of competent +jurisdiction to be unenforceable or invalid, that provision shall be limited or +eliminated to the minimum extent necessary so that this Agreement shall +otherwise remain in full force and effect and enforceable. + +14.13. Marketing Rights + +Parties have agreed upon Marketing Rights pursuant to Appendix 7, if any. + + + + +APPENDICES +The Agreement includes following Appendices 1-10, as applicable. +- Appendix 1: Licensed Software details +- Appendix 2: Pricing +- Appendix 3: Add-on Software details (optional) +- Appendix 4: Small business and startup Licenses (optional) +- Appendix 5: Non-commercial and educational Licenses (optional) +- Appendix 6: License Reporting (optional) +- Appendix 7: Marketing Rights (optional) +- Appendix 8: Intentionally left blank (optional) +- Appendix 9: Support Terms +- Appendix 10: Conversion from legacy Licenses to Subscription (optional) + + +APPENDIX 1: LICENSED SOFTWARE + +The modules and/or tools that are included in the latest publicly available +version of the respective product at the effective date of this Agreement- Qt +for Application Development Professional (ADP), Qt for Application Development +Enterprise (ADE), Qt for Device Creation Professional (DCP), Qt for Device +Creation Enterprise (DCE), - are marked with "X" in the below table. The +modules and tools are specific to each product version respectively and may +vary from version to version. Modules and tools included in the latest publicly +available version of the respective product at any given time are listed in +Appendix 1 of the latest version of this Agreement available at +www.qt.io/terms-conditions/. If a new version of Licensed Software does not +include a module or tool present in an older version which Licensee is entitled +to use under a valid license from The Qt Company, then Licensee will continue +to have such right during the Term of this Agreement. In the event a new +version of the Licensed Software adds modules or tools to any previous +version(s), Licensee's rights will extend to cover also such additional modules +and tools. + +Parts of the product that are permitted for distribution in object-code form +only ("Redistributables") are marked with "R" in the below table. + ++----------------------------------------------------------+ +| Modules / Tools | ADP | ADE | DCP | DCE | ++----------------------------------------------------------+ +| Active Qt | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt 3D | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt 5 Core Compatibility APIs | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Android Extras | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Bluetooth | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Canvas 3D | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Charts | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Concurrent | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Core | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Data Visualization | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt D-Bus | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt for Python | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt for WebAssembly | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Gamepad | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Graphical Effects | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt GUI | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Help | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Image Formats | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Location | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Lottie Animation | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Mac Extras | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Multimedia | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Multimedia Widgets | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Network | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Network Authorization | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt NFC | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt OpenGL | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt PDF | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Platform Headers | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Positioning | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Print Support | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Purchasing | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt QML | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Quick | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Quick 3D | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Quick Controls 1 | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Quick Controls | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Quick Dialogs | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Quick Extras | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Quick Layouts | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Quick Test | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Quick Timeline | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Quick WebGL | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Quick Widgets | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Remote Objects | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Script | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Script Tools | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt SCXML | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Sensors | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Serial Bus | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Serial Port | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Shader Tools | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Speech | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt State Machine | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt SQL | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt SVG | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Test | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt UI Tools | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Virtual Keyboard | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Wayland Compositor | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt WebChannel | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt WebEngine | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt WebSockets | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt WebView | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Widgets | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Windows Extras | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt X11 Extras | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt XML | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt XML Patterns | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Designer (Qt Widget Designer) | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Linguist | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt Assistant | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| lupdate | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| lrelease | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| lconvert | X,R | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt MQTT | | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt KNX | | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt OPC UA | | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Qt CoAP | | X,R | X,R | X,R | ++----------------------------------------------------------+ +| Boot 2 Qt stacks | | | X,R | X,R | ++----------------------------------------------------------+ +| Qt OTA | | | X,R | X,R | ++----------------------------------------------------------+ +| Device Utilities | | | X,R | X,R | ++----------------------------------------------------------+ +| Qt Debugging Bridge (QBD) Daemon | | | X,R | X,R | ++----------------------------------------------------------+ +| Qt Quick Ultralite Controls | | | X,R | X,R | ++----------------------------------------------------------+ +| Qt Quick Ultralite | | | X,R | X,R | ++----------------------------------------------------------+ +| Qt Safe Renderer (QSR) | | | | X,R | ++----------------------------------------------------------+ +| Qt Application Manager | | | | X,R | ++----------------------------------------------------------+ +| Qt Interface Framework | | | | X,R | ++----------------------------------------------------------+ +| Neptune Reference UI | | | | X,R | ++----------------------------------------------------------+ +| Qt for Android Automotive (QAA) | | | | X,R | ++----------------------------------------------------------+ +| Qt Creator | X | X | X | X | ++----------------------------------------------------------+ +| Qt Design Studio Professional | X | X | X | X | ++----------------------------------------------------------+ +| androiddeployqt | X | X | X | X | ++----------------------------------------------------------+ +| androidtestrunner | X | X | X | X | ++----------------------------------------------------------+ +| canbusutil | X | X | X | X | ++----------------------------------------------------------+ +| dumpcpp | X | X | X | X | ++----------------------------------------------------------+ +| dumpdoc | X | X | X | X | ++----------------------------------------------------------+ +| fixqt4headers.pl | X | X | X | X | ++----------------------------------------------------------+ +| idc | X | X | X | X | ++----------------------------------------------------------+ +| moc | X | X | X | X | ++----------------------------------------------------------+ +| pixeltool | X | X | X | X | ++----------------------------------------------------------+ +| qdbus | X | X | X | X | ++----------------------------------------------------------+ +| qdbuscpp2xml | X | X | X | X | ++----------------------------------------------------------+ +| qdbusviwer | X | X | X | X | ++----------------------------------------------------------+ +| qdbusxml2cpp | X | X | X | X | ++----------------------------------------------------------+ +| qdistancefieldgenerator | X | X | X | X | ++----------------------------------------------------------+ +| qdoc | X | X | X | X | ++----------------------------------------------------------+ +| qhelpgenerator | X | X | X | X | ++----------------------------------------------------------+ +| qlalr | X | X | X | X | ++----------------------------------------------------------+ +| qmake | X | X | X | X | ++----------------------------------------------------------+ +| qml | X | X | X | X | ++----------------------------------------------------------+ +| qmlcachegen | X | X | X | X | ++----------------------------------------------------------+ +| qmldom | X | X | X | X | ++----------------------------------------------------------+ +| qmleasing | X | X | X | X | ++----------------------------------------------------------+ +| qmlformat | X | X | X | X | ++----------------------------------------------------------+ +| qmllint | X | X | X | X | ++----------------------------------------------------------+ +| qmlpreview | X | X | X | X | ++----------------------------------------------------------+ +| qmlprofiler | X | X | X | X | ++----------------------------------------------------------+ +| qmlscene | X | X | X | X | ++----------------------------------------------------------+ +| qmltestrunner | X | X | X | X | ++----------------------------------------------------------+ +| qmltime | X | X | X | X | ++----------------------------------------------------------+ +| qmlviewer | X | X | X | X | ++----------------------------------------------------------+ +| qtdiag | X | X | X | X | ++----------------------------------------------------------+ +| qtpaths | X | X | X | X | ++----------------------------------------------------------+ +| qtplugininfo | X | X | X | X | ++----------------------------------------------------------+ +| qvkgen | X | X | X | X | ++----------------------------------------------------------+ +| rcc | X | X | X | X | ++----------------------------------------------------------+ +| tracegen | X | X | X | X | ++----------------------------------------------------------+ +| uic | X | X | X | X | ++----------------------------------------------------------+ +| windeployqt | X | X | X | X | ++----------------------------------------------------------+ +| Target toolchains | | | X | X | ++----------------------------------------------------------+ +| Qt Debugging Bridge Host Tools | | | X | X | ++----------------------------------------------------------+ +| qtconfig-gui | | | X | X | ++----------------------------------------------------------+ +| Qt Emulator | | | X | X | ++----------------------------------------------------------+ +| Qt Creator VxWorks plugin | | | X | X | ++----------------------------------------------------------+ +| Qt Creator plugin for Qt | | | | X | +| Application Manager | | | | | ++----------------------------------------------------------+ +| qmlinterfacegenerator | | | | X | ++----------------------------------------------------------+ +| qmltocpp | | | | X | ++----------------------------------------------------------+ +| qulfontcompiler | | | | X | ++----------------------------------------------------------+ +| Qt Deployment Server | | | | X | ++----------------------------------------------------------+ + + +Rights for Application and Device use cases + +Following table summarizes the rights afforded by different products of the +Licensed Software to create and distribute Applications and Devices as defined +in this Agreement (X marks for rights): + ++---------------------------------------------------------------+ +| | Applications | Devices | ++---------------------------------------------------------------+ +| ADP | X | | ++---------------------------------------------------------------+ +| ADE | X | | ++---------------------------------------------------------------+ +| DCP | X | X | ++---------------------------------------------------------------+ +| DCE | X | X | ++---------------------------------------------------------------+ + +Licensed Software: Designer tools and modules + +The modules and/or tools that are included in the respective product - Qt for +Design Studio Professional (DSP), Qt for Design Studio Enterprise (DSE) - are +marked with "X" in the below table. + +Designer tools provides no Redistributables. + ++---------------------------------------------+ +| | DSP | DSE | ++---------------------------------------------+ +| Qt Design Studio | X | X | ++---------------------------------------------+ +| Qt Design Bridges | | X | ++---------------------------------------------+ +| QML Live on host | X | X | ++---------------------------------------------+ +| QML Live on target | | X | ++---------------------------------------------+ +| Variant Management | | X | ++---------------------------------------------+ +| Shader creation tools | | X | ++---------------------------------------------+ +| Profiling tools | | X | ++---------------------------------------------+ +| Simulink support | | X | ++---------------------------------------------+ + + +Both DSP and DSE can be used to create an user interface for use cases covered +by ADP, ADE, DCP and DCE. + +Licensed Software: QA Tools + +The modules and/or tools that are included in the respective QA Tools product +- Squish (both Tester and execution Licenses), Coco or Test Center - are marked +with "X" in the below table. Optional features that will need additional +licenses are marked with "O". QA Tools include no Redistributables. + ++---------------------------------------------------------------------+ +| | Squish | Coco | Test Center | ++---------------------------------------------------------------------+ +| Squish IDE | X | | | ++---------------------------------------------------------------------+ +| QA Tool-specific command line tools | X | X | X | ++---------------------------------------------------------------------+ +| Coverage Browser | | X | | ++---------------------------------------------------------------------+ +| HTML interface | | | X | ++---------------------------------------------------------------------+ +| Qt Support Module | X | | | ++---------------------------------------------------------------------+ +| Java support module | X | | | ++---------------------------------------------------------------------+ +| Windows support module | X | | | ++---------------------------------------------------------------------+ +| iOS support module | X | | | ++---------------------------------------------------------------------+ +| Android support module | X | | | ++---------------------------------------------------------------------+ +| Web support module | X | | | ++---------------------------------------------------------------------+ +| macOS support module | X | | | ++---------------------------------------------------------------------+ +| VNC support module | X | | | ++---------------------------------------------------------------------+ +| MCU support module | X | | | ++---------------------------------------------------------------------+ +| C and C++ language module | | X | | ++---------------------------------------------------------------------+ +| C# language module | | X | | ++---------------------------------------------------------------------+ +| QML language module | | X | | ++---------------------------------------------------------------------+ +| Tester Cross-Compilation Add-On | O | O | | ++---------------------------------------------------------------------+ + +License capabilities for Squish + +License capabilities that are included in the Squish Tester and Execution +Licenses are marked with "X" in the below table. + ++-----------------------------------------------------------------------------+ +| | Squish Tester License | Squish Execution License | ++-----------------------------------------------------------------------------+ +| Ability to create, edit, | X | | +| and debug test cas | | | ++-----------------------------------------------------------------------------+ +| Ability to execute test | X | X | +| cases | | | ++-----------------------------------------------------------------------------+ + +Install and use capabilities for QA Tools + +Install and use capabilities that are included in the respective QA Tools +products are defined in the below table. + ++-----------------------------------------------------------------------------+ +| | Squish | Squish | Coco | Test | +| | Tester | Execution | License | Center | +| | License | License | | License | ++-----------------------------------------------------------------------------+ +| Number of installation | Unlimited | Unlimited | Unlimited | One(1) | +| instances per license | | | | | ++-----------------------------------------------------------------------------+ +| Number of concurrent | Limited by| Limited by | Limited by | Limited by | +| users | number of | number of | number of | number of | +| | Squish | Squish | Coco | Test Center | +| | Tester | Execution | Tester | Licenses | +| | Licenses | Licenses | Licenses | | ++-----------------------------------------------------------------------------+ + + +APPENDIX 2: PRICING + +Separate template + +APPENDIX 3: ADD-ON PRODUCTS TO LICENSED SOFTWARE + +Intentionally left blank. + +APPENDIX 4: SMALL BUSINESS AND STARTUP + +The provisions of this Appendix 4 are applicable for companies with an annual +revenue, including funding, equivalent to maximum of 250,000 USD (in applicable +currency) during the latest full calendar year, as evidenced by duly audited +records of the Licensee and approved by The Qt Company ("Start-up Company"). + +Start-up Companies are qualified for a discounted License Fee for maximum of +four (4) Development Licenses ("Start-up Development License") unless otherwise +agreed between the parties. + +Start-up Development License entitles the respective Designated User for +Support only for Install Support as defined in Appendix 9, Support Terms. + +Upon expiry of the respective Development License Term, the Start-up +Development Licenses shall be automatically extended, pursuant to Section 3.1 +of the Agreement, for a Renewal Term either as new Start-up Development +Licenses (if the Licensee still qualifies as a Start-up Company), or as normal +then standard list price Development Licenses (if the Licensee no longer +qualifies as a Start-up Company). + +APPENDIX 5: NON-COMMERCIAL AND EDUCATIONAL USE + +The provisions of this Appendix 5 are applicable for non-commercial use of the +Licensed Software by the Licensee. + +For the purpose of this Appendix 5, the following additional definitions +(replacing the relevant definition of the Agreement, where applicable) shall be +applicable: + +"Demo Units" shall mean (i) hardware development platform, which incorporates +the Licensed Software along with Licensee's software and/or hardware, and (ii) +prototype versions of Applications or Devices. + +"Designated User(s)" shall mean the employees and students of the Licensee. + +"Licensee Products" shall mean Applications and/or Devices. + +"Permitted Purpose" shall mean (i) Licensee's internal evaluation and testing +of Licensed Software, (ii) building Demo Units as well as (iii) educational +use. + +"Agreement Term" shall mean a period of twelve (12) months or any such other +period as may be agreed between the Parties. + +For the purpose of this Appendix 5, the following changes shall be agreed with +respect to relevant Sections of the Agreement: + I. Recital (A) shall be replaced in its entirety to read as follows: + "(A) Licensee wishes to use the Licensed Software for the Permitted + Purpose." + II. Section 3.1 shall be replaced in its entirety to read as follows: + "The Qt Company grants to Licensee a personal, non-exclusive, + non-transferable, revocable, royalty-free license, valid for the + Agreement Term, to use, modify and copy the Licensed Software solely + for the Permitted Purpose. Licensee may install copies of the Licensed + Software on five (5) computers per Designated User, provided that only + the Designated Users who have a valid Development License may use the + Licensed Software. Licensee may demonstrate the Demo Units, provided + that such demonstrations must be conducted by Licensee, and the Demo + Units must remain in Licensee's possession and under Licensee's control + at all times. + For clarity, this Agreement does not (i) entitle Licensee to use + Licensed Software to create Applications or Devices (other than + prototypes thereof) or (ii) carry any distribution rights to Licensee, + but such rights are subject to and conditional upon conclusion of a + separate license agreement with The Qt Company." + III. Sections 3.2, 3.3, 3.5, 3.6, 8 and 10 shall be deleted. + IV. Section 3.4 shall be replaced in its entirety to read as follows: + "Licensee shall not: + - remove or alter any copyright, trademark or other proprietary rights + notice contained in any portion of the Licensed Software; + - transfer, publish, sublicense, disclose, display or otherwise make + the Licensed Software available to any third party (except that + Licensee may demonstrate the Demo Units pursuant to Section 3.1); + - in any way combine, incorporate or integrate Licensed Software with, + or use Licensed Software for creation of, any software created with + or incorporating Open Source Qt; Licensee shall cause all Designated + Users who make use of the licenses granted under this Agreement, to + be contractually bound to comply with the relevant terms of this + Agreement and not to use the Licensed Software beyond the terms + hereof. Licensee shall be responsible for any and all actions and + omissions of its Designated Users relating to the Licensed Software + and use thereof. Any use of Licensed Software beyond the provisions + of this Agreement is strictly prohibited and requires an additional + license from The Qt Company." + V. Section 12 shall be replaced in its entirety to read as follows: + "This Agreement shall enter into force upon due acceptance by both + Parties and remain in force for the Agreement Term, unless and until + terminated pursuant to the terms of Section 12. + Upon termination of the Agreement, Licensee shall cease using the + Licensed Software. All other copies of Licensed Software in the + possession or control of Licensee must be erased or destroyed. An + officer of Licensee must, upon request, promptly deliver to The Qt + Company a written confirmation that this has occurred." + +Except for the modifications specified above, this Appendix carries no change +to the terms of the Agreement which shall remain in full force. + +APPENDIX 6: LICENSE REPORTING + +Separate template + +APPENDIX 7: MARKETING RIGHTS + +This Appendix 7 has the purpose to grant visibility through The Qt Company +marketing channels of the usage of Qt and related product and service in +Licensee product. Following related marketing right are agreed between the Qt +Company and the Licensee. + +1. LICENSEE NAME AND LICENSEE LOGO + +The Qt Company has the right to use Licensee name and Licensee logo in public +channel, in respect of the value proposition that the Qt company provided to +the Licensee. + +2. MARKETING CONTENT COOPERATION + +2.1. LICENSEE CASES + +The Licensee is open to collaborate on content creation for marketing and +communication purpose. The Licensee will nominate one responsible that will be +in charge to support The Qt company with this content creation, according to +content format paragraph, answering technical questions or sharing professional +picture or video of required content. The Qt Company will have the right to +advertise this in Content Format and Channel as mentioned in paragraph 3 and 4. + +2.2. FINAL PRODUCT REFERRAL + +Licensee agree that The Qt Company could connect their software product and +services with the Licensee device or application, that the Licensee has created +using The Qt Company technology and competence. Licensee will provide high +quality picture, and video of the created final product where the Qt technology +is running into. The Qt Company will have the right to advertise this in +Content Format and Channel as mentioned in paragraph 3 and 4. + +3. CONTENT FORMAT + +- Video +- Written Licensee case +- Press release +- Social media posts +- Emails +- Event booth Graphics +- Printed material + +4. CHANNELS + +- Social media +- The Qt Company resource center and website +- Email to the Qt company contact database +- Events +- Online webinars +- Public speech +- Public presentations + +APPENDIX 8: INTENTIONALLY LEFT BLANK + +APPENDIX 9: SUPPORT TERMS + +These Qt support terms and conditions ("Support Terms") set forth the legal +framework, where under The Qt Company ("The Qt Company") provides support +services (as herein defined) to the Licensee. + +1 DEFINITIONS + +"Application Code" shall mean a computer software program written strictly +using the Qt programming language, by or for the Licensee, with a user +interface, enabling the Licensee or their users to accomplish a specific task +and display any results of the task on the display monitor or screen. + +"Dedicated Contact" shall mean the employee of The Qt Company who will be the +first point of contact for all Designated Users' requests for Support. + +"Errors" shall mean an error, flaw, mistake, failure, or fault in Licensed +Software that prevents it from behaving as described in the relevant +documentation or as agreed between the Parties. + +"Extended Support" shall mean a continuation to the normal Support period, +which allows Designated Users to receive selected Support (Standard Support or +Premium Support) for a version of Licensed Software that is no longer generally +supported by The Qt Company. + +"Install Support" shall mean Support that is limited to installation related +Error(s) on Development Platforms specified as supported host platforms for +each Qt release under doc.qt.io. + +"Maintenance Release" shall mean a release or version of Licensed Software +containing bug fixes, error corrections and other changes targeted to +maintaining and improving product stability and quality. Maintenance Releases +are generally depicted as a change to the third digit of Licensed Software +version number. + +"Platforms" shall mean both Development Platforms and Deployment Platforms. +Supported host and target Platforms may vary from for each Qt release as +defined under doc.qt.io. + +"Premium Support" shall mean an upgraded level of Support that The Qt Company +provides pursuant to these Support Terms to Licensee if Licensee has purchased +Premium Support instead of Standard Support. Premium Support shall always be +purchased for all Designated User(s) in the respective development team of the +Licensee. + +"Response Time" shall mean the period of time from when Licensee notifies +TheQt Company about an Error or requests Support until The Qt Company provides +Licensee with a response that addresses (but not necessarily resolves) the +reported Error or provides the requested Support. + +"Standard Support" shall mean standard level of Support that The Qt Company +provides pursuant to these Support Terms to Licensee. + +"Support" shall mean developer assistance that is provided by The Qt Company +to assist eligible Designated Users in Licensed Software installation, usage +and functionality problem resolution for Error(s) and Error workarounds +pursuant to the terms of these Support Terms. Support for different products is +available as specified in the below table ("X" marking the Support that is +included in the license price, optional Add-on Support services are marked as +"O"): + ++-----------------------------------------------------------------------+ +| |ADP|ADE|DCP|DCE|DSP|DSE|Squish|Coco|Test Center| ++-----------------------------------------------------------------------+ +| Install Support | X | X | X | X | X | X | X | X | X | ++-----------------------------------------------------------------------+ +| Standard Support | | X | X | X | X | X | X | X | X | ++-----------------------------------------------------------------------+ +| Premium Support | | O | O | O | O | O | O | O | O | ++-----------------------------------------------------------------------+ +| Extended Support | | O | O | O | O | O | | | | ++-----------------------------------------------------------------------+ +| Tool Qualification Kit| | | | | | | O | O | | ++-----------------------------------------------------------------------+ + +"Support Validity Term" shall mean the Development License Term or any other +fixed time period agreed between the Parties during which time the Customer is +eligible to receive Support from The Qt Company. + +"Tool Qualification Kit" shall mean a customized set of documents and +validation test cases. + +2 SUPPORT SERVICES + +2.1 Support Services Provided by The Qt Company + +Subject to these Support Terms and during the Support Validity Term, The Qt +Company will via its web-based support user-interface, provide Designated +User(s) with Support for the Platforms which Customer has licensed under the +Agreement. +The Qt Company will make commercially reasonable efforts to solve any Errors +reported by Designated User(s). Resolution of an Error may be provided through +Designated User(s) themselves downloading of a later released version of the +applicable Licensed Software product(s) or providing the Designated User with a +temporary workaround addressing such Error. + +2.2 Licensee's Obligations + +To report an Error, the Designated User shall register the Error on The Qt +Company's web-based support user interface located at: +https://account.qt.io/login or at another location designated by The Qt Company. + +The Designated User must provide adequate information and documentation to The +Qt Company to enable it to recreate the Error or problem for which the +Designated User has sought assistance. +To ensure efficient handling of Errors, the Designated User must provide the +following information, where relevant: +- A clear, detailed description of the problem, question or suggestion; +- Identification of which Licensed Software product and version is affected; +- Identification of the operating environment (e.g. operating system, hardware + Platform, build tools, etc.) on which the problem exists; +- On Standard Support: A complete and compilable test case of not more than 500 + lines of code that demonstrates the problem; +- On Premium Support: A complete and compilable test case that demonstrates the + problem or access to Application Code source codes. + +Additional relevant content, such as screenshots, etc. +Additional content should be included as attachments. The preferred image +formats are JPEG and PNG. Compressed content should be included in zip or +tar.gz archives. Executable content and documents in platform specific formats +such as Microsoft Office' are not accepted. + +In order for The Qt Company to provide prompt handling of Errors, the +Designated User shall promptly respond to any requests from The Qt Company for +additional information. + +2.3 Support Limitations + +General limitations: + +Each version or release of the Licensed Software will be Supported under +Standard Support or Premium Support only for limited time period as set forth +in doc.qt.io. For example, regular releases of Qt Software are supported for +one (1) year from the release date of the version x.y.0 and Long Term Support +(LTS) Releases are supported for a period of three (3) years from the release +date of the LTS version x.y.0. + +The Qt Company shall only provide Support for Designated User(s). + +Support is made available for the entire development teams only: It is not +allowed to purchase Support only for some members of the development team, and +all Designated Users of the respective development team must be eligible for +the same level of Support. + +Support is not provided for snapshots, preview releases, beta releases or +release candidates. + +The Qt Company shall have no obligation to provide Support for hardware or +operating system specific problems or problems arising from improper use, +accident, neglect or modification of Qt. + +Limitations with Install Support: + +Support limited to Error(s) regarding installation and setting up of the Qt +development environment on host Platforms. + +Limitations with Standard Support: + +The Qt Company shall not provide Support for third-party software or problems +caused by third-party software even if such third-party software is distributed +together with Licensed Software product(s). + +The Qt Company shall only provide Support for Error(s) that are reported on and +can be reproduced on Platforms that are officially supported for the release of +the Licensed Software. + +Limitations with Premium support: + +The Qt Company shall not provide Support for third-party software or problems +caused by third-party software. However, if such third-party software is +distributed together with Licensed Software, The Qt Company will make +commercially reasonable efforts to solve such problems. + +The Qt Company shall only provide Support for Error(s) that can be reproduced +on Platforms that are officially supported for the release of the Licensed +Software. If the Error is on a Platform that is not supported, The Qt Company +will make commercially reasonable efforts to provide a solution on closest +corresponding supported Platform. + +Premium Support is optional and purchased for an agreed bucket of hours +("Bucket"). Hours can be used by any Designated User in the respective +development team. To encourage continuous usage of the Support, ten percent +(10%) of the purchased Bucket shall automatically expire (regardless of whether +such support hours are actually used or not by the Licensee) each month after +three (3) months from the purchase of the Premium Support. + +2.4 Extended Support + +Extended Support extends the Support Validity Term for a release of Licensed +Software that is no longer generally supported. + +Extended Support includes and is by default provided with Standard Support +rules and limitations, unless Extended Support is purchased with Premium +Support in which case Premium Support rules and limitations will apply. + +Extended Support is optional and purchased with annual fee and separately per +each Licensee product. Extended Support will need definition of (i) Licensee +product, (ii) used Platform(s) and (iii) Licensed Software version(s). + +2.5 Tool Qualification Kit + +The Qt Company shall provide set of customized documents and validation tests +that enable Licensee to qualify QA testing tool for the purpose of ISO 26262, +EN 50128, DO-330, IEC 61508, IEC 62304 or IEC 13485 certification Licensee end +to end solution. + +3 RESPONSE TIME + +In performing Support, The Qt Company shall commit to following, non-binding, +Response Times: + +Standard Support: Errors and Support requests will have a Response Time not to +exceed two (2) business days. + +Premium Support: Errors and Support requests will have a Response Time not to +exceed one (1) business day. + +For complex issues, The Qt Company may provide an initial response to the +Designated User and then follow up, without undue delay, with additional +communication before an Error is properly addressed or Support provided. + +4 ADDITIONAL SERVICES IN PREMIUM SUPPORT + +The Designated User(s) will be assigned a Dedicated Contact to handle requests +for Support. Dedicated Contact is subject to change in cases such as sick +leave, vacation and other similar reasons. + +The Designated User(s) can on request ask The Qt Company to access their +computer remotely in order to resolve problems directly. + +The Designated User(s) can request a session via Instant Messaging or phone +call in the support request to The Qt Company. + +Premium Support can assist Licensee in implementing new features, bug fixes +and accessing patches in Licensed Software or Application Code. + +All Support requests will be handled with high priority. + +5 MAINTENANCE RELEASES, UPDATES AND UPGRADES + +Under the Support the Customer is eligible for Maintenance Releases and Updates +that The Qt Company generally makes available to customers who has purchased +Support. Unless otherwise decided by The Company at its free and absolute +discretion, Upgrades will not be provided under the Support. + +The primary focus of Maintenance Releases is product quality. Therefore, each +Maintenance Release typically includes the following types of changes to the +previous version of Licensed Software: +- Bug fixes caused by changes to previously working code; +- Fixes related to build issues on supported Platforms; +- Error corrections specific to a single Platform that are not present on other + Platforms; +- Critical Error corrections such as crashes, data corruption, loss of data, + race conditions; and +- Updates to documentation and license information when deemed necessary by + The Qt Company. + +The primary focus of Updates is introducing new features to Licensed Software +and covering new platforms. Therefore, each Updates typically includes the +following types of changes to the previous version of Licensed Software: +- New platform support; +- New toolchain support; +- New features and Qt modules; + +6 WARRANTY DISCLAIMER + +The Qt Company makes no warranties that the Support provided will be successful +in resolving any difficulties or problems or in diagnosing faults reported by +Licensee. Support is provided to Licensee on an "as is" basis. To the maximum +extent permitted by applicable law, The Qt Company disclaims all warranties and +conditions, either express or implied, including, but not limited to, implied +warranties of merchantability and fitness for a particular purpose for the +Support provided by The Qt Company to Licensee. + +APPENDIX 10: CONVERSION TO SUBSCRIPTION + +Subject to the terms of this Appendix Licensee's current development licenses +("Current Licenses") for commercial version of Qt Software and the license +agreements governing such Current Licenses ("Existing Agreements") are being +replaced by this Agreement and subscription based Development Licenses +governed hereunder, as further specified below. + ++---------------------------------------------------------------------------+ +| Existing Agreement(s) | and | +| signing parties, version | | +| thereof | | ++---------------------------------------------------------------------------+ + +Parties hereby agree on conversion of Current Licenses listed in attached +Exhibit A to the subscription licenses listed in attached Exhibit B for use +through License Term. As of the date hereof, + +i. Licensee's Current Licenses as listed in Exhibit A shall terminate and be +replaced with the Subscription licenses listed in Exhibit B and; +ii. Existing Agreements are terminated. + +Prices for the conversion of Current Licenses are defined in Appendix 2 +Pricing or Quote. + +Notwithstanding anything in this Appendix to the contrary, and in addition to +any payments due pursuant to this Appendix, Licensee remains fully obligated to +fulfill any and all outstanding payment obligations to The Qt Company under any +applicable Existing Agreements. For the avoidance of doubt, if any payments +remain outstanding on the Current Licenses under the applicable terms Licensee +will continue to make such payments in accordance with the applicable order +documentation, notwithstanding the fact that the Current Licenses are being +converted to Development Licenses pursuant to this Appendix. diff --git a/.cmake.conf b/.cmake.conf new file mode 100644 index 0000000..40d4e4b --- /dev/null +++ b/.cmake.conf @@ -0,0 +1,2 @@ +set(QT_REPO_MODULE_VERSION "6.3.1") +set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "") diff --git a/.tag b/.tag new file mode 100644 index 0000000..53c61d1 --- /dev/null +++ b/.tag @@ -0,0 +1 @@ +c6f1f414aa9103b75f5f2d28a071b0807a0f91b2 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a17135f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.16) + +include(.cmake.conf) +project(QtRemoteObjects + VERSION "${QT_REPO_MODULE_VERSION}" + DESCRIPTION "Qt RemoteObjects Libraries" + HOMEPAGE_URL "https://qt.io/" + LANGUAGES CXX C +) + +find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals Core Network) +find_package(Qt6 ${PROJECT_VERSION} CONFIG OPTIONAL_COMPONENTS Gui Widgets Quick QuickTest) + +if(NOT TARGET Qt::Network) + message(NOTICE "Skipping the build as the condition \"TARGET Qt::Network\" is not met.") + return() +endif() +qt_build_repo() + +if(NOT QT_BUILD_STANDALONE_TESTS) + # Copy mkspecs for users preferring qmake builds + set(mkspecs_install_dir "${INSTALL_MKSPECSDIR}") + qt_path_join(mkspecs_install_dir ${QT_INSTALL_DIR} ${mkspecs_install_dir}) + + qt_copy_or_install(DIRECTORY mkspecs/ + DESTINATION "${mkspecs_install_dir}" + FILES_MATCHING PATTERN "*.pr[if]" + ) +endif() diff --git a/LICENSE.FDL b/LICENSE.FDL new file mode 100644 index 0000000..857214d --- /dev/null +++ b/LICENSE.FDL @@ -0,0 +1,451 @@ + + GNU Free Documentation License + Version 1.3, 3 November 2008 + + + Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +0. PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document "free" in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. + +This License is a kind of "copyleft", which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + + +1. APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The "Document", below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as "you". You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. + +A "Modified Version" of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A "Secondary Section" is a named appendix or a front-matter section of +the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall +subject (or to related matters) and contains nothing that could fall +directly within that overall subject. (Thus, if the Document is in +part a textbook of mathematics, a Secondary Section may not explain +any mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The "Invariant Sections" are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. + +The "Cover Texts" are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. + +A "Transparent" copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not "Transparent" is called "Opaque". + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input format, SGML +or XML using a publicly available DTD, and standard-conforming simple +HTML, PostScript or PDF designed for human modification. Examples of +transparent image formats include PNG, XCF and JPG. Opaque formats +include proprietary formats that can be read and edited only by +proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the +machine-generated HTML, PostScript or PDF produced by some word +processors for output purposes only. + +The "Title Page" means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, "Title Page" means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. + +The "publisher" means any person or entity that distributes copies of +the Document to the public. + +A section "Entitled XYZ" means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as "Acknowledgements", +"Dedications", "Endorsements", or "History".) To "Preserve the Title" +of such a section when you modify the Document means that it remains a +section "Entitled XYZ" according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. + +2. VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no +other conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + + +3. COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to +give them a chance to provide you with an updated version of the +Document. + + +4. MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +A. Use in the Title Page (and on the covers, if any) a title distinct + from that of the Document, and from those of previous versions + (which should, if there were any, be listed in the History section + of the Document). You may use the same title as a previous version + if the original publisher of that version gives permission. +B. List on the Title Page, as authors, one or more persons or entities + responsible for authorship of the modifications in the Modified + Version, together with at least five of the principal authors of the + Document (all of its principal authors, if it has fewer than five), + unless they release you from this requirement. +C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. +D. Preserve all the copyright notices of the Document. +E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. +F. Include, immediately after the copyright notices, a license notice + giving the public permission to use the Modified Version under the + terms of this License, in the form shown in the Addendum below. +G. Preserve in that license notice the full lists of Invariant Sections + and required Cover Texts given in the Document's license notice. +H. Include an unaltered copy of this License. +I. Preserve the section Entitled "History", Preserve its Title, and add + to it an item stating at least the title, year, new authors, and + publisher of the Modified Version as given on the Title Page. If + there is no section Entitled "History" in the Document, create one + stating the title, year, authors, and publisher of the Document as + given on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence. +J. Preserve the network location, if any, given in the Document for + public access to a Transparent copy of the Document, and likewise + the network locations given in the Document for previous versions + it was based on. These may be placed in the "History" section. + You may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission. +K. For any section Entitled "Acknowledgements" or "Dedications", + Preserve the Title of the section, and preserve in the section all + the substance and tone of each of the contributor acknowledgements + and/or dedications given therein. +L. Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section titles. +M. Delete any section Entitled "Endorsements". Such a section + may not be included in the Modified Version. +N. Do not retitle any existing section to be Entitled "Endorsements" + or to conflict in title with any Invariant Section. +O. Preserve any Warranty Disclaimers. + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled "Endorsements", provided it contains +nothing but endorsements of your Modified Version by various +parties--for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + + +5. COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections Entitled "History" +in the various original documents, forming one section Entitled +"History"; likewise combine any sections Entitled "Acknowledgements", +and any sections Entitled "Dedications". You must delete all sections +Entitled "Endorsements". + + +6. COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other +documents released under this License, and replace the individual +copies of this License in the various documents with a single copy +that is included in the collection, provided that you follow the rules +of this License for verbatim copying of each of the documents in all +other respects. + +You may extract a single document from such a collection, and +distribute it individually under this License, provided you insert a +copy of this License into the extracted document, and follow this +License in all other respects regarding verbatim copying of that +document. + + +7. AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an "aggregate" if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. + + +8. TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. + +If a section in the Document is Entitled "Acknowledgements", +"Dedications", or "History", the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. + + +9. TERMINATION + +You may not copy, modify, sublicense, or distribute the Document +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense, or distribute it is void, and +will automatically terminate your rights under this License. + +However, if you cease all violation of this License, then your license +from a particular copyright holder is reinstated (a) provisionally, +unless and until the copyright holder explicitly and finally +terminates your license, and (b) permanently, if the copyright holder +fails to notify you of the violation by some reasonable means prior to +60 days after the cessation. + +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, receipt of a copy of some or all of the same material does +not give you any rights to use it. + + +10. FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions of the +GNU Free Documentation License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in +detail to address new problems or concerns. See +https://www.gnu.org/licenses/. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. If the Document +specifies that a proxy can decide which future versions of this +License can be used, that proxy's public statement of acceptance of a +version permanently authorizes you to choose that version for the +Document. + +11. RELICENSING + +"Massive Multiauthor Collaboration Site" (or "MMC Site") means any +World Wide Web server that publishes copyrightable works and also +provides prominent facilities for anybody to edit those works. A +public wiki that anybody can edit is an example of such a server. A +"Massive Multiauthor Collaboration" (or "MMC") contained in the site +means any set of copyrightable works thus published on the MMC site. + +"CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0 +license published by Creative Commons Corporation, a not-for-profit +corporation with a principal place of business in San Francisco, +California, as well as future copyleft versions of that license +published by that same organization. + +"Incorporate" means to publish or republish a Document, in whole or in +part, as part of another Document. + +An MMC is "eligible for relicensing" if it is licensed under this +License, and if all works that were first published under this License +somewhere other than this MMC, and subsequently incorporated in whole or +in part into the MMC, (1) had no cover texts or invariant sections, and +(2) were thus incorporated prior to November 1, 2008. + +The operator of an MMC Site may republish an MMC contained in the site +under CC-BY-SA on the same site at any time before August 1, 2009, +provided the MMC is eligible for relicensing. + + +ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + + Copyright (c) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.3 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled "GNU + Free Documentation License". + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the "with...Texts." line with this: + + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. diff --git a/LICENSE.GPL2 b/LICENSE.GPL2 new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/LICENSE.GPL2 @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/LICENSE.GPL3 b/LICENSE.GPL3 new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/LICENSE.GPL3 @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/LICENSE.GPL3-EXCEPT b/LICENSE.GPL3-EXCEPT new file mode 100644 index 0000000..b1cb1be --- /dev/null +++ b/LICENSE.GPL3-EXCEPT @@ -0,0 +1,704 @@ +This is the GNU General Public License version 3, annotated with The +Qt Company GPL Exception 1.0: + +------------------------------------------------------------------------- + +The Qt Company GPL Exception 1.0 + +Exception 1: + +As a special exception you may create a larger work which contains the +output of this application and distribute that work under terms of your +choice, so long as the work is not otherwise derived from or based on +this application and so long as the work does not in itself generate +output that contains the output from this application in its original +or modified form. + +Exception 2: + +As a special exception, you have permission to combine this application +with Plugins licensed under the terms of your choice, to produce an +executable, and to copy and distribute the resulting executable under +the terms of your choice. However, the executable must be accompanied +by a prominent notice offering all users of the executable the entire +source code to this application, excluding the source code of the +independent modules, but including any changes you have made to this +application, under the terms of this license. + + +------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/LICENSE.LGPL3 b/LICENSE.LGPL3 new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/LICENSE.LGPL3 @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/coin/module_config.yaml b/coin/module_config.yaml new file mode 100644 index 0000000..16d158c --- /dev/null +++ b/coin/module_config.yaml @@ -0,0 +1,12 @@ +version: 2 +accept_configuration: + condition: property + property: features + not_contains_value: Disable + +instructions: + Build: + - !include "{{qt/qtbase}}/coin_module_build_template_v2.yaml" + + Test: + - !include "{{qt/qtbase}}/coin_module_test_template_v3.yaml" diff --git a/conanfile.py b/conanfile.py new file mode 100644 index 0000000..c6b0186 --- /dev/null +++ b/conanfile.py @@ -0,0 +1,60 @@ +############################################################################# +## +## Copyright (C) 2021 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the release tools of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:GPL-EXCEPT$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3 as published by the Free Software +## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +from conans import ConanFile +import re +from pathlib import Path + + +def _parse_qt_version_by_key(key: str) -> str: + with open(Path(__file__).parent.resolve() / ".cmake.conf") as f: + m = re.search(fr'{key} .*"(.*)"', f.read()) + return m.group(1) if m else "" + + +def _get_qt_minor_version() -> str: + return ".".join(_parse_qt_version_by_key("QT_REPO_MODULE_VERSION").split(".")[:2]) + + +class QtRemoteObjects(ConanFile): + name = "qtremoteobjects" + license = "LGPL-3.0, GPL-2.0+, Commercial Qt License Agreement" + author = "Brett Stottlemyer, Ford Motor Company" + url = "https://code.qt.io/cgit/qt/qtremoteobjects.git" + description = ( + "Qt Remote Objects (QtRO) is an Inter-Process Communication (IPC) module developed for Qt. " + "This module extends Qt's existing functionalities to enable information exchange between " + "processes or computers, easily." + ) + topics = "qt", "qt6", "QtRO", "IPC" + settings = "os", "compiler", "arch", "build_type" + # for referencing the version number and prerelease tag and dependencies info + exports = ".cmake.conf", "dependencies.yaml" + exports_sources = "*", "!conan*.*" + python_requires = f"qt-conan-common/{_get_qt_minor_version()}@qt/everywhere" + python_requires_extend = "qt-conan-common.QtLeafModule" diff --git a/dependencies.yaml b/dependencies.yaml new file mode 100644 index 0000000..33c1acc --- /dev/null +++ b/dependencies.yaml @@ -0,0 +1,7 @@ +dependencies: + ../qtbase: + ref: 8483dcde90f40cdfd0a0ec4245b03610b46b6cae + required: true + ../qtdeclarative: + ref: 47ef121e1a436fd46129cdaa1a4398c82045eb97 + required: false diff --git a/dist/changes-5.11.0 b/dist/changes-5.11.0 new file mode 100644 index 0000000..27072a6 --- /dev/null +++ b/dist/changes-5.11.0 @@ -0,0 +1,41 @@ +Qt 5.11 introduces many new features and improvements as well as bugfixes +over the 5.10.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +Note: Tech Preview modules are able to change APIs to refine or enhance the +module's functionality. Thus Qt's binary compatibility quarantees aren't +applicable. Code switching to 5.11.0 from earlier versions of Qt Remote +Objects will need to be recompiled. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Qt 5.11.0 Changes * +**************************************************************************** + + - QRemoteObjectNode + * [QTBUG-64086] Added heartbeatInterval property, which can be used to + periodically check the connection between replica and source. If the + connection is lost, the replica enters the "Suspect" state and will + attempt to reconnect. + * Extended acquireModel to allow prefetching data. + + - QRemoteObjectAbstractPersistedStore + * Renamed from QRemoteObjectPersistedStore, and made a QObject to allow + use from QML. + * Added QRemoteObjectSettingsStore (SettingsStore in QML) as a concrete + implementation using QSettings. + + - repc + * Added support for nested classes, via an extension to the .rep file + format. The syntax is `CLASS (), where type needs to be a + class defined in the same rep file, and name is the property name + used to access the sub-QObject. diff --git a/dist/changes-5.11.1 b/dist/changes-5.11.1 new file mode 100644 index 0000000..610e8ad --- /dev/null +++ b/dist/changes-5.11.1 @@ -0,0 +1,26 @@ +Qt 5.11.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.11.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +Note: Tech Preview modules are able to change APIs to refine or enhance the +module's functionality. Thus Qt's binary compatibility quarantees aren't +applicable. Code switching to 5.11.0 from earlier versions of Qt Remote +Objects will need to be recompiled. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Qt 5.11.1 Changes * +**************************************************************************** + + - This release contains several fixes for MODEL/SUBCLASS handling and tests. diff --git a/dist/changes-5.11.2 b/dist/changes-5.11.2 new file mode 100644 index 0000000..8efdf5e --- /dev/null +++ b/dist/changes-5.11.2 @@ -0,0 +1,24 @@ +Qt 5.11.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.11.0 through 5.11.1. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +The Qt version 5.11 series is binary compatible with the 5.10.x series. +Applications compiled for 5.10 will continue to run with 5.11. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Qt 5.11.2 Changes * +**************************************************************************** + + - This release contains only minor code improvements. diff --git a/dist/changes-5.11.3 b/dist/changes-5.11.3 new file mode 100644 index 0000000..28f337e --- /dev/null +++ b/dist/changes-5.11.3 @@ -0,0 +1,27 @@ +Qt 5.11.3 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.11.0 through 5.11.2. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +Note: Tech Preview modules are able to change APIs to refine or enhance the +module's functionality. Thus Qt's binary compatibility quarantees aren't +applicable. Code switching to 5.11.0 from earlier versions of Qt Remote +Objects will need to be recompiled. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Qt 5.11.3 Changes * +**************************************************************************** + + - QRemoteObjectNode + * Fix a constant reconnect issue diff --git a/dist/changes-5.12.0 b/dist/changes-5.12.0 new file mode 100644 index 0000000..0884e4f --- /dev/null +++ b/dist/changes-5.12.0 @@ -0,0 +1,46 @@ +Qt 5.12 introduces many new features and improvements as well as bugfixes +over the 5.11.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +Note: Tech Preview modules are able to change APIs to refine or enhance the +module's functionality. Thus Qt's binary compatibility quarantees aren't +applicable. Code switching to 5.12.0 from earlier versions of Qt Remote +Objects will need to be recompiled. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Qt 5.12.0 Changes * +**************************************************************************** + - General + * [QTBUG-68678] Graduate Qt Remote Objects from TP to fully supported + module of Qt + * [QTBUG-65727] QtRemoteObjects: Documentation doesn't match the code + + - QRemoteObjectNode + * Support externally created QIODevices, including SSL sockets. + * Added proxy() method to support use-cases like having a single node + provide a (for instance) tcp url for a device allowing access from + other devices, while using internal connections (like "local:*") on + the device. + + - repc + * [QTBUG-68976] Cannot add comments in .rep file + * [QTBUG-68975] Support multiline PODs and ENUMs in repc + * [QTBUG-67770] repc should be able to use tab characters as a normal + whitespace + +**************************************************************************** +* QML * +**************************************************************************** + + - Updated import statement to better match typical module pattern. From + QML "import QtRemoteObjects 5.12" should now be used. diff --git a/dist/changes-5.12.1 b/dist/changes-5.12.1 new file mode 100644 index 0000000..dfb633f --- /dev/null +++ b/dist/changes-5.12.1 @@ -0,0 +1,30 @@ +Qt 5.12.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +Note: Tech Preview modules are able to change APIs to refine or enhance the +module's functionality. Thus Qt's binary compatibility quarantees aren't +applicable. Code switching to 5.12 (when Remote Objects "graduated" from +Tech Preview) from earlier versions of Qt Remote Objects will need to be +recompiled. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Qt 5.12.1 Changes * +**************************************************************************** + - General + * [QTBUG-72064] QVariant is also a standalone type and we must treat it + accordingly + * Convert QNX backend to use shared pointers + * Various code cleanup diff --git a/dist/changes-5.12.2 b/dist/changes-5.12.2 new file mode 100644 index 0000000..0c8bd85 --- /dev/null +++ b/dist/changes-5.12.2 @@ -0,0 +1,20 @@ +Qt 5.12.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.0 through 5.12.1. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.12 series is binary compatible with the 5.11.x series. +Applications compiled for 5.11 will continue to run with 5.12. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + + - This release contains only minor code improvements. diff --git a/dist/changes-5.12.3 b/dist/changes-5.12.3 new file mode 100644 index 0000000..8503086 --- /dev/null +++ b/dist/changes-5.12.3 @@ -0,0 +1,29 @@ +Qt 5.12.3 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.0 through 5.12.2. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +Note: Tech Preview modules are able to change APIs to refine or enhance the +module's functionality. Thus Qt's binary compatibility quarantees aren't +applicable. Code switching to 5.12 (when Remote Objects "graduated" from +Tech Preview) from earlier versions of Qt Remote Objects will need to be +recompiled. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Qt 5.12.1 Changes * +**************************************************************************** + - General + * [QTBUG-74221] Fix restart/nullptr crash + * [QTBUG-73962] Fix crash with AllowExternalRegistration and QtRO schema + * Doc: Add link from index page to QML Types diff --git a/dist/changes-5.12.4 b/dist/changes-5.12.4 new file mode 100644 index 0000000..e415add --- /dev/null +++ b/dist/changes-5.12.4 @@ -0,0 +1,71 @@ +Qt 5.12.4 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.0 through 5.12.3 under most +conditions. There may be exceptions if you are using Qt Remote Objects +between proesses or devices running different versions Qt. The different +versions of Qt must be running compatible versions of QtRO's protocol. + +Changes to the Qt Remote Objects protocol are documented online: + +https://doc.qt.io/qt-5/qtremoteobjects-compatibility.html + +The QtRO protocol has been updated in Qt 5.12.4 and Qt 5.13.0 to 1.3. + +Background: Qt's QueuedConnections work by copying signal parameters so +the copy can be held and then later processed in another threads +eventloop, allowing the original data to be changed in the originating +thread. + +Qt Remote Objects leverages this capability and sends that data from a +QObject in one process to a QObject in another. There is a specific +protocol for this, as both sides need to interpret what is sent the +same way. For example, there are Invoke and PropertyChanged packets +exchanged. In addition to this, both sides need to know how to encode and +decode all types shared. This type awareness is easy to ensure if the +repc compiler is used to generate the headers for all sides. + +However, there are use cases where this isn't possible. In these cases +QtRO will send the type (metaobject) information as well, allowing the +receiving side to generate the required type information at runtime for +certain types (PODs and enumerations). + +There were issues found in this type serialization code that required a +change to the protocol. There are a number of commits going into both +Qt 5.13.0 and Qt 5.12.4 with fixes. This means that you will not be able +to use Qt Remote Objects on a device using Qt 5.12.3 or earlier and +communicate to another device using Qt 5.12.4/5.13.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.12 series is binary compatible with the 5.11.x series. +Applications compiled for 5.11 will continue to run with 5.12 as long as +the protocol change noted above is taken into account. + +**************************************************************************** +* Important Behavior Changes * +**************************************************************************** + + - Qt Remote Objects uses an internal protocol to pass data between + processes and/or devices. The same protocol version needs to be used on + all sides. The version was bumped from 1.2 to 1.3 in this release, + fixing potential crashes (see QTBUG-75017). If there is a mismatch, the + connecting node will output a warning and the host node will not send + any data. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +The following fixes were part of the above protocol change and are in +5.12.4 and 5.13.0. + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + + - QTBUG-75017: QtRO processes can crash if type registration is incorrect + - QTBUG-75056: Correctly handle QVariant properties on the replica side + - QTBUG-74084: QT remote objects false conversion warning in case of + QVariant property diff --git a/dist/changes-5.12.5 b/dist/changes-5.12.5 new file mode 100644 index 0000000..e8be931 --- /dev/null +++ b/dist/changes-5.12.5 @@ -0,0 +1,20 @@ +Qt 5.12.5 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.0 through 5.12.4. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.12 series is binary compatible with the 5.11.x series. +Applications compiled for 5.11 will continue to run with 5.12. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + + - This release contains only minor code improvements. diff --git a/dist/changes-5.13.0 b/dist/changes-5.13.0 new file mode 100644 index 0000000..cc8d4ff --- /dev/null +++ b/dist/changes-5.13.0 @@ -0,0 +1,57 @@ +Qt 5.13 introduces many new features and improvements as well as bugfixes +over the 5.12.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.13 series is binary compatible with the 5.12.x series. +Applications compiled for 5.12 will continue to run with 5.13 under most +conditions. There may be exceptions if you are using Qt Remote Objects +between proesses or devices running different versions Qt. The different +versions of Qt must be running compatible versions of QtRO's protocol. + +Changes to the Qt Remote Objects protocol are documented online: + +https://doc.qt.io/qt-5/qtremoteobjects-compatibility.html + +The QtRO protocol has been updated in Qt 5.12.4 and Qt 5.13.0 to 1.3. + +Background: Qt's QueuedConnections work by copying signal parameters so +the copy can be held and then later processed in another threads +eventloop, allowing the original data to be changed in the originating +thread. + +Qt Remote Objects leverages this capability and sends that data from a +QObject in one process to a QObject in another. There is a specific +protocol for this, as both sides need to interpret what is sent the +same way. For example, there are Invoke and PropertyChanged packets +exchanged. In addition to this, both sides need to know how to encode and +decode all types shared. This type awareness is easy to ensure if the +repc compiler is used to generate the headers for all sides. + +However, there are use cases where this isn't possible. In these cases +QtRO will send the type (metaobject) information as well, allowing the +receiving side to generate the required type information at runtime for +certain types (PODs and enumerations). + +There were issues found in this type serialization code that required a +change to the protocol. There are a number of commits going into both +Qt 5.13.0 and Qt 5.12.4 with fixes. This means that you will not be able +to use Qt Remote Objects on a device using Qt 5.12.3 or earlier and +communicate to another device using Qt 5.12.4/5.13.0. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +The following fixes were part of the above protocol change and are in +5.12.4 and 5.13.0. + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + + - QTBUG-75017: QtRO processes can crash if type registration is incorrect + - QTBUG-75056: Correctly handle QVariant properties on the replica side + - QTBUG-74084: QT remote objects false conversion warning in case of + QVariant property diff --git a/dist/changes-5.13.1 b/dist/changes-5.13.1 new file mode 100644 index 0000000..ce9927b --- /dev/null +++ b/dist/changes-5.13.1 @@ -0,0 +1,21 @@ +Qt 5.13.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.13.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.13 series is binary compatible with the 5.12.x series. +Applications compiled for 5.12 will continue to run with 5.13. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + + - Improved clarity and consistency of documentation. + - Made a number of fixes and improvements in the handling of enumerations. diff --git a/dist/changes-5.13.2 b/dist/changes-5.13.2 new file mode 100644 index 0000000..be59a25 --- /dev/null +++ b/dist/changes-5.13.2 @@ -0,0 +1,30 @@ +Qt 5.13.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.13.0 through 5.13.1. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.13 series is binary compatible with the 5.12.x series. +Applications compiled for 5.12 will continue to run with 5.13 under most +conditions. There may be exceptions if you are using Qt Remote Objects +between proesses or devices running different versions Qt. The different +versions of Qt must be running compatible versions of QtRO's protocol. + +Changes to the Qt Remote Objects protocol are documented online: + +https://doc.qt.io/qt-5/qtremoteobjects-compatibility.html + +The QtRO protocol has been updated in Qt 5.12.4 and Qt 5.13.0 to 1.3. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + + - This release contains only minor code improvements and some improvements + to the documentation. diff --git a/dist/changes-5.14.0 b/dist/changes-5.14.0 new file mode 100644 index 0000000..2270fc6 --- /dev/null +++ b/dist/changes-5.14.0 @@ -0,0 +1,25 @@ +Qt 5.14 introduces many new features and improvements as well as bugfixes +over the 5.13.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.14 series is binary compatible with the 5.13.x series. +Applications compiled for 5.13 will continue to run with 5.14. + +If you are using Qt Remote Objects between proesses or devices running +different versions Qt, the different versions of Qt must be running +compatible versions of QtRO's protocol. Changes to the Qt Remote Objects +protocol are documented online: + +https://doc.qt.io/qt-5/qtremoteobjects-compatibility.html + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + + - QTBUG-77178 Support SLOTs with return values in QML diff --git a/dist/changes-5.14.1 b/dist/changes-5.14.1 new file mode 100644 index 0000000..bdb1e12 --- /dev/null +++ b/dist/changes-5.14.1 @@ -0,0 +1,27 @@ +Qt 5.14.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.14.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.14 series is binary compatible with the 5.13.x series. +Applications compiled for 5.13 will continue to run with 5.14. + +If you are using Qt Remote Objects between processes or devices running +different versions Qt, the different versions of Qt must be running +compatible versions of QtRO's protocol. Changes to the Qt Remote Objects +protocol are documented online: + +https://doc.qt.io/qt-5/qtremoteobjects-compatibility.html + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + + - This release contains only minor code improvements. diff --git a/dist/changes-5.14.2 b/dist/changes-5.14.2 new file mode 100644 index 0000000..ca7ab1e --- /dev/null +++ b/dist/changes-5.14.2 @@ -0,0 +1,27 @@ +Qt 5.14.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.14.0 through 5.14.1. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.14 series is binary compatible with the 5.13.x series. +Applications compiled for 5.13 will continue to run with 5.14. + +If you are using Qt Remote Objects between processes or devices running +different versions Qt, the different versions of Qt must be running +compatible versions of QtRO's protocol. Changes to the Qt Remote Objects +protocol are documented online: + +https://doc.qt.io/qt-5/qtremoteobjects-compatibility.html + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + + - This release contains only minor code improvements. diff --git a/dist/changes-5.15.0 b/dist/changes-5.15.0 new file mode 100644 index 0000000..610d956 --- /dev/null +++ b/dist/changes-5.15.0 @@ -0,0 +1,22 @@ +Qt 5.15 introduces many new features and improvements as well as bugfixes +over the 5.14.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.15 series is binary compatible with the 5.14.x series. +Applications compiled for 5.14 will continue to run with 5.15. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* QML * +**************************************************************************** + + - Exposed Host to enable remoting of source objects from QML. diff --git a/dist/changes-5.15.1 b/dist/changes-5.15.1 new file mode 100644 index 0000000..332ee9d --- /dev/null +++ b/dist/changes-5.15.1 @@ -0,0 +1,20 @@ +Qt 5.15.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.15.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.15 series is binary compatible with the 5.14.x series. +Applications compiled for 5.14 will continue to run with 5.15. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + + - This release contains only minor code improvements. diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..364f333 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,5 @@ +qt_examples_build_begin(EXTERNAL_BUILD) + +add_subdirectory(remoteobjects) + +qt_examples_build_end() diff --git a/examples/examples.pro b/examples/examples.pro new file mode 100644 index 0000000..09f19f7 --- /dev/null +++ b/examples/examples.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS = \ + remoteobjects diff --git a/examples/remoteobjects/CMakeLists.txt b/examples/remoteobjects/CMakeLists.txt new file mode 100644 index 0000000..ecaabf5 --- /dev/null +++ b/examples/remoteobjects/CMakeLists.txt @@ -0,0 +1,18 @@ +qt_internal_add_example(remoteobjects_server) +qt_internal_add_example(cppclient) +add_subdirectory(simpleswitch) +add_subdirectory(websockets) +if(TARGET Qt::Widgets) + qt_internal_add_example(modelviewclient) + qt_internal_add_example(modelviewserver) +endif() +if(QT_FEATURE_ssl) + add_subdirectory(ssl) +endif() +if(TARGET Qt::Quick) + qt_internal_add_example(plugins) + qt_internal_add_example(clientapp) +endif() +if(TARGET Qt::Quick AND UNIX AND NOT ANDROID) + qt_internal_add_example(qmlmodelviewclient) +endif() diff --git a/examples/remoteobjects/clientapp/CMakeLists.txt b/examples/remoteobjects/clientapp/CMakeLists.txt new file mode 100644 index 0000000..4b92a5b --- /dev/null +++ b/examples/remoteobjects/clientapp/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.16) +project(clientapp LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/clientapp") + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Quick RemoteObjects) + +qt_add_executable(clientapp + main.cpp +) + +set_target_properties(clientapp PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) + +target_link_libraries(clientapp PUBLIC + Qt::Core + Qt::Gui + Qt::Quick + Qt::RemoteObjects +) + +# Resources: +set(clientapp_resource_files + "qml/plugins.qml" + "qml/plugins0.qml" + "qml/plugins1.qml" + "qml/plugins2.qml" +) + +qt6_add_resources(clientapp "clientapp" + PREFIX + "/qml" + FILES + ${clientapp_resource_files} +) + +install(TARGETS clientapp + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/remoteobjects/clientapp/clientapp.pro b/examples/remoteobjects/clientapp/clientapp.pro new file mode 100644 index 0000000..6d5a25d --- /dev/null +++ b/examples/remoteobjects/clientapp/clientapp.pro @@ -0,0 +1,11 @@ +SOURCES += main.cpp + +RESOURCES += \ + clientapp.qrc + +QT += remoteobjects quick + +contains(QT_CONFIG, c++11): CONFIG += c++11 + +target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/clientapp +INSTALLS += target diff --git a/examples/remoteobjects/clientapp/clientapp.qrc b/examples/remoteobjects/clientapp/clientapp.qrc new file mode 100644 index 0000000..23bdb39 --- /dev/null +++ b/examples/remoteobjects/clientapp/clientapp.qrc @@ -0,0 +1,8 @@ + + + qml/plugins0.qml + qml/plugins.qml + qml/plugins1.qml + qml/plugins2.qml + + diff --git a/examples/remoteobjects/clientapp/main.cpp b/examples/remoteobjects/clientapp/main.cpp new file mode 100644 index 0000000..8f0f5d2 --- /dev/null +++ b/examples/remoteobjects/clientapp/main.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + QQuickView viewer; + viewer.engine()->addImportPath(QStringLiteral("qrc:/qml")); + viewer.setSource(QUrl(QStringLiteral("qrc:/qml/qml/plugins.qml"))); + viewer.show(); + + return app.exec(); +} diff --git a/examples/remoteobjects/clientapp/qml/plugins.qml b/examples/remoteobjects/clientapp/qml/plugins.qml new file mode 100644 index 0000000..fe5a5a6 --- /dev/null +++ b/examples/remoteobjects/clientapp/qml/plugins.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + width: 200 + height: 400 + property int counter: 0; + MouseArea { + anchors.fill: parent + onClicked: + { + counter = (counter + 1) % 3; + console.log(counter); + pageLoader.source = "plugins"+counter+".qml" + } + } + Loader { + id: pageLoader + source: "plugins0.qml" + } +} +//![0] diff --git a/examples/remoteobjects/clientapp/qml/plugins0.qml b/examples/remoteobjects/clientapp/qml/plugins0.qml new file mode 100644 index 0000000..873225e --- /dev/null +++ b/examples/remoteobjects/clientapp/qml/plugins0.qml @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//![0] +import QtQuick 2.0 + +Rectangle { + width: 200 + height: 400 + color: "blue" +} +//![0] diff --git a/examples/remoteobjects/clientapp/qml/plugins1.qml b/examples/remoteobjects/clientapp/qml/plugins1.qml new file mode 100644 index 0000000..c1d15ab --- /dev/null +++ b/examples/remoteobjects/clientapp/qml/plugins1.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//![0] +import QtQuick 2.0 +import TimeExample 1.0 // import types from the plugin + +Rectangle { + width: 200 + height: 400 + color: "blue" + Clock { // this class is defined in QML (imports/TimeExample/Clock.qml) + id: clock1 + anchors.top: parent.top + Time { // this class is defined in C++ (plugin.cpp) + id: time + } + + hours: time.hour + minutes: time.minute + + } +} +//![0] diff --git a/examples/remoteobjects/clientapp/qml/plugins2.qml b/examples/remoteobjects/clientapp/qml/plugins2.qml new file mode 100644 index 0000000..f4eaf94 --- /dev/null +++ b/examples/remoteobjects/clientapp/qml/plugins2.qml @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//![0] +import QtQuick 2.0 +import TimeExample 1.0 // import types from the plugin + +Rectangle { + width: 200 + height: 400 + Clock { // this class is defined in QML (imports/TimeExample/Clock.qml) + id: clock1 + anchors.top: parent.top + Time { // this class is defined in C++ (plugin.cpp) + id: time + } + + hours: time.hour + minutes: time.minute + + } + Clock { // this class is defined in QML (imports/TimeExample/Clock.qml) + id: clock2 + anchors.top: clock1.bottom + Time { // this class is defined in C++ (plugin.cpp) + id: time2 + } + + hours: time2.hour + minutes: time2.minute + + } + +} +//![0] diff --git a/examples/remoteobjects/cppclient/CMakeLists.txt b/examples/remoteobjects/cppclient/CMakeLists.txt new file mode 100644 index 0000000..a30e7a1 --- /dev/null +++ b/examples/remoteobjects/cppclient/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 3.16) +project(CppClient LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/cppclient") + +find_package(Qt6 REQUIRED COMPONENTS Core RemoteObjects) + +qt_add_executable(CppClient + main.cpp +) + +set_target_properties(CppClient PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE FALSE +) + +target_link_libraries(CppClient PUBLIC + Qt::Core + Qt::RemoteObjects +) + +qt6_add_repc_replicas(CppClient + timemodel.rep +) + +install(TARGETS CppClient + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/remoteobjects/cppclient/cppclient.pro b/examples/remoteobjects/cppclient/cppclient.pro new file mode 100644 index 0000000..7b57442 --- /dev/null +++ b/examples/remoteobjects/cppclient/cppclient.pro @@ -0,0 +1,19 @@ +QT += core + +REPC_REPLICA += timemodel.rep +QT += remoteobjects + +QT -= gui + +TARGET = CppClient +CONFIG -= app_bundle + +TEMPLATE = app + +SOURCES += main.cpp + +OTHER_FILES += \ + timemodel.rep + +target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/cppclient +INSTALLS += target diff --git a/examples/remoteobjects/cppclient/main.cpp b/examples/remoteobjects/cppclient/main.cpp new file mode 100644 index 0000000..08e36b6 --- /dev/null +++ b/examples/remoteobjects/cppclient/main.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include "rep_timemodel_replica.h" + +class tester : public QObject +{ + Q_OBJECT +public: + tester() : QObject(nullptr) + { + QRemoteObjectNode m_client(QUrl(QStringLiteral("local:registry"))); + ptr1.reset(m_client.acquire< MinuteTimerReplica >()); + ptr2.reset(m_client.acquire< MinuteTimerReplica >()); + ptr3.reset(m_client.acquire< MinuteTimerReplica >()); + QTimer::singleShot(0, this, &tester::clear); + QTimer::singleShot(1, this, &tester::clear); + QTimer::singleShot(10000, this, &tester::clear); + QTimer::singleShot(11000, this, &tester::clear); + } +public slots: + void clear() + { + static int i = 0; + if (i == 0) { + i++; + ptr1.reset(); + } else if (i == 1) { + i++; + ptr2.reset(); + } else if (i == 2) { + i++; + ptr3.reset(); + } else { + qApp->quit(); + } + } + +private: + QScopedPointer ptr1, ptr2, ptr3; +}; + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + tester t; + return a.exec(); +} + +#include "main.moc" diff --git a/examples/remoteobjects/cppclient/timemodel.rep b/examples/remoteobjects/cppclient/timemodel.rep new file mode 100644 index 0000000..cbfaf24 --- /dev/null +++ b/examples/remoteobjects/cppclient/timemodel.rep @@ -0,0 +1,12 @@ +#include + +POD PresetInfo(int presetNumber, float frequency, QString stationName) +class MinuteTimer +{ + PROP(int hour=1); + PROP(int minute=51); + SIGNAL(timeChanged()); + SIGNAL(timeChanged2(QTime t)); + SIGNAL(sendCustom(PresetInfo info)); + SLOT(void SetTimeZone(int zn)); +}; diff --git a/examples/remoteobjects/modelviewclient/CMakeLists.txt b/examples/remoteobjects/modelviewclient/CMakeLists.txt new file mode 100644 index 0000000..03c5591 --- /dev/null +++ b/examples/remoteobjects/modelviewclient/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.16) +project(modelviewclient LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/modelviewclient") + +find_package(Qt6 REQUIRED COMPONENTS Core Gui RemoteObjects Widgets) + +qt_add_executable(modelviewclient + main.cpp +) + +set_target_properties(modelviewclient PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE FALSE +) + +target_link_libraries(modelviewclient PUBLIC + Qt::Core + Qt::Gui + Qt::RemoteObjects + Qt::Widgets +) + +install(TARGETS modelviewclient + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/remoteobjects/modelviewclient/doc/src/modelviewclient.qdoc b/examples/remoteobjects/modelviewclient/doc/src/modelviewclient.qdoc new file mode 100644 index 0000000..dc54e2f --- /dev/null +++ b/examples/remoteobjects/modelviewclient/doc/src/modelviewclient.qdoc @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example modelviewclient + \title Model-View Client + + This is the client-side application that accompanies the + \l {Model-View Server}. + + This example showcases how to make a very simple client program which + displays the content and changes made on a server. + + \snippet modelviewclient/main.cpp ObjectNode creation + + We start by creating a QRemoteObjectNode and connecting it to a registry + found on the local machine. We also set a + \l{QRemoteObjectNode::heartbeatInterval}{heartbeat interval}. + The heartbeat is useful to detect if the connection to the \l{Source} has + been disrupted. In this case, since all the traffic is local, it would + detect when the server has been closed. + + \snippet modelviewclient/main.cpp Model acquisition + + We then \l {QRemoteObjectNode::acquireModel}{acquire} the model which + contains all of our data. In this case, we're looking to acquire a model + named \c{RemoteModel} from the remote object network we are connected to. + + \snippet modelviewclient/main.cpp QTreeView-creation + + And finally, we display the model in a very basic application. +*/ diff --git a/examples/remoteobjects/modelviewclient/main.cpp b/examples/remoteobjects/modelviewclient/main.cpp new file mode 100644 index 0000000..a3361df --- /dev/null +++ b/examples/remoteobjects/modelviewclient/main.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + + QLoggingCategory::setFilterRules("qt.remoteobjects.debug=false\n" + "qt.remoteobjects.warning=false\n" + "qt.remoteobjects.models.debug=false\n" + "qt.remoteobjects.models.debug=false"); + + QApplication app(argc, argv); + +//! [ObjectNode creation] + QRemoteObjectNode node(QUrl(QStringLiteral("local:registry"))); + node.setHeartbeatInterval(1000); +//! [ObjectNode creation] +//! [Model acquisition] + QScopedPointer model(node.acquireModel(QStringLiteral("RemoteModel"))); +//! [Model acquisition] + +//! [QTreeView-creation] + QTreeView view; + view.setWindowTitle(QStringLiteral("RemoteView")); + view.resize(640,480); + view.setModel(model.data()); + view.show(); +//! [QTreeView-creation] + + return app.exec(); +} diff --git a/examples/remoteobjects/modelviewclient/modelviewclient.pro b/examples/remoteobjects/modelviewclient/modelviewclient.pro new file mode 100644 index 0000000..473f38f --- /dev/null +++ b/examples/remoteobjects/modelviewclient/modelviewclient.pro @@ -0,0 +1,10 @@ +SOURCES = main.cpp + +CONFIG -= app_bundle + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/modelviewclient +INSTALLS += target + +QT += widgets remoteobjects +requires(qtConfig(treeview)) diff --git a/examples/remoteobjects/modelviewserver/CMakeLists.txt b/examples/remoteobjects/modelviewserver/CMakeLists.txt new file mode 100644 index 0000000..c194743 --- /dev/null +++ b/examples/remoteobjects/modelviewserver/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.16) +project(modelviewserver LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/modelviewserver") + +find_package(Qt6 REQUIRED COMPONENTS Core Gui RemoteObjects Widgets) + +qt_add_executable(modelviewserver + main.cpp +) + +set_target_properties(modelviewserver PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) + +target_link_libraries(modelviewserver PUBLIC + Qt::Core + Qt::Gui + Qt::RemoteObjects + Qt::Widgets +) + +install(TARGETS modelviewserver + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/remoteobjects/modelviewserver/doc/src/modelviewserver.qdoc b/examples/remoteobjects/modelviewserver/doc/src/modelviewserver.qdoc new file mode 100644 index 0000000..789af82 --- /dev/null +++ b/examples/remoteobjects/modelviewserver/doc/src/modelviewserver.qdoc @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example modelviewserver + \title Model-View Server + + This is the server-side application that accompanies the + \l {Model-View Client}. + + This example showcases how to make a simple server program that displays + and makes changes to a QTreeView which is made available on a Remote + Objects network. + + \snippet modelviewserver/main.cpp RegistryHost setup + + We start by creating a QRemoteObjectRegistryHost with which other + Remote Objects will connect, be registered and then be advertised by. + The model we create can then be easily acquired from the client side by just + connecting to the registry. + + \snippet modelviewserver/main.cpp Model-creation and role-selection + + Now we have to create the model we need. The exact implementation is + available in the source code, to which you can navigate by pressing the + link further down on this page. We also define which \e roles we want to + expose to the \l{Replica} on the client side. + + \snippet modelviewserver/main.cpp Model-remoting + + Here, we create the QRemoteObjectHost that connects to, and shares all its + Remote Objects with, the Registry we created earlier. We then start remoting + the model we just created with the name \c{RemoteModel}. We also pass the + \e roles argument here. + + \snippet modelviewserver/main.cpp TreeView-creation + + We then display the model with a QTreeView widget. + + \snippet modelviewserver/main.cpp Automated actions + + For the sake of keeping the example light-weight it performs some + automated actions to affect the model shortly after the server application + launches. These changes can then be seen on both the server and client side. + You can also change the text in the fields on the server side and see it + update on the client side. +*/ diff --git a/examples/remoteobjects/modelviewserver/main.cpp b/examples/remoteobjects/modelviewserver/main.cpp new file mode 100644 index 0000000..d86c688 --- /dev/null +++ b/examples/remoteobjects/modelviewserver/main.cpp @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include + +struct TimerHandler : public QObject +{ + Q_OBJECT +public: + QStandardItemModel *model; +public Q_SLOTS: + void changeData() { + Q_ASSERT(model); + Q_ASSERT(model->rowCount() > 50); + Q_ASSERT(model->columnCount() > 1); + for (int i = 10; i < 50; ++i) + model->setData(model->index(i, 1), QColor(Qt::blue), Qt::BackgroundRole); + } + void insertData() { + Q_ASSERT(model); + Q_ASSERT(model->rowCount() > 50); + Q_ASSERT(model->columnCount() > 1); + model->insertRows(2, 9); + for (int i = 2; i < 11; ++i) { + model->setData(model->index(i, 1), QColor(Qt::green), Qt::BackgroundRole); + model->setData(model->index(i, 1), QLatin1String("InsertedRow"), Qt::DisplayRole); + } + } + void removeData() { + model->removeRows(2, 4); + } + + void changeFlags() { + QStandardItem *item = model->item(0, 0); + item->setEnabled(false); + item = item->child(0, 0); + item->setFlags(item->flags() & Qt::ItemIsSelectable); + } + + void moveData() { + model->moveRows(QModelIndex(), 2, 4, QModelIndex(), 10); + } +}; + +QList addChild(int numChildren, int nestingLevel) +{ + QList result; + if (nestingLevel == 0) + return result; + for (int i = 0; i < numChildren; ++i) { + QStandardItem *child = new QStandardItem(QStringLiteral("Child num %1, nesting Level %2").arg(i+1).arg(nestingLevel)); + if (i == 0) + child->appendRow(addChild(numChildren, nestingLevel -1)); + result.push_back(child); + } + return result; +} + +std::unique_ptr createModel() +{ + std::unique_ptr sourceModel = std::make_unique(); + const int modelSize = 100000; + QStringList list; + QStringList hHeaderList; + hHeaderList << QStringLiteral("First Column with spacing") << QStringLiteral("Second Column with spacing"); + sourceModel->setHorizontalHeaderLabels(hHeaderList); + list.reserve(modelSize); + for (int i = 0; i < modelSize; ++i) { + QStandardItem *firstItem = new QStandardItem(QStringLiteral("FancyTextNumber %1").arg(i)); + if (i == 0) + firstItem->appendRow(addChild(2, 2)); + QStandardItem *secondItem = new QStandardItem(QStringLiteral("FancyRow2TextNumber %1").arg(i)); + if (i % 2 == 0) + firstItem->setBackground(Qt::red); + QList row; + row << firstItem << secondItem; + sourceModel->invisibleRootItem()->appendRow(row); + list << QStringLiteral("FancyTextNumber %1").arg(i); + } + + // Needed by QMLModelViewClient + QHash roleNames = { + {Qt::DisplayRole, "_text"}, + {Qt::BackgroundRole, "_color"} + }; + sourceModel->setItemRoleNames(roleNames); + return sourceModel; +} + +int main(int argc, char *argv[]) +{ + QLoggingCategory::setFilterRules("qt.remoteobjects.debug=false\n" + "qt.remoteobjects.warning=false"); + QApplication app(argc, argv); + + qDebug() << "Creating registry host"; +//! [RegistryHost setup] + QRemoteObjectRegistryHost node(QUrl(QStringLiteral("local:registry"))); +//! [RegistryHost setup] + +//! [Model-creation and role-selection] + std::unique_ptr sourceModel = createModel(); + + QList roles; + roles << Qt::DisplayRole << Qt::BackgroundRole; +//! [Model-creation and role-selection] + +//! [Model-remoting] + QRemoteObjectHost node2(QUrl(QStringLiteral("local:replica")), QUrl(QStringLiteral("local:registry"))); + node2.enableRemoting(sourceModel.get(), QStringLiteral("RemoteModel"), roles); +//! [Model-remoting] + +//! [TreeView-creation] + QTreeView view; + view.setWindowTitle(QStringLiteral("SourceView")); + view.setModel(sourceModel.get()); + view.show(); +//! [TreeView-creation] + +//! [Automated actions] + TimerHandler handler; + handler.model = sourceModel.get(); + QTimer::singleShot(5000, &handler, &TimerHandler::changeData); + QTimer::singleShot(10000, &handler, &TimerHandler::insertData); + QTimer::singleShot(11000, &handler, &TimerHandler::changeFlags); + QTimer::singleShot(12000, &handler, &TimerHandler::removeData); + QTimer::singleShot(13000, &handler, &TimerHandler::moveData); +//! [Automated actions] + + + return app.exec(); +} + +#include "main.moc" diff --git a/examples/remoteobjects/modelviewserver/modelviewserver.pro b/examples/remoteobjects/modelviewserver/modelviewserver.pro new file mode 100644 index 0000000..d2fc6c4 --- /dev/null +++ b/examples/remoteobjects/modelviewserver/modelviewserver.pro @@ -0,0 +1,11 @@ +QT += widgets remoteobjects +requires(qtConfig(treeview)) + +TEMPLATE = app + +CONFIG += c++11 + +SOURCES += main.cpp + +target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/modelviewserver +INSTALLS += target diff --git a/examples/remoteobjects/plugins/CMakeLists.txt b/examples/remoteobjects/plugins/CMakeLists.txt new file mode 100644 index 0000000..848b93f --- /dev/null +++ b/examples/remoteobjects/plugins/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 3.16) +project(qmlqrotimeexampleplugin LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/plugins/imports/TimeExample") + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml RemoteObjects) + +qt6_add_qml_module(qmlqrotimeexampleplugin + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/imports/TimeExample" + VERSION 1.0 + URI "TimeExample" +) + +target_sources(qmlqrotimeexampleplugin PRIVATE + plugin.cpp +) + +set_target_properties(qmlqrotimeexampleplugin PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) + +target_link_libraries(qmlqrotimeexampleplugin PUBLIC + Qt::Core + Qt::Gui + Qt::Qml + Qt::RemoteObjects +) + +qt6_add_repc_replicas(qmlqrotimeexampleplugin + ../timemodel.rep +) + +install(TARGETS qmlqrotimeexampleplugin + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/remoteobjects/plugins/imports/TimeExample/Clock.qml b/examples/remoteobjects/plugins/imports/TimeExample/Clock.qml new file mode 100644 index 0000000..8c83e70 --- /dev/null +++ b/examples/remoteobjects/plugins/imports/TimeExample/Clock.qml @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + id: clock + width: 200; height: 200; color: "gray" + + property alias city: cityLabel.text + property variant hours + property variant minutes + property variant shift : 0 + + Image { id: background; source: "clock.png" } + + Image { + x: 92.5; y: 27 + source: "hour.png" + transform: Rotation { + id: hourRotation + origin.x: 7.5; origin.y: 73; + angle: (clock.hours * 30) + (clock.minutes * 0.5) + Behavior on angle { + SpringAnimation{ spring: 2; damping: 0.2; modulus: 360 } + } + } + } + + Image { + x: 93.5; y: 17 + source: "minute.png" + transform: Rotation { + id: minuteRotation + origin.x: 6.5; origin.y: 83; + angle: clock.minutes * 6 + Behavior on angle { + SpringAnimation{ spring: 2; damping: 0.2; modulus: 360 } + } + } + } + + Image { + anchors.centerIn: background; source: "center.png" + } + + Text { + id: cityLabel; font.bold: true; font.pixelSize: 14; y:200; color: "white" + anchors.horizontalCenter: parent.horizontalCenter + } +} diff --git a/examples/remoteobjects/plugins/imports/TimeExample/center.png b/examples/remoteobjects/plugins/imports/TimeExample/center.png new file mode 100644 index 0000000000000000000000000000000000000000..7fbd802a44e4242cb2ce11fd78efa0e2e9123591 GIT binary patch literal 765 zcmVwm?cmZyN`*KT0&&bzT5WB7@L(auxOrlE<9L|IL z&i8)L&uf>4S*T)OE8F->35(24d5sX5GeKScQ1}Zk0{U)AOeg56F@@r z9&i_k$@vIi#IHYN1sVpTz-?fBeSQ6DCX;#L`@V5q_xHlW!biXb&PAI*M>7u%0F42O z&CSilY&QEQkw`q(Y+9|>+rz`dd@7ZCCyf6B4GRvyQa(U#F>=uz;8CGacvY|0gJD{& zR*!%=;GskpvRQC?*oNeXsg;$Lg75nb(|9~ScW`jV&hDzY)D;F81#ZpE%q)7I$4wLnZ)|KVO0gq?V>GZMsffhm@h95(I@ZZ# z@|p5Cm%2j9NTbnchQr~}K4*QUR;xAXnTaa{0<=q|(&w9`!7|R}a-RSX+iE?)KF|i5 zdwY9dZUWrtbf{D+rE0Z$O1Fn?9|syZpgTcsu~% z2a54IaFR}^*UIJc*Fkx8UH5EjYin(1XXi+K>f-M$<%5e|vAb&Q;)&8-GE=~VTrQWI zpPx@oPftIdoSeL0E|vh*lr=Z!!jm-Q2}+N`W?w>U9_n|b&dh-G77}8A*@a$++Si(L{Cv$O@m%xtVMFJ vUl6^??F-^D;CUJdtS*47?_QuH>?{8O-DBHcK9x2C00000NkvXXu0mjfY~)gG literal 0 HcmV?d00001 diff --git a/examples/remoteobjects/plugins/imports/TimeExample/clock.png b/examples/remoteobjects/plugins/imports/TimeExample/clock.png new file mode 100644 index 0000000000000000000000000000000000000000..462edacc0eaae9f2789ba6ae2c92ed533bba7207 GIT binary patch literal 20653 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�$@7S8U3ymd7s7tyOHWAvUm z!t8j;y?C2<2}e`&NBs zk|RSR9_R4Kg=Z_uc_R(0ACjxF<KbE$Lo&3+4H z^-oQ4`H5?8exV)c>u1Dr0kTvFTg+)a8?8bsZwpqqX4r2oz8QT40DQmj`P6*QrBm>V7YV%01x_JADEx%^ zYr);e3s%p$=CZLzuClr$rRa0A`ju}-P<7iI{`Q`4)24ZEZqVnxG9SyXV&z_!Wd`%z zcVvG&ybwli^(yJ@>A{_Ob>)%J!=DGKNXOy1Jtb*^m!xa}Mzho4i2eXqq#bjk9FMd^ z8V^ntW~3cz#40NrK_b|AKh5Pl@X5^Qj`XWG zg1NcPnfY(~#SJg#&X_g6_1DAEkoGm=6g)pmB&Gv`&Ugwe?Xb-v3K2s;3O&vdUn>)6 zNbhzTNrphVr~;_n>$V{lZjvIRlU&TIiaBFql|r3%7EpzD`Zl=;nN&^^4*{)Byzpbgy7Ztu1Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXc9 z05S=eKQo^I00HqyL_t(o!|j;6j?+LChQH(WKrRH9n~*5B+Xf+}qoCp?QbhDr+aW4C zdL)WeG|*73Qt}2#5GYa#8lHeyT5%Jx6^|Vs3TCpi3#*N^(5!rAP(?i zpbcDdi`#BafhF)0_yH_{<^G;j-Z65HSAi?QwQje2qu=lE8e?QQ9DbTiCZB$!PRzWG#b6g^IYfixlNKp zlO)mkd~WkR*XeZn9N2LsMIPI@O}e#MEZ(MRdQ(+f!4V-MX{XaUXti1ofGWn%B2ph!ja_4( zllQqksv7%D*vIGV-L8MJ_1E)%V^D@!@0!USLDI&%-Tf!(+)zhuk*v@?gELHWx3HVl3-#ZiS4OG{=?eVR(k3}SQ z4HfIgcM*xLwNJwSkc5pTA8#HNca1U6fcp;rT~QQIAHFmn!*#y^s*t+D3$g`_00000 LNkvXXu0mjfjzPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXc9 z05TtA>xRw%00HqyL_t(o!{wO0j?+L8fWO%|770J$s8EVS0#RN|$77_WqdO@D#YwzF zQsph6q@&?ABGEeN5LNhz?tJXf%o=NP@WtU|M~t+J=8lH8w8rzgYVaAXtQF)NbbYoOc(p3G*mm#fw4({j1|oMqYhd_F$|o&k?c z$4P0>0C<>X+1vGceG&pR8jU`V$Kw~kIq(Jeo)AfzrjMnt82bJGIM#9eDMGar2~Dbc z%cPR{zmaMssiJHlu@`A?^Q0;eRi?UYgu2B*)FwBg`kN!&oKJD|>hjcx)N9wLMxs9`<{e7>)D_3?Qbu$pY$hFJ3sqOT zr3pU0HwA!=s=hNTe7MaiqGvBO&o5r3X?iIl&sFt9p69OvA?W@B51fzRJAdej00000 LNkvXXu0mjfJuMrm literal 0 HcmV?d00001 diff --git a/examples/remoteobjects/plugins/imports/TimeExample/qmldir b/examples/remoteobjects/plugins/imports/TimeExample/qmldir new file mode 100644 index 0000000..be259d4 --- /dev/null +++ b/examples/remoteobjects/plugins/imports/TimeExample/qmldir @@ -0,0 +1,3 @@ +module TimeExample +Clock 1.0 Clock.qml +plugin qmlqrotimeexampleplugin diff --git a/examples/remoteobjects/plugins/plugin.cpp b/examples/remoteobjects/plugins/plugin.cpp new file mode 100644 index 0000000..eac6313 --- /dev/null +++ b/examples/remoteobjects/plugins/plugin.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rep_timemodel_replica.h" + +// Implements a "TimeModel" class with hour and minute properties +// that change on-the-minute yet efficiently sleep the rest +// of the time. + +static QRemoteObjectNode m_client; + +class TimeModel : public QObject +{ + Q_OBJECT + Q_PROPERTY(int hour READ hour NOTIFY timeChanged) + Q_PROPERTY(int minute READ minute NOTIFY timeChanged) + Q_PROPERTY(bool isValid READ isValid NOTIFY isValidChanged) + +public: + TimeModel(QObject *parent = nullptr) : QObject(parent), d_ptr(nullptr) + { + d_ptr.reset(m_client.acquire< MinuteTimerReplica >()); + connect(d_ptr.data(), &MinuteTimerReplica::hourChanged, this, &TimeModel::timeChanged); + connect(d_ptr.data(), &MinuteTimerReplica::minuteChanged, this, &TimeModel::timeChanged); + connect(d_ptr.data(), &MinuteTimerReplica::timeChanged, this, &TimeModel::timeChanged); + connect(d_ptr.data(), &MinuteTimerReplica::timeChanged2, this, &TimeModel::test); + connect(d_ptr.data(), &MinuteTimerReplica::sendCustom, this, &TimeModel::testCustom); + } + + ~TimeModel() override + { + } + + int minute() const { return d_ptr->minute(); } + int hour() const { return d_ptr->hour(); } + bool isValid() const { return d_ptr->state() == QRemoteObjectReplica::Valid; } + +public slots: + //Test a signal with parameters + void test(QTime t) + { + qDebug()<<"Test"<SetTimeZone(t.minute()); + } + //Test a signal with a custom type + void testCustom(PresetInfo info) + { + qDebug()<<"testCustom"< d_ptr; +}; + +class QExampleQmlPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + +public: + void initializeEngine(QQmlEngine *engine, const char *uri) override + { + Q_UNUSED(engine) + Q_UNUSED(uri) + Q_ASSERT(uri == QLatin1String("TimeExample")); + engine->addImportPath(QStringLiteral("qrc:/qml")); + m_client.setRegistryUrl(QUrl(QStringLiteral("local:registry"))); + } + void registerTypes(const char *uri) override + { + Q_ASSERT(uri == QLatin1String("TimeExample")); + qmlRegisterType(uri, 1, 0, "Time"); + } + +}; + +#include "plugin.moc" diff --git a/examples/remoteobjects/plugins/plugins.pro b/examples/remoteobjects/plugins/plugins.pro new file mode 100644 index 0000000..9d3f3d1 --- /dev/null +++ b/examples/remoteobjects/plugins/plugins.pro @@ -0,0 +1,30 @@ +QT += qml remoteobjects + +TEMPLATE = lib +CONFIG += plugin + +REPC_REPLICA += $$PWD/../timemodel.rep + +DESTDIR = imports/TimeExample +TARGET = qmlqrotimeexampleplugin + +SOURCES += plugin.cpp + +pluginfiles.files += \ + imports/TimeExample/qmldir \ + imports/TimeExample/center.png \ + imports/TimeExample/clock.png \ + imports/TimeExample/Clock.qml \ + imports/TimeExample/hour.png \ + imports/TimeExample/minute.png + +qml.files = plugins.qml +qml.path += $$[QT_INSTALL_EXAMPLES]/remoteobjects/plugins +target.path += $$[QT_INSTALL_EXAMPLES]/remoteobjects/plugins/imports/TimeExample +pluginfiles.path += $$[QT_INSTALL_EXAMPLES]/remoteobjects/plugins/imports/TimeExample + +INSTALLS += target qml pluginfiles + +CONFIG += install_ok # Do not cargo-cult this! + +contains(QT_CONFIG, c++11): CONFIG += c++11 diff --git a/examples/remoteobjects/plugins/plugins.qml b/examples/remoteobjects/plugins/plugins.qml new file mode 100644 index 0000000..0f3f9d3 --- /dev/null +++ b/examples/remoteobjects/plugins/plugins.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + width: 200 + height: 400 + property int counter: 0; + MouseArea { + anchors.fill: parent + onClicked: + { + counter = (counter + 1) % 3; + console.log(counter); + pageLoader.source = "plugins"+counter+".qml" + } + } + Loader { + id: pageLoader + source: "plugins0.qml" + } +} +//![0] diff --git a/examples/remoteobjects/plugins/plugins0.qml b/examples/remoteobjects/plugins/plugins0.qml new file mode 100644 index 0000000..873225e --- /dev/null +++ b/examples/remoteobjects/plugins/plugins0.qml @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//![0] +import QtQuick 2.0 + +Rectangle { + width: 200 + height: 400 + color: "blue" +} +//![0] diff --git a/examples/remoteobjects/plugins/plugins1.qml b/examples/remoteobjects/plugins/plugins1.qml new file mode 100644 index 0000000..c1d15ab --- /dev/null +++ b/examples/remoteobjects/plugins/plugins1.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//![0] +import QtQuick 2.0 +import TimeExample 1.0 // import types from the plugin + +Rectangle { + width: 200 + height: 400 + color: "blue" + Clock { // this class is defined in QML (imports/TimeExample/Clock.qml) + id: clock1 + anchors.top: parent.top + Time { // this class is defined in C++ (plugin.cpp) + id: time + } + + hours: time.hour + minutes: time.minute + + } +} +//![0] diff --git a/examples/remoteobjects/plugins/plugins2.qml b/examples/remoteobjects/plugins/plugins2.qml new file mode 100644 index 0000000..f4eaf94 --- /dev/null +++ b/examples/remoteobjects/plugins/plugins2.qml @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//![0] +import QtQuick 2.0 +import TimeExample 1.0 // import types from the plugin + +Rectangle { + width: 200 + height: 400 + Clock { // this class is defined in QML (imports/TimeExample/Clock.qml) + id: clock1 + anchors.top: parent.top + Time { // this class is defined in C++ (plugin.cpp) + id: time + } + + hours: time.hour + minutes: time.minute + + } + Clock { // this class is defined in QML (imports/TimeExample/Clock.qml) + id: clock2 + anchors.top: clock1.bottom + Time { // this class is defined in C++ (plugin.cpp) + id: time2 + } + + hours: time2.hour + minutes: time2.minute + + } + +} +//![0] diff --git a/examples/remoteobjects/qmlmodelviewclient/CMakeLists.txt b/examples/remoteobjects/qmlmodelviewclient/CMakeLists.txt new file mode 100644 index 0000000..6d3aafe --- /dev/null +++ b/examples/remoteobjects/qmlmodelviewclient/CMakeLists.txt @@ -0,0 +1,47 @@ +cmake_minimum_required(VERSION 3.16) +project(qmlmodelviewclient LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/qmlmodelviewclient") + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick RemoteObjects) + +qt_add_executable(qmlmodelviewclient + main.cpp +) + +set_target_properties(qmlmodelviewclient PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) + +target_link_libraries(qmlmodelviewclient PUBLIC + Qt::Core + Qt::Gui + Qt::Qml + Qt::Quick + Qt::RemoteObjects +) + +# Resources: +set(qml_resource_files + "main.qml" +) + +qt6_add_resources(qmlmodelviewclient "qml" + PREFIX + "/" + FILES + ${qml_resource_files} +) + +install(TARGETS qmlmodelviewclient + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/remoteobjects/qmlmodelviewclient/doc/src/qmlmodelviewclient.qdoc b/examples/remoteobjects/qmlmodelviewclient/doc/src/qmlmodelviewclient.qdoc new file mode 100644 index 0000000..00c1874 --- /dev/null +++ b/examples/remoteobjects/qmlmodelviewclient/doc/src/qmlmodelviewclient.qdoc @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example qmlmodelviewclient + \title QML Model-View Client + + This is an alternate client application you can use along with the + \l {Model-View Server}. + + This short example showcases how to quickly make a QAbstractItemModelReplica + available to and use from QML. See the \l {Model-View Client} example for a + more detailed explanation on how the model is acquired and used. +*/ diff --git a/examples/remoteobjects/qmlmodelviewclient/main.cpp b/examples/remoteobjects/qmlmodelviewclient/main.cpp new file mode 100644 index 0000000..a0186f1 --- /dev/null +++ b/examples/remoteobjects/qmlmodelviewclient/main.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + QLoggingCategory::setFilterRules("qt.remoteobjects.debug=false\n" + "qt.remoteobjects.warning=false\n" + "qt.remoteobjects.models.debug=false\n" + "qt.remoteobjects.models.debug=false"); + + QGuiApplication app(argc, argv); + + QRemoteObjectNode node(QUrl(QStringLiteral("local:registry"))); + QQmlApplicationEngine engine; + QScopedPointer model(node.acquireModel(QStringLiteral("RemoteModel"))); + engine.rootContext()->setContextProperty("remoteModel", model.data()); + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + + return app.exec(); +} diff --git a/examples/remoteobjects/qmlmodelviewclient/main.qml b/examples/remoteobjects/qmlmodelviewclient/main.qml new file mode 100644 index 0000000..f1926df --- /dev/null +++ b/examples/remoteobjects/qmlmodelviewclient/main.qml @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.5 +import QtQuick.Window 2.2 + +Window { + visible: true + width: 800 + height: 600 + Text { + id: dummy + } + + ListView { + id: view + anchors.fill: parent + focus: true + + currentIndex: 10 + + model: remoteModel + + snapMode: ListView.SnapToItem + highlightFollowsCurrentItem: true + highlightMoveDuration: 0 + + delegate: Rectangle { + width: view.width + height: dummy.font.pixelSize * 2 + color: _color + Text { + anchors.centerIn: parent + text: _text + } + } + Keys.onPressed: { + switch (event.key) { + case Qt.Key_Home: + view.currentIndex = 0; + break; + case Qt.Key_PageUp: + currentIndex -= Math.random() * 300; + if (currentIndex < 0) + currentIndex = 0; + break; + case Qt.Key_PageDown: + currentIndex += Math.random() * 300; + if (currentIndex >= count) + currentIndex = count - 1; + break; + case Qt.Key_End: + currentIndex = count - 1; + break; + } + } + } +} diff --git a/examples/remoteobjects/qmlmodelviewclient/qml.qrc b/examples/remoteobjects/qmlmodelviewclient/qml.qrc new file mode 100644 index 0000000..5f6483a --- /dev/null +++ b/examples/remoteobjects/qmlmodelviewclient/qml.qrc @@ -0,0 +1,5 @@ + + + main.qml + + diff --git a/examples/remoteobjects/qmlmodelviewclient/qmlmodelviewclient.pro b/examples/remoteobjects/qmlmodelviewclient/qmlmodelviewclient.pro new file mode 100644 index 0000000..4e9c12d --- /dev/null +++ b/examples/remoteobjects/qmlmodelviewclient/qmlmodelviewclient.pro @@ -0,0 +1,11 @@ +TEMPLATE = app + +QT += qml quick remoteobjects +CONFIG += c++11 + +SOURCES += main.cpp + +RESOURCES += qml.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/qmlmodelviewclient +INSTALLS += target diff --git a/examples/remoteobjects/remoteobjects.pro b/examples/remoteobjects/remoteobjects.pro new file mode 100644 index 0000000..096d88b --- /dev/null +++ b/examples/remoteobjects/remoteobjects.pro @@ -0,0 +1,23 @@ +TEMPLATE = subdirs +CONFIG += debug_and_release ordered +SUBDIRS = \ + remoteobjects_server \ + cppclient \ + simpleswitch \ + websockets + +qtHaveModule(widgets) { + SUBDIRS += \ + modelviewclient \ + modelviewserver +} + +contains(QT_CONFIG, ssl): SUBDIRS += ssl + +qtHaveModule(quick) { + SUBDIRS += \ + plugins \ + clientapp + + unix:!android: SUBDIRS += qmlmodelviewclient +} diff --git a/examples/remoteobjects/remoteobjects_server/CMakeLists.txt b/examples/remoteobjects/remoteobjects_server/CMakeLists.txt new file mode 100644 index 0000000..21ce955 --- /dev/null +++ b/examples/remoteobjects/remoteobjects_server/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.16) +project(remoteobjects_server LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/remoteobjects_server") + +find_package(Qt6 REQUIRED COMPONENTS Core RemoteObjects) + +qt_add_executable(remoteobjects_server + main.cpp + timemodel.cpp timemodel.h +) + +set_target_properties(remoteobjects_server PROPERTIES + WIN32_EXECUTABLE FALSE + MACOSX_BUNDLE TRUE +) + +target_link_libraries(remoteobjects_server PUBLIC + Qt::Core + Qt::RemoteObjects +) + +qt6_add_repc_sources(remoteobjects_server + ../timemodel.rep +) + +install(TARGETS remoteobjects_server + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/remoteobjects/remoteobjects_server/main.cpp b/examples/remoteobjects/remoteobjects_server/main.cpp new file mode 100644 index 0000000..7eaab06 --- /dev/null +++ b/examples/remoteobjects/remoteobjects_server/main.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "timemodel.h" + +#include +/* +* http://stackoverflow.com/questions/7404163/windows-handling-ctrlc-in-different-thread +*/ + +void SigIntHandler() +{ + qDebug()<<"Ctrl-C received. Quitting."; + qApp->quit(); +} + +#if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) + #include + + void unix_handler(int s) + { + if (s==SIGINT) + SigIntHandler(); + } + +#elif defined(Q_OS_WIN32) + #include + + BOOL WINAPI WinHandler(DWORD CEvent) + { + switch (CEvent) + { + case CTRL_C_EVENT: + SigIntHandler(); + break; + } + return TRUE; + } +#endif + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + #if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) + signal(SIGINT, &unix_handler); + #elif defined(Q_OS_WIN32) + SetConsoleCtrlHandler((PHANDLER_ROUTINE)WinHandler, TRUE); + #endif + QRemoteObjectHost node(QUrl(QStringLiteral("local:replica")),QUrl(QStringLiteral("local:registry"))); + QRemoteObjectRegistryHost node2(QUrl(QStringLiteral("local:registry"))); + MinuteTimer timer; + node2.enableRemoting(&timer); + + Q_UNUSED(timer) + return app.exec(); +} diff --git a/examples/remoteobjects/remoteobjects_server/remoteobjects_server.pro b/examples/remoteobjects/remoteobjects_server/remoteobjects_server.pro new file mode 100644 index 0000000..1c1441d --- /dev/null +++ b/examples/remoteobjects/remoteobjects_server/remoteobjects_server.pro @@ -0,0 +1,13 @@ +CONFIG += console + + +REPC_SOURCE += ../timemodel.rep +QT = remoteobjects core + +SOURCES += timemodel.cpp main.cpp +HEADERS += timemodel.h + +contains(QT_CONFIG, c++11): CONFIG += c++11 + +target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/remoteobjects_server +INSTALLS += target diff --git a/examples/remoteobjects/remoteobjects_server/timemodel.cpp b/examples/remoteobjects/remoteobjects_server/timemodel.cpp new file mode 100644 index 0000000..a444f6e --- /dev/null +++ b/examples/remoteobjects/remoteobjects_server/timemodel.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "timemodel.h" + +MinuteTimer::MinuteTimer(QObject *parent) : MinuteTimerSimpleSource(parent), zone(0) +{ + time = QTime::currentTime(); + setHour(time.hour()); + setMinute(time.minute()); + timer.start(60000-time.second()*1000, this); +} +MinuteTimer::~MinuteTimer() +{ + timer.stop(); +} +void MinuteTimer::timerEvent(QTimerEvent *) +{ + QTime now = QTime::currentTime(); + if (now.second() == 59 && now.minute() == time.minute() && now.hour() == time.hour()) { + // just missed time tick over, force it, wait extra 0.5 seconds + time = time.addSecs(60); + timer.start(60500, this); + } else { + time = now; + timer.start(60000-time.second()*1000, this); + } + qDebug()<<"Time"< +#include "rep_timemodel_source.h" + +class MinuteTimer : public MinuteTimerSimpleSource +{ + Q_OBJECT +public: + MinuteTimer(QObject *parent = nullptr); + ~MinuteTimer() override; + +public slots: + void SetTimeZone(const int &zn) override; + +protected: + void timerEvent(QTimerEvent *) override; + +private: + QTime time; + QBasicTimer timer; + int zone; +}; diff --git a/examples/remoteobjects/simpleswitch/CMakeLists.txt b/examples/remoteobjects/simpleswitch/CMakeLists.txt new file mode 100644 index 0000000..d827823 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/CMakeLists.txt @@ -0,0 +1,5 @@ +qt_internal_add_example(directconnectclient) +qt_internal_add_example(directconnectdynamicclient) +qt_internal_add_example(directconnectserver) +qt_internal_add_example(registryconnectedclient) +qt_internal_add_example(registryconnectedserver) diff --git a/examples/remoteobjects/simpleswitch/directconnectclient/CMakeLists.txt b/examples/remoteobjects/simpleswitch/directconnectclient/CMakeLists.txt new file mode 100644 index 0000000..8159efb --- /dev/null +++ b/examples/remoteobjects/simpleswitch/directconnectclient/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.16) +project(directconnectclient LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/simpleswitch/directconnectclient") + +find_package(Qt6 REQUIRED COMPONENTS Core RemoteObjects) + +qt_add_executable(directconnectclient + client.cpp client.h + main.cpp +) + +set_target_properties(directconnectclient PROPERTIES + WIN32_EXECUTABLE FALSE + MACOSX_BUNDLE FALSE +) + +target_link_libraries(directconnectclient PUBLIC + Qt::Core + Qt::RemoteObjects +) + +qt6_add_repc_replicas(directconnectclient + simpleswitch.rep +) + +install(TARGETS directconnectclient + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/remoteobjects/simpleswitch/directconnectclient/client.cpp b/examples/remoteobjects/simpleswitch/directconnectclient/client.cpp new file mode 100644 index 0000000..a8e3133 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/directconnectclient/client.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "client.h" + +// constructor +Client::Client(QSharedPointer ptr) : + QObject(nullptr), clientSwitchState(false), reptr(ptr) +{ + //connect signal for replica initialized with initialization slot + initConnections(); + // We can connect to SimpleSwitchReplica signals/slots + //directly because our Replica was generated by repc +} + +//destructor +Client::~Client() +{ + +} + + +void Client::initConnections(void) +{ + // initialize connections between signals and slots + + // connect source replica signal currStateChanged() with client's recSwitchState() slot to receive source's current state + QObject::connect(reptr.data(), &SimpleSwitchReplica::currStateChanged, this, &Client::recSwitchState_slot); + // connect client's echoSwitchState(..) signal with replica's server_slot(..) to echo back received state + QObject::connect(this, &Client::echoSwitchState, reptr.data(), &SimpleSwitchReplica::server_slot); +} + +void Client::recSwitchState_slot(bool value) +{ + qDebug() << "Received source state "<< value << reptr.data()->currState(); + clientSwitchState = reptr.data()->currState(); + Q_EMIT echoSwitchState(clientSwitchState); // Emit signal to echo received state back to server +} diff --git a/examples/remoteobjects/simpleswitch/directconnectclient/client.h b/examples/remoteobjects/simpleswitch/directconnectclient/client.h new file mode 100644 index 0000000..9d86b74 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/directconnectclient/client.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef _CLIENT_H +#define _CLIENT_H + +#include +#include + +#include "rep_simpleswitch_replica.h" + +class Client : public QObject +{ + Q_OBJECT +public: + Client(QSharedPointer ptr); + ~Client() override; + void initConnections();// function connect signals and slots of source and client + +Q_SIGNALS: + void echoSwitchState(bool switchState);// this signal is connected with server_slot(..) on the source object and echoes back switch state received from source + +public Q_SLOTS: + void recSwitchState_slot(bool); // slot to receive source state +private: + bool clientSwitchState; // holds received server switch state + QSharedPointer reptr;// holds reference to replica + + }; + +#endif diff --git a/examples/remoteobjects/simpleswitch/directconnectclient/directconnectclient.pro b/examples/remoteobjects/simpleswitch/directconnectclient/directconnectclient.pro new file mode 100644 index 0000000..3624821 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/directconnectclient/directconnectclient.pro @@ -0,0 +1,23 @@ +QT += remoteobjects core + +QT -= gui + +TARGET = directconnectclient +CONFIG += console +CONFIG -= app_bundle + +REPC_REPLICA = simpleswitch.rep + +TEMPLATE = app + +target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/simpleswitch/directconnectclient +INSTALLS += target + +SOURCES += main.cpp \ + client.cpp + +HEADERS += \ + client.h + +DISTFILES += \ + simpleswitch.rep diff --git a/examples/remoteobjects/simpleswitch/directconnectclient/main.cpp b/examples/remoteobjects/simpleswitch/directconnectclient/main.cpp new file mode 100644 index 0000000..1854dd3 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/directconnectclient/main.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "client.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + + QSharedPointer ptr; + + QRemoteObjectNode repNode; // create remote object node + repNode.connectToNode(QUrl(QStringLiteral("local:replica"))); // connect with remote host node + + ptr.reset(repNode.acquire()); // acquire replica of source from host node + + Client rswitch(ptr); // create client switch object and pass reference of replica to it + + return a.exec(); +} diff --git a/examples/remoteobjects/simpleswitch/directconnectclient/simpleswitch.rep b/examples/remoteobjects/simpleswitch/directconnectclient/simpleswitch.rep new file mode 100644 index 0000000..b2d7cd2 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/directconnectclient/simpleswitch.rep @@ -0,0 +1,7 @@ +#include + +class SimpleSwitch +{ + PROP(bool currState=false); + SLOT(void server_slot(bool clientState)); +}; diff --git a/examples/remoteobjects/simpleswitch/directconnectdynamicclient/CMakeLists.txt b/examples/remoteobjects/simpleswitch/directconnectdynamicclient/CMakeLists.txt new file mode 100644 index 0000000..3941f8d --- /dev/null +++ b/examples/remoteobjects/simpleswitch/directconnectdynamicclient/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.16) +project(directconnectdynamicclient LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/simpleswitch/directconnectdynamicclient") + +find_package(Qt6 REQUIRED COMPONENTS Core RemoteObjects) + +qt_add_executable(directconnectdynamicclient + dynamicclient.cpp dynamicclient.h + main.cpp +) + +set_target_properties(directconnectdynamicclient PROPERTIES + WIN32_EXECUTABLE FALSE + MACOSX_BUNDLE FALSE +) + +target_link_libraries(directconnectdynamicclient PUBLIC + Qt::Core + Qt::RemoteObjects +) + +install(TARGETS directconnectdynamicclient + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/remoteobjects/simpleswitch/directconnectdynamicclient/directconnectdynamicclient.pro b/examples/remoteobjects/simpleswitch/directconnectdynamicclient/directconnectdynamicclient.pro new file mode 100644 index 0000000..8b907de --- /dev/null +++ b/examples/remoteobjects/simpleswitch/directconnectdynamicclient/directconnectdynamicclient.pro @@ -0,0 +1,18 @@ +QT += remoteobjects core + +QT -= gui + +TARGET = directconnectdynamicclient +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/simpleswitch/directconnectdynamicclient +INSTALLS += target + +SOURCES += main.cpp \ + dynamicclient.cpp + +HEADERS += \ + dynamicclient.h diff --git a/examples/remoteobjects/simpleswitch/directconnectdynamicclient/dynamicclient.cpp b/examples/remoteobjects/simpleswitch/directconnectdynamicclient/dynamicclient.cpp new file mode 100644 index 0000000..88a3fd8 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/directconnectdynamicclient/dynamicclient.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "dynamicclient.h" + #include + +// constructor +DynamicClient::DynamicClient(QSharedPointer ptr) : + QObject(nullptr), clientSwitchState(false), reptr(ptr) +{ + //connect signal for replica valid changed with signal slot initialization + QObject::connect(reptr.data(), &QRemoteObjectDynamicReplica::initialized, this, + &DynamicClient::initConnection_slot); +} + +//destructor +DynamicClient::~DynamicClient() +{ + +} + +// Function to initialize connections between slots and signals +void DynamicClient::initConnection_slot() +{ + + // connect source replica signal currStateChanged() with client's recSwitchState() slot to receive source's current state + QObject::connect(reptr.data(), SIGNAL(currStateChanged(bool)), this, SLOT(recSwitchState_slot(bool))); + // connect client's echoSwitchState(..) signal with replica's server_slot(..) to echo back received state + QObject::connect(this, SIGNAL(echoSwitchState(bool)),reptr.data(), SLOT(server_slot(bool))); +} + + +void DynamicClient::recSwitchState_slot(bool value) +{ + clientSwitchState = reptr->property("currState").toBool(); // use replica property to get "currState" from source + qDebug() << "Received source state " << value << clientSwitchState; + Q_EMIT echoSwitchState(clientSwitchState); // Emit signal to echo received state back to server +} + diff --git a/examples/remoteobjects/simpleswitch/directconnectdynamicclient/dynamicclient.h b/examples/remoteobjects/simpleswitch/directconnectdynamicclient/dynamicclient.h new file mode 100644 index 0000000..ad948a9 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/directconnectdynamicclient/dynamicclient.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef _DYNAMICCLIENT_H +#define _DYNAMICCLIENT_H + +#include +#include + +#include +#include + +class DynamicClient : public QObject +{ + Q_OBJECT +public: + DynamicClient(QSharedPointer ptr); + ~DynamicClient() override; + +Q_SIGNALS: + void echoSwitchState(bool switchState);// this signal is connected with server_slot(..) slot of source object and echoes back switch state received from source + +public Q_SLOTS: + void recSwitchState_slot(bool); // slot to receive source state + void initConnection_slot(); + +private: + bool clientSwitchState; // holds received server switch state + QSharedPointer reptr;// holds reference to replica + }; + +#endif + diff --git a/examples/remoteobjects/simpleswitch/directconnectdynamicclient/main.cpp b/examples/remoteobjects/simpleswitch/directconnectdynamicclient/main.cpp new file mode 100644 index 0000000..17008ae --- /dev/null +++ b/examples/remoteobjects/simpleswitch/directconnectdynamicclient/main.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "dynamicclient.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + QSharedPointer ptr; // shared pointer to hold replica + + QRemoteObjectNode repNode; // create remote object node + repNode.connectToNode(QUrl(QStringLiteral("local:replica"))); // connect with remote host node + + ptr.reset(repNode.acquireDynamic("SimpleSwitch")); // acquire replica of source from host node + + DynamicClient rswitch(ptr); // create client switch object and pass replica reference to it + + return a.exec(); +} diff --git a/examples/remoteobjects/simpleswitch/directconnectserver/CMakeLists.txt b/examples/remoteobjects/simpleswitch/directconnectserver/CMakeLists.txt new file mode 100644 index 0000000..8405d75 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/directconnectserver/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.16) +project(directconnectserver LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/simpleswitch/directconnectserver") + +find_package(Qt6 REQUIRED COMPONENTS Core RemoteObjects) + +qt_add_executable(directconnectserver + main.cpp + simpleswitch.cpp simpleswitch.h +) + +set_target_properties(directconnectserver PROPERTIES + WIN32_EXECUTABLE FALSE + MACOSX_BUNDLE FALSE +) + +target_link_libraries(directconnectserver PUBLIC + Qt::Core + Qt::RemoteObjects +) + +qt6_add_repc_sources(directconnectserver + simpleswitch.rep +) + +install(TARGETS directconnectserver + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/remoteobjects/simpleswitch/directconnectserver/directconnectserver.pro b/examples/remoteobjects/simpleswitch/directconnectserver/directconnectserver.pro new file mode 100644 index 0000000..bbc3d7e --- /dev/null +++ b/examples/remoteobjects/simpleswitch/directconnectserver/directconnectserver.pro @@ -0,0 +1,21 @@ +QT += remoteobjects core + +QT -= gui + +TARGET = directconnectserver +CONFIG += console +CONFIG -= app_bundle + +REPC_SOURCE = simpleswitch.rep + +TEMPLATE = app + +target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/simpleswitch/directconnectserver +INSTALLS += target + +SOURCES += main.cpp \ + simpleswitch.cpp + + +HEADERS += \ + simpleswitch.h diff --git a/examples/remoteobjects/simpleswitch/directconnectserver/main.cpp b/examples/remoteobjects/simpleswitch/directconnectserver/main.cpp new file mode 100644 index 0000000..18532b6 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/directconnectserver/main.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "simpleswitch.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + SimpleSwitch srcSwitch; // create simple switch + + QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:replica"))); // create host node without Registry + srcNode.enableRemoting(&srcSwitch); // enable remoting/Sharing + + return a.exec(); +} diff --git a/examples/remoteobjects/simpleswitch/directconnectserver/simpleswitch.cpp b/examples/remoteobjects/simpleswitch/directconnectserver/simpleswitch.cpp new file mode 100644 index 0000000..5418ce1 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/directconnectserver/simpleswitch.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "simpleswitch.h" + +// constructor +SimpleSwitch::SimpleSwitch(QObject *parent) : SimpleSwitchSimpleSource(parent) +{ + stateChangeTimer = new QTimer(this); // Initialize timer + QObject::connect(stateChangeTimer, &QTimer::timeout, this, &SimpleSwitch::timeout_slot); // connect timeout() signal from stateChangeTimer to timeout_slot() of simpleSwitch + stateChangeTimer->start(2000); // Start timer and set timout to 2 seconds + qDebug() << "Source Node Started"; +} + +//destructor +SimpleSwitch::~SimpleSwitch() +{ + stateChangeTimer->stop(); +} + +void SimpleSwitch::server_slot(bool clientState) +{ + qDebug() << "Replica state is " << clientState; // print switch state echoed back by client +} + +void SimpleSwitch::timeout_slot(void) +{ + // slot called on timer timeout + if (currState()) // check if current state is true, currState() is defined in repc generated rep_simpleswitch_source.h + setCurrState(false); // set state to false + else + setCurrState(true); // set state to true + qDebug() << "Source State is "< + +class SimpleSwitch +{ + PROP(bool currState=false); + SLOT(void server_slot(bool clientState)); +}; diff --git a/examples/remoteobjects/simpleswitch/registryconnectedclient/CMakeLists.txt b/examples/remoteobjects/simpleswitch/registryconnectedclient/CMakeLists.txt new file mode 100644 index 0000000..432796f --- /dev/null +++ b/examples/remoteobjects/simpleswitch/registryconnectedclient/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.16) +project(registryconnectedclient LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/simpleswitch/registryconnectedclient") + +find_package(Qt6 REQUIRED COMPONENTS Core RemoteObjects) + +qt_add_executable(registryconnectedclient + dynamicclient.cpp dynamicclient.h + main.cpp +) + +set_target_properties(registryconnectedclient PROPERTIES + WIN32_EXECUTABLE FALSE + MACOSX_BUNDLE FALSE +) + +target_link_libraries(registryconnectedclient PUBLIC + Qt::Core + Qt::RemoteObjects +) + +install(TARGETS registryconnectedclient + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/remoteobjects/simpleswitch/registryconnectedclient/dynamicclient.cpp b/examples/remoteobjects/simpleswitch/registryconnectedclient/dynamicclient.cpp new file mode 100644 index 0000000..88a3fd8 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/registryconnectedclient/dynamicclient.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "dynamicclient.h" + #include + +// constructor +DynamicClient::DynamicClient(QSharedPointer ptr) : + QObject(nullptr), clientSwitchState(false), reptr(ptr) +{ + //connect signal for replica valid changed with signal slot initialization + QObject::connect(reptr.data(), &QRemoteObjectDynamicReplica::initialized, this, + &DynamicClient::initConnection_slot); +} + +//destructor +DynamicClient::~DynamicClient() +{ + +} + +// Function to initialize connections between slots and signals +void DynamicClient::initConnection_slot() +{ + + // connect source replica signal currStateChanged() with client's recSwitchState() slot to receive source's current state + QObject::connect(reptr.data(), SIGNAL(currStateChanged(bool)), this, SLOT(recSwitchState_slot(bool))); + // connect client's echoSwitchState(..) signal with replica's server_slot(..) to echo back received state + QObject::connect(this, SIGNAL(echoSwitchState(bool)),reptr.data(), SLOT(server_slot(bool))); +} + + +void DynamicClient::recSwitchState_slot(bool value) +{ + clientSwitchState = reptr->property("currState").toBool(); // use replica property to get "currState" from source + qDebug() << "Received source state " << value << clientSwitchState; + Q_EMIT echoSwitchState(clientSwitchState); // Emit signal to echo received state back to server +} + diff --git a/examples/remoteobjects/simpleswitch/registryconnectedclient/dynamicclient.h b/examples/remoteobjects/simpleswitch/registryconnectedclient/dynamicclient.h new file mode 100644 index 0000000..ad948a9 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/registryconnectedclient/dynamicclient.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef _DYNAMICCLIENT_H +#define _DYNAMICCLIENT_H + +#include +#include + +#include +#include + +class DynamicClient : public QObject +{ + Q_OBJECT +public: + DynamicClient(QSharedPointer ptr); + ~DynamicClient() override; + +Q_SIGNALS: + void echoSwitchState(bool switchState);// this signal is connected with server_slot(..) slot of source object and echoes back switch state received from source + +public Q_SLOTS: + void recSwitchState_slot(bool); // slot to receive source state + void initConnection_slot(); + +private: + bool clientSwitchState; // holds received server switch state + QSharedPointer reptr;// holds reference to replica + }; + +#endif + diff --git a/examples/remoteobjects/simpleswitch/registryconnectedclient/main.cpp b/examples/remoteobjects/simpleswitch/registryconnectedclient/main.cpp new file mode 100644 index 0000000..fde8d02 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/registryconnectedclient/main.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "dynamicclient.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + QSharedPointer ptr; // shared pointer to hold replica + + QRemoteObjectNode repNode(QUrl(QStringLiteral("local:registry"))); + + ptr.reset(repNode.acquireDynamic("SimpleSwitch")); // acquire replica of source from host node + + DynamicClient rswitch(ptr); // create client switch object and pass replica reference to it + + return a.exec(); +} diff --git a/examples/remoteobjects/simpleswitch/registryconnectedclient/registryconnectedclient.pro b/examples/remoteobjects/simpleswitch/registryconnectedclient/registryconnectedclient.pro new file mode 100644 index 0000000..02aa54c --- /dev/null +++ b/examples/remoteobjects/simpleswitch/registryconnectedclient/registryconnectedclient.pro @@ -0,0 +1,24 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2015-02-13T15:22:50 +# +#------------------------------------------------- + +QT += remoteobjects core + +QT -= gui + +TARGET = registryconnectedclient +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/simpleswitch/registryconnectedclient +INSTALLS += target + +SOURCES += main.cpp \ + dynamicclient.cpp + +HEADERS += \ + dynamicclient.h diff --git a/examples/remoteobjects/simpleswitch/registryconnectedserver/CMakeLists.txt b/examples/remoteobjects/simpleswitch/registryconnectedserver/CMakeLists.txt new file mode 100644 index 0000000..47a51d4 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/registryconnectedserver/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.16) +project(registryconnectedserver LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/simpleswitch/registryconnectedserver") + +find_package(Qt6 REQUIRED COMPONENTS Core RemoteObjects) + +qt_add_executable(registryconnectedserver + main.cpp + simpleswitch.cpp simpleswitch.h +) + +set_target_properties(registryconnectedserver PROPERTIES + WIN32_EXECUTABLE FALSE + MACOSX_BUNDLE FALSE +) + +target_link_libraries(registryconnectedserver PUBLIC + Qt::Core + Qt::RemoteObjects +) + +qt6_add_repc_sources(registryconnectedserver + simpleswitch.rep +) + +install(TARGETS registryconnectedserver + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/remoteobjects/simpleswitch/registryconnectedserver/main.cpp b/examples/remoteobjects/simpleswitch/registryconnectedserver/main.cpp new file mode 100644 index 0000000..5d71894 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/registryconnectedserver/main.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "simpleswitch.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + SimpleSwitch srcSwitch; // create simple switch + + QRemoteObjectRegistryHost regNode(QUrl(QStringLiteral("local:registry"))); // create node that hosts registy + QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:replica")), QUrl(QStringLiteral("local:registry"))); // create node that will host source and connect to registry + + //Note, you can add srcSwitch directly to regNode if desired. + //We use two Nodes here, as the regNode could easily be in a third process. + + srcNode.enableRemoting(&srcSwitch); // enable remoting of source object + + return a.exec(); +} + diff --git a/examples/remoteobjects/simpleswitch/registryconnectedserver/registryconnectedserver.pro b/examples/remoteobjects/simpleswitch/registryconnectedserver/registryconnectedserver.pro new file mode 100644 index 0000000..d00687f --- /dev/null +++ b/examples/remoteobjects/simpleswitch/registryconnectedserver/registryconnectedserver.pro @@ -0,0 +1,30 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2015-02-13T15:02:06 +# +#------------------------------------------------- + +QT += remoteobjects core + +QT -= gui + +TARGET = registryconnectedserver +CONFIG += console +CONFIG -= app_bundle + +REPC_SOURCE = simpleswitch.rep + + +TEMPLATE = app + +target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/simpleswitch/registryconnectedserver +INSTALLS += target + +SOURCES += main.cpp \ + simpleswitch.cpp + +HEADERS += \ + simpleswitch.h + +DISTFILES += \ + simpleswitch.rep diff --git a/examples/remoteobjects/simpleswitch/registryconnectedserver/simpleswitch.cpp b/examples/remoteobjects/simpleswitch/registryconnectedserver/simpleswitch.cpp new file mode 100644 index 0000000..5418ce1 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/registryconnectedserver/simpleswitch.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "simpleswitch.h" + +// constructor +SimpleSwitch::SimpleSwitch(QObject *parent) : SimpleSwitchSimpleSource(parent) +{ + stateChangeTimer = new QTimer(this); // Initialize timer + QObject::connect(stateChangeTimer, &QTimer::timeout, this, &SimpleSwitch::timeout_slot); // connect timeout() signal from stateChangeTimer to timeout_slot() of simpleSwitch + stateChangeTimer->start(2000); // Start timer and set timout to 2 seconds + qDebug() << "Source Node Started"; +} + +//destructor +SimpleSwitch::~SimpleSwitch() +{ + stateChangeTimer->stop(); +} + +void SimpleSwitch::server_slot(bool clientState) +{ + qDebug() << "Replica state is " << clientState; // print switch state echoed back by client +} + +void SimpleSwitch::timeout_slot(void) +{ + // slot called on timer timeout + if (currState()) // check if current state is true, currState() is defined in repc generated rep_simpleswitch_source.h + setCurrState(false); // set state to false + else + setCurrState(true); // set state to true + qDebug() << "Source State is "< + +class SimpleSwitch +{ + PROP(bool currState=false); + SLOT(void server_slot(bool clientState)); +}; + diff --git a/examples/remoteobjects/simpleswitch/simpleswitch.pro b/examples/remoteobjects/simpleswitch/simpleswitch.pro new file mode 100644 index 0000000..8b70a12 --- /dev/null +++ b/examples/remoteobjects/simpleswitch/simpleswitch.pro @@ -0,0 +1,8 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + directconnectclient \ + directconnectdynamicclient \ + directconnectserver \ + registryconnectedclient \ + registryconnectedserver diff --git a/examples/remoteobjects/ssl/CMakeLists.txt b/examples/remoteobjects/ssl/CMakeLists.txt new file mode 100644 index 0000000..2d4ac63 --- /dev/null +++ b/examples/remoteobjects/ssl/CMakeLists.txt @@ -0,0 +1,2 @@ +qt_internal_add_example(sslserver) +qt_internal_add_example(sslcppclient) diff --git a/examples/remoteobjects/ssl/doc/src/ssl.qdoc b/examples/remoteobjects/ssl/doc/src/ssl.qdoc new file mode 100644 index 0000000..d77f35e --- /dev/null +++ b/examples/remoteobjects/ssl/doc/src/ssl.qdoc @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example ssl + \title QtRemoteObjects SSL Example + + This example shows how you can set up a secure Remote Object network using + QSslSockets! Encrypting communication is critical when you need to pass data + through a network you don't have full control over. +*/ diff --git a/examples/remoteobjects/ssl/ssl.pro b/examples/remoteobjects/ssl/ssl.pro new file mode 100644 index 0000000..f36383f --- /dev/null +++ b/examples/remoteobjects/ssl/ssl.pro @@ -0,0 +1,6 @@ +TEMPLATE = subdirs +CONFIG += debug_and_release ordered + +SUBDIRS = \ + sslserver \ + sslcppclient diff --git a/examples/remoteobjects/ssl/sslcppclient/CMakeLists.txt b/examples/remoteobjects/ssl/sslcppclient/CMakeLists.txt new file mode 100644 index 0000000..62aa1a8 --- /dev/null +++ b/examples/remoteobjects/ssl/sslcppclient/CMakeLists.txt @@ -0,0 +1,59 @@ +cmake_minimum_required(VERSION 3.16) +project(SslCppClient LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/ssl/sslcppclient") + +find_package(Qt6 REQUIRED COMPONENTS Core RemoteObjects) + +qt_add_executable(SslCppClient + main.cpp +) + +set_target_properties(SslCppClient PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE FALSE +) + +target_link_libraries(SslCppClient PUBLIC + # Remove: gui + Qt::Core + Qt::RemoteObjects + Qt::RemoteObjectsPrivate +) + +# Resources: +set(cert_resource_files + "../sslserver/cert/client.crt" + "../sslserver/cert/client.key" + "../sslserver/cert/rootCA.key" + "../sslserver/cert/rootCA.pem" + "../sslserver/cert/rootCA.srl" + "../sslserver/cert/server.crt" + "../sslserver/cert/server.key" +) + +qt6_add_resources(SslCppClient "cert" + PREFIX + "/sslcert" + BASE + "../sslserver/cert" + FILES + ${cert_resource_files} +) + +qt6_add_repc_replicas(SslCppClient + timemodel.rep +) + +install(TARGETS SslCppClient + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/remoteobjects/ssl/sslcppclient/main.cpp b/examples/remoteobjects/ssl/sslcppclient/main.cpp new file mode 100644 index 0000000..a4f6b1c --- /dev/null +++ b/examples/remoteobjects/ssl/sslcppclient/main.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "rep_timemodel_replica.h" + +#include + +class tester : public QObject +{ + Q_OBJECT +public: + tester() : QObject(nullptr) + { + QRemoteObjectNode m_client; + auto socket = setupConnection(); + connect(socket, &QSslSocket::errorOccurred, + socket, [](QAbstractSocket::SocketError error){ + qDebug() << "QSslSocket::error" << error; + }) ; + m_client.addClientSideConnection(socket); + + ptr1.reset(m_client.acquire< MinuteTimerReplica >()); + ptr2.reset(m_client.acquire< MinuteTimerReplica >()); + ptr3.reset(m_client.acquire< MinuteTimerReplica >()); + QTimer::singleShot(0, this, &tester::clear); + QTimer::singleShot(1, this, &tester::clear); + QTimer::singleShot(10000, this, &tester::clear); + QTimer::singleShot(11000, this, &tester::clear); + } +public slots: + void clear() + { + static int i = 0; + if (i == 0) { + i++; + ptr1.reset(); + } else if (i == 1) { + i++; + ptr2.reset(); + } else if (i == 2) { + i++; + ptr3.reset(); + } else { + qApp->quit(); + } + } + +private: + QScopedPointer ptr1, ptr2, ptr3; + + QSslSocket *setupConnection() + { + auto socketClient = new QSslSocket; + socketClient->setLocalCertificate(QStringLiteral(":/sslcert/client.crt")); + socketClient->setPrivateKey(QStringLiteral(":/sslcert/client.key")); + socketClient->setPeerVerifyMode(QSslSocket::VerifyPeer); + socketClient->connectToHostEncrypted(QStringLiteral("127.0.0.1"), 65511); + if (!socketClient->waitForEncrypted(-1)) { + qWarning("Failed to connect to server %s", + qPrintable(socketClient->errorString())); + exit(0); + } + return socketClient; + } +}; + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + auto config = QSslConfiguration::defaultConfiguration(); + config.setCaCertificates(QSslCertificate::fromPath(QStringLiteral(":/sslcert/rootCA.pem"))); + QSslConfiguration::setDefaultConfiguration(config); + + tester t; + return a.exec(); +} + +#include "main.moc" diff --git a/examples/remoteobjects/ssl/sslcppclient/sslcppclient.pro b/examples/remoteobjects/ssl/sslcppclient/sslcppclient.pro new file mode 100644 index 0000000..07fb8da --- /dev/null +++ b/examples/remoteobjects/ssl/sslcppclient/sslcppclient.pro @@ -0,0 +1,24 @@ +QT_FOR_CONFIG += network +requires(qtConfig(ssl)) + +REPC_REPLICA += timemodel.rep +QT = remoteobjects remoteobjects-private core + +QT -= gui + +TARGET = SslCppClient +CONFIG -= app_bundle + +TEMPLATE = app + +SOURCES += main.cpp + +OTHER_FILES += \ + timemodel.rep + +RESOURCES += \ + ../sslserver/cert/cert.qrc + + +target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/ssl/sslcppclient +INSTALLS += target diff --git a/examples/remoteobjects/ssl/sslcppclient/timemodel.rep b/examples/remoteobjects/ssl/sslcppclient/timemodel.rep new file mode 100644 index 0000000..cbfaf24 --- /dev/null +++ b/examples/remoteobjects/ssl/sslcppclient/timemodel.rep @@ -0,0 +1,12 @@ +#include + +POD PresetInfo(int presetNumber, float frequency, QString stationName) +class MinuteTimer +{ + PROP(int hour=1); + PROP(int minute=51); + SIGNAL(timeChanged()); + SIGNAL(timeChanged2(QTime t)); + SIGNAL(sendCustom(PresetInfo info)); + SLOT(void SetTimeZone(int zn)); +}; diff --git a/examples/remoteobjects/ssl/sslserver/CMakeLists.txt b/examples/remoteobjects/ssl/sslserver/CMakeLists.txt new file mode 100644 index 0000000..a276b9d --- /dev/null +++ b/examples/remoteobjects/ssl/sslserver/CMakeLists.txt @@ -0,0 +1,60 @@ +cmake_minimum_required(VERSION 3.16) +project(sslserver LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/ssl/sslserver") + +find_package(Qt6 REQUIRED COMPONENTS Core RemoteObjects) + +qt_add_executable(sslserver + main.cpp + sslserver.cpp sslserver.h + timemodel.cpp timemodel.h +) + +set_target_properties(sslserver PROPERTIES + WIN32_EXECUTABLE FALSE + MACOSX_BUNDLE TRUE +) + +target_link_libraries(sslserver PUBLIC + Qt::Core + Qt::RemoteObjects + Qt::RemoteObjectsPrivate +) + +# Resources: +set(cert_resource_files + "cert/client.crt" + "cert/client.key" + "cert/rootCA.key" + "cert/rootCA.pem" + "cert/rootCA.srl" + "cert/server.crt" + "cert/server.key" +) + +qt6_add_resources(sslserver "cert" + PREFIX + "/sslcert" + BASE + "cert" + FILES + ${cert_resource_files} +) + +qt6_add_repc_sources(sslserver + ../../timemodel.rep +) + +install(TARGETS sslserver + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/remoteobjects/ssl/sslserver/cert/cert.qrc b/examples/remoteobjects/ssl/sslserver/cert/cert.qrc new file mode 100644 index 0000000..65f92e2 --- /dev/null +++ b/examples/remoteobjects/ssl/sslserver/cert/cert.qrc @@ -0,0 +1,11 @@ + + + client.crt + client.key + rootCA.key + rootCA.pem + rootCA.srl + server.crt + server.key + + diff --git a/examples/remoteobjects/ssl/sslserver/cert/client.crt b/examples/remoteobjects/ssl/sslserver/cert/client.crt new file mode 100644 index 0000000..3aa0ff8 --- /dev/null +++ b/examples/remoteobjects/ssl/sslserver/cert/client.crt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICrTCCAZUCFHOQggvUf1o8c5i3yNyiGLNcLC4pMA0GCSqGSIb3DQEBCwUAMBIx +EDAOBgNVBAMMB1F0Uk8gQ0EwHhcNMjEwMjI0MTEzMzU1WhcNMjMwNTMwMTEzMzU1 +WjAUMRIwEAYDVQQDDAkxMjcuMC4wLjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDbl9iuedw0oSbtpC2m30YdzwRmemijasP9SQGQ6+piUOFUKCZsoGWc +RcEnLGzC+KJ7FXh8jA1kTXSW6ghqvrUysN8VzjgmcCLFee4JAkCUY8yNrlq13ciR +19BE09kJdOPZeI57pCSBNA6iy03Q4nc/GJpG63QTqJv/WUUgMek0UsmZIzDcWaqr +MCMnLMaRi5oKFCnnl8E0XDuRm1nqPAzT+us/4upMv+7Q2xs4QFXbLUpSIToNc1wm +tP6OAGaYClbJZgZbUNowj0wJeCUAwGGcDpliYj1JB8R015z8Kd8pDCvdD7XL35JR +rT+eaBFNLUrl30aIl3lWf/buv3OoRmuVAgMBAAEwDQYJKoZIhvcNAQELBQADggEB +AJjdfuy2pb3KgnpxYiXfKXCqGlN7E1RyoCIsMhldWcxAN5cwIJCrvde5MNI8kDvd +0SfDpRpCP/hZqpR6DsR9iNYJprXlQNZ7Rs41Eswwlb66DqmBlb5ZQcYl8KsKV5fw +7PhvLpjC5hEg1OBg1Ooz+aNvI9OJYIRFUJ1smtRzwXWuQd5QoqYVRpzvmrFawnGa +2NHywiwgKyGvY/y82pPuj1rt0L+bae85cZm32f6gp1me9OuLIqA2G5UafSiigWBY +YL249Rd4rrT87GAeaiBo8ZxZ8de8O7TOBjSNrfAMySepDWjfFfoNpyp+4foRKmpE +aZmgGTIj5rfhYh4Gcj1nZBw= +-----END CERTIFICATE----- diff --git a/examples/remoteobjects/ssl/sslserver/cert/client.key b/examples/remoteobjects/ssl/sslserver/cert/client.key new file mode 100644 index 0000000..b3f4f1a --- /dev/null +++ b/examples/remoteobjects/ssl/sslserver/cert/client.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEA25fYrnncNKEm7aQtpt9GHc8EZnpoo2rD/UkBkOvqYlDhVCgm +bKBlnEXBJyxswviiexV4fIwNZE10luoIar61MrDfFc44JnAixXnuCQJAlGPMja5a +td3IkdfQRNPZCXTj2XiOe6QkgTQOostN0OJ3PxiaRut0E6ib/1lFIDHpNFLJmSMw +3FmqqzAjJyzGkYuaChQp55fBNFw7kZtZ6jwM0/rrP+LqTL/u0NsbOEBV2y1KUiE6 +DXNcJrT+jgBmmApWyWYGW1DaMI9MCXglAMBhnA6ZYmI9SQfEdNec/CnfKQwr3Q+1 +y9+SUa0/nmgRTS1K5d9GiJd5Vn/27r9zqEZrlQIDAQABAoIBAEDLm4pQNuPosV3p +1fapZz0gesHqWLnvpQk145ppom2ERBjbCAuBgLoN8yKl/ynAx+DdwwGtKb5xBHgL +cpRc1YaxngIHKZZd/ESc59oMqhWfJRqhWe7UFHzEW5YTlLUvopPm+NQO6R6ex7rN +lpaOXHVnww4uJ8AtPmqoYrdPQurG/txveRMLo84JJT+IH2YVWOzccp809zw4WZZD +qBcgm/dV8ir+8nUHQlR+loMMrEoKeacNxtHUXWL6d6P93Q72L07t41/l0XmXXq7I +cVJnGxcJtkeqj03FSHqDU3XM5fRg6f+XnnSnhnd4AUmHe8cvyeCnEf4bdh4UpzBG +sCie+XkCgYEA93FU0X6ttWdb+rJNHRnHmb4DxOVo2LeXEk1A1ul+Yj+jFP+TwJH+ +bm8PbV7ALdyH2u66ElQG60gW9ztu86xl5ZLVdhijWJpjHKB45eXVhnRcb2Fy9tDc +pUeRs8+IrrYbWDrNZZYWby83MqPHimCLTmAZl11NMB2ohyFDxr5voGMCgYEA4y/0 +2WN8r74H9I3L2Ghfe8e3i/W35BpjtElJxiL3L1vzGdU5Wo1hDnvjoHvdTxB7LtGU +I+P0l77fwuAC8G8bh4SZ59jcxlqCmbXy7wDAyrYaCja5OWK9xWXvYuya5CCPrg6h +wo7TcrxjdEvEVQ97PMZcq6HVBOtINZGfJeSieacCgYAHyQsQJFo20O+17ZI7jioX +jkD0Gvu3hd889i1KFcKiOLpa2Me/UVieBOSJXmfRiZTEsKouFXK6SGRglwAgrpXu +KTaKJrBNA16G8g2bviV/u32FC53gYiXvFVdiPu9f/97QYdlAjv5ZtTSZZUnL8smv +R5rGhmr9TpGU3tkREcDVXQKBgBUfJ0dyvWvlYf31lOcYxQ/QAJuNi7w0S+K+EZLP +O2X2yYI0VbG6hTSAhigse+XW5Wzz5S71CY92Gn2WsA9EdS3DQT/R5Ky4S34Y8W4R +BtuR1JfwgIX6TSRmFrx+vOPKtzD6gUWCW9xF8YUlaipyVwXOd10pnZFogn0gfchb +GlPvAoGAG2xikjlCTrnKv7KRF9sxO1eLixfzHwWKiAhrtFBoHSM4AwynrpAb0eMf +ObSIjXeBy93LhTluVOsD5J9iXA/SKYoXqt/tDMCHRdwpTsJNBa56GMkpFHHLo6oC +si20nmMXP949gpRIvrYsgYC8WObbi+RQEWDVutv7hVPCF0QvUHs= +-----END RSA PRIVATE KEY----- diff --git a/examples/remoteobjects/ssl/sslserver/cert/readme b/examples/remoteobjects/ssl/sslserver/cert/readme new file mode 100644 index 0000000..1386169 --- /dev/null +++ b/examples/remoteobjects/ssl/sslserver/cert/readme @@ -0,0 +1,2 @@ +These files are generated by the script located at tests/auto/external_IODevice/cert/generate.sh + diff --git a/examples/remoteobjects/ssl/sslserver/cert/rootCA.key b/examples/remoteobjects/ssl/sslserver/cert/rootCA.key new file mode 100644 index 0000000..1647817 --- /dev/null +++ b/examples/remoteobjects/ssl/sslserver/cert/rootCA.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAulVnnHwRF6e2aAThSi1cZpUlO3ZdqzPIuf75NBbRY2y9Vm+F +cyCqUquNxP/qDE02nfQFBd/PUKqUWQs0EXVEVZPEG6s/l7ionYHkMmWSjh+AAWp7 +Iwx3MlHFNi9c5Xrod7iS1igg0YhDQlnT0xGfTXZasUJ/s6NuNoZiN5L6sEKYDSAu +kzyyqS23WrqE4RvsGAaoaaJqu1MT8DBqI9xoPpIvwb/4gdOZn4YClW2WWrVjCTT2 +zEzUAh1BjdH3dktXogiFfXHuOP4W8suOx46NXDcZ3f5LF8CT/2uq9l8vta+pV2ci +BAIctGu5z+fEdTCojvCWOvCzYmjtep/yTukT+QIDAQABAoIBAQCRvRjkCRnpUZDW +vPJk7SO3THIplwPeUwtthqLtfedaB4PzphhPmr39GRcyfSNXadENK/39wTbKlhCf +sKaR/RFsib26EnATwCeJwj10uYMuTC73bIxRNn/ISLKiFdtn1YEbmq6meA5rNFO/ +Arkt/juF/8shl6yAGZSrauJJK1mOH8ItMaGR+6tVPWLIZOLk6TiOJhj9SXvMTCw/ +HzgNZMgFGfqnbctg1ki/CY0BkIkYNUTCjhoCwjcgBJl4ERCfTQS6UeEG9Ad+beIH +g8WKzpfjF5+Jnjzqw87aWx1200OdlEdouTt677RXHJFN5naUc+GJZGpmA3RGZA17 +LqA4zBYNAoGBAOGwtg7JQkBOmUC0SiKdXnxG1hVnS4N3DMIDVX2tAe/wWIrP168e +0UpCvswLD+JqO1IgWqw9+QUPnhJSQ9JbYB+678esOTLsT5Yd18VcsiRxSacvQfUw +H4YJaHrFuuFlnxYMlMdPYS3knbIPsft9DVQLFBLL7qPVHbrJ3V6Sn4XrAoGBANNb +mfhgVr5m0n3sQVTlYhWwbJq5K+Htzzl7Xl3JHpMLm2C/GoorP/2zLVhbH20lsE3A +FyIfjcwRxGRu2TXCVnMc4GttlMX5leTxykEd2VrZuEVnTdrudm45Z6sZQpdf1QTg +WebwKgN1eCg7Jkuk5YlRX/KwMtuq4MVzPtOvR+CrAoGAA8uC5DDCKm6n6QyfCoH2 +6sQOKYH5JRbFYiXINDrKg4xZEMx55fnwrvz8VFYDSF1c7f6ZR7grDci7cbdsaIcc +0KvGCGd+9ro+hFmwHSN342D8ShFjXIoYnZpe5WGZyNx6llZT0h4lli338NyOs5ng +tX8SMVa4hoy42UE3tbVldU0CgYA0l/K0b6SmNIfkdcm8Cmhh5UjhJ3rX+Yk7UIum +4skM5jJ/3I4KG8EMrG14MxSa4GoCru4Su69ZPIKWS08ZpYZFlsXxdY8zxGucUN53 +XaochVjpTE9/Tx+BRh+Z3+tGJ76mO/2jDdgmjDCeMjnRUPMdPHaXuWiuaNMNzyOv +IUrNiQKBgGvxEQ0Oe3d/om2Lp/cHbkhZkw/jO/FG5HtodxiO3+1YLhExsDOc5GVn ++x2eNv+dQSIrGagko9TJe1p9WqFnD19Ls+ezqfw2fR5Amg1KHKGUA7k1+Qe/QgoK +D+T4/RkvdGRoBv/il+Rj1rfmMAhEzdD7Axek9a6rUj8geO22kp7I +-----END RSA PRIVATE KEY----- diff --git a/examples/remoteobjects/ssl/sslserver/cert/rootCA.pem b/examples/remoteobjects/ssl/sslserver/cert/rootCA.pem new file mode 100644 index 0000000..7f6cce5 --- /dev/null +++ b/examples/remoteobjects/ssl/sslserver/cert/rootCA.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDBTCCAe2gAwIBAgIUV9eILCYaC+qwZHR7OO23uyd2UjwwDQYJKoZIhvcNAQEL +BQAwEjEQMA4GA1UEAwwHUXRSTyBDQTAeFw0yMTAyMjQxMTMzNTVaFw0yMzA2MTAx +MTMzNTVaMBIxEDAOBgNVBAMMB1F0Uk8gQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQC6VWecfBEXp7ZoBOFKLVxmlSU7dl2rM8i5/vk0FtFjbL1Wb4Vz +IKpSq43E/+oMTTad9AUF389QqpRZCzQRdURVk8Qbqz+XuKidgeQyZZKOH4ABansj +DHcyUcU2L1zleuh3uJLWKCDRiENCWdPTEZ9NdlqxQn+zo242hmI3kvqwQpgNIC6T +PLKpLbdauoThG+wYBqhpomq7UxPwMGoj3Gg+ki/Bv/iB05mfhgKVbZZatWMJNPbM +TNQCHUGN0fd2S1eiCIV9ce44/hbyy47Hjo1cNxnd/ksXwJP/a6r2Xy+1r6lXZyIE +Ahy0a7nP58R1MKiO8JY68LNiaO16n/JO6RP5AgMBAAGjUzBRMB0GA1UdDgQWBBSu +ehS/XLejTiDbCddGU2mMZ1t3CjAfBgNVHSMEGDAWgBSuehS/XLejTiDbCddGU2mM +Z1t3CjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB8JzSuhHPK +cjhLqOHUGMKtKWOd5p9g2D45cAWh6jdzU/AhmslMPbsO5hZkqfE+3xARtcMmQfF2 +k1Qyp3hDTN1ZqHSM6Urq9uR33/wXZbNRUNCD8lAmqKyzF9NF7Q+tmC//IMRtVQhK +aMN3LciyYGQjT0XhDKFWEz9/AvUQD97mLow2m0/izqE4SI6ekQDNL26IiCWFgFjh +ScZjcJ1ogluD2a6sEUGywRXLNV/bdSjRgkAbpvJFrok7dDZ8xCNhOg4xJJQJRWm7 +ZusUydiVyfgrFan6MD+EdldRHjAs8S9BJfZ0RTOWnD9V8auKuVomzKDed54QlXXi +zwowb3Objpqh +-----END CERTIFICATE----- diff --git a/examples/remoteobjects/ssl/sslserver/cert/rootCA.srl b/examples/remoteobjects/ssl/sslserver/cert/rootCA.srl new file mode 100644 index 0000000..d292c9f --- /dev/null +++ b/examples/remoteobjects/ssl/sslserver/cert/rootCA.srl @@ -0,0 +1 @@ +7390820BD47F5A3C7398B7C8DCA218B35C2C2E29 diff --git a/examples/remoteobjects/ssl/sslserver/cert/server.crt b/examples/remoteobjects/ssl/sslserver/cert/server.crt new file mode 100644 index 0000000..df9d55c --- /dev/null +++ b/examples/remoteobjects/ssl/sslserver/cert/server.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDFTCCAf2gAwIBAgIUc5CCC9R/WjxzmLfI3KIYs1wsLigwDQYJKoZIhvcNAQEL +BQAwEjEQMA4GA1UEAwwHUXRSTyBDQTAeFw0yMTAyMjQxMTMzNTVaFw0yMzA1MzAx +MTMzNTVaMBQxEjAQBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAOKHte9tB66OD+Um/WkqxHtW3sKrBs4IxKuWAef0UMRt3ld6 +5HvWk+xsCZdPxeL53nMOIy9FS6wKGvEWTwYRR4Id9iX2XQsI4cRJWl25qgCYohnm +Eet9CUkXa3ywbyrSBWFD0r956sS+mwhHU9z05jphd6iZEonHu2b4BFFXMN7+prwj +00EtGbte5wSWWE9ZfXzeGYd4cZBReNCRjaS5XJ3IgjZ4tfxsB3JzBjVafCfnth7r +Is8a2SKCGnhYmV+A6Agth4xtSKDho+BSDYSuMux3dftM/eqtxF0wXzlnX5ApNwGB +zWjcoUL63vjjy17oNEtbs5X2e1g8bGRaGRxGUHUCAwEAAaNhMF8wHwYDVR0jBBgw +FoAUrnoUv1y3o04g2wnXRlNpjGdbdwowCQYDVR0TBAIwADALBgNVHQ8EBAMCBPAw +EwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0B +AQsFAAOCAQEAqhBhxRgG9N1ZghwWC3ZhWSx4BFl3YrStWlQcjffcQ6p8NDxsrkFc +gMG51TmJdaz8J4v2AZW8k9GJlEIaZdV/8czeyEwvjKD4vrUw88waeW7n6o8H+8k+ +ak9fRFvnerFrLEWNpyRqbjJWwm8bQ4T5UKsVNXkZnNLyG2Ha29L9gUHffgSMiyLO +hWqcanPxsMJaDVhw/Gd8JwqaEC1nRPCGxhog2/D2sh4vCj1UykykjPwNz5fP/vfA +VujNCA23eXAdgD3lALHu2WrmyPkQCM7Z61g4k8+v0KjhyJjdLSVTwkPePEo87Fv4 +sn4Jp5gPPBf7jDFKp8PDdbPmk0qN+Wm8gA== +-----END CERTIFICATE----- diff --git a/examples/remoteobjects/ssl/sslserver/cert/server.key b/examples/remoteobjects/ssl/sslserver/cert/server.key new file mode 100644 index 0000000..05144f4 --- /dev/null +++ b/examples/remoteobjects/ssl/sslserver/cert/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEA4oe1720Hro4P5Sb9aSrEe1bewqsGzgjEq5YB5/RQxG3eV3rk +e9aT7GwJl0/F4vnecw4jL0VLrAoa8RZPBhFHgh32JfZdCwjhxElaXbmqAJiiGeYR +630JSRdrfLBvKtIFYUPSv3nqxL6bCEdT3PTmOmF3qJkSice7ZvgEUVcw3v6mvCPT +QS0Zu17nBJZYT1l9fN4Zh3hxkFF40JGNpLlcnciCNni1/GwHcnMGNVp8J+e2Husi +zxrZIoIaeFiZX4DoCC2HjG1IoOGj4FINhK4y7Hd1+0z96q3EXTBfOWdfkCk3AYHN +aNyhQvre+OPLXug0S1uzlfZ7WDxsZFoZHEZQdQIDAQABAoIBAGuKEYzALc1oE5Ot +ls++RdhnvQidOHXHI9ZxOCZtjYoyvkK5TI6dp0utXkA+1qqSBFCKfZmLRAlAItog +xRMUUOYsYxZShokehk8wo32rDlGKJCo3Vnp8uVPBkn13JM8nNPafxASyVAlikyay +9dUHTeSZML0RLgPKleSkCSi0Q7cYOFG/HB9aNjp8F5rdut02KrmC3cxlHKF7QXXG +VU+op1Z9o0V2/iUFJnF5CR40sW2THEbBJkkeYwbvUTnavz4XQtZst//DKsDQEe2r +UrhsIHduvG4tWiBE77m1vyigTxUWCsLQ2KCnn9O+4KyTg9HWCiQ2QSU3istX/rpI +zN2lOgECgYEA9PVVMnY+t59Q73IQ9LRg5KRqg6YyGQOrwJKbCUxDrA6ikh3MDgwV +CkC6Jdl6e4DMog51l3CizrfR2+mtNSTUJDGFE1iGgI+Faem4aopRtFRiLWJ8n4m7 +U8pl3XTP0XFT68aBCAE6O/xVPXs0I/eKNvaF5vokB5zm4R79o37WP+UCgYEA7L26 +TiCFA73Fil/bPupqWJnvm896RlO1S+IBOKlPyCHVvxiGLvtv+YTucCFwXQ4FeNRh +bQEWlURsgeNr7PHATtFUZ/zo/7l1WYNLXZDZwWD+JYllVPwskJOJMx5Rc77Q0aQ6 +7v60XMGwD5cxQ29RHuJs09Iwc9b1WqwOAEJAJVECgYBNsxQXMZKrRAm0KgZe2Ghz +ngN7RthVPujX6KjsxhghF3NRzcnQGt0Bp45kOxuy2SQPs25xXvUFhSE4FGMwnEH+ +SQbhIA9p8BxtgAlTIhTQkoOhyb+mC1Y0Odsd59OTp9Lq0shS9bC3Hk8bdV0Qm5Bn +5sKKhYWwNIC3n9Dsb2seUQKBgAS7biPtpnsCqhYwAFPrn6CRwyZcKVeKiM8xf1DA +oaWgd4NQXC5IPF7Cd3mqUXKquxVFOYVSRj9JlNmr0BZ2Zp+ss4E4nvetn1jgtPrz +0EZ7R9k8O9hNCh8Bs/ZfnsUvhUELhVoNoVFRVdGZ9hQg/4AcioxZYTqPi2v6kHUU +3e9hAoGAec7anF5TiTx2jjcDFS9hrRw0w2PsNX24qjqPFqeuzDIorh6rq4Ip4aA0 +7rxeIXmxjmYA7pPCT9rPxtpEp4BQovF9kHMutd8lyB4rGbLpNpOY4m5v8Oo7cLQ3 +kLAwE+jrEwLNtuq+kUlGwK7YLeiGUm4Rsof5IXlSkXzL/99gHC4= +-----END RSA PRIVATE KEY----- diff --git a/examples/remoteobjects/ssl/sslserver/main.cpp b/examples/remoteobjects/ssl/sslserver/main.cpp new file mode 100644 index 0000000..fac2584 --- /dev/null +++ b/examples/remoteobjects/ssl/sslserver/main.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "timemodel.h" + +#include +#include + +#include "sslserver.h" + +#include +/* +* http://stackoverflow.com/questions/7404163/windows-handling-ctrlc-in-different-thread +*/ + +void SigIntHandler() +{ + qDebug()<<"Ctrl-C received. Quitting."; + qApp->quit(); +} + +#if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) +#include + +void unix_handler(int s) +{ + if (s==SIGINT) + SigIntHandler(); +} + +#elif defined(Q_OS_WIN32) +#include + +BOOL WINAPI WinHandler(DWORD CEvent) +{ + switch (CEvent) + { + case CTRL_C_EVENT: + SigIntHandler(); + break; + } + return TRUE; +} +#endif + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + auto config = QSslConfiguration::defaultConfiguration(); + config.setCaCertificates(QSslCertificate::fromPath(QStringLiteral(":/sslcert/rootCA.pem"))); + QSslConfiguration::setDefaultConfiguration(config); + +#if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) + signal(SIGINT, &unix_handler); +#elif defined(Q_OS_WIN32) + SetConsoleCtrlHandler((PHANDLER_ROUTINE)WinHandler, TRUE); +#endif + QRemoteObjectHost host; + SslServer server; + server.listen(QHostAddress::Any, 65511); + + host.setHostUrl(server.serverAddress().toString(), QRemoteObjectHost::AllowExternalRegistration); + + QObject::connect(&server, &SslServer::encryptedSocketReady, &server, [&host](QSslSocket *socket) { + QObject::connect(socket, &QSslSocket::errorOccurred, + socket, [](QAbstractSocket::SocketError error){ + qDebug() << "QSslSocket::error" << error; + }) ; + host.addHostSideConnection(socket); + }); + + MinuteTimer timer; + host.enableRemoting(&timer); + + Q_UNUSED(timer) + return app.exec(); +} + diff --git a/examples/remoteobjects/ssl/sslserver/sslserver.cpp b/examples/remoteobjects/ssl/sslserver/sslserver.cpp new file mode 100644 index 0000000..02eeaa6 --- /dev/null +++ b/examples/remoteobjects/ssl/sslserver/sslserver.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "sslserver.h" +#include + +SslServer::SslServer(QObject *parent) + : QTcpServer(parent) +{} + + +void SslServer::incomingConnection(qintptr socketDescriptor) +{ + auto serverSocket = new QSslSocket; + if (serverSocket->setSocketDescriptor(socketDescriptor)) { + addPendingConnection(serverSocket); + connect(serverSocket, &QSslSocket::encrypted, this, [this, serverSocket] { + Q_EMIT encryptedSocketReady(serverSocket); + }); + connect(serverSocket, static_cast&)>(&QSslSocket::sslErrors), + this, [serverSocket](const QList& errors){ + qWarning() << "Error:" << serverSocket << errors; + delete serverSocket; + }); + serverSocket->setPeerVerifyMode(QSslSocket::VerifyPeer); + serverSocket->setLocalCertificate(QStringLiteral(":/sslcert/server.crt")); + serverSocket->setPrivateKey(QStringLiteral(":/sslcert/server.key")); + serverSocket->startServerEncryption(); + } else { + delete serverSocket; + } +} diff --git a/examples/remoteobjects/ssl/sslserver/sslserver.h b/examples/remoteobjects/ssl/sslserver/sslserver.h new file mode 100644 index 0000000..3dfd511 --- /dev/null +++ b/examples/remoteobjects/ssl/sslserver/sslserver.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SSLSERVER_H +#define SSLSERVER_H + +#include + +QT_BEGIN_NAMESPACE +class QSslSocket; +QT_END_NAMESPACE + +class SslServer : public QTcpServer +{ + Q_OBJECT +public: + SslServer(QObject *parent=nullptr); + void incomingConnection(qintptr socketDescriptor) override; + +signals: + void encryptedSocketReady(QSslSocket *socket); +}; + +#endif // SSLSERVER_H diff --git a/examples/remoteobjects/ssl/sslserver/sslserver.pro b/examples/remoteobjects/ssl/sslserver/sslserver.pro new file mode 100644 index 0000000..b8081d2 --- /dev/null +++ b/examples/remoteobjects/ssl/sslserver/sslserver.pro @@ -0,0 +1,21 @@ +QT_FOR_CONFIG += network +requires(qtConfig(ssl)) + +CONFIG += console + + +REPC_SOURCE += ../../timemodel.rep +QT = remoteobjects remoteobjects-private core + +SOURCES += timemodel.cpp main.cpp \ + sslserver.cpp +HEADERS += timemodel.h \ + sslserver.h + +contains(QT_CONFIG, c++11): CONFIG += c++11 + +target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/ssl/sslserver +INSTALLS += target + +RESOURCES += \ + cert/cert.qrc diff --git a/examples/remoteobjects/ssl/sslserver/timemodel.cpp b/examples/remoteobjects/ssl/sslserver/timemodel.cpp new file mode 100644 index 0000000..a444f6e --- /dev/null +++ b/examples/remoteobjects/ssl/sslserver/timemodel.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "timemodel.h" + +MinuteTimer::MinuteTimer(QObject *parent) : MinuteTimerSimpleSource(parent), zone(0) +{ + time = QTime::currentTime(); + setHour(time.hour()); + setMinute(time.minute()); + timer.start(60000-time.second()*1000, this); +} +MinuteTimer::~MinuteTimer() +{ + timer.stop(); +} +void MinuteTimer::timerEvent(QTimerEvent *) +{ + QTime now = QTime::currentTime(); + if (now.second() == 59 && now.minute() == time.minute() && now.hour() == time.hour()) { + // just missed time tick over, force it, wait extra 0.5 seconds + time = time.addSecs(60); + timer.start(60500, this); + } else { + time = now; + timer.start(60000-time.second()*1000, this); + } + qDebug()<<"Time"< +#include "rep_timemodel_source.h" + +class MinuteTimer : public MinuteTimerSimpleSource +{ + Q_OBJECT +public: + MinuteTimer(QObject *parent = nullptr); + ~MinuteTimer() override; + +public slots: + void SetTimeZone(const int &zn) override; + +protected: + void timerEvent(QTimerEvent *) override; + +private: + QTime time; + QBasicTimer timer; + int zone; +}; diff --git a/examples/remoteobjects/timemodel.rep b/examples/remoteobjects/timemodel.rep new file mode 100644 index 0000000..c07ee2c --- /dev/null +++ b/examples/remoteobjects/timemodel.rep @@ -0,0 +1,14 @@ +#include + +POD PresetInfo(int presetNumber, float frequency, QString stationName) +POD PresetData(QList bla) +class MinuteTimer +{ + PROP(int hour=1); + PROP(int minute=51); + SIGNAL(timeChanged()); + SIGNAL(timeChanged2(QTime t)); + SIGNAL(sendCustom(PresetInfo info)); + SIGNAL(foo(QMap foo)); + SLOT(void SetTimeZone(const int &)); +}; diff --git a/examples/remoteobjects/websockets/CMakeLists.txt b/examples/remoteobjects/websockets/CMakeLists.txt new file mode 100644 index 0000000..5441f66 --- /dev/null +++ b/examples/remoteobjects/websockets/CMakeLists.txt @@ -0,0 +1,4 @@ +if(TARGET Qt::WebSockets AND TARGET Qt::Widgets) + qt_internal_add_example(wsclient) + qt_internal_add_example(wsserver) +endif() diff --git a/examples/remoteobjects/websockets/common/cert/cert.qrc b/examples/remoteobjects/websockets/common/cert/cert.qrc new file mode 100644 index 0000000..65f92e2 --- /dev/null +++ b/examples/remoteobjects/websockets/common/cert/cert.qrc @@ -0,0 +1,11 @@ + + + client.crt + client.key + rootCA.key + rootCA.pem + rootCA.srl + server.crt + server.key + + diff --git a/examples/remoteobjects/websockets/common/cert/client.crt b/examples/remoteobjects/websockets/common/cert/client.crt new file mode 100644 index 0000000..3aa0ff8 --- /dev/null +++ b/examples/remoteobjects/websockets/common/cert/client.crt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICrTCCAZUCFHOQggvUf1o8c5i3yNyiGLNcLC4pMA0GCSqGSIb3DQEBCwUAMBIx +EDAOBgNVBAMMB1F0Uk8gQ0EwHhcNMjEwMjI0MTEzMzU1WhcNMjMwNTMwMTEzMzU1 +WjAUMRIwEAYDVQQDDAkxMjcuMC4wLjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDbl9iuedw0oSbtpC2m30YdzwRmemijasP9SQGQ6+piUOFUKCZsoGWc +RcEnLGzC+KJ7FXh8jA1kTXSW6ghqvrUysN8VzjgmcCLFee4JAkCUY8yNrlq13ciR +19BE09kJdOPZeI57pCSBNA6iy03Q4nc/GJpG63QTqJv/WUUgMek0UsmZIzDcWaqr +MCMnLMaRi5oKFCnnl8E0XDuRm1nqPAzT+us/4upMv+7Q2xs4QFXbLUpSIToNc1wm +tP6OAGaYClbJZgZbUNowj0wJeCUAwGGcDpliYj1JB8R015z8Kd8pDCvdD7XL35JR +rT+eaBFNLUrl30aIl3lWf/buv3OoRmuVAgMBAAEwDQYJKoZIhvcNAQELBQADggEB +AJjdfuy2pb3KgnpxYiXfKXCqGlN7E1RyoCIsMhldWcxAN5cwIJCrvde5MNI8kDvd +0SfDpRpCP/hZqpR6DsR9iNYJprXlQNZ7Rs41Eswwlb66DqmBlb5ZQcYl8KsKV5fw +7PhvLpjC5hEg1OBg1Ooz+aNvI9OJYIRFUJ1smtRzwXWuQd5QoqYVRpzvmrFawnGa +2NHywiwgKyGvY/y82pPuj1rt0L+bae85cZm32f6gp1me9OuLIqA2G5UafSiigWBY +YL249Rd4rrT87GAeaiBo8ZxZ8de8O7TOBjSNrfAMySepDWjfFfoNpyp+4foRKmpE +aZmgGTIj5rfhYh4Gcj1nZBw= +-----END CERTIFICATE----- diff --git a/examples/remoteobjects/websockets/common/cert/client.key b/examples/remoteobjects/websockets/common/cert/client.key new file mode 100644 index 0000000..b3f4f1a --- /dev/null +++ b/examples/remoteobjects/websockets/common/cert/client.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEA25fYrnncNKEm7aQtpt9GHc8EZnpoo2rD/UkBkOvqYlDhVCgm +bKBlnEXBJyxswviiexV4fIwNZE10luoIar61MrDfFc44JnAixXnuCQJAlGPMja5a +td3IkdfQRNPZCXTj2XiOe6QkgTQOostN0OJ3PxiaRut0E6ib/1lFIDHpNFLJmSMw +3FmqqzAjJyzGkYuaChQp55fBNFw7kZtZ6jwM0/rrP+LqTL/u0NsbOEBV2y1KUiE6 +DXNcJrT+jgBmmApWyWYGW1DaMI9MCXglAMBhnA6ZYmI9SQfEdNec/CnfKQwr3Q+1 +y9+SUa0/nmgRTS1K5d9GiJd5Vn/27r9zqEZrlQIDAQABAoIBAEDLm4pQNuPosV3p +1fapZz0gesHqWLnvpQk145ppom2ERBjbCAuBgLoN8yKl/ynAx+DdwwGtKb5xBHgL +cpRc1YaxngIHKZZd/ESc59oMqhWfJRqhWe7UFHzEW5YTlLUvopPm+NQO6R6ex7rN +lpaOXHVnww4uJ8AtPmqoYrdPQurG/txveRMLo84JJT+IH2YVWOzccp809zw4WZZD +qBcgm/dV8ir+8nUHQlR+loMMrEoKeacNxtHUXWL6d6P93Q72L07t41/l0XmXXq7I +cVJnGxcJtkeqj03FSHqDU3XM5fRg6f+XnnSnhnd4AUmHe8cvyeCnEf4bdh4UpzBG +sCie+XkCgYEA93FU0X6ttWdb+rJNHRnHmb4DxOVo2LeXEk1A1ul+Yj+jFP+TwJH+ +bm8PbV7ALdyH2u66ElQG60gW9ztu86xl5ZLVdhijWJpjHKB45eXVhnRcb2Fy9tDc +pUeRs8+IrrYbWDrNZZYWby83MqPHimCLTmAZl11NMB2ohyFDxr5voGMCgYEA4y/0 +2WN8r74H9I3L2Ghfe8e3i/W35BpjtElJxiL3L1vzGdU5Wo1hDnvjoHvdTxB7LtGU +I+P0l77fwuAC8G8bh4SZ59jcxlqCmbXy7wDAyrYaCja5OWK9xWXvYuya5CCPrg6h +wo7TcrxjdEvEVQ97PMZcq6HVBOtINZGfJeSieacCgYAHyQsQJFo20O+17ZI7jioX +jkD0Gvu3hd889i1KFcKiOLpa2Me/UVieBOSJXmfRiZTEsKouFXK6SGRglwAgrpXu +KTaKJrBNA16G8g2bviV/u32FC53gYiXvFVdiPu9f/97QYdlAjv5ZtTSZZUnL8smv +R5rGhmr9TpGU3tkREcDVXQKBgBUfJ0dyvWvlYf31lOcYxQ/QAJuNi7w0S+K+EZLP +O2X2yYI0VbG6hTSAhigse+XW5Wzz5S71CY92Gn2WsA9EdS3DQT/R5Ky4S34Y8W4R +BtuR1JfwgIX6TSRmFrx+vOPKtzD6gUWCW9xF8YUlaipyVwXOd10pnZFogn0gfchb +GlPvAoGAG2xikjlCTrnKv7KRF9sxO1eLixfzHwWKiAhrtFBoHSM4AwynrpAb0eMf +ObSIjXeBy93LhTluVOsD5J9iXA/SKYoXqt/tDMCHRdwpTsJNBa56GMkpFHHLo6oC +si20nmMXP949gpRIvrYsgYC8WObbi+RQEWDVutv7hVPCF0QvUHs= +-----END RSA PRIVATE KEY----- diff --git a/examples/remoteobjects/websockets/common/cert/readme b/examples/remoteobjects/websockets/common/cert/readme new file mode 100644 index 0000000..1386169 --- /dev/null +++ b/examples/remoteobjects/websockets/common/cert/readme @@ -0,0 +1,2 @@ +These files are generated by the script located at tests/auto/external_IODevice/cert/generate.sh + diff --git a/examples/remoteobjects/websockets/common/cert/rootCA.key b/examples/remoteobjects/websockets/common/cert/rootCA.key new file mode 100644 index 0000000..1647817 --- /dev/null +++ b/examples/remoteobjects/websockets/common/cert/rootCA.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAulVnnHwRF6e2aAThSi1cZpUlO3ZdqzPIuf75NBbRY2y9Vm+F +cyCqUquNxP/qDE02nfQFBd/PUKqUWQs0EXVEVZPEG6s/l7ionYHkMmWSjh+AAWp7 +Iwx3MlHFNi9c5Xrod7iS1igg0YhDQlnT0xGfTXZasUJ/s6NuNoZiN5L6sEKYDSAu +kzyyqS23WrqE4RvsGAaoaaJqu1MT8DBqI9xoPpIvwb/4gdOZn4YClW2WWrVjCTT2 +zEzUAh1BjdH3dktXogiFfXHuOP4W8suOx46NXDcZ3f5LF8CT/2uq9l8vta+pV2ci +BAIctGu5z+fEdTCojvCWOvCzYmjtep/yTukT+QIDAQABAoIBAQCRvRjkCRnpUZDW +vPJk7SO3THIplwPeUwtthqLtfedaB4PzphhPmr39GRcyfSNXadENK/39wTbKlhCf +sKaR/RFsib26EnATwCeJwj10uYMuTC73bIxRNn/ISLKiFdtn1YEbmq6meA5rNFO/ +Arkt/juF/8shl6yAGZSrauJJK1mOH8ItMaGR+6tVPWLIZOLk6TiOJhj9SXvMTCw/ +HzgNZMgFGfqnbctg1ki/CY0BkIkYNUTCjhoCwjcgBJl4ERCfTQS6UeEG9Ad+beIH +g8WKzpfjF5+Jnjzqw87aWx1200OdlEdouTt677RXHJFN5naUc+GJZGpmA3RGZA17 +LqA4zBYNAoGBAOGwtg7JQkBOmUC0SiKdXnxG1hVnS4N3DMIDVX2tAe/wWIrP168e +0UpCvswLD+JqO1IgWqw9+QUPnhJSQ9JbYB+678esOTLsT5Yd18VcsiRxSacvQfUw +H4YJaHrFuuFlnxYMlMdPYS3knbIPsft9DVQLFBLL7qPVHbrJ3V6Sn4XrAoGBANNb +mfhgVr5m0n3sQVTlYhWwbJq5K+Htzzl7Xl3JHpMLm2C/GoorP/2zLVhbH20lsE3A +FyIfjcwRxGRu2TXCVnMc4GttlMX5leTxykEd2VrZuEVnTdrudm45Z6sZQpdf1QTg +WebwKgN1eCg7Jkuk5YlRX/KwMtuq4MVzPtOvR+CrAoGAA8uC5DDCKm6n6QyfCoH2 +6sQOKYH5JRbFYiXINDrKg4xZEMx55fnwrvz8VFYDSF1c7f6ZR7grDci7cbdsaIcc +0KvGCGd+9ro+hFmwHSN342D8ShFjXIoYnZpe5WGZyNx6llZT0h4lli338NyOs5ng +tX8SMVa4hoy42UE3tbVldU0CgYA0l/K0b6SmNIfkdcm8Cmhh5UjhJ3rX+Yk7UIum +4skM5jJ/3I4KG8EMrG14MxSa4GoCru4Su69ZPIKWS08ZpYZFlsXxdY8zxGucUN53 +XaochVjpTE9/Tx+BRh+Z3+tGJ76mO/2jDdgmjDCeMjnRUPMdPHaXuWiuaNMNzyOv +IUrNiQKBgGvxEQ0Oe3d/om2Lp/cHbkhZkw/jO/FG5HtodxiO3+1YLhExsDOc5GVn ++x2eNv+dQSIrGagko9TJe1p9WqFnD19Ls+ezqfw2fR5Amg1KHKGUA7k1+Qe/QgoK +D+T4/RkvdGRoBv/il+Rj1rfmMAhEzdD7Axek9a6rUj8geO22kp7I +-----END RSA PRIVATE KEY----- diff --git a/examples/remoteobjects/websockets/common/cert/rootCA.pem b/examples/remoteobjects/websockets/common/cert/rootCA.pem new file mode 100644 index 0000000..7f6cce5 --- /dev/null +++ b/examples/remoteobjects/websockets/common/cert/rootCA.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDBTCCAe2gAwIBAgIUV9eILCYaC+qwZHR7OO23uyd2UjwwDQYJKoZIhvcNAQEL +BQAwEjEQMA4GA1UEAwwHUXRSTyBDQTAeFw0yMTAyMjQxMTMzNTVaFw0yMzA2MTAx +MTMzNTVaMBIxEDAOBgNVBAMMB1F0Uk8gQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQC6VWecfBEXp7ZoBOFKLVxmlSU7dl2rM8i5/vk0FtFjbL1Wb4Vz +IKpSq43E/+oMTTad9AUF389QqpRZCzQRdURVk8Qbqz+XuKidgeQyZZKOH4ABansj +DHcyUcU2L1zleuh3uJLWKCDRiENCWdPTEZ9NdlqxQn+zo242hmI3kvqwQpgNIC6T +PLKpLbdauoThG+wYBqhpomq7UxPwMGoj3Gg+ki/Bv/iB05mfhgKVbZZatWMJNPbM +TNQCHUGN0fd2S1eiCIV9ce44/hbyy47Hjo1cNxnd/ksXwJP/a6r2Xy+1r6lXZyIE +Ahy0a7nP58R1MKiO8JY68LNiaO16n/JO6RP5AgMBAAGjUzBRMB0GA1UdDgQWBBSu +ehS/XLejTiDbCddGU2mMZ1t3CjAfBgNVHSMEGDAWgBSuehS/XLejTiDbCddGU2mM +Z1t3CjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB8JzSuhHPK +cjhLqOHUGMKtKWOd5p9g2D45cAWh6jdzU/AhmslMPbsO5hZkqfE+3xARtcMmQfF2 +k1Qyp3hDTN1ZqHSM6Urq9uR33/wXZbNRUNCD8lAmqKyzF9NF7Q+tmC//IMRtVQhK +aMN3LciyYGQjT0XhDKFWEz9/AvUQD97mLow2m0/izqE4SI6ekQDNL26IiCWFgFjh +ScZjcJ1ogluD2a6sEUGywRXLNV/bdSjRgkAbpvJFrok7dDZ8xCNhOg4xJJQJRWm7 +ZusUydiVyfgrFan6MD+EdldRHjAs8S9BJfZ0RTOWnD9V8auKuVomzKDed54QlXXi +zwowb3Objpqh +-----END CERTIFICATE----- diff --git a/examples/remoteobjects/websockets/common/cert/rootCA.srl b/examples/remoteobjects/websockets/common/cert/rootCA.srl new file mode 100644 index 0000000..d292c9f --- /dev/null +++ b/examples/remoteobjects/websockets/common/cert/rootCA.srl @@ -0,0 +1 @@ +7390820BD47F5A3C7398B7C8DCA218B35C2C2E29 diff --git a/examples/remoteobjects/websockets/common/cert/server.crt b/examples/remoteobjects/websockets/common/cert/server.crt new file mode 100644 index 0000000..df9d55c --- /dev/null +++ b/examples/remoteobjects/websockets/common/cert/server.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDFTCCAf2gAwIBAgIUc5CCC9R/WjxzmLfI3KIYs1wsLigwDQYJKoZIhvcNAQEL +BQAwEjEQMA4GA1UEAwwHUXRSTyBDQTAeFw0yMTAyMjQxMTMzNTVaFw0yMzA1MzAx +MTMzNTVaMBQxEjAQBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAOKHte9tB66OD+Um/WkqxHtW3sKrBs4IxKuWAef0UMRt3ld6 +5HvWk+xsCZdPxeL53nMOIy9FS6wKGvEWTwYRR4Id9iX2XQsI4cRJWl25qgCYohnm +Eet9CUkXa3ywbyrSBWFD0r956sS+mwhHU9z05jphd6iZEonHu2b4BFFXMN7+prwj +00EtGbte5wSWWE9ZfXzeGYd4cZBReNCRjaS5XJ3IgjZ4tfxsB3JzBjVafCfnth7r +Is8a2SKCGnhYmV+A6Agth4xtSKDho+BSDYSuMux3dftM/eqtxF0wXzlnX5ApNwGB +zWjcoUL63vjjy17oNEtbs5X2e1g8bGRaGRxGUHUCAwEAAaNhMF8wHwYDVR0jBBgw +FoAUrnoUv1y3o04g2wnXRlNpjGdbdwowCQYDVR0TBAIwADALBgNVHQ8EBAMCBPAw +EwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0B +AQsFAAOCAQEAqhBhxRgG9N1ZghwWC3ZhWSx4BFl3YrStWlQcjffcQ6p8NDxsrkFc +gMG51TmJdaz8J4v2AZW8k9GJlEIaZdV/8czeyEwvjKD4vrUw88waeW7n6o8H+8k+ +ak9fRFvnerFrLEWNpyRqbjJWwm8bQ4T5UKsVNXkZnNLyG2Ha29L9gUHffgSMiyLO +hWqcanPxsMJaDVhw/Gd8JwqaEC1nRPCGxhog2/D2sh4vCj1UykykjPwNz5fP/vfA +VujNCA23eXAdgD3lALHu2WrmyPkQCM7Z61g4k8+v0KjhyJjdLSVTwkPePEo87Fv4 +sn4Jp5gPPBf7jDFKp8PDdbPmk0qN+Wm8gA== +-----END CERTIFICATE----- diff --git a/examples/remoteobjects/websockets/common/cert/server.key b/examples/remoteobjects/websockets/common/cert/server.key new file mode 100644 index 0000000..05144f4 --- /dev/null +++ b/examples/remoteobjects/websockets/common/cert/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEA4oe1720Hro4P5Sb9aSrEe1bewqsGzgjEq5YB5/RQxG3eV3rk +e9aT7GwJl0/F4vnecw4jL0VLrAoa8RZPBhFHgh32JfZdCwjhxElaXbmqAJiiGeYR +630JSRdrfLBvKtIFYUPSv3nqxL6bCEdT3PTmOmF3qJkSice7ZvgEUVcw3v6mvCPT +QS0Zu17nBJZYT1l9fN4Zh3hxkFF40JGNpLlcnciCNni1/GwHcnMGNVp8J+e2Husi +zxrZIoIaeFiZX4DoCC2HjG1IoOGj4FINhK4y7Hd1+0z96q3EXTBfOWdfkCk3AYHN +aNyhQvre+OPLXug0S1uzlfZ7WDxsZFoZHEZQdQIDAQABAoIBAGuKEYzALc1oE5Ot +ls++RdhnvQidOHXHI9ZxOCZtjYoyvkK5TI6dp0utXkA+1qqSBFCKfZmLRAlAItog +xRMUUOYsYxZShokehk8wo32rDlGKJCo3Vnp8uVPBkn13JM8nNPafxASyVAlikyay +9dUHTeSZML0RLgPKleSkCSi0Q7cYOFG/HB9aNjp8F5rdut02KrmC3cxlHKF7QXXG +VU+op1Z9o0V2/iUFJnF5CR40sW2THEbBJkkeYwbvUTnavz4XQtZst//DKsDQEe2r +UrhsIHduvG4tWiBE77m1vyigTxUWCsLQ2KCnn9O+4KyTg9HWCiQ2QSU3istX/rpI +zN2lOgECgYEA9PVVMnY+t59Q73IQ9LRg5KRqg6YyGQOrwJKbCUxDrA6ikh3MDgwV +CkC6Jdl6e4DMog51l3CizrfR2+mtNSTUJDGFE1iGgI+Faem4aopRtFRiLWJ8n4m7 +U8pl3XTP0XFT68aBCAE6O/xVPXs0I/eKNvaF5vokB5zm4R79o37WP+UCgYEA7L26 +TiCFA73Fil/bPupqWJnvm896RlO1S+IBOKlPyCHVvxiGLvtv+YTucCFwXQ4FeNRh +bQEWlURsgeNr7PHATtFUZ/zo/7l1WYNLXZDZwWD+JYllVPwskJOJMx5Rc77Q0aQ6 +7v60XMGwD5cxQ29RHuJs09Iwc9b1WqwOAEJAJVECgYBNsxQXMZKrRAm0KgZe2Ghz +ngN7RthVPujX6KjsxhghF3NRzcnQGt0Bp45kOxuy2SQPs25xXvUFhSE4FGMwnEH+ +SQbhIA9p8BxtgAlTIhTQkoOhyb+mC1Y0Odsd59OTp9Lq0shS9bC3Hk8bdV0Qm5Bn +5sKKhYWwNIC3n9Dsb2seUQKBgAS7biPtpnsCqhYwAFPrn6CRwyZcKVeKiM8xf1DA +oaWgd4NQXC5IPF7Cd3mqUXKquxVFOYVSRj9JlNmr0BZ2Zp+ss4E4nvetn1jgtPrz +0EZ7R9k8O9hNCh8Bs/ZfnsUvhUELhVoNoVFRVdGZ9hQg/4AcioxZYTqPi2v6kHUU +3e9hAoGAec7anF5TiTx2jjcDFS9hrRw0w2PsNX24qjqPFqeuzDIorh6rq4Ip4aA0 +7rxeIXmxjmYA7pPCT9rPxtpEp4BQovF9kHMutd8lyB4rGbLpNpOY4m5v8Oo7cLQ3 +kLAwE+jrEwLNtuq+kUlGwK7YLeiGUm4Rsof5IXlSkXzL/99gHC4= +-----END RSA PRIVATE KEY----- diff --git a/examples/remoteobjects/websockets/common/common.pri b/examples/remoteobjects/websockets/common/common.pri new file mode 100644 index 0000000..4ee7eef --- /dev/null +++ b/examples/remoteobjects/websockets/common/common.pri @@ -0,0 +1,11 @@ +CONFIG -= app_bundle + +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/websocketiodevice.h + +SOURCES += \ + $$PWD/websocketiodevice.cpp + +RESOURCES += $$PWD/cert/cert.qrc diff --git a/examples/remoteobjects/websockets/common/websocketiodevice.cpp b/examples/remoteobjects/websockets/common/websocketiodevice.cpp new file mode 100644 index 0000000..39cb4eb --- /dev/null +++ b/examples/remoteobjects/websockets/common/websocketiodevice.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "websocketiodevice.h" + +#include + +WebSocketIoDevice::WebSocketIoDevice(QWebSocket *webSocket, QObject *parent) + : QIODevice(parent) + , m_socket(webSocket) +{ + open(QIODevice::ReadWrite); + connect(webSocket, &QWebSocket::disconnected, this, &WebSocketIoDevice::disconnected); + connect(webSocket, &QWebSocket::binaryMessageReceived, this, [this](const QByteArray &message){ + m_buffer.append(message); + emit readyRead(); + }); + connect(webSocket, &QWebSocket::bytesWritten, this, &WebSocketIoDevice::bytesWritten); +} + +qint64 WebSocketIoDevice::bytesAvailable() const +{ + return QIODevice::bytesAvailable() + m_buffer.size(); +} + +bool WebSocketIoDevice::isSequential() const +{ + return true; +} + +void WebSocketIoDevice::close() +{ + if (m_socket) + m_socket->close(); +} + +qint64 WebSocketIoDevice::readData(char *data, qint64 maxlen) +{ + auto sz = std::min(maxlen, qint64(m_buffer.size())); + if (sz <= 0) + return sz; + memcpy(data, m_buffer.constData(), size_t(sz)); + m_buffer.remove(0, sz); + return sz; +} + +qint64 WebSocketIoDevice::writeData(const char *data, qint64 len) +{ + if (m_socket) + return m_socket->sendBinaryMessage(QByteArray{data, int(len)}); + return -1; +} diff --git a/examples/remoteobjects/websockets/common/websocketiodevice.h b/examples/remoteobjects/websockets/common/websocketiodevice.h new file mode 100644 index 0000000..0e5609c --- /dev/null +++ b/examples/remoteobjects/websockets/common/websocketiodevice.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WEBSOCKETIODEVICE_H +#define WEBSOCKETIODEVICE_H + +#include +#include +#include + +class QWebSocket; + +class WebSocketIoDevice : public QIODevice +{ + Q_OBJECT +public: + WebSocketIoDevice(QWebSocket *webSocket, QObject *parent = nullptr); + +signals: + void disconnected(); + + // QIODevice interface +public: + qint64 bytesAvailable() const override; + bool isSequential() const override; + void close() override; + +protected: + qint64 readData(char *data, qint64 maxlen) override; + qint64 writeData(const char *data, qint64 len) override; + +private: + QPointer m_socket; + QByteArray m_buffer; +}; + +#endif // WEBSOCKETIODEVICE_H diff --git a/examples/remoteobjects/websockets/doc/src/websocket.qdoc b/examples/remoteobjects/websockets/doc/src/websocket.qdoc new file mode 100644 index 0000000..3db2e3c --- /dev/null +++ b/examples/remoteobjects/websockets/doc/src/websocket.qdoc @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example websockets + \title QtRemoteObjects WebSockets Example + + This example shows how you could use a non-QIODevice-based transport + (QWebSocket) with QtRemoteObjects. This is achieved by implementing a + small QIODevice-derived wrapper for QWebSocket. +*/ diff --git a/examples/remoteobjects/websockets/websockets.pro b/examples/remoteobjects/websockets/websockets.pro new file mode 100644 index 0000000..bb2685a --- /dev/null +++ b/examples/remoteobjects/websockets/websockets.pro @@ -0,0 +1,7 @@ +TEMPLATE = subdirs + +qtHaveModule(widgets): qtHaveModule(websockets) { + SUBDIRS += \ + wsclient \ + wsserver +} diff --git a/examples/remoteobjects/websockets/wsclient/CMakeLists.txt b/examples/remoteobjects/websockets/wsclient/CMakeLists.txt new file mode 100644 index 0000000..fb121be --- /dev/null +++ b/examples/remoteobjects/websockets/wsclient/CMakeLists.txt @@ -0,0 +1,60 @@ +cmake_minimum_required(VERSION 3.16) +project(wsclient LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/websockets/wsclient") + +find_package(Qt6 REQUIRED COMPONENTS Core Gui RemoteObjects WebSockets Widgets) + +qt_add_executable(wsclient + ../common/websocketiodevice.cpp ../common/websocketiodevice.h + main.cpp +) + +set_target_properties(wsclient PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE FALSE +) + +target_include_directories(wsclient PUBLIC + ../common +) + +target_link_libraries(wsclient PUBLIC + Qt::Core + Qt::Gui + Qt::RemoteObjects + Qt::WebSockets + Qt::Widgets +) + +# Resources: +set(cert_resource_files + "../common/cert/client.crt" + "../common/cert/client.key" + "../common/cert/rootCA.key" + "../common/cert/rootCA.pem" + "../common/cert/rootCA.srl" + "../common/cert/server.crt" + "../common/cert/server.key" +) + +qt6_add_resources(wsclient "cert" + PREFIX + "/sslcert" + BASE + "../common/cert" + FILES + ${cert_resource_files} +) + +install(TARGETS wsclient + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/remoteobjects/websockets/wsclient/main.cpp b/examples/remoteobjects/websockets/wsclient/main.cpp new file mode 100644 index 0000000..19b7672 --- /dev/null +++ b/examples/remoteobjects/websockets/wsclient/main.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +#ifndef QT_NO_SSL +# include +# include +# include +#endif +#include "websocketiodevice.h" + +int main(int argc, char **argv) +{ + + QLoggingCategory::setFilterRules("qt.remoteobjects.debug=false\n" + "qt.remoteobjects.warning=false\n" + "qt.remoteobjects.models.debug=false\n" + "qt.remoteobjects.models.debug=false"); + + QApplication app(argc, argv); + + + + QScopedPointer webSocket{new QWebSocket}; + WebSocketIoDevice socket(webSocket.data()); +#ifndef QT_NO_SSL + // Always use secure connections when available + QSslConfiguration sslConf; + QFile certFile(QStringLiteral(":/sslcert/client.crt")); + if (!certFile.open(QIODevice::ReadOnly)) + qFatal("Can't open client.crt file"); + sslConf.setLocalCertificate(QSslCertificate{certFile.readAll()}); + + QFile keyFile(QStringLiteral(":/sslcert/client.key")); + if (!keyFile.open(QIODevice::ReadOnly)) + qFatal("Can't open client.key file"); + sslConf.setPrivateKey(QSslKey{keyFile.readAll(), QSsl::Rsa}); + + sslConf.setPeerVerifyMode(QSslSocket::VerifyPeer); + webSocket->setSslConfiguration(sslConf); +#endif + QRemoteObjectNode node; + node.addClientSideConnection(&socket); + node.setHeartbeatInterval(1000); + webSocket->open(QStringLiteral("ws://localhost:8088")); + + QTreeView view; + view.setWindowTitle(QStringLiteral("RemoteView")); + view.resize(640,480); + QScopedPointer model(node.acquireModel(QStringLiteral("RemoteModel"))); + view.setModel(model.data()); + view.show(); + + return app.exec(); +} diff --git a/examples/remoteobjects/websockets/wsclient/wsclient.pro b/examples/remoteobjects/websockets/wsclient/wsclient.pro new file mode 100644 index 0000000..f329e4a --- /dev/null +++ b/examples/remoteobjects/websockets/wsclient/wsclient.pro @@ -0,0 +1,9 @@ +QT += widgets remoteobjects websockets +requires(qtConfig(treeview)) + +SOURCES += main.cpp + +include(../common/common.pri) + +target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/websockets/wsclient +INSTALLS += target diff --git a/examples/remoteobjects/websockets/wsserver/CMakeLists.txt b/examples/remoteobjects/websockets/wsserver/CMakeLists.txt new file mode 100644 index 0000000..34e53b3 --- /dev/null +++ b/examples/remoteobjects/websockets/wsserver/CMakeLists.txt @@ -0,0 +1,60 @@ +cmake_minimum_required(VERSION 3.16) +project(wsserver LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/websockets/wsserver") + +find_package(Qt6 REQUIRED COMPONENTS Core Gui RemoteObjects WebSockets Widgets) + +qt_add_executable(wsserver + ../common/websocketiodevice.cpp ../common/websocketiodevice.h + main.cpp +) + +set_target_properties(wsserver PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE FALSE +) + +target_include_directories(wsserver PUBLIC + ../common +) + +target_link_libraries(wsserver PUBLIC + Qt::Core + Qt::Gui + Qt::RemoteObjects + Qt::WebSockets + Qt::Widgets +) + +# Resources: +set(cert_resource_files + "../common/cert/client.crt" + "../common/cert/client.key" + "../common/cert/rootCA.key" + "../common/cert/rootCA.pem" + "../common/cert/rootCA.srl" + "../common/cert/server.crt" + "../common/cert/server.key" +) + +qt6_add_resources(wsserver "cert" + PREFIX + "/sslcert" + BASE + "../common/cert" + FILES + ${cert_resource_files} +) + +install(TARGETS wsserver + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/remoteobjects/websockets/wsserver/main.cpp b/examples/remoteobjects/websockets/wsserver/main.cpp new file mode 100644 index 0000000..391e1b7 --- /dev/null +++ b/examples/remoteobjects/websockets/wsserver/main.cpp @@ -0,0 +1,207 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef QT_NO_SSL +# include +# include +# include +#endif + +#include "websocketiodevice.h" + +struct TimerHandler : public QObject +{ + Q_OBJECT +public: + QStandardItemModel *model; +public Q_SLOTS: + void changeData() { + Q_ASSERT(model); + Q_ASSERT(model->rowCount() > 50); + Q_ASSERT(model->columnCount() > 1); + for (int i = 10; i < 50; ++i) + model->setData(model->index(i, 1), QColor(Qt::blue), Qt::BackgroundRole); + } + void insertData() { + Q_ASSERT(model); + Q_ASSERT(model->rowCount() > 50); + Q_ASSERT(model->columnCount() > 1); + model->insertRows(2, 9); + for (int i = 2; i < 11; ++i) { + model->setData(model->index(i, 1), QColor(Qt::green), Qt::BackgroundRole); + model->setData(model->index(i, 1), QLatin1String("InsertedRow"), Qt::DisplayRole); + } + } + void removeData() { + model->removeRows(2, 4); + } + + void changeFlags() { + QStandardItem *item = model->item(0, 0); + item->setEnabled(false); + item = item->child(0, 0); + item->setFlags(item->flags() & Qt::ItemIsSelectable); + } + + void moveData() { + model->moveRows(QModelIndex(), 2, 4, QModelIndex(), 10); + } +}; + +QList addChild(int numChildren, int nestingLevel) +{ + QList result; + if (nestingLevel == 0) + return result; + for (int i = 0; i < numChildren; ++i) { + QStandardItem *child = new QStandardItem(QStringLiteral("Child num %1, nesting Level %2").arg(i+1).arg(nestingLevel)); + if (i == 0) + child->appendRow(addChild(numChildren, nestingLevel -1)); + result.push_back(child); + } + return result; +} + +int main(int argc, char *argv[]) +{ + QLoggingCategory::setFilterRules("qt.remoteobjects.debug=false\n" + "qt.remoteobjects.warning=false"); + QApplication app(argc, argv); + + const int modelSize = 100000; + QStringList list; + QStandardItemModel sourceModel; + QStringList hHeaderList; + hHeaderList << QStringLiteral("First Column with spacing") << QStringLiteral("Second Column with spacing"); + sourceModel.setHorizontalHeaderLabels(hHeaderList); + list.reserve(modelSize); + for (int i = 0; i < modelSize; ++i) { + QStandardItem *firstItem = new QStandardItem(QStringLiteral("FancyTextNumber %1").arg(i)); + if (i == 0) + firstItem->appendRow(addChild(2, 2)); + QStandardItem *secondItem = new QStandardItem(QStringLiteral("FancyRow2TextNumber %1").arg(i)); + if (i % 2 == 0) + firstItem->setBackground(Qt::red); + QList row; + row << firstItem << secondItem; + sourceModel.invisibleRootItem()->appendRow(row); + //sourceModel.appendRow(row); + list << QStringLiteral("FancyTextNumber %1").arg(i); + } + + // Needed by QMLModelViewClient + QHash roleNames = { + {Qt::DisplayRole, "_text"}, + {Qt::BackgroundRole, "_color"} + }; + sourceModel.setItemRoleNames(roleNames); + + QList roles; + roles << Qt::DisplayRole << Qt::BackgroundRole; + + QWebSocketServer webSockServer{QStringLiteral("WS QtRO"), QWebSocketServer::NonSecureMode}; + webSockServer.listen(QHostAddress::Any, 8088); + + QRemoteObjectHost hostNode; + hostNode.setHostUrl(webSockServer.serverAddress().toString(), QRemoteObjectHost::AllowExternalRegistration); + + hostNode.enableRemoting(&sourceModel, QStringLiteral("RemoteModel"), roles); + + QObject::connect(&webSockServer, &QWebSocketServer::newConnection, &hostNode, [&hostNode, &webSockServer]{ + while (auto conn = webSockServer.nextPendingConnection()) { +#ifndef QT_NO_SSL + // Always use secure connections when available + QSslConfiguration sslConf; + QFile certFile(QStringLiteral(":/sslcert/server.crt")); + if (!certFile.open(QIODevice::ReadOnly)) + qFatal("Can't open client.crt file"); + sslConf.setLocalCertificate(QSslCertificate{certFile.readAll()}); + + QFile keyFile(QStringLiteral(":/sslcert/server.key")); + if (!keyFile.open(QIODevice::ReadOnly)) + qFatal("Can't open client.key file"); + sslConf.setPrivateKey(QSslKey{keyFile.readAll(), QSsl::Rsa}); + + sslConf.setPeerVerifyMode(QSslSocket::VerifyPeer); + conn->setSslConfiguration(sslConf); + QObject::connect(conn, &QWebSocket::sslErrors, conn, &QWebSocket::deleteLater); +#endif + QObject::connect(conn, &QWebSocket::disconnected, conn, &QWebSocket::deleteLater); + QObject::connect(conn, QOverload::of(&QWebSocket::error), conn, &QWebSocket::deleteLater); + auto ioDevice = new WebSocketIoDevice(conn); + QObject::connect(conn, &QWebSocket::destroyed, ioDevice, &WebSocketIoDevice::deleteLater); + hostNode.addHostSideConnection(ioDevice); + } + }); + + QTreeView view; + view.setWindowTitle(QStringLiteral("SourceView")); + view.setModel(&sourceModel); + view.show(); + TimerHandler handler; + handler.model = &sourceModel; + QTimer::singleShot(5000, &handler, &TimerHandler::changeData); + QTimer::singleShot(10000, &handler, &TimerHandler::insertData); + QTimer::singleShot(11000, &handler, &TimerHandler::changeFlags); + QTimer::singleShot(12000, &handler, &TimerHandler::removeData); + QTimer::singleShot(13000, &handler, &TimerHandler::moveData); + + return app.exec(); +} + +#include "main.moc" diff --git a/examples/remoteobjects/websockets/wsserver/wsserver.pro b/examples/remoteobjects/websockets/wsserver/wsserver.pro new file mode 100644 index 0000000..e892091 --- /dev/null +++ b/examples/remoteobjects/websockets/wsserver/wsserver.pro @@ -0,0 +1,9 @@ +QT += widgets remoteobjects websockets +requires(qtConfig(treeview)) + +SOURCES += main.cpp + +include(../common/common.pri) + +target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/websockets/wsserver +INSTALLS += target diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_local_backend_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_local_backend_p.h new file mode 100644 index 0000000..a056f08 --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_local_backend_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qconnection_local_backend_p.h" diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_qnx_backend_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_qnx_backend_p.h new file mode 100644 index 0000000..3d676da --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_qnx_backend_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qconnection_qnx_backend_p.h" diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_qnx_global_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_qnx_global_p.h new file mode 100644 index 0000000..b1df3a5 --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_qnx_global_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qconnection_qnx_global_p.h" diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_qnx_qiodevices_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_qnx_qiodevices_p.h new file mode 100644 index 0000000..fb61d2b --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_qnx_qiodevices_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qconnection_qnx_qiodevices_p.h" diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_qnx_server_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_qnx_server_p.h new file mode 100644 index 0000000..c9c4733 --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_qnx_server_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qconnection_qnx_server_p.h" diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_tcpip_backend_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_tcpip_backend_p.h new file mode 100644 index 0000000..5b920f2 --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnection_tcpip_backend_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qconnection_tcpip_backend_p.h" diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnectionfactories_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnectionfactories_p.h new file mode 100644 index 0000000..501d938 --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qconnectionfactories_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qconnectionfactories_p.h" diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectabstractitemmodeladapter_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectabstractitemmodeladapter_p.h new file mode 100644 index 0000000..e9c8964 --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectabstractitemmodeladapter_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qremoteobjectabstractitemmodeladapter_p.h" diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectabstractitemmodelreplica_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectabstractitemmodelreplica_p.h new file mode 100644 index 0000000..64da33f --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectabstractitemmodelreplica_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qremoteobjectabstractitemmodelreplica_p.h" diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectabstractitemmodeltypes_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectabstractitemmodeltypes_p.h new file mode 100644 index 0000000..646a4bc --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectabstractitemmodeltypes_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qremoteobjectabstractitemmodeltypes_p.h" diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectcontainers_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectcontainers_p.h new file mode 100644 index 0000000..8d637d5 --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectcontainers_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qremoteobjectcontainers_p.h" diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectnode_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectnode_p.h new file mode 100644 index 0000000..be73dae --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectnode_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qremoteobjectnode_p.h" diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectpacket_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectpacket_p.h new file mode 100644 index 0000000..bdad605 --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectpacket_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qremoteobjectpacket_p.h" diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectpendingcall_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectpendingcall_p.h new file mode 100644 index 0000000..7c2b703 --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectpendingcall_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qremoteobjectpendingcall_p.h" diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectregistrysource_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectregistrysource_p.h new file mode 100644 index 0000000..bb6f128 --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectregistrysource_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qremoteobjectregistrysource_p.h" diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectreplica_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectreplica_p.h new file mode 100644 index 0000000..f457bca --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectreplica_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qremoteobjectreplica_p.h" diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectsource_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectsource_p.h new file mode 100644 index 0000000..b7e50ab --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectsource_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qremoteobjectsource_p.h" diff --git a/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectsourceio_p.h b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectsourceio_p.h new file mode 100644 index 0000000..20eeb5e --- /dev/null +++ b/include/QtRemoteObjects/6.3.1/QtRemoteObjects/private/qremoteobjectsourceio_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjects/qremoteobjectsourceio_p.h" diff --git a/include/QtRemoteObjects/QAbstractItemModelReplica b/include/QtRemoteObjects/QAbstractItemModelReplica new file mode 100644 index 0000000..790a361 --- /dev/null +++ b/include/QtRemoteObjects/QAbstractItemModelReplica @@ -0,0 +1 @@ +#include "qremoteobjectabstractitemmodelreplica.h" diff --git a/include/QtRemoteObjects/QConnectionAbstractServer b/include/QtRemoteObjects/QConnectionAbstractServer new file mode 100644 index 0000000..9306cd4 --- /dev/null +++ b/include/QtRemoteObjects/QConnectionAbstractServer @@ -0,0 +1 @@ +#include "qconnectionfactories.h" diff --git a/include/QtRemoteObjects/QIOQnxSource b/include/QtRemoteObjects/QIOQnxSource new file mode 100644 index 0000000..bd609a9 --- /dev/null +++ b/include/QtRemoteObjects/QIOQnxSource @@ -0,0 +1 @@ +#include "qconnection_qnx_qiodevices.h" diff --git a/include/QtRemoteObjects/QIntHash b/include/QtRemoteObjects/QIntHash new file mode 100644 index 0000000..46b3e1b --- /dev/null +++ b/include/QtRemoteObjects/QIntHash @@ -0,0 +1 @@ +#include "qtremoteobjectglobal.h" diff --git a/include/QtRemoteObjects/QQnxNativeIo b/include/QtRemoteObjects/QQnxNativeIo new file mode 100644 index 0000000..bd609a9 --- /dev/null +++ b/include/QtRemoteObjects/QQnxNativeIo @@ -0,0 +1 @@ +#include "qconnection_qnx_qiodevices.h" diff --git a/include/QtRemoteObjects/QQnxNativeServer b/include/QtRemoteObjects/QQnxNativeServer new file mode 100644 index 0000000..ee615ae --- /dev/null +++ b/include/QtRemoteObjects/QQnxNativeServer @@ -0,0 +1 @@ +#include "qconnection_qnx_server.h" diff --git a/include/QtRemoteObjects/QRemoteObjectAbstractPersistedStore b/include/QtRemoteObjects/QRemoteObjectAbstractPersistedStore new file mode 100644 index 0000000..789612f --- /dev/null +++ b/include/QtRemoteObjects/QRemoteObjectAbstractPersistedStore @@ -0,0 +1 @@ +#include "qremoteobjectnode.h" diff --git a/include/QtRemoteObjects/QRemoteObjectDynamicReplica b/include/QtRemoteObjects/QRemoteObjectDynamicReplica new file mode 100644 index 0000000..3c8ac01 --- /dev/null +++ b/include/QtRemoteObjects/QRemoteObjectDynamicReplica @@ -0,0 +1 @@ +#include "qremoteobjectdynamicreplica.h" diff --git a/include/QtRemoteObjects/QRemoteObjectHost b/include/QtRemoteObjects/QRemoteObjectHost new file mode 100644 index 0000000..789612f --- /dev/null +++ b/include/QtRemoteObjects/QRemoteObjectHost @@ -0,0 +1 @@ +#include "qremoteobjectnode.h" diff --git a/include/QtRemoteObjects/QRemoteObjectHostBase b/include/QtRemoteObjects/QRemoteObjectHostBase new file mode 100644 index 0000000..789612f --- /dev/null +++ b/include/QtRemoteObjects/QRemoteObjectHostBase @@ -0,0 +1 @@ +#include "qremoteobjectnode.h" diff --git a/include/QtRemoteObjects/QRemoteObjectNode b/include/QtRemoteObjects/QRemoteObjectNode new file mode 100644 index 0000000..789612f --- /dev/null +++ b/include/QtRemoteObjects/QRemoteObjectNode @@ -0,0 +1 @@ +#include "qremoteobjectnode.h" diff --git a/include/QtRemoteObjects/QRemoteObjectPendingCall b/include/QtRemoteObjects/QRemoteObjectPendingCall new file mode 100644 index 0000000..c2db880 --- /dev/null +++ b/include/QtRemoteObjects/QRemoteObjectPendingCall @@ -0,0 +1 @@ +#include "qremoteobjectpendingcall.h" diff --git a/include/QtRemoteObjects/QRemoteObjectPendingCallWatcher b/include/QtRemoteObjects/QRemoteObjectPendingCallWatcher new file mode 100644 index 0000000..c2db880 --- /dev/null +++ b/include/QtRemoteObjects/QRemoteObjectPendingCallWatcher @@ -0,0 +1 @@ +#include "qremoteobjectpendingcall.h" diff --git a/include/QtRemoteObjects/QRemoteObjectPendingReply b/include/QtRemoteObjects/QRemoteObjectPendingReply new file mode 100644 index 0000000..c2db880 --- /dev/null +++ b/include/QtRemoteObjects/QRemoteObjectPendingReply @@ -0,0 +1 @@ +#include "qremoteobjectpendingcall.h" diff --git a/include/QtRemoteObjects/QRemoteObjectRegistry b/include/QtRemoteObjects/QRemoteObjectRegistry new file mode 100644 index 0000000..5a3cc82 --- /dev/null +++ b/include/QtRemoteObjects/QRemoteObjectRegistry @@ -0,0 +1 @@ +#include "qremoteobjectregistry.h" diff --git a/include/QtRemoteObjects/QRemoteObjectRegistryHost b/include/QtRemoteObjects/QRemoteObjectRegistryHost new file mode 100644 index 0000000..789612f --- /dev/null +++ b/include/QtRemoteObjects/QRemoteObjectRegistryHost @@ -0,0 +1 @@ +#include "qremoteobjectnode.h" diff --git a/include/QtRemoteObjects/QRemoteObjectReplica b/include/QtRemoteObjects/QRemoteObjectReplica new file mode 100644 index 0000000..62475a9 --- /dev/null +++ b/include/QtRemoteObjects/QRemoteObjectReplica @@ -0,0 +1 @@ +#include "qremoteobjectreplica.h" diff --git a/include/QtRemoteObjects/QRemoteObjectSettingsStore b/include/QtRemoteObjects/QRemoteObjectSettingsStore new file mode 100644 index 0000000..6a38595 --- /dev/null +++ b/include/QtRemoteObjects/QRemoteObjectSettingsStore @@ -0,0 +1 @@ +#include "qremoteobjectsettingsstore.h" diff --git a/include/QtRemoteObjects/QRemoteObjectSourceLocation b/include/QtRemoteObjects/QRemoteObjectSourceLocation new file mode 100644 index 0000000..46b3e1b --- /dev/null +++ b/include/QtRemoteObjects/QRemoteObjectSourceLocation @@ -0,0 +1 @@ +#include "qtremoteobjectglobal.h" diff --git a/include/QtRemoteObjects/QRemoteObjectSourceLocationInfo b/include/QtRemoteObjects/QRemoteObjectSourceLocationInfo new file mode 100644 index 0000000..46b3e1b --- /dev/null +++ b/include/QtRemoteObjects/QRemoteObjectSourceLocationInfo @@ -0,0 +1 @@ +#include "qtremoteobjectglobal.h" diff --git a/include/QtRemoteObjects/QRemoteObjectSourceLocations b/include/QtRemoteObjects/QRemoteObjectSourceLocations new file mode 100644 index 0000000..46b3e1b --- /dev/null +++ b/include/QtRemoteObjects/QRemoteObjectSourceLocations @@ -0,0 +1 @@ +#include "qtremoteobjectglobal.h" diff --git a/include/QtRemoteObjects/QtROClientFactory b/include/QtRemoteObjects/QtROClientFactory new file mode 100644 index 0000000..9306cd4 --- /dev/null +++ b/include/QtRemoteObjects/QtROClientFactory @@ -0,0 +1 @@ +#include "qconnectionfactories.h" diff --git a/include/QtRemoteObjects/QtROClientIoDevice b/include/QtRemoteObjects/QtROClientIoDevice new file mode 100644 index 0000000..9306cd4 --- /dev/null +++ b/include/QtRemoteObjects/QtROClientIoDevice @@ -0,0 +1 @@ +#include "qconnectionfactories.h" diff --git a/include/QtRemoteObjects/QtROIoDeviceBase b/include/QtRemoteObjects/QtROIoDeviceBase new file mode 100644 index 0000000..9306cd4 --- /dev/null +++ b/include/QtRemoteObjects/QtROIoDeviceBase @@ -0,0 +1 @@ +#include "qconnectionfactories.h" diff --git a/include/QtRemoteObjects/QtROServerFactory b/include/QtRemoteObjects/QtROServerFactory new file mode 100644 index 0000000..9306cd4 --- /dev/null +++ b/include/QtRemoteObjects/QtROServerFactory @@ -0,0 +1 @@ +#include "qconnectionfactories.h" diff --git a/include/QtRemoteObjects/QtROServerIoDevice b/include/QtRemoteObjects/QtROServerIoDevice new file mode 100644 index 0000000..9306cd4 --- /dev/null +++ b/include/QtRemoteObjects/QtROServerIoDevice @@ -0,0 +1 @@ +#include "qconnectionfactories.h" diff --git a/include/QtRemoteObjects/QtRemoteObjects b/include/QtRemoteObjects/QtRemoteObjects new file mode 100644 index 0000000..e5053ec --- /dev/null +++ b/include/QtRemoteObjects/QtRemoteObjects @@ -0,0 +1,15 @@ +#ifndef QT_QTREMOTEOBJECTS_MODULE_H +#define QT_QTREMOTEOBJECTS_MODULE_H +#include +#include "qtremoteobjectglobal.h" +#include "qconnectionfactories.h" +#include "qremoteobjectabstractitemmodelreplica.h" +#include "qremoteobjectdynamicreplica.h" +#include "qremoteobjectnode.h" +#include "qremoteobjectpendingcall.h" +#include "qremoteobjectregistry.h" +#include "qremoteobjectreplica.h" +#include "qremoteobjectsettingsstore.h" +#include "qremoteobjectsource.h" +#include "qtremoteobjectsversion.h" +#endif diff --git a/include/QtRemoteObjects/QtRemoteObjectsVersion b/include/QtRemoteObjects/QtRemoteObjectsVersion new file mode 100644 index 0000000..7cce23e --- /dev/null +++ b/include/QtRemoteObjects/QtRemoteObjectsVersion @@ -0,0 +1 @@ +#include "qtremoteobjectsversion.h" diff --git a/include/QtRemoteObjects/headers.pri b/include/QtRemoteObjects/headers.pri new file mode 100644 index 0000000..0da051c --- /dev/null +++ b/include/QtRemoteObjects/headers.pri @@ -0,0 +1,6 @@ +SYNCQT.HEADER_FILES = qconnection_qnx_qiodevices.h qconnection_qnx_server.h qconnectionfactories.h qremoteobjectabstractitemmodelreplica.h qremoteobjectdynamicreplica.h qremoteobjectnode.h qremoteobjectpendingcall.h qremoteobjectregistry.h qremoteobjectreplica.h qremoteobjectsettingsstore.h qremoteobjectsource.h qtremoteobjectglobal.h +SYNCQT.GENERATED_HEADER_FILES = QQnxNativeIo QIOQnxSource QQnxNativeServer QtROIoDeviceBase QtROServerIoDevice QConnectionAbstractServer QtROClientIoDevice QtROServerFactory QtROClientFactory QAbstractItemModelReplica QRemoteObjectDynamicReplica QRemoteObjectAbstractPersistedStore QRemoteObjectNode QRemoteObjectHostBase QRemoteObjectHost QRemoteObjectRegistryHost QRemoteObjectPendingCall QRemoteObjectPendingCallWatcher QRemoteObjectPendingReply QRemoteObjectRegistry QRemoteObjectReplica QRemoteObjectSettingsStore QRemoteObjectSourceLocationInfo QRemoteObjectSourceLocation QRemoteObjectSourceLocations QIntHash qtremoteobjectsversion.h QtRemoteObjectsVersion QtRemoteObjects +SYNCQT.PRIVATE_HEADER_FILES = qconnection_local_backend_p.h qconnection_qnx_backend_p.h qconnection_qnx_global_p.h qconnection_qnx_qiodevices_p.h qconnection_qnx_server_p.h qconnection_tcpip_backend_p.h qconnectionfactories_p.h qremoteobjectabstractitemmodeladapter_p.h qremoteobjectabstractitemmodelreplica_p.h qremoteobjectabstractitemmodeltypes_p.h qremoteobjectcontainers_p.h qremoteobjectnode_p.h qremoteobjectpacket_p.h qremoteobjectpendingcall_p.h qremoteobjectregistrysource_p.h qremoteobjectreplica_p.h qremoteobjectsource_p.h qremoteobjectsourceio_p.h +SYNCQT.QPA_HEADER_FILES = +SYNCQT.CLEAN_HEADER_FILES = qconnection_qnx_qiodevices.h qconnection_qnx_server.h qconnectionfactories.h qremoteobjectabstractitemmodelreplica.h qremoteobjectdynamicreplica.h qremoteobjectnode.h qremoteobjectpendingcall.h qremoteobjectregistry.h qremoteobjectreplica.h qremoteobjectsettingsstore.h qremoteobjectsource.h qtremoteobjectglobal.h +SYNCQT.INJECTIONS = diff --git a/include/QtRemoteObjects/qconnection_qnx_qiodevices.h b/include/QtRemoteObjects/qconnection_qnx_qiodevices.h new file mode 100644 index 0000000..8b42dad --- /dev/null +++ b/include/QtRemoteObjects/qconnection_qnx_qiodevices.h @@ -0,0 +1 @@ +#include "../../src/remoteobjects/qconnection_qnx_qiodevices.h" diff --git a/include/QtRemoteObjects/qconnection_qnx_server.h b/include/QtRemoteObjects/qconnection_qnx_server.h new file mode 100644 index 0000000..5a13ab4 --- /dev/null +++ b/include/QtRemoteObjects/qconnection_qnx_server.h @@ -0,0 +1 @@ +#include "../../src/remoteobjects/qconnection_qnx_server.h" diff --git a/include/QtRemoteObjects/qconnectionfactories.h b/include/QtRemoteObjects/qconnectionfactories.h new file mode 100644 index 0000000..e6e32f6 --- /dev/null +++ b/include/QtRemoteObjects/qconnectionfactories.h @@ -0,0 +1 @@ +#include "../../src/remoteobjects/qconnectionfactories.h" diff --git a/include/QtRemoteObjects/qremoteobjectabstractitemmodelreplica.h b/include/QtRemoteObjects/qremoteobjectabstractitemmodelreplica.h new file mode 100644 index 0000000..1498e88 --- /dev/null +++ b/include/QtRemoteObjects/qremoteobjectabstractitemmodelreplica.h @@ -0,0 +1 @@ +#include "../../src/remoteobjects/qremoteobjectabstractitemmodelreplica.h" diff --git a/include/QtRemoteObjects/qremoteobjectdynamicreplica.h b/include/QtRemoteObjects/qremoteobjectdynamicreplica.h new file mode 100644 index 0000000..b889d05 --- /dev/null +++ b/include/QtRemoteObjects/qremoteobjectdynamicreplica.h @@ -0,0 +1 @@ +#include "../../src/remoteobjects/qremoteobjectdynamicreplica.h" diff --git a/include/QtRemoteObjects/qremoteobjectnode.h b/include/QtRemoteObjects/qremoteobjectnode.h new file mode 100644 index 0000000..14ce150 --- /dev/null +++ b/include/QtRemoteObjects/qremoteobjectnode.h @@ -0,0 +1 @@ +#include "../../src/remoteobjects/qremoteobjectnode.h" diff --git a/include/QtRemoteObjects/qremoteobjectpendingcall.h b/include/QtRemoteObjects/qremoteobjectpendingcall.h new file mode 100644 index 0000000..aaf584d --- /dev/null +++ b/include/QtRemoteObjects/qremoteobjectpendingcall.h @@ -0,0 +1 @@ +#include "../../src/remoteobjects/qremoteobjectpendingcall.h" diff --git a/include/QtRemoteObjects/qremoteobjectregistry.h b/include/QtRemoteObjects/qremoteobjectregistry.h new file mode 100644 index 0000000..6b95543 --- /dev/null +++ b/include/QtRemoteObjects/qremoteobjectregistry.h @@ -0,0 +1 @@ +#include "../../src/remoteobjects/qremoteobjectregistry.h" diff --git a/include/QtRemoteObjects/qremoteobjectreplica.h b/include/QtRemoteObjects/qremoteobjectreplica.h new file mode 100644 index 0000000..52bdfa8 --- /dev/null +++ b/include/QtRemoteObjects/qremoteobjectreplica.h @@ -0,0 +1 @@ +#include "../../src/remoteobjects/qremoteobjectreplica.h" diff --git a/include/QtRemoteObjects/qremoteobjectsettingsstore.h b/include/QtRemoteObjects/qremoteobjectsettingsstore.h new file mode 100644 index 0000000..aa40e8c --- /dev/null +++ b/include/QtRemoteObjects/qremoteobjectsettingsstore.h @@ -0,0 +1 @@ +#include "../../src/remoteobjects/qremoteobjectsettingsstore.h" diff --git a/include/QtRemoteObjects/qremoteobjectsource.h b/include/QtRemoteObjects/qremoteobjectsource.h new file mode 100644 index 0000000..4cff76a --- /dev/null +++ b/include/QtRemoteObjects/qremoteobjectsource.h @@ -0,0 +1 @@ +#include "../../src/remoteobjects/qremoteobjectsource.h" diff --git a/include/QtRemoteObjects/qtremoteobjectglobal.h b/include/QtRemoteObjects/qtremoteobjectglobal.h new file mode 100644 index 0000000..79db2d9 --- /dev/null +++ b/include/QtRemoteObjects/qtremoteobjectglobal.h @@ -0,0 +1 @@ +#include "../../src/remoteobjects/qtremoteobjectglobal.h" diff --git a/include/QtRemoteObjects/qtremoteobjectsversion.h b/include/QtRemoteObjects/qtremoteobjectsversion.h new file mode 100644 index 0000000..2f737b5 --- /dev/null +++ b/include/QtRemoteObjects/qtremoteobjectsversion.h @@ -0,0 +1,9 @@ +/* This file was generated by syncqt. */ +#ifndef QT_QTREMOTEOBJECTS_VERSION_H +#define QT_QTREMOTEOBJECTS_VERSION_H + +#define QTREMOTEOBJECTS_VERSION_STR "6.3.1" + +#define QTREMOTEOBJECTS_VERSION 0x060301 + +#endif // QT_QTREMOTEOBJECTS_VERSION_H diff --git a/include/QtRemoteObjectsQml/6.3.1/QtRemoteObjectsQml/private/qremoteobjectsqml_p.h b/include/QtRemoteObjectsQml/6.3.1/QtRemoteObjectsQml/private/qremoteobjectsqml_p.h new file mode 100644 index 0000000..ab64b5b --- /dev/null +++ b/include/QtRemoteObjectsQml/6.3.1/QtRemoteObjectsQml/private/qremoteobjectsqml_p.h @@ -0,0 +1 @@ +#include "../../../../../src/remoteobjectsqml/qremoteobjectsqml_p.h" diff --git a/include/QtRemoteObjectsQml/QtRemoteObjectsQml b/include/QtRemoteObjectsQml/QtRemoteObjectsQml new file mode 100644 index 0000000..32f9e54 --- /dev/null +++ b/include/QtRemoteObjectsQml/QtRemoteObjectsQml @@ -0,0 +1,5 @@ +#ifndef QT_QTREMOTEOBJECTSQML_MODULE_H +#define QT_QTREMOTEOBJECTSQML_MODULE_H +#include +#include "qtremoteobjectsqmlversion.h" +#endif diff --git a/include/QtRemoteObjectsQml/QtRemoteObjectsQmlVersion b/include/QtRemoteObjectsQml/QtRemoteObjectsQmlVersion new file mode 100644 index 0000000..a8394c8 --- /dev/null +++ b/include/QtRemoteObjectsQml/QtRemoteObjectsQmlVersion @@ -0,0 +1 @@ +#include "qtremoteobjectsqmlversion.h" diff --git a/include/QtRemoteObjectsQml/headers.pri b/include/QtRemoteObjectsQml/headers.pri new file mode 100644 index 0000000..2a30a82 --- /dev/null +++ b/include/QtRemoteObjectsQml/headers.pri @@ -0,0 +1,6 @@ +SYNCQT.HEADER_FILES = +SYNCQT.GENERATED_HEADER_FILES = qtremoteobjectsqmlversion.h QtRemoteObjectsQmlVersion QtRemoteObjectsQml +SYNCQT.PRIVATE_HEADER_FILES = qremoteobjectsqml_p.h +SYNCQT.QPA_HEADER_FILES = +SYNCQT.CLEAN_HEADER_FILES = +SYNCQT.INJECTIONS = diff --git a/include/QtRemoteObjectsQml/qtremoteobjectsqmlversion.h b/include/QtRemoteObjectsQml/qtremoteobjectsqmlversion.h new file mode 100644 index 0000000..4562e27 --- /dev/null +++ b/include/QtRemoteObjectsQml/qtremoteobjectsqmlversion.h @@ -0,0 +1,9 @@ +/* This file was generated by syncqt. */ +#ifndef QT_QTREMOTEOBJECTSQML_VERSION_H +#define QT_QTREMOTEOBJECTSQML_VERSION_H + +#define QTREMOTEOBJECTSQML_VERSION_STR "6.3.1" + +#define QTREMOTEOBJECTSQML_VERSION 0x060301 + +#endif // QT_QTREMOTEOBJECTSQML_VERSION_H diff --git a/include/QtRepParser/QRegexParser b/include/QtRepParser/QRegexParser new file mode 100644 index 0000000..53e35e0 --- /dev/null +++ b/include/QtRepParser/QRegexParser @@ -0,0 +1 @@ +#include "qregexparser.h" diff --git a/include/QtRepParser/QtRepParser b/include/QtRepParser/QtRepParser new file mode 100644 index 0000000..e9bfb36 --- /dev/null +++ b/include/QtRepParser/QtRepParser @@ -0,0 +1,6 @@ +#ifndef QT_QTREPPARSER_MODULE_H +#define QT_QTREPPARSER_MODULE_H +#include +#include "qregexparser.h" +#include "qtrepparserversion.h" +#endif diff --git a/include/QtRepParser/QtRepParserVersion b/include/QtRepParser/QtRepParserVersion new file mode 100644 index 0000000..a896408 --- /dev/null +++ b/include/QtRepParser/QtRepParserVersion @@ -0,0 +1 @@ +#include "qtrepparserversion.h" diff --git a/include/QtRepParser/headers.pri b/include/QtRepParser/headers.pri new file mode 100644 index 0000000..70bd16d --- /dev/null +++ b/include/QtRepParser/headers.pri @@ -0,0 +1,6 @@ +SYNCQT.HEADER_FILES = qregexparser.h +SYNCQT.GENERATED_HEADER_FILES = QRegexParser qtrepparserversion.h QtRepParserVersion QtRepParser +SYNCQT.PRIVATE_HEADER_FILES = +SYNCQT.QPA_HEADER_FILES = +SYNCQT.CLEAN_HEADER_FILES = qregexparser.h +SYNCQT.INJECTIONS = diff --git a/include/QtRepParser/qregexparser.h b/include/QtRepParser/qregexparser.h new file mode 100644 index 0000000..b0ffb5c --- /dev/null +++ b/include/QtRepParser/qregexparser.h @@ -0,0 +1 @@ +#include "../../src/repparser/qregexparser.h" diff --git a/include/QtRepParser/qtrepparserversion.h b/include/QtRepParser/qtrepparserversion.h new file mode 100644 index 0000000..9fc5391 --- /dev/null +++ b/include/QtRepParser/qtrepparserversion.h @@ -0,0 +1,9 @@ +/* This file was generated by syncqt. */ +#ifndef QT_QTREPPARSER_VERSION_H +#define QT_QTREPPARSER_VERSION_H + +#define QTREPPARSER_VERSION_STR "6.3.1" + +#define QTREPPARSER_VERSION 0x060301 + +#endif // QT_QTREPPARSER_VERSION_H diff --git a/mkspecs/features/features.pro b/mkspecs/features/features.pro new file mode 100644 index 0000000..572235f --- /dev/null +++ b/mkspecs/features/features.pro @@ -0,0 +1,18 @@ +TEMPLATE = aux + +prf.files = remoteobjects_repc.prf repcclient.pri repcserver.pri repcmerged.pri repccommon.pri repparser.prf +prf.path = $$[QT_HOST_DATA]/mkspecs/features +INSTALLS += prf + +# Ensure files are copied to qtbase mkspecs for non-prefixed builds +!force_independent:if(!debug_and_release|!build_all|CONFIG(release, debug|release)) { + defineReplace(stripSrcDir) { + return($$relative_path($$1, $$_PRO_FILE_PWD_)) + } + prffiles2build.input = prf.files + prffiles2build.output = $$[QT_HOST_DATA]/mkspecs/features/${QMAKE_FUNC_FILE_IN_stripSrcDir} + prffiles2build.commands = $$QMAKE_COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT} + prffiles2build.name = COPY ${QMAKE_FILE_IN} + prffiles2build.CONFIG = no_link target_predeps + QMAKE_EXTRA_COMPILERS += prffiles2build +} diff --git a/mkspecs/features/remoteobjects_repc.prf b/mkspecs/features/remoteobjects_repc.prf new file mode 100644 index 0000000..8c79ed5 --- /dev/null +++ b/mkspecs/features/remoteobjects_repc.prf @@ -0,0 +1,26 @@ +include(repcclient.pri) +include(repcserver.pri) +include(repcmerged.pri) + +!isEmpty(QOBJECT_REP) { + qtPrepareLibExecTool(QMAKE_REPC, repc) + + for (path, QT.remoteobjects.includes) { + REPC_INCLUDEPATH += -I $$shell_quote($$path) + } + + qtPrepareLibExecTool(MOC_CREATE_JSON, moc) + moc_json.output = ${QMAKE_FILE_BASE}.json + moc_json.CONFIG = no_link moc_verify + moc_json.commands = $$MOC_CREATE_JSON -o ${QMAKE_FILE_BASE} ${QMAKE_FILE_NAME} --output-json + moc_json.depends = ${QMAKE_FILE_NAME} + moc_json.input = QOBJECT_REP + moc_json.variable_out = MOC_JSON + + source2rep.input = MOC_JSON + source2rep.output = ${QMAKE_FILE_BASE}.rep + source2rep.commands = $$QMAKE_REPC $$REPC_INCLUDEPATH -o rep -i json ${QMAKE_FILE_NAME} ${QMAKE_FILE_OUT} + source2rep.depends = ${QMAKE_FILE_NAME} $$QT_TOOL.repc.binary + source2rep.CONFIG += target_predeps no_link + QMAKE_EXTRA_COMPILERS += moc_json source2rep +} diff --git a/mkspecs/features/repcclient.pri b/mkspecs/features/repcclient.pri new file mode 100644 index 0000000..9e8bad4 --- /dev/null +++ b/mkspecs/features/repcclient.pri @@ -0,0 +1,4 @@ +repc_type = replica +repc_option = -o replica + +include(repccommon.pri) diff --git a/mkspecs/features/repccommon.pri b/mkspecs/features/repccommon.pri new file mode 100644 index 0000000..d014bc8 --- /dev/null +++ b/mkspecs/features/repccommon.pri @@ -0,0 +1,75 @@ +# Detect repc when QtRO is installed into non-Qt prefix +cmd = $${QT.remoteobjects.bins}/repc +contains(QMAKE_HOST.os, Windows) { + cmd = $$system_path($${cmd}.exe) +} +exists($$cmd): QT_TOOL.repc.binary = $$cmd + +# qtPrepareLibExecTool honors QT_TOOL.repc.binary if set +qtPrepareLibExecTool(QMAKE_REPC, repc) + +REPC_INCLUDEPATHES = $$QT.remoteobjects.includes +for (path, REPC_INCLUDEPATHES) { + REPC_INCLUDEPATH += -I $$path +} + +isEmpty(QMAKE_MOD_REPC):QMAKE_MOD_REPC = rep_ + +repc_TYPE = $$upper($$repc_type) + +load(moc) + +groups = +for(entry, REPC_$$repc_TYPE) { + files = $$eval($${entry}.files) + isEmpty(files) { + files = $$entry + group = repc_$${repc_type} + } else { + group = $${entry}_repc_$${repc_type} + } + groups *= $$group + + input_list = $$upper($$group)_LIST + json_list = $$upper($$group)_JSONLIST + for(subent, $$list($$unique(files))) { + if (contains(subent, .*\\.h$)|contains(subent, .*\\.hpp$)) { + $$json_list += $$subent + } else { + $$input_list += $$subent + } + + # Add directory of *.rep file to include path + file_path = $$_PRO_FILE_PWD_/$$subent + INCLUDEPATH *= $$dirname(file_path) + } +} + +for(group, groups) { + GROUP = $$upper($$group) + input_list = $${GROUP}_LIST + json_list = $${GROUP}_JSONLIST + + qtPrepareLibExecTool(MOC_CREATE_JSON, moc) + $${group}_moc_json.output = ${QMAKE_FILE_BASE}.json + $${group}_moc_json.CONFIG = no_link moc_verify + $${group}_moc_json.commands = $$MOC_CREATE_JSON -o ${QMAKE_FILE_BASE} ${QMAKE_FILE_NAME} --output-json + $${group}_moc_json.depends = ${QMAKE_FILE_NAME} + $${group}_moc_json.input = $$json_list + $${group}_moc_json.variable_out = MOC_JSON + + $${group}_header.output = $$QMAKE_MOD_REPC${QMAKE_FILE_BASE}_$${repc_type}.h + $${group}_header.commands = $$QMAKE_REPC $$repc_option $$REPC_INCLUDEPATH ${QMAKE_FILE_NAME} ${QMAKE_FILE_OUT} + $${group}_header.depends = ${QMAKE_FILE_NAME} $$QT_TOOL.repc.binary + $${group}_header.variable_out = $${GROUP}_HEADERS + $${group}_header.input = $$input_list MOC_JSON + + $${group}_moc.commands = $$moc_header.commands $$REPC_INCLUDEPATH + $${group}_moc.output = $$moc_header.output + $${group}_moc.input = $${GROUP}_HEADERS + $${group}_moc.variable_out = GENERATED_SOURCES + !contains(TEMPLATE, vc.*): \ + $${group}_moc.name = $$moc_header.name + + QMAKE_EXTRA_COMPILERS += $${group}_moc_json $${group}_header $${group}_moc +} diff --git a/mkspecs/features/repcmerged.pri b/mkspecs/features/repcmerged.pri new file mode 100644 index 0000000..0f672d2 --- /dev/null +++ b/mkspecs/features/repcmerged.pri @@ -0,0 +1,4 @@ +repc_type = merged +repc_option = -o merged + +include(repccommon.pri) diff --git a/mkspecs/features/repcserver.pri b/mkspecs/features/repcserver.pri new file mode 100644 index 0000000..035467a --- /dev/null +++ b/mkspecs/features/repcserver.pri @@ -0,0 +1,4 @@ +repc_type = source +repc_option = -o source + +include(repccommon.pri) diff --git a/mkspecs/features/repparser.prf b/mkspecs/features/repparser.prf new file mode 100644 index 0000000..cb5ae6b --- /dev/null +++ b/mkspecs/features/repparser.prf @@ -0,0 +1,9 @@ +CONFIG += qlalr +INCLUDEPATH *= $$QT.repparser.includes + +for (include, INCLUDEPATH) { + exists($${include}/parser.g) { + msvc: QMAKE_CXXFLAGS += /wd4129 + QLALRSOURCES += $${include}/parser.g + } +} diff --git a/mkspecs/mkspecs.pro b/mkspecs/mkspecs.pro new file mode 100644 index 0000000..95262a0 --- /dev/null +++ b/mkspecs/mkspecs.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs + +SUBDIRS += features diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..22babd4 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,8 @@ + +add_subdirectory(repparser) +if(QT_FEATURE_localserver) + add_subdirectory(remoteobjects) +endif() +if(TARGET Qt::Quick) + add_subdirectory(remoteobjectsqml) +endif() diff --git a/src/remoteobjects/CMakeLists.txt b/src/remoteobjects/CMakeLists.txt new file mode 100644 index 0000000..cd2619f --- /dev/null +++ b/src/remoteobjects/CMakeLists.txt @@ -0,0 +1,69 @@ + +##################################################################### +## RemoteObjects Module: +##################################################################### + +qt_internal_add_module(RemoteObjects + QMAKE_MODULE_CONFIG remoteobjects_repc + SOURCES + qconnection_local_backend.cpp qconnection_local_backend_p.h + qconnection_tcpip_backend.cpp qconnection_tcpip_backend_p.h + qconnectionfactories.cpp qconnectionfactories.h qconnectionfactories_p.h + qremoteobjectabstractitemmodeladapter.cpp qremoteobjectabstractitemmodeladapter_p.h + qremoteobjectabstractitemmodelreplica.cpp qremoteobjectabstractitemmodelreplica.h qremoteobjectabstractitemmodelreplica_p.h + qremoteobjectabstractitemmodeltypes_p.h + qremoteobjectcontainers.cpp qremoteobjectcontainers_p.h + qremoteobjectdynamicreplica.cpp qremoteobjectdynamicreplica.h + qremoteobjectnode.cpp qremoteobjectnode.h qremoteobjectnode_p.h + qremoteobjectpacket.cpp qremoteobjectpacket_p.h + qremoteobjectpendingcall.cpp qremoteobjectpendingcall.h qremoteobjectpendingcall_p.h + qremoteobjectregistry.cpp qremoteobjectregistry.h + qremoteobjectregistrysource.cpp qremoteobjectregistrysource_p.h + qremoteobjectreplica.cpp qremoteobjectreplica.h qremoteobjectreplica_p.h + qremoteobjectsettingsstore.cpp qremoteobjectsettingsstore.h + qremoteobjectsource.cpp qremoteobjectsource.h qremoteobjectsource_p.h + qremoteobjectsourceio.cpp qremoteobjectsourceio_p.h + qtremoteobjectglobal.cpp qtremoteobjectglobal.h + DEFINES + QT_BUILD_REMOTEOBJECTS_LIB + QT_NO_CAST_FROM_ASCII + QT_NO_CAST_FROM_BYTEARRAY + QT_NO_CAST_TO_ASCII + QT_NO_URL_CAST_FROM_STRING + INCLUDE_DIRECTORIES + . + LIBRARIES + Qt::CorePrivate + PUBLIC_LIBRARIES + Qt::Core + Qt::Network + PRIVATE_MODULE_INTERFACE + Qt::CorePrivate + GENERATE_CPP_EXPORTS +) + +#### Keys ignored in scope 1:.:.:remoteobjects.pro:: +# MODULE = "remoteobjects" +# MODULE_CONFIG = "remoteobjects_repc" +# OTHER_FILES = "doc/qtremoteobjects.qdocconf" "doc/src/remoteobjects-cpp.qdoc" "doc/src/remoteobjects-index.qdoc" "doc/src/remoteobjects-overview.qdoc" "doc/src/remoteobjects-repc.qdoc" + +## Scopes: +##################################################################### + +qt_internal_extend_target(RemoteObjects CONDITION QNX + SOURCES + qconnection_qnx_backend.cpp qconnection_qnx_backend_p.h + qconnection_qnx_global_p.h + qconnection_qnx_qiodevices.cpp qconnection_qnx_qiodevices.h qconnection_qnx_qiodevices_p.h + qconnection_qnx_server.cpp qconnection_qnx_server.h qconnection_qnx_server_p.h +) + +qt_internal_extend_target(RemoteObjects CONDITION QNX AND QT_FEATURE_use_ham + PUBLIC_LIBRARIES + ham +) +qt_internal_add_docs(RemoteObjects + doc/qtremoteobjects.qdocconf +) + +include(Qt6RemoteObjectsMacros.cmake) diff --git a/src/remoteobjects/Qt5RemoteObjectsConfigExtras.cmake.in b/src/remoteobjects/Qt5RemoteObjectsConfigExtras.cmake.in new file mode 100644 index 0000000..f98c37a --- /dev/null +++ b/src/remoteobjects/Qt5RemoteObjectsConfigExtras.cmake.in @@ -0,0 +1,62 @@ +# +# Copyright (C) 2015 Ford Motor Company +# Contact: https://www.qt.io/licensing/ +# +# This file is part of the QtRemoteObjects module of the Qt Toolkit. +# +# $QT_BEGIN_LICENSE:LGPL$ +# Commercial License Usage +# Licensees holding valid commercial Qt licenses may use this file in +# accordance with the commercial license agreement provided with the +# Software or, alternatively, in accordance with the terms contained in +# a written agreement between you and The Qt Company. For licensing terms +# and conditions see https://www.qt.io/terms-conditions. For further +# information use the contact form at https://www.qt.io/contact-us. +# +# GNU Lesser General Public License Usage +# Alternatively, this file may be used under the terms of the GNU Lesser +# General Public License version 3 as published by the Free Software +# Foundation and appearing in the file LICENSE.LGPL3 included in the +# packaging of this file. Please review the following information to +# ensure the GNU Lesser General Public License version 3 requirements +# will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +# +# GNU General Public License Usage +# Alternatively, this file may be used under the terms of the GNU +# General Public License version 2.0 or (at your option) the GNU General +# Public license version 3 or any later version approved by the KDE Free +# Qt Foundation. The licenses are as published by the Free Software +# Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +# included in the packaging of this file. Please review the following +# information to ensure the GNU General Public License requirements will +# be met: https://www.gnu.org/licenses/gpl-2.0.html and +# https://www.gnu.org/licenses/gpl-3.0.html. +# +# $QT_END_LICENSE$ + +if (NOT TARGET Qt5::repc) + add_executable(Qt5::repc IMPORTED) + +!!IF isEmpty(CMAKE_BIN_DIR_IS_ABSOLUTE) + set(imported_location \"${_qt5RemoteObjects_install_prefix}/$${CMAKE_BIN_DIR}repc$$CMAKE_BIN_SUFFIX\") +!!ELSE + set(imported_location \"$${CMAKE_BIN_DIR}repc$$CMAKE_BIN_SUFFIX\") +!!ENDIF + _qt5_RemoteObjects_check_file_exists(${imported_location}) + + set_target_properties(Qt5::repc PROPERTIES + IMPORTED_LOCATION ${imported_location} + ) + get_target_property(Qt5RemoteObjects_REPC_EXECUTABLE Qt5::repc LOCATION) +endif() + +# Create versionless tool targets. +foreach(__qt_tool repc) + if(NOT \"${QT_NO_CREATE_VERSIONLESS_TARGETS}\" AND NOT TARGET Qt::${__qt_tool} + AND TARGET Qt5::${__qt_tool}) + add_executable(Qt::${__qt_tool} IMPORTED) + get_target_property(__qt_imported_location Qt5::${__qt_tool} IMPORTED_LOCATION) + set_target_properties(Qt::${__qt_tool} + PROPERTIES IMPORTED_LOCATION \"${__qt_imported_location}\") + endif() +endforeach() diff --git a/src/remoteobjects/Qt6RemoteObjectsMacros.cmake b/src/remoteobjects/Qt6RemoteObjectsMacros.cmake new file mode 100644 index 0000000..3f2b0cf --- /dev/null +++ b/src/remoteobjects/Qt6RemoteObjectsMacros.cmake @@ -0,0 +1,202 @@ +# +# Copyright (C) 2019 The Qt Company Ltd. +# Contact: https://www.qt.io/licensing/ +# +# This file is part of the QtRepc module of the Qt Toolkit. +# +# $QT_BEGIN_LICENSE:LGPL$ +# Commercial License Usage +# Licensees holding valid commercial Qt licenses may use this file in +# accordance with the commercial license agreement provided with the +# Software or, alternatively, in accordance with the terms contained in +# a written agreement between you and The Qt Company. For licensing terms +# and conditions see https://www.qt.io/terms-conditions. For further +# information use the contact form at https://www.qt.io/contact-us. +# +# GNU Lesser General Public License Usage +# Alternatively, this file may be used under the terms of the GNU Lesser +# General Public License version 3 as published by the Free Software +# Foundation and appearing in the file LICENSE.LGPL3 included in the +# packaging of this file. Please review the following information to +# ensure the GNU Lesser General Public License version 3 requirements +# will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +# +# GNU General Public License Usage +# Alternatively, this file may be used under the terms of the GNU +# General Public License version 2.0 or (at your option) the GNU General +# Public license version 3 or any later version approved by the KDE Free +# Qt Foundation. The licenses are as published by the Free Software +# Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +# included in the packaging of this file. Please review the following +# information to ensure the GNU General Public License requirements will +# be met: https://www.gnu.org/licenses/gpl-2.0.html and +# https://www.gnu.org/licenses/gpl-3.0.html. +# +# $QT_END_LICENSE$ + +# With a macOS framework Qt build, moc needs to be passed -F arguments to resolve +# framework style includes like #include +# Extract the location of the Qt frameworks by querying the imported location of QtRemoteObjects +# framework parent directory. +function(_qt_internal_get_remote_objects_framework_path out_var) + set(value "") + if(APPLE AND QT_FEATURE_framework) + get_target_property(ro_path ${QT_CMAKE_EXPORT_NAMESPACE}::RemoteObjects IMPORTED_LOCATION) + string(REGEX REPLACE "(.*)/Qt[^/]+\\.framework.*" "\\1" ro_fw_path "${ro_path}") + if(ro_fw_path) + set(value "${ro_fw_path}") + endif() + endif() + set(${out_var} "${value}" PARENT_SCOPE) +endfunction() + +function(_qt_internal_get_remote_objects_framework_path_moc_options out_var) + _qt_internal_get_remote_objects_framework_path(ro_fw_path) + if(ro_fw_path) + set(${out_var} "OPTIONS" "-F${ro_fw_path}" PARENT_SCOPE) + else() + set(${out_var} "" PARENT_SCOPE) + endif() +endfunction() + +function(_qt_internal_add_repc_files type target) + set(options) + set(oneValueArgs) + set(multiValueArgs SOURCES) + + cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + set(outfiles) + if(QT_REPC_DEBUG_MODE) + set(debug "-d") + else() + set(debug "") + endif() + set(repc_incpath) ########### TODO + + _qt_internal_get_remote_objects_framework_path_moc_options(extra_moc_options) + _qt_internal_wrap_tool_command(repc_command SET + "$") + foreach(it ${ARGS_SOURCES}) + get_filename_component(outfilename ${it} NAME_WE) + get_filename_component(extension ${it} EXT) + if ("${extension}" STREQUAL ".h" OR "${extension}" STREQUAL ".hpp") + # This calls moc on an existing header file to extract metatypes json information + # which is then passed to the tool to generate another header. + qt6_wrap_cpp(qtro_moc_files "${it}" + __QT_INTERNAL_OUTPUT_MOC_JSON_FILES json_list + TARGET "${target}" + ${extra_moc_options}) + + # Pass the generated metatypes .json file to the tool. + set(infile ${json_list}) + set_source_files_properties(${qtro_moc_files} PROPERTIES HEADER_FILE_ONLY ON) + list(APPEND outfiles ${qtro_moc_files}) + else() + # Pass the .rep file to the tool. + get_filename_component(infile ${it} ABSOLUTE) + endif() + set(outfile ${CMAKE_CURRENT_BINARY_DIR}/rep_${outfilename}_${type}.h) + + add_custom_command( + OUTPUT ${outfile} + ${repc_command} ${debug} -o ${type} ${repc_incpath} ${infile} ${outfile} + MAIN_DEPENDENCY ${infile} + DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::repc + VERBATIM + ) + list(APPEND outfiles ${outfile}) + + # The generated header file needs to be manually moc'ed (without using AUTOMOC) and then + # added as source to compile into the target. + qt6_wrap_cpp(qtro_moc_files "${outfile}" TARGET "${target}" ${extra_moc_options}) + set_source_files_properties("${outfile}" PROPERTIES + GENERATED TRUE + SKIP_AUTOGEN ON) + list(APPEND outfiles ${qtro_moc_files}) + endforeach() + target_sources(${target} PRIVATE ${outfiles}) +endfunction() + +# Add .rep source files to a target to generate source header files +function(qt6_add_repc_sources target) + list(POP_FRONT ARGV) + _qt_internal_add_repc_files(source ${target} SOURCES ${ARGV}) +endfunction() + +# Add .rep source files to a target to generate replica header files +function(qt6_add_repc_replicas target) + list(POP_FRONT ARGV) + _qt_internal_add_repc_files(replica ${target} SOURCES ${ARGV}) +endfunction() + +# Add .rep source files to a target to generate combined (source and replica) header files +function(qt6_add_repc_merged target) + list(POP_FRONT ARGV) + _qt_internal_add_repc_files(merged ${target} SOURCES ${ARGV}) +endfunction() + +# Create .rep interface file from QObject header +function(qt6_reps_from_headers target) + list(POP_FRONT ARGV) + _qt_internal_get_remote_objects_framework_path_moc_options(extra_moc_options) + _qt_internal_wrap_tool_command(repc_command SET + "$") + + foreach(it ${ARGV}) + get_filename_component(outfilename ${it} NAME_WE) + # This calls moc on an existing header file to extract metatypes json information + # which is then passed to the tool to generate a .rep file. + qt6_wrap_cpp(qtro_moc_files "${it}" + __QT_INTERNAL_OUTPUT_MOC_JSON_FILES json_list + TARGET "${target}" + ${extra_moc_options}) + set(infile ${json_list}) + set_source_files_properties(${qtro_moc_files} PROPERTIES HEADER_FILE_ONLY ON) + list(APPEND outfiles ${qtro_moc_files}) + set(outfile ${CMAKE_CURRENT_BINARY_DIR}/${outfilename}.rep) + add_custom_command(OUTPUT ${outfile} + ${QT_TOOL_PATH_SETUP_COMMAND} + ${repc_command} -o rep ${infile} ${outfile} + MAIN_DEPENDENCY ${infile} + DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::repc + VERBATIM) + list(APPEND outfiles ${outfile}) + endforeach() + target_sources(${target} PRIVATE ${outfiles}) +endfunction() + +if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS) + function(qt_add_repc_sources) + if(QT_DEFAULT_MAJOR_VERSION EQUAL 6) + qt6_add_repc_sources(${ARGN}) + else() + message(FATAL_ERROR "qt_add_repc_sources() is only available in Qt 6. " + "Please check the repc documentation for alternatives.") + endif() + endfunction() + function(qt_add_repc_replicas) + if(QT_DEFAULT_MAJOR_VERSION EQUAL 6) + qt6_add_repc_replicas(${ARGN}) + else() + message(FATAL_ERROR "qt_add_repc_replicas() is only available in Qt 6. " + "Please check the repc documentation for alternatives.") + endif() + endfunction() + function(qt_add_repc_merged) + if(QT_DEFAULT_MAJOR_VERSION EQUAL 6) + qt6_add_repc_merged(${ARGN}) + else() + message(FATAL_ERROR "qt_add_repc_merged() is only available in Qt 6. " + "Please check the repc documentation for alternatives.") + endif() + endfunction() + function(qt_reps_from_headers) + if(QT_DEFAULT_MAJOR_VERSION EQUAL 6) + qt6_reps_from_headers(${ARGN}) + else() + message(FATAL_ERROR "qt_reps_from_headers() is only available in Qt 6. " + "Please check the repc documentation for alternatives.") + endif() + endfunction() +endif() diff --git a/src/remoteobjects/configure.cmake b/src/remoteobjects/configure.cmake new file mode 100644 index 0000000..b5b3687 --- /dev/null +++ b/src/remoteobjects/configure.cmake @@ -0,0 +1,26 @@ + + +#### Inputs + + + +#### Libraries + + + +#### Tests + + + +#### Features + +qt_feature("use_ham" PUBLIC + LABEL "High Availability Manager (ham)" + PURPOSE "Use QNX's High Availability Manager (ham) library" + AUTODETECT OFF + CONDITION QNX +) +qt_feature_definition("use_ham" "QT_NO_USE_HAM" NEGATE VALUE "1") +qt_configure_add_summary_section(NAME "Qt Remote Objects") +qt_configure_add_summary_entry(ARGS "use_ham") +qt_configure_end_summary_section() # end of "Qt Remote Objects" section diff --git a/src/remoteobjects/doc/images/DirectConnectClientServerOutput.png b/src/remoteobjects/doc/images/DirectConnectClientServerOutput.png new file mode 100644 index 0000000000000000000000000000000000000000..3b3166d7fee10a8bd7dfbda3982b89289cfe591e GIT binary patch literal 34559 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 literal 0 HcmV?d00001 diff --git a/src/remoteobjects/doc/images/DirectConnectServerOutput.png b/src/remoteobjects/doc/images/DirectConnectServerOutput.png new file mode 100644 index 0000000000000000000000000000000000000000..a82c272be087191effec8104421d263ed71c2570 GIT binary patch literal 16105 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 literal 0 HcmV?d00001 diff --git a/src/remoteobjects/doc/qtremoteobjects.qdocconf b/src/remoteobjects/doc/qtremoteobjects.qdocconf new file mode 100644 index 0000000..89bfc79 --- /dev/null +++ b/src/remoteobjects/doc/qtremoteobjects.qdocconf @@ -0,0 +1,54 @@ +include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) +include($QT_INSTALL_DOCS/config/exampleurl-qtremoteobjects.qdocconf) + +project = QtRemoteObjects +description = Qt Remote Objects Reference Documentation +version = $QT_VERSION + +qhp.projects = QtRemoteObjects + +qhp.QtRemoteObjects.file = qtremoteobjects.qhp +qhp.QtRemoteObjects.namespace = org.qt-project.qtremoteobjects.$QT_VERSION_TAG +qhp.QtRemoteObjects.virtualFolder = remoteobjects +qhp.QtRemoteObjects.indexTitle = Qt Remote Objects +qhp.QtRemoteObjects.indexRoot = + +qhp.QtRemoteObjects.subprojects = overviews classes repc +qhp.QtRemoteObjects.subprojects.overviews.title = Getting Started +qhp.QtRemoteObjects.subprojects.overviews.indexTitle = Getting Started with Qt Remote Objects +qhp.QtRemoteObjects.subprojects.overviews.selectors = fake:page,group,module +qhp.QtRemoteObjects.subprojects.classes.title = C++ Classes +qhp.QtRemoteObjects.subprojects.classes.indexTitle = Qt Remote Objects C++ Classes +qhp.QtRemoteObjects.subprojects.classes.selectors = class fake:headerfile +qhp.QtRemoteObjects.subprojects.classes.sortPages = true + +depends += qtcore \ + qtnetwork \ + qtdoc \ + qtcmake \ + qmake + +tagfile = ../../../doc/qtremoteobjects/qtremoteobjects.tags + +headerdirs += .. \ + ../../remoteobjects + +sourcedirs += .. \ + ../../remoteobjects + +exampledirs += ../../../examples/remoteobjects \ + snippets/ + +#add thumbnail images for the example docs that does not have an image. +manifestmeta.thumbnail.names += "QtRemoteObjects/Model*" \ + "QtRemoteObjects/QML*" \ + "QtRemoteObjects/QtRemote*" + + +examplesinstallpath = remoteobjects + +imagedirs += images + +navigation.landingpage = "Qt Remote Objects" +navigation.cppclassespage = "Qt Remote Objects C++ Classes" +navigation.qmltypespage = "Qt Remote Objects QML Types" diff --git a/src/remoteobjects/doc/snippets/README b/src/remoteobjects/doc/snippets/README new file mode 100644 index 0000000..72ad410 --- /dev/null +++ b/src/remoteobjects/doc/snippets/README @@ -0,0 +1 @@ +Put all snipplets into this folder. diff --git a/src/remoteobjects/doc/snippets/cmake-macros/CMakeLists.txt b/src/remoteobjects/doc/snippets/cmake-macros/CMakeLists.txt new file mode 100644 index 0000000..f43125c --- /dev/null +++ b/src/remoteobjects/doc/snippets/cmake-macros/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.16) + +project(directconnectserver) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(CMAKE_VERSION VERSION_LESS "3.7.0") + set(CMAKE_INCLUDE_CURRENT_DIR ON) +endif() + +#! [remote_objects_cmake] +find_package(Qt6 REQUIRED COMPONENTS RemoteObjects) +#! [remote_objects_cmake] + +set(SOURCES + main.cpp + simpleswitch.cpp +) + +#! [simpleSwitch_cmake_add_repc_source] +qt6_add_repc_sources(directconnectserver + simpleswitch.rep +) +#! [simpleSwitch_cmake_add_repc_source] + +#! [simpleSwitch_cmake_add_repc_replica] +qt6_add_repc_replicas(directconnectclient + simpleswitch.rep +) +#! [simpleSwitch_cmake_add_repc_replica] + +#! [simpleSwitch_cmake_add_repc_merged] +qt6_add_repc_merged(directconnectexample + simpleswitch.rep +) +#! [simpleSwitch_cmake_add_repc_merged] + +add_executable(directconnectserver ${SOURCES}) +#! [remote_objects_cmake_link] +target_link_libraries(directconnectserver PRIVATE Qt6::RemoteObjects) +#! [remote_objects_cmake_link] + +#! [simpleSwitch_cmake_rep_from_header] +qt6_reps_from_headers(directconnectexample + simpleswitch.h +) +#! [simpleSwitch_cmake_rep_from_header] diff --git a/src/remoteobjects/doc/snippets/cmake-macros/main.cpp b/src/remoteobjects/doc/snippets/cmake-macros/main.cpp new file mode 100644 index 0000000..18532b6 --- /dev/null +++ b/src/remoteobjects/doc/snippets/cmake-macros/main.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "simpleswitch.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + SimpleSwitch srcSwitch; // create simple switch + + QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:replica"))); // create host node without Registry + srcNode.enableRemoting(&srcSwitch); // enable remoting/Sharing + + return a.exec(); +} diff --git a/src/remoteobjects/doc/snippets/cmake-macros/simpleswitch.cpp b/src/remoteobjects/doc/snippets/cmake-macros/simpleswitch.cpp new file mode 100644 index 0000000..7ee8e57 --- /dev/null +++ b/src/remoteobjects/doc/snippets/cmake-macros/simpleswitch.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "simpleswitch.h" + +// constructor +SimpleSwitch::SimpleSwitch(QObject *parent) : SimpleSwitchSimpleSource(parent) +{ + stateChangeTimer = new QTimer(this); // Initialize timer + QObject::connect(stateChangeTimer, &SimpleSwitch::timeout, this, &SimpleSwitch::timeout_slot); // connect timeout() signal from stateChangeTimer to timeout_slot() of simpleSwitch + stateChangeTimer->start(2000); // Start timer and set timout to 2 seconds + qDebug() << "Source Node Started"; +} + +//destructor +SimpleSwitch::~SimpleSwitch() +{ + stateChangeTimer->stop(); +} + +void SimpleSwitch::server_slot(bool clientState) +{ + qDebug() << "Replica state is " << clientState; // print switch state echoed back by client +} + +void SimpleSwitch::timeout_slot(void) +{ + // slot called on timer timeout + if (currState()) // check if current state is true, currState() is defined in repc generated rep_simpleswitch_source.h + setCurrState(false); // set state to false + else + setCurrState(true); // set state to true + qDebug() << "Source State is "< + +class SimpleSwitch +{ + PROP(bool currState=false); + SLOT(void server_slot(bool clientState)); +}; diff --git a/src/remoteobjects/doc/snippets/doc_src_remoteobjects.h b/src/remoteobjects/doc/snippets/doc_src_remoteobjects.h new file mode 100644 index 0000000..066b8d4 --- /dev/null +++ b/src/remoteobjects/doc/snippets/doc_src_remoteobjects.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [qtremoteobject_include] +#include +//! [qtremoteobject_include] + +//! [implementing_source] +#include "rep_TimeModel_source.h" + +class MinuteTimer : public MinuteTimerSource +{ +Q_OBJECT +public: + MinuteTimer(QObject *parent = nullptr); + virtual ~MinuteTimer(); + +public slots: + virtual void SetTimeZone(int zn) { //this is a pure virtual method in MinuteTimerSource + qDebug()<<"SetTimeZone"<start(2000); // Start timer and set timout to 2 seconds + qDebug() << "Source Node Started"; +} + +//destructor +SimpleSwitch::~SimpleSwitch() +{ + stateChangeTimer->stop(); +} + +void SimpleSwitch::server_slot(bool clientState) +{ + qDebug() << "Replica state is " << clientState; // print switch state echoed back by client +} + +void SimpleSwitch::timeout_slot() +{ + // slot called on timer timeout + if (currState()) // check if current state is true, currState() is defined in repc generated rep_simpleswitch_source.h + setCurrState(false); // set state to false + else + setCurrState(true); // set state to true + qDebug() << "Source State is "< +#include "simpleswitch.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + SimpleSwitch srcSwitch; // create simple switch + + QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:switch"))); // create host node without Registry + srcNode.enableRemoting(&srcSwitch); // enable remoting/sharing + + return a.exec(); +} +//! [simpleSwitch_servermaincpp_example1] + +//! [simpleSwitch_clientrep_example1] +REPC_REPLICA = simpleswitch.rep +//! [simpleSwitch_clientrep_example1] + +//! [simpleSwitch_clientremotenode_example1] +QRemoteObjectNode repNode; // create remote object node +repNode.connectToNode(QUrl(QStringLiteral("local:switch"))); // connect with remote host node + //! [simpleSwitch_clientremotenode_example1] + + //! [simpleSwitch_clientacquirereplica_example1] +QSharedPointer ptr; +ptr.reset(repNode.acquire()); // acquire replica of source from host node +//! [simpleSwitch_clientacquirereplica_example1] + +//! [simpleSwitch_clientheader_example1] +#ifndef _CLIENT_H +#define _CLIENT_H + +#include +#include + +#include "rep_simpleswitch_replica.h" + +class Client : public QObject +{ + Q_OBJECT +public: + Client(QSharedPointer ptr); + ~Client(); + void initConnections();// Function to connect signals and slots of source and client + +Q_SIGNALS: + void echoSwitchState(bool switchState);// this signal is connected with server_slot(..) on the source object and echoes back switch state received from source + +public Q_SLOTS: + void recSwitchState_slot(); // slot to receive source state +private: + bool clientSwitchState; // holds received server switch state + QSharedPointer reptr;// holds reference to replica + + }; + +#endif +//! [simpleSwitch_clientheader_example1] + +//! [simpleSwitch_clientcpp_example1] +#include "client.h" + +// constructor +Client::Client(QSharedPointer ptr) : + QObject(nullptr),reptr(ptr) +{ + initConnections(); + //We can connect to SimpleSwitchReplica Signals/Slots + //directly because our Replica was generated by repc. +} + +//destructor +Client::~Client() +{ +} + +void Client::initConnections() +{ + // initialize connections between signals and slots + + // connect source replica signal currStateChanged() with client's recSwitchState() slot to receive source's current state + QObject::connect(reptr.data(), &SimpleSwitchReplica::currStateChanged, this, &Client::recSwitchState_slot); + // connect client's echoSwitchState(..) signal with replica's server_slot(..) to echo back received state + QObject::connect(this, &Client::echoSwitchState, reptr.data(), &SimpleSwitchReplica::server_slot); +} + +void Client::recSwitchState_slot(bool value) +{ + qDebug() << "Received source state "<< value << reptr.data()->currState(); + clientSwitchState = reptr.data()->currState(); + Q_EMIT echoSwitchState(clientSwitchState); // Emit signal to echo received state back to server +} +//! [simpleSwitch_clientcpp_example1] + +//! [simpleSwitch_clientmain_example1] +#include +#include "client.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + + QSharedPointer ptr; // shared pointer to hold source replica + + QRemoteObjectNode repNode; // create remote object node + repNode.connectToNode(QUrl(QStringLiteral("local:switch"))); // connect with remote host node + + ptr.reset(repNode.acquire()); // acquire replica of source from host node + + Client rswitch(ptr); // create client switch object and pass reference of replica to it + + return a.exec(); +} +//! [simpleSwitch_clientmain_example1] + +//! [simpleSwitch_dynamicclientnode_example2] +QRemoteObjectNode repNode; // create remote object node +repNode.connectToNode(QUrl(QStringLiteral("local:switch"))); // connect with remote host node +//! [simpleSwitch_dynamicclientnode_example2] + +//! [simpleSwitch_dynamicclientacquirereplica_example2] +QSharedPointer ptr; // shared pointer to hold replica +ptr.reset(repNode.acquire("SimpleSwitch")); // acquire replica of source from host node +//! [simpleSwitch_dynamicclientacquirereplica_example2] + +//! [simpleSwitch_dynamicclientheader_example2] +#ifndef _DYNAMICCLIENT_H +#define _DYNAMICCLIENT_H + +#include +#include + +#include +#include + +class DynamicClient : public QObject +{ + Q_OBJECT +public: + DynamicClient(QSharedPointer ptr); + ~DynamicClient(); + +Q_SIGNALS: + void echoSwitchState(bool switchState);// this signal is connected with server_slot(..) slot of source object and echoes back switch state received from source + +public Q_SLOTS: + void recSwitchState_slot(); // Slot to receive source state + void initConnection_slot(); //Slot to connect signals/slot on replica initialization + +private: + bool clientSwitchState; // holds received server switch state + QSharedPointer reptr;// holds reference to replica + }; + +#endif +//! [simpleSwitch_dynamicclientheader_example2] + +//! [simpleSwitch_dynamicclientcpp_example2] +#include "dynamicclient.h" + +// constructor +DynamicClient::DynamicClient(QSharedPointer ptr) : + QObject(nullptr), reptr(ptr) +{ + + //connect signal for replica valid changed with signal slot initialization + QObject::connect(reptr.data(), &QRemoteObjectDynamicReplica::initialized, this, + &DynamicClient::initConnection_slot); +} + +//destructor +DynamicClient::~DynamicClient() +{ +} + +// Function to initialize connections between slots and signals +void DynamicClient::initConnection_slot() +{ + + // connect source replica signal currStateChanged() with client's recSwitchState() slot to receive source's current state + QObject::connect(reptr.data(), SIGNAL(currStateChanged()), this, SLOT(recSwitchState_slot())); + // connect client's echoSwitchState(..) signal with replica's server_slot(..) to echo back received state + QObject::connect(this, SIGNAL(echoSwitchState(bool)),reptr.data(), SLOT(server_slot(bool))); +} + +void DynamicClient::recSwitchState_slot() +{ + clientSwitchState = reptr->property("currState").toBool(); // use replica property to get currState from source + qDebug() << "Received source state " << clientSwitchState; + Q_EMIT echoSwitchState(clientSwitchState); // Emit signal to echo received state back to server +} + +//! [simpleSwitch_dynamicclientcpp_example2] + +//! [simpleSwitch_dynamicclientmaincpp_example2] +#include + +#include "dynamicclient.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + QSharedPointer ptr; // shared pointer to hold replica + + QRemoteObjectNode repNode; + repNode.connectToNode(QUrl(QStringLiteral("local:switch"))); + + ptr.reset(repNode.acquireDynamic("SimpleSwitch")); // acquire replica of source from host node + + DynamicClient rswitch(ptr); // create client switch object and pass replica reference to it +} +//! [simpleSwitch_dynamicclientmaincpp_example2] + +//! [simpleSwitch_registrymaincpp_example3] +#include +#include "simpleswitch.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + SimpleSwitch srcSwitch; // create SimpleSwitch + + QRemoteObjectRegistryHost regNode(QUrl(QStringLiteral("local:registry"))); // create node that hosts registry + QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:switch")), QUrl(QStringLiteral("local:registry"))); // create node that will host source and connect to registry + //Note, you can add srcSwitch directly to regNode if desired. + //We use two Nodes here, as the regNode could easily be in a third process. + + srcNode.enableRemoting(&srcSwitch); // enable remoting of source object + + return a.exec(); +} +//! [simpleSwitch_registrymaincpp_example3] + +//! [simpleSwitch_registrydynamicclientmaincpp_example3] + QRemoteObjectNode repNode(QUrl(QStringLiteral("local:registry"))); +//! [simpleSwitch_registrydynamicclientmaincpp_example3] diff --git a/src/remoteobjects/doc/src/cmake-macros.qdoc b/src/remoteobjects/doc/src/cmake-macros.qdoc new file mode 100644 index 0000000..46047f9 --- /dev/null +++ b/src/remoteobjects/doc/src/cmake-macros.qdoc @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\page qtremoteobjects-cmake-qt-add-repc-replicas.html +\ingroup cmake-macros-qtremoteobjects + +\title qt_add_repc_replicas +\target qt6_add_repc_replicas + +\brief Creates C++ header files for replica types from the Qt Remote Objects .rep files. + +\cmakecommandsince 6.2 + +\section1 Synopsis + +\badcode +qt_add_repc_replicas( rep_files) + +qt6_add_repc_replicas( rep_files) +\endcode + +\section1 Description + +Runs \l repc and generates \l {Qt Remote Objects Replica} header files based +on the given \c rep_files. Adds the generated files to \c{}. + +\section1 Examples + +\snippet cmake-macros/CMakeLists.txt simpleSwitch_cmake_add_repc_replica + +The generated file(s) will be of the form \c {rep__replica.h}, +in this case \c rep_simpleswitch_replica.h +*/ + +/*! +\page qtremoteobjects-cmake-qt-add-repc-sources.html +\ingroup cmake-macros-qtremoteobjects + +\title qt_add_repc_sources +\target qt6_add_repc_sources + +\brief Creates C++ header files for source types from the Qt Remote Objects .rep files. + +\cmakecommandsince 6.2 + +\section1 Synopsis + +\badcode +qt_add_repc_sources( rep_files) + +qt6_add_repc_sources( rep_files) +\endcode + +\section1 Description + +Runs \l repc and generates \l {Qt Remote Objects Source} header files based +on the given \c rep_files. Adds the generated files to \c{}. + +\section1 Examples + +\snippet cmake-macros/CMakeLists.txt simpleSwitch_cmake_add_repc_source + +The generated file(s) will be of the form \c {rep__source.h}, +in this case \c rep_simpleswitch_source.h +*/ + +/*! +\page qtremoteobjects-cmake-qt-add-repc-merged.html +\ingroup cmake-macros-qtremoteobjects + +\title qt_add_repc_merged +\target qt6_add_repc_merged + +\brief Creates C++ header files for source and replica types from the Qt Remote Objects .rep files. + +\cmakecommandsince 6.2 + +\section1 Synopsis + +\badcode +qt_add_repc_merged( rep_files) + +qt6_add_repc_merged( rep_files) +\endcode + +\section1 Description + +Runs \l repc and generates \l {Qt Remote Objects Replica} and \l {Qt Remote Objects Source} +header files based on the given \c rep_files combined in a single header. Adds the +generated files to \c{}. + +\section1 Examples + +\snippet cmake-macros/CMakeLists.txt simpleSwitch_cmake_add_repc_merged + +The generated file(s) will be of the form \c {rep__merged.h}, +in this case \c rep_simpleswitch_merged.h + +\note Typically sources and replicas live in separate processes or devices, so +this function is not commonly used. +*/ + +/*! +\page qtremoteobjects-cmake-qt-rep-from-headers.html +\ingroup cmake-macros-qtremoteobjects + +\title qt_reps_from_headers +\target qt6_reps_from_headers + +\brief Creates .rep files from the QObject header files. + +\cmakecommandsince 6.2 + +\section1 Synopsis + +\badcode +qt_reps_from_headers( header_files) + +qt6_reps_from_headers( header_files) +\endcode + +\section1 Description + +Generates corresponding \c .rep files from the existing QObject \c header_files. + +\section1 Examples + +\snippet cmake-macros/CMakeLists.txt simpleSwitch_cmake_rep_from_header + +This will generate an interface file called \c simpleswitch.rep in the build +directory. +*/ diff --git a/src/remoteobjects/doc/src/qt6-changes.qdoc b/src/remoteobjects/doc/src/qt6-changes.qdoc new file mode 100644 index 0000000..b426061 --- /dev/null +++ b/src/remoteobjects/doc/src/qt6-changes.qdoc @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page remoteobjects-changes-qt6.html + \title Changes to Qt Remote Objects + \ingroup changes-qt-5-to-6 + \brief Migrate Qt Remote Objects to Qt 6. + + Qt 6 is a result of the conscious effort to make the framework more + efficient and easy to use. + + We try to maintain binary and source compatibility for all the public + APIs in each release. But some changes were inevitable in an effort to + make Qt a better framework. + + In this topic we summarize those changes in Qt Remote Objects, and provide + guidance to handle them. + + \section1 API changes + + \section2 Functions taking const-ref QString changing to QStringView + + QRemoteObjectHostBase::proxy, QRemoteObjectHostBase::reverseProxy and + QRemoteObjectNode::instances now accept a QStringView instead + of \c{const QString &}. The largest difference caused by this is that it + no longer accepts implicit conversion from string literals + (i.e. \c{node.instances("abc");}). Instead, you could use a UTF-16 + string literal (\c{node.instances(u"abc")}). + + \section2 Changes to classes for custom transport backend support + + The "semi-private" \c IoDeviceBase, \c ServerIoDevice, and \c ClientIoDevice + classes are now renamed to \c QtROIoDeviceBase, \c QtROServerIoDevice, and + \c QtROClientIoDevice respectively, to be consistent with naming in Qt. + They are also moved from the private \c qconnectionfactories_p.h header to + \c qconnectionfactories.h. + + \note These classes are provided to give more flexibility for implementing + custom communication protocols for Qt Remote Objects, but there are no + source or binary compatibility guarantees for them. We recommend using the + QRemoteObjectNode::addClientSideConnection() and + QRemoteObjectHostBase::addHostSideConnection() methods, if you need + support for \l {External QIODevices} {external} communication channels. + + \section1 CMake changes + + The \c cmake instructions for calling \l repc and adding the generated + \c .rep files to a CMake project have slightly changed. Instead of the + \c qt5_generate_repc macro, you should now use \c qt6_add_repc_sources, + \c qt6_add_repc_replicas and \c qt6_add_repc_merged functions. + For example, the following code: + + \code + set(SOURCES + main.cpp + simpleswitch.cpp + ) + + qt5_generate_repc(SOURCES simpleswitch.rep SOURCE) + add_executable(directconnectserver ${SOURCES}) + \endcode + + Should change to: + + \code + set(SOURCES + main.cpp + simpleswitch.cpp + ) + add_executable(directconnectserver ${SOURCES}) + qt6_add_repc_sources(directconnectserver simpleswitch.rep) + \endcode + + More detailed descriptions for these CMake functions can be found + \l {CMake functions} {here}. +*/ diff --git a/src/remoteobjects/doc/src/remoteobjects-compatibility.qdoc b/src/remoteobjects/doc/src/remoteobjects-compatibility.qdoc new file mode 100644 index 0000000..31b7e44 --- /dev/null +++ b/src/remoteobjects/doc/src/remoteobjects-compatibility.qdoc @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\page qtremoteobjects-compatibility.html +\title Qt Remote Objects Protocol Versioning + +Qt Remote Objects uses an internal protocol to pass data between processes +and/or devices. The same protocol version needs to be used by all parties: if +there is a mismatch, the connecting node will output a warning and the host +node will not send any data. + +Currently released versions: + +\table +\header + \li Protocol Version + \li Qt Version +\row + \li <1.2 + \li Used during QtRO's tech preview phase. +\row + \li 1.2 + \li 5.12.0 +\row + \li 1.3 + \li 5.12.4 +\row + \li 2.0 + \li 6.2.0 +\endtable +*/ diff --git a/src/remoteobjects/doc/src/remoteobjects-cpp.qdoc b/src/remoteobjects/doc/src/remoteobjects-cpp.qdoc new file mode 100644 index 0000000..c355177 --- /dev/null +++ b/src/remoteobjects/doc/src/remoteobjects-cpp.qdoc @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\module QtRemoteObjects +\title Qt Remote Objects C++ Classes +\brief Provides an easy to use mechanism for sharing a QObject's properties, signals, or slots, between processes. +\ingroup modules +\qtcmakepackage RemoteObjects +\qtvariable remoteobjects + + To link against the module using CMake, add the following lines to your \c cmake file: + + \snippet cmake-macros/CMakeLists.txt remote_objects_cmake + + \snippet cmake-macros/CMakeLists.txt remote_objects_cmake_link + + To link against the module using \c qmake, add this line to your \c{.pro} file: + + \snippet doc_src_simpleswitch.cpp simpleSwitch_remoteobjectsadd_example1 + + For more information, see \l{Getting Started with Qt Remote Objects}. +*/ diff --git a/src/remoteobjects/doc/src/remoteobjects-custom-transport.qdoc b/src/remoteobjects/doc/src/remoteobjects-custom-transport.qdoc new file mode 100644 index 0000000..659c3b4 --- /dev/null +++ b/src/remoteobjects/doc/src/remoteobjects-custom-transport.qdoc @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\page qtremoteobjects-custom-transport.html +\title APIs for Implementing Custom Transport Backends +\brief Gives an overview of abstract APIs for implementing custom transport +backends for Qt Remote Objects. + +Qt Remote Objects provides several abstract interfaces for implementing custom +transport backends. The concept behind these classes is that there needs to be +a host node, which has an address that can be connected to. Then there is a +client object, which can be publicly constructed, and can connect to the server. +When the server gets a connection request, it creates the server side of the +connection, which communicates directly with the client. There are thus three +abstractions, one for the server (\c QConnectionAbstractServer), one for the +client-side of the connection (\c QtROClientIoDevice), and the third for the +server-side of the connection (\c QtROServerIoDevice). The latter two inherit +from \c QtROIoDeviceBase. + +\section1 API Overview + +\list +\li \c QtROIoDeviceBase +\li \c QtROClientIoDevice +\li \c QtROServerIoDevice +\li \c QConnectionAbstractServer +\endlist + +After implementing these interfaces, you can register your custom protocol +using the qRegisterRemoteObjectsServer() and qRegisterRemoteObjectsClient() +methods. + +\note These APIs are provided to give more flexibility for implementing custom +communication protocols for Qt Remote Objects. There are no source or binary +compatibility guarantees for them, meaning that the API is only guaranteed to work +with the Qt version it was developed against. API changes will however only be made +in minor releases. (6.1, 6.2, and so on.) + +*/ diff --git a/src/remoteobjects/doc/src/remoteobjects-example-dynamic-replica.qdoc b/src/remoteobjects/doc/src/remoteobjects-example-dynamic-replica.qdoc new file mode 100644 index 0000000..48b26e8 --- /dev/null +++ b/src/remoteobjects/doc/src/remoteobjects-example-dynamic-replica.qdoc @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\page remoteobjects-example-dynamic-replica.html +\title Example 2: Direct Connection with a Dynamic Replica +\brief Describes how the Qt Remote Objects establishes a direct connection with a dynamic replica. +\target qtro-example2 + +Initially, a dynamic replica is created as a "bare" QObject - without +properties, signals or slots. Then, during initialization, QtRO returns the +API for the object, after the connection to the source is made. Thus, the API +is added to the object at runtime. + +There are no changes to be made on the source side, as a dynamic \l Replica +only impacts how the requestor node acquires the replica. So, we use the +source-side code shown in \l {qtro-example1}{Example 1}. + +\list 1 + \li Add replica generation to the project. + + Because the replica is dynamically acquired, no \c .rep file is + required unlike in \l {qtro-example1}{Example 1}. + + \li Create the remote node and connect it to the source host node. + + The code for this step is unchanged from \l {qtro-example1}{Example 1}. + \snippet doc_src_simpleswitch.cpp simpleSwitch_dynamicclientnode_example2 + + \li Acquire a replica of the remote source object. + + In \c main.cpp, we use a QSharedPointer to hold a replica of the + remote object, and then instantiate a replica requestor object: + + \snippet doc_src_simpleswitch.cpp simpleSwitch_dynamicclientmaincpp_example2 +\endlist + +The complete declaration and definition of the requestor class, +\c DynamicClient, is as follows: + +\c dynamicclient.h +\snippet doc_src_simpleswitch.cpp simpleSwitch_dynamicclientheader_example2 + +\c dynamicclient.cpp +\snippet doc_src_simpleswitch.cpp simpleSwitch_dynamicclientcpp_example2 + +When run together with the source-side example, the output is identical +to \l {qtro-example1}{Example 1}. + +*/ diff --git a/src/remoteobjects/doc/src/remoteobjects-example-registry.qdoc b/src/remoteobjects/doc/src/remoteobjects-example-registry.qdoc new file mode 100644 index 0000000..7ffa295 --- /dev/null +++ b/src/remoteobjects/doc/src/remoteobjects-example-registry.qdoc @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + +\page remoteobjects-example-registry.html +\title Example 3: Connections to Remote Nodes using a Registry +\brief Describes how the Qt Remote Objects registry establishes connections between nodes. +\target qtro-example3 + +This example illustrates the use of a \l {Registry} to build the node topology. +For simple networks, we use a QUrl to create a direct connection between two +nodes. For complex networks, we use a registry, where you use a different QUrl +to point both the host and replica nodes to the registry. For only two nodes, +the benefits of using a registry are minimal. But, as the network grows, using +a registry means that all nodes only need to connect to the registry via a single +QUrl. In comparison, with direct connections, nodes would have to maintain a +list of QUrls for every single node that they link to. + +\section2 Set up the Source + +The \c simpleswitch.h and \c simpleswitch.cpp sources from \l {qtro-example1} +{Example} can be used without modification. The difference is in the way a host +node is created and connected to the registry: + +\c main.cpp +\snippet doc_src_simpleswitch.cpp simpleSwitch_registrymaincpp_example3 + +\section2 Set up the Replica + +The requestor object used for this example is the dynamic replica client +discussed in \l {qtro-example2}{Example 2}. + +The only modification is in \c main.cpp: a \l {Registry} node is created +to acquire a \l {Replica}: + +\snippet doc_src_simpleswitch.cpp simpleSwitch_registrydynamicclientmaincpp_example3 + +When run together with the source-side example, the output is identical +to \l {qtro-example1}{Example 1}. + +*/ diff --git a/src/remoteobjects/doc/src/remoteobjects-example-static-source.qdoc b/src/remoteobjects/doc/src/remoteobjects-example-static-source.qdoc new file mode 100644 index 0000000..95af8e1 --- /dev/null +++ b/src/remoteobjects/doc/src/remoteobjects-example-static-source.qdoc @@ -0,0 +1,206 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\page remoteobjects-example-static-source +\title Example 1: Direct Connection using a Static Source +\brief Describes how the Qt Remote Objects establishes a direct connection using a static source. +\target qtro-example1 + +In this example, the source object is a simple binary switch that toggles its +state based on a timer. When the state changes, a signal is emitted by the +source which QtRO propagates to all replicas. Since the replicas have the same +properties, signals, and slots as were exposed from the source, any slots +connected to the replica's signal will be called when the replica receives that +signal. The client process then echoes back the received switch state to the +source by emitting its own signal which is connected to a slot on the replica. + +\list 1 +\li \b {Create a source object} + +To create this \l Source object, first we create the definition file, +\c simpleswitch.rep. This file describes the properties and methods for the +object and is input to the Qt Remote Objects Compiler \l{repc}. This file only +defines interfaces that are necessary to expose to the \l{Replica}{Replicas}. + +\c simpleswitch.rep +\snippet doc_src_simpleswitch.cpp simpleSwitch_rep + +In \c simpleswitch.rep, +\list + \li \c currState holds the current state of the switch. + \li \c server_slot() allows us to interact with the source - it will be + connected to the \c echoSwitchState(bool newstate) signal. +\endlist + +For repc to process this file, add the following line to your \c cmake file: + +\snippet cmake-macros/CMakeLists.txt simpleSwitch_cmake_add_repc_source + +If you're using \c qmake: + +\snippet doc_src_simpleswitch.cpp simpleSwitch_repsource_example1 + +These instructions are only relevant for the Qt Remote Object module, +so you need to add it to your project as well. If you're using CMake, +add: + +\snippet cmake-macros/CMakeLists.txt remote_objects_cmake + +\snippet cmake-macros/CMakeLists.txt remote_objects_cmake_link + +If you're using \c qmake: + +\snippet doc_src_simpleswitch.cpp simpleSwitch_remoteobjectsadd_example1 + +repc creates the \c rep_SimpleSwitch_source.h header in the build directory +that you specify. For more information, see \l{Source}. + +repc creates three helper classes for use with QtRO. For this example, we +use the basic: \c SimpleSwitchSimpleSource. It's an abstract class, defined in +\c rep_SimpleSwitch_source.h. We derive from it to define our SimpleSwitch +implementation class as shown below: + +\c simpleswitch.h + +\snippet doc_src_simpleswitch.cpp simpleSwitch_serverheader_example1 + +In \c simpleswitch.h, +\list + \li \c stateChangeTimer is a QTimer that is used to toggle the state of our + SimpleSwitch. + \li \c timeout_slot() is connected to \c stateChangeTimer's timeout() signal. + \li \c server_slot() -- which is called automatically on the source whenever + any replica calls their version of the slot -- outputs the received value. + \li \c currStateChanged(bool), defined in the \l{repc}-generated + \c rep_SimpleSwitch_source.h, is emitted whenever \c currState toggles. + In this example, we ignore the signal on the source side, and handle it + later on the replica side. +\endlist + +The definition of our \c SwitchState class is shown below: + +\c simpleswitch.cpp + +\snippet doc_src_simpleswitch.cpp simpleSwitch_serversource_example1 + +\li \b {Create a registry} + +Because this example uses a direct connection between nodes, we can omit this +step. + +\li \b {Create a host node} + +The host node is created as shown below: + +\snippet doc_src_simpleswitch.cpp simpleSwitch_serverhostnode_example1 + +\li \b {Host source object and remoting} + +The following statements instantiate the \l {Source} object and pass it on to +the host to enable "remoting", which is the process of making an object visible +to the QtRO network: + +\snippet doc_src_simpleswitch.cpp simpleSwitch_enableremoting_example1 + +The contents of \c main.cpp file that implements the steps described above are +as follows: + +\c main.cpp + +\snippet doc_src_simpleswitch.cpp simpleSwitch_servermaincpp_example1 + +Compile and run this source-side project. The output, without any replicas +created, should look as shown below with the switch state toggling between +\c true and \c false every two seconds. + +\image DirectConnectServerOutput.png "Example 1: Server Output" + +\endlist + +The subsequent steps are for creating the replica side of the network, which in +this example gets the state of switch from the \l {Source} and echoes it back. + +\section2 Replica Code + +\list 1 +\li \b {Use repc to add a replica to your project} + +We use the same API definition file as we did on the source side, +\c SimpleSwitch.rep, to create a \l {Replica} header file using the \l {repc}. +If you're using \c cmake, include the following line in your client side +\c cmake file, specifying a \c .rep file input: + +\snippet cmake-macros/CMakeLists.txt simpleSwitch_cmake_add_repc_replica + +If you're using \c qmake, add the following line to your client side \c .pro +file: + +\snippet doc_src_simpleswitch.cpp simpleSwitch_clientrep_example1 + +The \l {repc} tool generates a \c rep_SimpleSwitch_replica.h file in the build +directory. For more information, see \l{Replica}. + +\li \b {Create a node to connect with the source's host node} + +The following code instantiates the second node on the network and connects it +with the source host node: + +\snippet doc_src_simpleswitch.cpp simpleSwitch_clientremotenode_example1 + +\li \b {Call the node's \l{QRemoteObjectNode::}{acquire()} to create a pointer + to a replica} + +First, we instantiate a replica: + +\snippet doc_src_simpleswitch.cpp simpleSwitch_clientacquirereplica_example1 + +\note \l{QRemoteObjectNode::}{acquire()} returns a pointer to the replica, but +doesn't manage its lifetime. This example shows the recommended process of +wrapping the returned pointer in a QSharedPointer or QScopedPointer to ensure +that the pointer is always deleted properly. + +\c main.cpp implements the steps described above and instantiates our object: + +\c main.cpp +\snippet doc_src_simpleswitch.cpp simpleSwitch_clientmain_example1 + +The complete declaration and definition for the \c Client class is as follows: + +\c client.h +\snippet doc_src_simpleswitch.cpp simpleSwitch_clientheader_example1 + +\c client.cpp +\snippet doc_src_simpleswitch.cpp simpleSwitch_clientcpp_example1 + +Compiling and running this example together with the source-side example +generates the following output: + +\image DirectConnectClientServerOutput.png "Direct Connect Server Client Communication output" +\endlist + +*/ diff --git a/src/remoteobjects/doc/src/remoteobjects-external-schemas.qdoc b/src/remoteobjects/doc/src/remoteobjects-external-schemas.qdoc new file mode 100644 index 0000000..cbda73b --- /dev/null +++ b/src/remoteobjects/doc/src/remoteobjects-external-schemas.qdoc @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\page qtremoteobjects-external-schemas.html +\title Qt Remote Objects - External QIODevices +\brief Describes how Qt Remote Objects supports custom QIODevice channels. + +\section1 External QIODevices + +Qt Remote Objects supports several communications channels out-of-the-box, such +as the \l QTcpServer and \l QTcpSocket pair. Given the desired \l QUrl for tcp, +or the desired name (for the \l QLocalServer and \l QLocalSocket pair), the +code needed to listen and connect are boilerplate and handled internally by Qt. +Qt Remote Objects supports other types of \l QIODevice as well, and the \l +QRemoteObjectNode classes provide additional methods to support cases where +custom code is needed. + +A contrived example with TCP/IP is shown below. A more realistic example would +use an SSL connection, which would require configuration of certificates, etc. + +\code + // Create the server and listen outside of QtRO + QTcpServer tcpServer; + tcpServer.listen(QHostAddress(QStringLiteral("127.0.0.1")), 65213); + + // Create the host node. We don't need a hostUrl unless we want to take + // advantage of external schemas (see next example). + QRemoteObjectHost srcNode; + + // Make sure any connections are handed to QtRO + QObject::connect(&tcpServer, &QTcpServer::newConnection, &srcNode, + [&srcNode, &tcpServer]() { + srcNode.addHostSideConnection(tcpServer.nextPendingConnection()); + }); +\endcode + +The Replica side code needs to manually connect to the Host +\code + QRemoteObjectNode repNode; + QTcpSocket *socket = new QTcpSocket(&repNode); + QObject::connect(socket, &QTcpSocket::connected, &repNode, + [socket, &repNode]() { + repNode.addClientSideConnection(socket); + }); + socket->connectToHost(QHostAddress(QStringLiteral("127.0.0.1")), 65213); +\endcode + +\section1 External Schemas + +It is possible to create each side of the QIODevice and call \l +{QRemoteObjectNode::addClientSideConnection(QIODevice *ioDevice)} and \l +{QRemoteObjectHostBase::addHostSideConnection(QIODevice *ioDevice)} as shown +above. This is fully supported, but requires the client know how to establish +the connection or have a way to discover that information. This is exactly the +problem the registry was designed to solve. + +Qt Remote Objects also allows "External Schemas" to be used with the registry, +which helps with connection setup. On the \l QRemoteObjectHost side, the +user must set the hostUrl with the desired schema. + +\code + // Use standard tcp url for the registry + const QUrl registryUrl = QUrl(QStringLiteral("tcp://127.0.0.1:65212")); + // Use "exttcp" for the "external" interface + const QUrl extUrl = QUrl(QStringLiteral("exttcp://127.0.0.1:65213")); + + // Create the server and listen outside of QtRO + QTcpServer tcpServer; + tcpServer.listen(QHostAddress(extUrl.host()), extUrl.port()); + + // We need a registry for everyone to connect to + QRemoteObjectRegistryHost registry(registryUrl); + + // Finally, we create our host node and register "exttcp" as our schema. + // We need the AllowExternalRegistration parameter to prevent the node from + // setting a hostUrlInvalid error. + QRemoteObjectHost srcNode(extUrl, registryUrl, QRemoteObjectHost::AllowExternalRegistration); + // From now on, when we call enableRemoting() from this node, the registry + // will be updated to show the Source object at extUrl. +\endcode + +On the \l Replica side, the \l QRemoteObjectNode needs to register a callback +to be used when the external schema is detected. The callback must be a +\l {QRemoteObjectNode::}{RemoteObjectSchemaHandler}. + +\code + // Use standard tcp url for the registry + const QUrl registryUrl = QUrl(QStringLiteral("tcp://127.0.0.1:65212")); + + // This time create the node connected to the registry + QRemoteObjectNode repNode(registryUrl); + + // Create the RemoteObjectSchemaHandler callback + QRemoteObjectNode::RemoteObjectSchemaHandler setupTcp = [&repNode](QUrl url) { + QTcpSocket *socket = new QTcpSocket(&repNode); + connect(socket, &QTcpSocket::connected, + [socket, &repNode]() { + repNode.addClientSideConnection(socket); + }); + connect(socket, &QSslSocket::errorOccurred, + [socket](QAbstractSocket::SocketError error) { + delete socket; + }); + socket->connectToHost(url.host(), url.port()); + }; + + // Once we call registerExternalSchema, the above method will be called + // whenever the registry sees an object we are interested in on "exttcp" + repNode.registerExternalSchema(QStringLiteral("exttcp"), setupTcp); +\endcode +*/ diff --git a/src/remoteobjects/doc/src/remoteobjects-gettingstarted.qdoc b/src/remoteobjects/doc/src/remoteobjects-gettingstarted.qdoc new file mode 100644 index 0000000..f4bec3f --- /dev/null +++ b/src/remoteobjects/doc/src/remoteobjects-gettingstarted.qdoc @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\page qtremoteobjects-gettingstarted.html +\title Getting Started with Qt Remote Objects +\brief Detailed information on how to use Qt Remote Objects. + +\section1 Introduction + +The Qt Remote Objects module provides an easy way to share Qt APIs between +processes and devices. For this to work, we require a data channel between +processes and devices. To establish this data channel, first, you need a +QRemoteObjectNode. + +In QtRO, a node is an endpoint for communication. In a remote objects network, +each participant, be it a process or a device, needs its own node. QtRO is a +peer-to-peer network, with connected nodes being the links in the network. + +Nodes, by themselves, don’t provide much use. But their value comes when you +add QObject classes to a node to share. Then, any peer node can request a copy +or instance of the shared object from the \e{host node}, the node that shares +it. + +Unlike when using normal class instances (with independent properties and +signal emissions), QtRO automatically synchronizes changes to the shared object +across all of its copies. With a few exceptions, these copies have the +identical Qt API as the original object, and are meant to be used exactly as if +the original object were available. + +In QtRO, the original object is called the \l{Source}. It's a fully-implemented +C++ class, with the necessary business logic to provide the required +functionality. Copies of this object are called \l{Replica}s. You don’t need +to write any C++ code for a replica; you request an instance from a node +instead. While you do need some code to use the replica, such as connecting +signals to your own slots, you don’t need to implement the internal behavior – +that's already done for you in the source. + +Because the source can be in a different process or even on a different device, +there are factors in QtRO that you need to consider, which you typically +wouldn't run into when developing without Inter-Process Communication (IPC). +Specifically, what happens if the process or device isn't there? This is where +the additions to the Replica API come in: + +\list + \li The \l{QRemoteObjectReplica::}{initialized()} signal is emitted once the + replica has received the \l{Source}{source} state from the QtRO + network. + \li Both the \l{QRemoteObjectReplica::}{isReplicaValid} property and the + \l{QRemoteObjectReplica::}{stateChanged()} signal alert you if the + connection is lost. +\endlist + +Objects shared over QtRO use the links (conduits) between nodes for all +communication. If you want to share a QObject, you must create a \e{host node} +with a URL other nodes can connect to. You can also use the \l{Registry} to +facilitate connections, but your nodes that share \l{Source}{sources} still need +to be host nodes. Each shared object is given a name (a QString), used to +identify it on the QtRO network. + +\section1 Implementation + +To illustrate the use of remote objects, on the source side, we need to: + +\list 1 + \li Create the \l {Source} object that is replicated to other nodes, with or + without using \l repc, the Qt Remote Objects Compiler. + \li Optionally, create the \l{Registry}. Otherwise, use direct connections. + \li Create a host node so that the source object can be shared. + \li Call the node's \l{QRemoteObjectHostBase::}{enableRemoting()} function + to share the source object. +\endlist + +On the replica side, we need to: + +\list 1 + \li Optionally, use \l repc to generate a \l{Replica} header for your project. + \li Create the node that will connect with the \l{Source} host node. + \li Call the node's \l{QRemoteObjectNode::}{acquire()} function to create a + pointer to a replica. +\endlist + +The following examples illustrate both \l{repc}-compiled static objects and dynamic +source objects. Additionally, they also show direct connections as well as +connections that use a \l{Registry} between nodes. + +\list + \li \l{Example 1: Direct Connection using a Static Source} + \li \l{Example 2: Direct Connection with a Dynamic Replica} + \li \l{Example 3: Connections to Remote Nodes using a Registry} +\endlist + +*/ diff --git a/src/remoteobjects/doc/src/remoteobjects-index.qdoc b/src/remoteobjects/doc/src/remoteobjects-index.qdoc new file mode 100644 index 0000000..a727aa2 --- /dev/null +++ b/src/remoteobjects/doc/src/remoteobjects-index.qdoc @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\page qtremoteobjects-index.html +\title Qt Remote Objects +\ingroup overviews +\brief Provides APIs for inter-process communication. + +\target Qt Remote Objects +\section1 Remote Object Concepts + +Qt Remote Objects (QtRO) is an Inter-Process Communication (IPC) module +developed for Qt. This module extends Qt's existing functionalities to enable +information exchange between processes or computers, easily. + +One of Qt's key features, to enable this information exchange, is the +distinction between an object's API (defined by its properties, signals, and +slots) and the implementation of that API. QtRO's purpose is to meet that +expected API, even if the true QObject is in a different process. A slot +called on a copy of an object (the \l {Replica} in QtRO) is forwarded to the +true object (the \l {Source} in QtRO) for handling. Every Replica receives +updates to the Source, either property changes or emitted signals. + +A \l {Replica} is a light-weight proxy for the \l {Source} object, but a +Replica supports the same connections and behavior of QObjects, which makes it +usable in the same way as any other QObject that Qt provides. Behind the +scenes, QtRO handles everything that's necessary for the Replica to look like +its Source. + +Note that Remote Objects behave differently from traditional Remote Procedure +Call (RPC) implementations, for example: + +\list + \li In RPC, the client makes a request and waits for the response. + \li In RPC, the server doesn't push anything to the client unless it's in + response to a request. + \li Often, the design of RPC is such that different clients are independent + of each other: for instance, two clients can ask a mapping service for + directions and get different results. +\endlist + +While it is possible to implement this RPC-style behavior in QtRO, as Sources +without properties, and slots that have return values, QtRO hides the fact that +the processing is really remote. You let a node give you the Replica instead of +creating it yourself, possibly use the status signals +(\l {QRemoteObjectReplica::} {isReplicaValid()}), but then interact with the +object like you would with any other QObject-based type. + +\section1 Use Case: GPS + +Consider a sensor such as a Global Positioning System (GPS) receiver. In +QtRO terms: + +\list + \li The \l{Source} would be the process that directly interacts with the + GPS hardware and derives your current location. + \li The location would be exposed as QObject properties; the periodic + updates to the location would update these properties and emit property + changed signals. + \li \l{Replica}{Replicas} would be created in other processes and would + always know your current location, but wouldn't need any of the logic + to compute the location from the sensor data. + \li Connecting to the location changed signal on the Replica would work as + expected: the signal emitted from the Source would trigger the signal + emission on every Replica. +\endlist + +\section1 Use Case: Printer Access + +Consider a service that provides access to a printer. In QtRO terms: + +\list + \li The \l{Source} would be the process controlling the printer directly. + \li The ink levels and printer status would be monitored by QObject + properties. Updates to these properties would emit property changed + signals. + \li The key feature -- being able to print something -- needs to be passed + back to the printer. Incidentally, this aligns with the Qt slot mechanism, + which QtRO uses as the way for \l{Replica}{Replicas} to make calls on the + Source. In effect, properties and signals go from Source to Replicas; + slots go from Replica to Source. + \li When a print request is accepted, the printer status would change, + triggering a change in the status property. This would then be reported + to all Replicas. +\endlist + +\include module-use.qdocinc using qt module +\snippet cmake-macros/CMakeLists.txt remote_objects_cmake + +See also the \l {Build with CMake} overview. + +\include module-use.qdocinc building with qmake +\snippet doc_src_simpleswitch.cpp simpleSwitch_remoteobjectsadd_example1 + +\section1 Articles and Guides + \list + \li \l {Getting Started with Qt Remote Objects} + \li \l {Qt Remote Objects Nodes}{Nodes} + \li \l {Qt Remote Objects Source}{Sources} + \li \l {Qt Remote Objects Replica}{Replicas} + \li \l {Qt Remote Objects Registry}{Registry} + \li Using Custom Transports + \list + \li \l {Qt Remote Objects - External QIODevices}{External QIODevices} + \li \l {APIs for Implementing Custom Transport Backends} + {Implementing Custom Transport Backends} + \endlist + \li \l {Qt Remote Objects Compiler}{Compiler} + \li \l {Remote Object Interaction} + \li \l {Troubleshooting Qt Remote Objects}{Troubleshooting} + \li \l {Qt Remote Objects Protocol Versioning}{Protocol Versioning} + \endlist + +\section2 API Reference + +\list + \li \l {Qt Remote Objects C++ Classes} + \li \l {Qt Remote Objects QML Types} +\endlist + +\section1 Licenses + +Qt Remote Objects is available under commercial licenses from \l{The Qt Company}. +In addition, it is available under the +\l{GNU Lesser General Public License, version 3}, or the +\l{GNU General Public License, version 2}. +See \l{Qt Licensing} for further details. + +*/ diff --git a/src/remoteobjects/doc/src/remoteobjects-interaction.qdoc b/src/remoteobjects/doc/src/remoteobjects-interaction.qdoc new file mode 100644 index 0000000..003c8a4 --- /dev/null +++ b/src/remoteobjects/doc/src/remoteobjects-interaction.qdoc @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ +/*! +\page qtremoteobjects-interaction.html +\brief Describes how a source and replicas interact with one another. +\section1 Remote Object Interaction + +The interaction between source and replicas is directional. Property changes +and signal emission happen on the source, and are propagated to all replicas. +If a property is writable, you can call the setter function on a replica, which +is then forwarded to the source. Afterwards, if this call results in a new +property value, that value is first changed at the source and then subsequently +forwarded to all replicas. To the replica, it is then an asynchronous call, +with latency before the change takes effect. + +While technically you can emit a signal on a replica, this is discouraged as it +may have unexpected results. It will only trigger slots connected to the +replica itself; not slots connected to the source or other replicas. Like +property setters, slot invocations on a replica are forwarded to the source to +run. + +Qt Remote Objects automatically implements the behavior described above. There +is no need to write any replica implementation code. For dynamic replicas, +this is handled automatically at runtime. For \l{repc} generated headers, this +is handled at compile time. +*/ diff --git a/src/remoteobjects/doc/src/remoteobjects-nodes.qdoc b/src/remoteobjects/doc/src/remoteobjects-nodes.qdoc new file mode 100644 index 0000000..e95958b --- /dev/null +++ b/src/remoteobjects/doc/src/remoteobjects-nodes.qdoc @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ +/*! +\page qtremoteobjects-node.html +\title Qt Remote Objects Nodes +\brief Describes how Qt Remote Objects pass data between nodes. + +In a QtRO network, information is passed between processes via +QRemoteObjectNodes ("nodes"). This peer-to-peer functionality uses a small +number of distinct packets passing the necessary data between nodes. + +Each process that participates in the network instantiates a Node-based type, +such as QRemoteObjectNode, QRemoteObjectHost, or QRemoteObjectRegistryHost. +The host types of Nodes provide additional functionality. Both +QRemoteObjectHost and QRemoteObjectRegistryHost support the +\l{QRemoteObjectHostBase::}{enableRemoting()} and the corresponding +\l{QRemoteObjectHostBase::}{disableRemoting()} methods, which are the key +methods to expose source objects to the network. To use the \l Registry +functionality, you need to have a QRemoteObjectRegistryHost on the network. +Then, all other nodes can pass the RegistryHost's URL to the Node's +\c registryAddress constructor parameter, or pass the URL to the +\l {QRemoteObjectNode::}{setRegistryUrl()} method. + +Since QtRO is a peer-to-peer network, to +\l{QRemoteObjectNode::acquire()}{acquire()} a valid \l{Replica}, the replica's +node needs to be connected to the node that hosts its \l{Source}. A host node is a +node that allows other nodes to connect to it, which is accomplished by giving +hosts unique addresses. This address is provided to the QRemoteObjectHost +constructor or set by the setHostUrl method. The node from which a replica is +requested must establish the connection to the host node, to initialize the +replica and keep it up to date. + +\section1 Connecting Nodes using QtRO URLs + +Host Nodes use custom URLs to simplify connections. Currently, QtRO supports +two types of connections: + +\list 1 + \li A TCP connection using the standard TCP/IP protocol - supports + connections between devices as well as between processes on the same + device. + \li A local connection - supports connections between processes on the same + device. This type of connection can have less overhead, depending on + the underlying Operating System features. +\endlist + +For local connections, you must use a unique name. For TCP connections, you +must provide a unique address and port number combination. + +Currently, QtRO does not include a \l {http://www.zeroconf.org/} {zeroconf} +facility. Therefore, all processes or devices must know beforehand, how to +connect to each other. A \l {QRemoteObjectRegistry} can be used to simplify +the connection process for a network with multiple Host Nodes. + +The table below summarizes the connection types available: + + \table 90% + \header + \li URL + \li Notes + \row + \li {QUrl}("local:service") + \li Uses (internally) {QLocalServer}/{QLocalSocket} classes to + communicate between nodes. + \row + \li {QUrl}("tcp://192.168.1.1:9999") + \li Uses (internally) {QTcpServer}/{QTcpSocket} classes to + communicate between nodes. + \row + \li {QUrl}("qnx:service") + \li QNX OS only. Uses a custom (named) channel for native + communication between nodes. + \row + \li {QUrl}("localabstract:service") + \li Since 6.2. Linux/Android OSes only. Uses an abstract namespace + for Unix domain sockets. This allows QLocalSocket behavior to work on + non-writable devices. + \endtable + +Nodes have a few \l{QRemoteObjectHostBase::enableRemoting()} +{enableRemoting()} methods that are used to share objects on the network. +However, if the node is not a host node, an error is returned. + +Other processes or devices that want to interact with a shared object can +use one of the \l{QRemoteObjectNode::acquire()} {node's acquire()} methods, +to instantiate a replica. + +*/ diff --git a/src/remoteobjects/doc/src/remoteobjects-qml.qdoc b/src/remoteobjects/doc/src/remoteobjects-qml.qdoc new file mode 100644 index 0000000..3d75faf --- /dev/null +++ b/src/remoteobjects/doc/src/remoteobjects-qml.qdoc @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\qmlmodule QtRemoteObjects 6.\QtMinorVersion +\title Qt Remote Objects QML Types +\ingroup qmlmodules +\brief Provides QML types for remote objects support. + +The QML types for \l{Qt Remote Objects} provide the helper pieces needed to build a remote objects network. +They are typically used in conjunction with custom-registered replica types that make up a specific +network. + +As an example, consider the following .rep file: +\code +class MyType { + PROP(QString myProp="Hello World") +}; +\endcode + +The generated replica can be registered as a QML type: +\code +qmlRegisterType("custom",1,0,"MyTypeReplica") +\endcode + +And then used from QML in conjunction with the base type Node: +\qml +import QtQuick +import QtRemoteObjects +import custom 1.0 + +Item { + MyTypeReplica { + id: myType + node: Node { registryUrl: "local:registry" } + } + + Text { text: myType.myProp } + + MouseArea { + anchors.fill: parent + onClicked: myType.pushMyProp("Updated Text") + } +} +\endqml + +Note that by default you cannot directly assign to a replica property, but rather use a \c push function. +This is due to the potential problems that arise from the mix of declarative programming and asynchronous updates. +Specifically, we want to avoid issues like the following: +\badcode +myType.myProp = "Updated Text" +console.log(myType.myProp) // logs "Hello World", as the new text has not yet been round-tripped +\endcode + +The QML types in this module can be imported into your application using the following import +statement in your .qml file: +\qml +import QtRemoteObjects +\endqml + +\section1 QML Types +*/ + +/*! +\qmltype QtRemoteObjects +\inqmlmodule QtRemoteObjects +\since 5.14 +\brief The QtRemoteObjects global object provides useful functions for working with remote + types in QML. +*/ + +/*! + \qmlmethod Promise QtRemoteObjects::QtRemoteObjects::watch(QRemoteObjectPendingCall reply, int timeout = 30000) + Encapsulates the return value, represented by \a reply, from a replica in a JavaScript Promise. + A timeout can be set with \a timeout. The default timeout value is 30 seconds. + + \qml + QtRemoteObjects.watch(replica.fetchDetails(identifier)) + .then(function(value) { details = value }, + function(error) { console.log("error fetching details:", error) }) + \endqml +*/ diff --git a/src/remoteobjects/doc/src/remoteobjects-registry.qdoc b/src/remoteobjects/doc/src/remoteobjects-registry.qdoc new file mode 100644 index 0000000..c122da0 --- /dev/null +++ b/src/remoteobjects/doc/src/remoteobjects-registry.qdoc @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\page qtremoteobjects-registry.html +\title Qt Remote Objects Registry +\brief Describes how the Qt Remote Objects registry establishes connections + between nodes. +\target Registry + +When you \l {QRemoteObjectNode::acquire()} a replica, the node URL is not passed +as an argument. This means you do not need to specify the host node, but it does +require you to have some other means of connecting to that host. Without the +registry, it is necessary to manually call \l {QRemoteObjectNode::connectToNode()}, +from each node, to every host node that has \l {Source} objects it should +replicate. This is fine for small or static networks, but does not scale. + +The registry provides a simpler way to establish these connections. Every node +that wants to be part of the registry's network connects to the registry. The +registry is itself a specialized source object, and thus is hosted by a node. +Connecting to the registry is simply a matter of passing the registry's URL to +the QRemoteObjectNode or QRemoteObjectHost constructor, or passing the URL to +the setRegistryUrl method. + +The registry is tightly integrated with QtRO. Whenever a \l {Source} is added +or removed, the name/URL is updated in the registry automatically. So once +your node is connected to the registry, it is not necessary to connect to any +other nodes manually. If you request an object on the network and you aren't +connected to the hosting node, the registry will know what URL to connect to +and will initiate the connection. Once connected (and the list of available +objects is passed along, including the desired \l {Source}), the initialization +process for the requested \l Replica will start automatically. +*/ diff --git a/src/remoteobjects/doc/src/remoteobjects-repc.qdoc b/src/remoteobjects/doc/src/remoteobjects-repc.qdoc new file mode 100644 index 0000000..717cb14 --- /dev/null +++ b/src/remoteobjects/doc/src/remoteobjects-repc.qdoc @@ -0,0 +1,434 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \externalpage https://en.wikipedia.org/wiki/Domain-specific_language + \title Domain Specific Language (DSL) +*/ + +/*! +\page qtremoteobjects-repc.html +\title Qt Remote Objects Compiler +\brief The Qt Remote Objects Compiler creates \l {Source} and \l {Replica} header files +\ingroup overviews +\keyword repc + + \section1 REPC Overview + + The \underline {Rep}lica \underline {C}ompiler (repc) generates QObject + header files based on an API definition file. The file (called a "rep" + file) uses a specific (text) syntax to describe the API. By convention, + these files are given a .rep file extension, short for Replica. When these + files are processed by repc, repc generates both \l {Source} and \l + {Replica} header files. + + The Qt Remote Objects module also includes \l {CMake functions} and + \l {qmake variables} that can be added to your project file to automatically run + repc, and add the resulting files to the list of files processed by + \l{moc}{Meta Object Compiler} during the build process, making use of Qt + Remote Objects in your projects simple. + + While Qt Remote Objects supports sharing any QObject over the network (using + enableRemoting on the Source side and acquireDynamic on the Replica side), + there are a couple of advantages to letting repc define your objects. First + of all, while \l {QRemoteObjectDynamicReplica} {DynamicReplicas} are + useful, they are more cumbersome to work with. The API is not known until + the object is initialized, and using the API from C++ requires string + lookups through QMetaObject's methods. Secondly, having the interface known + at compile time finds any issues at compile vs. at runtime. Thirdly, the rep + format supports default values, which can be handy if you are unable to + ensure the Source is available when the Replica is instantiated. + + See the documentation \l {Source} {here} for information on using + the generated files in your code. Here we will focus on the repc format and + options. + + \section1 The rep file format + + The rep file format is a simple \l {Domain Specific Language (DSL)} for + describing an interface supported over Qt Remote Objects (QtRO). Since QtRO + is an object based system, these interfaces are defined by APIs available + through objects, that is, classes with properties, signals, and slots. + + \section2 The class type + + Each class defined in a rep file becomes a QObject in the generated header + files, with the described API generated for you. + + To define a class use the \c class keyword, followed by the name you + want for your type, and then enclose your API in brackets like so + \code + class MyType + { + //PROP/CLASS/MODEL/SIGNAL/SLOT/ENUM declarations to define your API + }; + \endcode + + \section3 PROP + + Q_PROPERTY elements are created by using the PROP keyword in the rep + file. The syntax is the \c PROP keyword followed by the definition enclosed + in parentheses, where the definition is the type, the name, and (optionally) a + default value or attributes. + \code + PROP(bool simpleBool) // boolean named simpleBool + PROP(bool defaultFalseBool=false) // boolean named defaultFalseBool, with false + // as the default value + + PROP(int lifeUniverseEverything=42) // int value that defaults to 42 + PROP(QByteArray myBinaryInfo) // Qt types are fine, may need #include + // additional headers in your rep file + + PROP(QString name CONSTANT) // Property with the CONSTANT attribute + PROP(QString setable READWRITE) // Property with the READWRITE attribute + // note: Properties default to READPUSH + // (see description below) + + PROP(SomeOtherType myCustomType) // Custom types work. Needs #include for the + // appropriate header for your type, make + // sure your type is known to the metabject + // system, and make sure it supports Queued + // Connections (see Q_DECLARE_METATYPE and + // qRegisterMetaType) + \endcode + More information about creating custom types can be found \l {Creating + Custom Qt Types} {here}. + + By default, properties will have getters and a "push" slot defined, as well + as a notify signal emitted when the value is changed. Qt Remote Objects + requires the notify signal on the Source object to trigger sending updates + to the attached Replicas. In earlier versions of QtRO, properties defaulted + to being read/write, that is, having getters and setters. However, due to the + asynchronous nature of QtRO, this led to unintuitive behavior at times. + Setting the READWRITE attribute on the PROP will provide the old (getter + and setter) behavior. + \code + // In .rep file, old (setter) behavior + PROP(int myVal READWRITE) // Old behavior with setMyVal(int myVal) method + + // In code... Assume myVal is initially set to 0 in Source + int originalValue = rep->myVal(); // Will be 0 + rep->setMyVal(10); // Call setter, expecting a blocking/ + // non-asynchronous return + + if (rep->myVal() == 10) ... // Test will usually fail + \endcode + + If it is necessary to block until the value is changed, something like the + following is necessary. + \code + // In .rep file, old (setter) behavior + PROP(int myVal READWRITE) // Old behavior with setMyVal(int myVal) method + + // In code... Assume myVal is initially set to 0 in Source + bool originalValue = rep->myVal(); // Will be 0 + + // We can wait for the change using \l QSignalSpy + QSignalSpy spy(rep, SIGNAL(myValChanged(int))); + + rep->setMyVal(10); // Call setter, expecting a blocking/ + // non-asynchronous return + + spy.wait(); // spy.wait() blocks until changed signal + // is received + if (rep->myVal() == 10) ... // Test will succeed assuming + // 1. Source object is connected + // 2. Nobody else (Source or other Replica) + // sets the myVal to something else (race + // condition) + // Rather than use QSignalSpy, the event-driven practice would be to connect the + // myValChanged notify signal to a slot that responds to the changes. + \endcode + + QtRO now defaults to READPUSH, which provides an automatically generated + slot for requesting a property change. + \code + // In .rep file, defaults to READPUSH + PROP(bool myVal) // No setMyVal(int myVal) on Replica, has + // pushMyVal(int myVal) instead + + // In code... Assume myVal is initially set to 0 in Source + bool originalValue = rep->myVal(); // Will be 0 + + // We can wait for the change using \l QSignalSpy + QSignalSpy spy(rep, SIGNAL(myValChanged(int))); + + rep->pushMyVal(10); // Call push method, no expectation that change + // is applied upon method completion. + + // Some way of waiting for change to be received by the Replica is still necessary, + // but hopefully not a surprise with the new pushMyVal() Slot. + spy.wait(); // spy.wait() blocks until changed signal + // is received + if (rep->myVal() == 10) ... // Test will succeed assuming + // 1. Source object is connected + // 2. Nobody else (Source or other Replica) + // set the myVal to something else (race + // condition) + \endcode + + You can also use the \c CONSTANT, \c READONLY, \c PERSISTED, \c READWRITE, + \c READPUSH, or \c SOURCEONLYSETTER keywords in the PROP declaration, which + affects how the property is implemented. READPUSH is the default value if no value + used. + + \code + PROP(int lifeUniverseEverything=42 CONSTANT) + PROP(QString name READONLY) + \endcode + + Please note there are some subtleties here. A CONSTANT PROP has a + Q_PROPERTY declared as CONSTANT on the SOURCE side. However, replicas + cannot know the correct value until they are initialized, which means the + property value has to be allowed to change during initialization. For + READONLY, the source will have neither a setter nor a push slot, and the + replica side will not have a push slot generated. Adding the PERSISTED + trait to a PROP will have the PROP use the \l QRemoteObjectAbstractPersistedStore + instance set on a Node (if any) to save/restore PROP values. + + Another nuanced value is SOURCEONLYSETTER, which provides another way of + specifying asymmetric behavior, where the \l Source (specifically the helper + class, \c SimpleSource) will have a public getter and setter for the + property, but it will be ReadOnly (with a notify signal) on the \l Replica + side. Thus the property can be fully controlled from the \l Source side, + but only observed from the \l Replica side. SOURCEONLYSETTER is the mode + used by repc for MODEL and CLASS instances, meaning the \l Source can + change the pointed to object, but the \l Replica can not provide a new + object, as no set or push method is generated. Note, this does + not impact the behavior of the pointed to type's properties, just the + ability to change the pointer itself. + + \sa QRemoteObjectAbstractPersistedStore + + \section3 CLASS + + The CLASS keyword generates special Q_PROPERTY elements for objects derived from QObject. + These properties have the same semantics as SOURCEONLYSETTER. The syntax is the \c CLASS + keyword followed by the property name and then the type of subobject enclosed in parentheses. + \code + // In .rep file + class OtherClass + { + PROP(int value) + } + + class MainClass + { + CLASS subObject(OtherClass) + } + \endcode + + \section3 MODEL + + The MODEL keyword generates special Q_PROPERTY elements for objects derived from QAbstractItemModel. + These properties have the same semantics as SOURCEONLYSETTER. The syntax is the \c MODEL + keyword followed by the property name and then parentheses enclosing the (comma-separated) roles + that should be exposed to the replica. + \code + // In .rep file + class CdClass + { + PROP(QString title READONLY) + MODEL tracks(title, artist, length) + } + \endcode + + \section3 SIGNAL + + \l [DOC QtCore] {Signals} {Signal} methods are created by using the SIGNAL keyword in the rep file. + + Usage is to declare \c SIGNAL followed by the desired signature wrapped in + parentheses. The void return value should be skipped. + + \code + SIGNAL(test()) + SIGNAL(test(QString foo, int bar)) + SIGNAL(test(QMap foo)) + SIGNAL(test(const QString &foo)) + SIGNAL(test(QString &foo)) + \endcode + + Just like in Qt \l {Qt::ConnectionType} {queued connections}, parameters in signals that are + references will be copied when being passed to replicas. + + \section3 SLOT + + \l [DOC QtCore] {Slots} {Slot} methods are created by using the SLOT keyword in the rep file. + + Usage is to declare \c SLOT followed by the desired signature wrapped in + parentheses. The return value can be included in the declaration. If the + return value is skipped, void will be used in the generated files. + + \code + SLOT(test()) + SLOT(void test(QString foo, int bar)) + SLOT(test(QMap foo)) + SLOT(test(QMap foo, QMap bar)) + SLOT(test(QMap,int> foo)) + SLOT(test(const QString &foo)) + SLOT(test(QString &foo)) + SLOT(test(const QMap,int> &foo)) + SLOT(test(const QString &foo, int bar)) + \endcode + + Just like in Qt \l {Qt::ConnectionType} {queued connections} and QtRO + SIGNALS, parameters in slots that are references will be copied when being + passed to Replicas. + + \section3 ENUM + + Enumerations (which use a combination of C++ enum and Qt's Q_ENUM in QtRO) + are described using the ENUM keyword. + + \code + ENUM MyEnum {Foo} + ENUM MyEnum {Foo, Bar} + ENUM MyEnum {Foo, Bar = -1} + ENUM MyEnum {Foo=-1, Bar} + ENUM MyEnum {Foo=0xf, Bar} + ENUM MyEnum {Foo=1, Bar=3, Bas=5} + \endcode + + Related topics: \l {The ENUM type}, \l {USE_ENUM keyword} + + \section2 The POD type + + Plain Old Data (POD) is a term to describe a simple data collection, along + the lines of a C++ struct. For example, if you have an API for a phonebook, + you may want to use the concept of an "address" in its interface (where + address might include street, city, state, country, and postal code). You + can use the POD keyword to define objects like this, which can then be used + by in PROP/SIGNAL/SLOT definitions in your class definitions. + + Usage is to declare \c POD followed by the name for the generated type, + followed by type and name pairs separated by commas, where the type/name + pairs are wrapped in parentheses. + + \code + POD Foo(int bar) + POD Foo(int bar, double bas) + POD Foo(QMap bar) + POD Foo(QList bar) + POD Foo(QMap bar, QMap bas) + \endcode + + A full example would look like this + \code + POD Foo(QList bar) + class MyType + { + SIGNAL(sendCustom(Foo foo)); + }; + \endcode + + The code generated by repc creates a Q_GADGET class for each POD, with + corresponding Q_PROPERTY members for each type defined for the POD. + + \section2 The ENUM type + + It is often easier and cleaner to define an ENUM inside a class (see \l ENUM), + but if you need a standalone enum type, using the ENUM keyword outside of a + class definition can be helpful. This will generate a new class in your + header files that handles marshalling, etc.. The syntax is identical to \l + ENUM, with the exception that the declaration in this case is not contained + in a \c class declaration. + + Related topics: \l {ENUM}, \l {USE_ENUM keyword} + + \section2 USE_ENUM keyword + + The USE_ENUM keyword was implemented before autogeneration via the ENUM + keyword was added. It is kept for backwards compatibility. + + Related topics: \l {ENUM}, \l {The ENUM type} + + \section2 Directives + + The rep file defines an interface, but interfaces often require external + elements. In order to support this, repc will include any (single line) + directives at the top of the generated files. This allows you to, for + instance, use #include or #define directives that support the logic or + datatypes needed. + + The repc tool currently ignores everything from the "#" symbol to the + end-of-line and adds that to the generated files. So multi-line + #if/#else/#endif statements and multi-line macros are not supported. + + \section1 CMake functions + + The CMake functions for generating source and replica types are listed below. + + \annotatedlist cmake-macros-qtremoteobjects + + \section1 qmake variables + \section2 REPC_REPLICA + + Specifies the names of all rep files in the project that should be used to generate + replica header files. + + For example: + \code + REPC_REPLICA = media.rep \ + location.rep + \endcode + + The generated file(s) will be of the form \c {rep__replica.h}. + + \section2 REPC_SOURCE + + Specifies the names of all rep files in the project that should be used to generate + source header files. + + For example: + \code + REPC_SOURCE = media.rep \ + location.rep + \endcode + + The generated file(s) will be of the form \c {rep__source.h}. + + \section2 REPC_MERGED + + Specifies the names of all rep files in the project that should be used to generate + combined (source and replica) header files. + + For example: + \code + REPC_MERGED = media.rep \ + location.rep + \endcode + + The generated file(s) will be of the form \c {rep__merged.h}. + + \note Typically sources and replicas live in separate processes or devices, so this variable + is not commonly used. + + \section2 QOBJECT_REP + + Specifies the names of existing QObject header files that should be used to generate corresponding + .rep files. +*/ diff --git a/src/remoteobjects/doc/src/remoteobjects-replica.qdoc b/src/remoteobjects/doc/src/remoteobjects-replica.qdoc new file mode 100644 index 0000000..9f62677 --- /dev/null +++ b/src/remoteobjects/doc/src/remoteobjects-replica.qdoc @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ +/*! +\page qtremoteobjects-replica.html +\title Qt Remote Objects Replica +\brief Describes the concept of a replica and how it works as a surrogate object. +\target Replica + +A QRemoteObjectReplica ("replica") is a surrogate object that has approximately +the same API as the \l {Source} QObject it replicates. Additionally, there are +a few properties and signals to make it possible to detect when the replica is +initialized or if it loses its connection to the source object. There +are a few other differences, notably, a constant property on the source cannot +be constant on the replica. The value will not be known at the time when the +replica is instantiated; it will only be known once the replica is initialized. +For more information, see \l {Remote Object Interaction}. + +A compiled replica is a \l {QRemoteObjectReplica} based type, where the derived +class definition is automatically generated by the \l {repc} compiler. When you +use \l {CMake functions} or \l {qmake variables} for running the \l repc compiler, +this makes the generation part of the build process. Although only a header is +generated, it's a complete type. There is no public constructor, so you need to +use the \l {QRemoteObjectNode::acquire} template function to create the Replica +instance. + +A \l {QRemoteObjectDynamicReplica} can be generated at runtime. To do so, you +call \l {QRemoteObjectNode::acquireDynamic()}, passing in the source name +(a QString) as an argument. Dynamic replicas are a bit more verbose to use from +C++, but they do not require compilation. Dynamic replicas do not support +initial property values, or introspection until they have been initialized. + +An important difference between these two ways of creating replicas is the +behavior before the replica is initialized. Since a dynamic replica only gets +a metaObject after initialization, it has basically no API before +initialization -- no properties, and no signals to connect slots to. + +Because metaObjects for compiled replicas are created at compile-time, their +API is available when the replica is instantiated. You can even provide default +values for properties in the template file, which are used until the replica is +initialized with current values from the source. + +\section1 Replica Initialization + +A host node will share the list of sources that it hosts with every other node +that connects to it. This host sends updates when sources are added to or +removed from the list. In this way, a connected node will always know what +sources it can attach itself to. Changes to a specific source are only +propagated to nodes that have a replica of that source. Consequently, this +avoids any unnecessary network traffic. + +When a node acquires a replica for a known source, it sends a request for that +source to the host node. Upon receiving this request, the host creates a reply +packet with the current values for all properties of that source. If the +requested replica is \l{QRemoteObjectDynamicReplica}{dynamic}, the reply packet +includes the API definition for the source. From then on, the replica's node +will be included in the list of connections that receive changes to that +source. + +If a replica is instantiated but its node is not connected to the node that +hosts the requested source -- or that object lives in a host node process, but +sharing/remoting has not been enabled for the QObject -- the Replica will still +be created, but remain uninitialized. + +If, at a later time, the replica's node gets notified that the requested source +is available from a connected node, at that point it will request the source +and start the initialization process. + +If the connection to a host node is lost, the replica will transition to the +invalid state. It will attempt to reconnect and will re-initialize if the +connection is restored; this makes sure all properties are current. + +\section1 Replica Ownership + +The acquire methods return a pointer to the replica QObject instantiated by the +node. The node has no way of knowing the replica's intended lifetime. +Consequently, when the replica is not longer needed, it is the calling +program's responsibility to delete it. + +You can instantiate multiple copies of the same replica. All replicas of the +same source from a single node will share a private data member which handles +the network communication. This means multiple instances of a replica do not +introduce additional network traffic, although there will be some additional +processing overhead. Failing to delete replicas will prevent the reference +count on this private object from reaching 0, and cause unnecessary network +communication until the calling process exits. For this reason, it is +recommended to use \l {QScopedPointer} or \l {QSharedPointer} to help track +the lifetime of replicas. + +*/ diff --git a/src/remoteobjects/doc/src/remoteobjects-source.qdoc b/src/remoteobjects/doc/src/remoteobjects-source.qdoc new file mode 100644 index 0000000..3ac8136 --- /dev/null +++ b/src/remoteobjects/doc/src/remoteobjects-source.qdoc @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ +/*! +\page qtremoteobjects-source.html +\title Qt Remote Objects Source +\brief Describes the concept of a source and how to use the source header that the repc generates. +\target Source + +A QRemoteObjectSource ("source") is the QObject that is responsible for +implementing the exposed API. + +At a high level, you can choose to use a QObject type directly as a source; or +you can define the desired API in a \c{.rep} template for use with the +\l {repc} compiler. + +If you already have a fully defined QObject, you can use it as a source by +passing it to \l {QRemoteObjectHostBase::enableRemoting()}. This way, other +processes or devices can then create +\l{QRemoteObjectDynamicReplica}{dynamics replicas} of the object to interact +with. + +For more information, see \l{Remote Object Interaction}. + +Letting repc generate a source header file for your project, using the +\l {REPC_SOURCE} variable, provides three different options to implement the +required API. + +Suppose your class name is Foo, you then have the following options: + +\list + \li \l {TypeSimpleSource} {FooSimpleSource} inheritance + \li \l {TypeSource} {FooSource} inheritance + \li \l {TypeAPI} {FooSourceAPI} usage with your own QObject +\endlist + +For more details on how to create a \c{.rep} file, see \l{The rep file format}. + +\target TypeSimpleSource +There is a SimpleSource class defined in the header, which provides the +basic getter/setter methods for each property and implements data members of +the correct property type in the header. "" here represents the class +name from the \c{.rep} file, so if your class is of type "MyType" in the +\c{.rep} file, then the generated header file will have a MyTypeSimpleSource +class declared. This is a quick way to get started using the API. To use this +class, you need to write a class that inherits from it and implement any slots +defined, which are marked as pure virtual in the generated header file. +You need to add the necessary logic to manage the exposed properties and emit +signals, to your class as well. + +\target TypeSource +If you need to hide your implementation details, use the second class declared +in the header file, the Source class. This class' definition does not +provide data members, and also makes the getter/setter functions pure virtual. +While you may need to write more code, using this class gives you more +flexibility in your implementation. + +\target TypeAPI +The third class generated in the header is SourceAPI. This is a templated +class, for use specifically by the templated version of +\l {QRemoteObjectHostBase::enableRemoting()}, which allows you to use any +QObject that supports the required API as the source. Use this class to hide or +convert properties or signal/slot parameters. If your implementation +does not provide the correct API, there will be compile-time warnings. + +\note Replicas and sources both derive from QObject; but their QObject API is +\b never exposed. For instance, while a replica has a \l{QObject::}{destroyed} +signal, the source's \l{QObject::}{destroyed} signal is not propagated. The +source and each of its replica are unique QObjects with their own connections +and lifetimes. Instead, the API that is exposed is defined by the \c{.rep} +template used by repc. In the case of raw QObjects, all API elements are defined +in the inheritance chain from a specific ancestor. The QObject's parent is always +used, unless you define \c{Q_CLASSINFO("RemoteObject Type")} in an ancestor. If +you use \c{Q_CLASSINFO("RemoteObject Type")}, that class's API is the lowest +level of API used. + +\section1 Identifying Sources + +Because a host node can share more than one source, each source requires a name. +All repc-generated headers include a way for the node to determine the class name: +Q_CLASSINFO for replica, simplesource, or source types; or a static \c name() +function for the SourceAPI type. If you pass your own QObject type to +\l {QRemoteObjectHostBase::enableRemoting()}, the name is determined using the +following logic: +\list + \li A name can optionally be passed to \l {QRemoteObjectHostBase::enableRemoting()}. + If provided, that name is used. + \li If the object or any of its ancestors has Q_CLASSINFO of type + "RemoteObject Type" defined, that type name is used. + \li If the QObject's objectName is set, then it is used. + \li If none of the above are available, the call to + \l {QRemoteObjectHostBase::enableRemoting()} fails, returning false. +\endlist +*/ diff --git a/src/remoteobjects/doc/src/remoteobjects-troubleshooting.qdoc b/src/remoteobjects/doc/src/remoteobjects-troubleshooting.qdoc new file mode 100644 index 0000000..db5b8d9 --- /dev/null +++ b/src/remoteobjects/doc/src/remoteobjects-troubleshooting.qdoc @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ +/*! +\page qtremoteobjects-troubleshooting.html +\title Troubleshooting Qt Remote Objects +\section1 Troubleshooting + +QtRO includes a number of internal logging categories that can be used for further debugging: + +\code +qt.remoteobjects +qt.remoteobjects.io +qt.remoteobjects.models +\endcode + +*/ diff --git a/src/remoteobjects/qconnection_local_backend.cpp b/src/remoteobjects/qconnection_local_backend.cpp new file mode 100644 index 0000000..cd91a8a --- /dev/null +++ b/src/remoteobjects/qconnection_local_backend.cpp @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qconnection_local_backend_p.h" + +QT_BEGIN_NAMESPACE + +LocalClientIo::LocalClientIo(QObject *parent) + : QtROClientIoDevice(parent) + , m_socket(new QLocalSocket(this)) +{ + connect(m_socket, &QLocalSocket::readyRead, this, &QtROClientIoDevice::readyRead); + connect(m_socket, &QLocalSocket::errorOccurred, this, &LocalClientIo::onError); + connect(m_socket, &QLocalSocket::stateChanged, this, &LocalClientIo::onStateChanged); +} + +LocalClientIo::~LocalClientIo() +{ + close(); +} + +QIODevice *LocalClientIo::connection() const +{ + return m_socket; +} + +void LocalClientIo::doClose() +{ + if (m_socket->isOpen()) { + connect(m_socket, &QLocalSocket::disconnected, this, &QObject::deleteLater); + m_socket->disconnectFromServer(); + } else { + this->deleteLater(); + } +} + +void LocalClientIo::doDisconnectFromServer() +{ + m_socket->disconnectFromServer(); +} + +void LocalClientIo::connectToServer() +{ +#ifdef Q_OS_ANDROID + if (!m_socket->socketOptions().testFlag(QLocalSocket::AbstractNamespaceOption)) + qWarning() << "It is recommended to use 'localabstract' over 'local' on Android."; +#endif + if (!isOpen()) + m_socket->connectToServer(url().path()); +} + +bool LocalClientIo::isOpen() const +{ + return !isClosing() && (m_socket->state() == QLocalSocket::ConnectedState + || m_socket->state() == QLocalSocket::ConnectingState); +} + +void LocalClientIo::onError(QLocalSocket::LocalSocketError error) +{ + qCDebug(QT_REMOTEOBJECT) << "onError" << error << m_socket->serverName(); + + switch (error) { + case QLocalSocket::ServerNotFoundError: + case QLocalSocket::UnknownSocketError: + case QLocalSocket::PeerClosedError: + //Host not there, wait and try again + emit shouldReconnect(this); + break; + case QLocalSocket::ConnectionError: + case QLocalSocket::ConnectionRefusedError: + //... TODO error reporting +#ifdef Q_OS_UNIX + emit shouldReconnect(this); +#endif + break; + default: + break; + } +} + +void LocalClientIo::onStateChanged(QLocalSocket::LocalSocketState state) +{ + if (state == QLocalSocket::ClosingState && !isClosing()) { + m_socket->abort(); + emit shouldReconnect(this); + } + if (state == QLocalSocket::ConnectedState) + initializeDataStream(); +} + +LocalServerIo::LocalServerIo(QLocalSocket *conn, QObject *parent) + : QtROServerIoDevice(parent), m_connection(conn) +{ + m_connection->setParent(this); + connect(conn, &QIODevice::readyRead, this, &QtROServerIoDevice::readyRead); + connect(conn, &QLocalSocket::disconnected, this, &QtROServerIoDevice::disconnected); +} + +QIODevice *LocalServerIo::connection() const +{ + return m_connection; +} + +void LocalServerIo::doClose() +{ + m_connection->disconnectFromServer(); +} + +LocalServerImpl::LocalServerImpl(QObject *parent) + : QConnectionAbstractServer(parent) +{ + connect(&m_server, &QLocalServer::newConnection, this, &QConnectionAbstractServer::newConnection); +} + +LocalServerImpl::~LocalServerImpl() +{ + m_server.close(); +} + +QtROServerIoDevice *LocalServerImpl::configureNewConnection() +{ + if (!m_server.isListening()) + return nullptr; + + return new LocalServerIo(m_server.nextPendingConnection(), this); +} + +bool LocalServerImpl::hasPendingConnections() const +{ + return m_server.hasPendingConnections(); +} + +QUrl LocalServerImpl::address() const +{ + QUrl result; + result.setPath(m_server.serverName()); + result.setScheme(QRemoteObjectStringLiterals::local()); + + return result; +} + +bool LocalServerImpl::listen(const QUrl &address) +{ +#ifdef Q_OS_ANDROID + if (!m_server.socketOptions().testFlag(QLocalServer::AbstractNamespaceOption)) + qWarning() << "It is recommended to use 'localabstract' over 'local' on Android."; +#endif +#ifdef Q_OS_UNIX + bool res = m_server.listen(address.path()); + if (!res) { + QLocalServer::removeServer(address.path()); + res = m_server.listen(address.path()); + } + return res; +#else + return m_server.listen(address.path()); +#endif +} + +QAbstractSocket::SocketError LocalServerImpl::serverError() const +{ + return m_server.serverError(); +} + +void LocalServerImpl::close() +{ + m_server.close(); +} + +#ifdef Q_OS_LINUX + +AbstractLocalClientIo::AbstractLocalClientIo(QObject *parent) + : LocalClientIo(parent) +{ + m_socket->setSocketOptions(QLocalSocket::AbstractNamespaceOption); +} + +AbstractLocalServerImpl::AbstractLocalServerImpl(QObject *parent) + : LocalServerImpl(parent) +{ + m_server.setSocketOptions(QLocalServer::AbstractNamespaceOption); +} + +QUrl AbstractLocalServerImpl::address() const +{ + QUrl result; + result.setPath(m_server.serverName()); + result.setScheme(QRemoteObjectStringLiterals::localabstract()); + + return result; +} + +#endif // Q_OS_LINUX + +QT_END_NAMESPACE diff --git a/src/remoteobjects/qconnection_local_backend_p.h b/src/remoteobjects/qconnection_local_backend_p.h new file mode 100644 index 0000000..d0adb2d --- /dev/null +++ b/src/remoteobjects/qconnection_local_backend_p.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2017-2015 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCONNECTIONCLIENTFACTORY_P_H +#define QCONNECTIONCLIENTFACTORY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qconnectionfactories_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class LocalClientIo : public QtROClientIoDevice +{ + Q_OBJECT + +public: + explicit LocalClientIo(QObject *parent = nullptr); + ~LocalClientIo() override; + + QIODevice *connection() const override; + void connectToServer() override; + bool isOpen() const override; + +public Q_SLOTS: + void onError(QLocalSocket::LocalSocketError error); + void onStateChanged(QLocalSocket::LocalSocketState state); + +protected: + void doClose() override; + void doDisconnectFromServer() override; + QLocalSocket* m_socket; +}; + +#ifdef Q_OS_LINUX + +class AbstractLocalClientIo final : public LocalClientIo +{ + Q_OBJECT + +public: + explicit AbstractLocalClientIo(QObject *parent = nullptr); +}; + +#endif // Q_OS_LINUX + +class LocalServerIo final : public QtROServerIoDevice +{ + Q_OBJECT +public: + explicit LocalServerIo(QLocalSocket *conn, QObject *parent = nullptr); + + QIODevice *connection() const override; +protected: + void doClose() override; + +private: + QLocalSocket *m_connection; +}; + +class LocalServerImpl : public QConnectionAbstractServer +{ + Q_OBJECT + Q_DISABLE_COPY(LocalServerImpl) + +public: + explicit LocalServerImpl(QObject *parent); + ~LocalServerImpl() override; + + bool hasPendingConnections() const override; + QtROServerIoDevice *configureNewConnection() override; + QUrl address() const override; + bool listen(const QUrl &address) override; + QAbstractSocket::SocketError serverError() const override; + void close() override; + +protected: + QLocalServer m_server; +}; + +#ifdef Q_OS_LINUX + +class AbstractLocalServerImpl final : public LocalServerImpl +{ + Q_OBJECT + +public: + explicit AbstractLocalServerImpl(QObject *parent); + QUrl address() const override; +}; + +#endif // Q_OS_LINUX + +QT_END_NAMESPACE + +#endif diff --git a/src/remoteobjects/qconnection_qnx_backend.cpp b/src/remoteobjects/qconnection_qnx_backend.cpp new file mode 100644 index 0000000..e5fd680 --- /dev/null +++ b/src/remoteobjects/qconnection_qnx_backend.cpp @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2017-2016 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qconnection_qnx_backend_p.h" + +QT_BEGIN_NAMESPACE + +QnxClientIo::QnxClientIo(QObject *parent) + : QtROClientIoDevice(parent) + , m_socket(new QQnxNativeIo(this)) +{ + connect(m_socket, &QQnxNativeIo::readyRead, this, &QtROClientIoDevice::readyRead); + connect(m_socket, + static_cast(&QQnxNativeIo::error), + this, + &QnxClientIo::onError); + connect(m_socket, &QQnxNativeIo::stateChanged, this, &QnxClientIo::onStateChanged); +} + +QnxClientIo::~QnxClientIo() +{ + close(); +} + +QIODevice *QnxClientIo::connection() const +{ + return m_socket; +} + +void QnxClientIo::doClose() +{ + if (m_socket->isOpen()) { + connect(m_socket, &QQnxNativeIo::disconnected, this, &QObject::deleteLater); + m_socket->disconnectFromServer(); + } else { + deleteLater(); + } +} + +void QnxClientIo::doDisconnectFromServer() +{ + m_socket->disconnectFromServer(); +} + +void QnxClientIo::connectToServer() +{ + if (!isOpen()) + m_socket->connectToServer(url().path()); +} + +bool QnxClientIo::isOpen() const +{ + return !isClosing() && (m_socket->state() == QAbstractSocket::ConnectedState + || m_socket->state() == QAbstractSocket::ConnectingState); +} + +void QnxClientIo::onError(QAbstractSocket::SocketError error) +{ + qCDebug(QT_REMOTEOBJECT) << "onError" << error << m_socket->serverName(); + + switch (error) { + case QAbstractSocket::RemoteHostClosedError: + m_socket->close(); + qCWarning(QT_REMOTEOBJECT) << "RemoteHostClosedError"; + Q_FALLTHROUGH(); + case QAbstractSocket::HostNotFoundError: //Host not there, wait and try again + case QAbstractSocket::AddressInUseError: + case QAbstractSocket::ConnectionRefusedError: + //... TODO error reporting + emit shouldReconnect(this); + break; + default: + break; + } +} + +void QnxClientIo::onStateChanged(QAbstractSocket::SocketState state) +{ + if (state == QAbstractSocket::ClosingState && !isClosing()) { + m_socket->abort(); + emit shouldReconnect(this); + } else if (state == QAbstractSocket::ConnectedState) + initializeDataStream(); +} + +QnxServerIo::QnxServerIo(QSharedPointer conn, QObject *parent) + : QtROServerIoDevice(parent), m_connection(conn) +{ + connect(conn.data(), &QIODevice::readyRead, this, &QtROServerIoDevice::readyRead); + connect(conn.data(), &QIOQnxSource::disconnected, this, &QtROServerIoDevice::disconnected); +} + +QIODevice *QnxServerIo::connection() const +{ + return m_connection.data(); +} + +void QnxServerIo::doClose() +{ + m_connection->close(); +} + +QnxServerImpl::QnxServerImpl(QObject *parent) + : QConnectionAbstractServer(parent) +{ + connect(&m_server, + &QQnxNativeServer::newConnection, + this, + &QConnectionAbstractServer::newConnection); +} + +QnxServerImpl::~QnxServerImpl() +{ + m_server.close(); +} + +QtROServerIoDevice *QnxServerImpl::configureNewConnection() +{ + if (!m_server.isListening()) + return nullptr; + + return new QnxServerIo(m_server.nextPendingConnection(), this); +} + +bool QnxServerImpl::hasPendingConnections() const +{ + return m_server.hasPendingConnections(); +} + +QUrl QnxServerImpl::address() const +{ + QUrl result; + result.setPath(m_server.serverName()); + result.setScheme(QStringLiteral("qnx")); + + return result; +} + +bool QnxServerImpl::listen(const QUrl &address) +{ + return m_server.listen(address.path()); +} + +QAbstractSocket::SocketError QnxServerImpl::serverError() const +{ + //TODO implement on QQnxNativeServer and here + //return m_server.serverError(); + return QAbstractSocket::AddressInUseError; +} + +void QnxServerImpl::close() +{ + close(); +} + +QT_END_NAMESPACE diff --git a/src/remoteobjects/qconnection_qnx_backend_p.h b/src/remoteobjects/qconnection_qnx_backend_p.h new file mode 100644 index 0000000..3110ed8 --- /dev/null +++ b/src/remoteobjects/qconnection_qnx_backend_p.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2017-2016 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCONNECTIONQNXBACKEND_P_H +#define QCONNECTIONQNXBACKEND_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qconnectionfactories_p.h" +#include "qconnection_qnx_qiodevices.h" +#include "qconnection_qnx_server.h" + +QT_BEGIN_NAMESPACE + +/*! + QtRO provides QtROClientIoDevice, QtROServerIoDevice and QConnectionAbstractServer + as abstract interfaces to allow different backends to be used by QtRO. The + concept behind these classes is that there needs to be a Host node, which + has an address that can be connected to. Then there is a client object, + which can be publicly constructed, and can connect to the server. When the + server gets a connection request, it creates the server side of the + connection, which communicates directly with the client. There are thus + three abstractions, one for the server, one for the client-side of the + connection, and the third for the server-side of the connection. The later + two need to inherit from QIODevice. + + Creating a backend for something that is already implemented in Qt is a + matter of creating the three needed abstractions. In the case of creating a + QNX backend using QNX's Native Messaging, the backend needs to create the + Server (which has an address for accepting connections), the client + QIODevice, and the server side QIODevice. Since Native Messaging is one + way, and recommends using pulses to support two-way communication, the + logic for the client-side and server-side QIODevice are very different. + Thus, three additional backend classes are needed as well. + + QnxClientIo implements the QtRO QtROClientIoDevice wrapper around the QNX + specific QQnxNativeIo QIODevice (the client-side QIODevice). + + QnxServerIo implements the QtRO QtROServerIoDevice wrapper around the QNX + specific QIOQnxSource QIODevice (the server-side QIODevice). + + QnxServerImpl implements the QtRO QConnectionAbstractServer wrapper around + the QNX specific QQnxNativeServer, which is the server object listening for + connections. + + Not sure if it is of interest to the Qt community, but it seems like + QQnxNativeIo, QIOQnxSource and QQnxNativeServer could used as an optimized + QLocalServer/QLocalSocket QPA for QNX. +*/ + +class QnxClientIo final : public QtROClientIoDevice +{ + Q_OBJECT + +public: + explicit QnxClientIo(QObject *parent = nullptr); + ~QnxClientIo() override; + + QIODevice *connection() const override; + void connectToServer() override; + bool isOpen() const override; + +public Q_SLOTS: + void onError(QAbstractSocket::SocketError error); + void onStateChanged(QAbstractSocket::SocketState state); + +protected: + void doClose() override; + void doDisconnectFromServer() override; +private: + QQnxNativeIo *m_socket; +}; + +class QnxServerIo final : public QtROServerIoDevice +{ +public: + explicit QnxServerIo(QSharedPointer conn, QObject *parent = nullptr); + + QIODevice *connection() const override; +protected: + void doClose() override; + +private: + //TODO Source or Replica + QSharedPointer m_connection; +}; + +class QnxServerImpl final : public QConnectionAbstractServer +{ + Q_OBJECT + +public: + explicit QnxServerImpl(QObject *parent); + ~QnxServerImpl() override; + + bool hasPendingConnections() const override; + QtROServerIoDevice *configureNewConnection() override; + QUrl address() const override; + bool listen(const QUrl &address) override; + QAbstractSocket::SocketError serverError() const override; + void close() override; + +private: + QQnxNativeServer m_server; +}; + +QT_END_NAMESPACE + +#endif // QCONNECTIONQNXBACKEND_P_H + diff --git a/src/remoteobjects/qconnection_qnx_global_p.h b/src/remoteobjects/qconnection_qnx_global_p.h new file mode 100644 index 0000000..bf87431 --- /dev/null +++ b/src/remoteobjects/qconnection_qnx_global_p.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2017-2016 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNXIPCPRIVATE_GLOBAL_H +#define QNXIPCPRIVATE_GLOBAL_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include // provides SETIOV +#include //FOR ND_LOCAL_NODE +#include +#include +#ifdef USE_HAM +# include +#endif + +#define WARNING(cmd) qCWarning(QT_REMOTEOBJECT) << "Warning " #cmd << strerror(errno) \ + << Q_FUNC_INFO << __FILE__ << __LINE__; + +#define WARN_ON_ERROR(cmd, ...) if (cmd(__VA_ARGS__) == -1) qCWarning(QT_REMOTEOBJECT) \ + << "Error " #cmd << strerror(errno) << Q_FUNC_INFO << __FILE__ << __LINE__; + +#define WARN_AND_RETURN_ON_ERROR(cmd, retval, ...) if (cmd(__VA_ARGS__) == -1) \ + { qCWarning(QT_REMOTEOBJECT) << "Error " #cmd << strerror(errno) \ + << Q_FUNC_INFO << __FILE__ << __LINE__; return (retval); } + +#define FATAL_ON_ERROR(cmd, ...) if (cmd(__VA_ARGS__) == -1) qFatal("Error %s: %s %s %s %d", \ + #cmd, strerror(errno), Q_FUNC_INFO, __FILE__, __LINE__); + +QT_BEGIN_NAMESPACE + +const int MAX_RETRIES = 3; + +enum MsgType : uint16_t { REPLICA_INIT = _IO_MAX+100, + REPLICA_TX_RECV, + SOURCE_TX_RESP, + SOURCE_TX_RESP_REPEAT, + }; +enum PulseType : uint8_t { SOURCE_TX_RQ = _PULSE_CODE_MINAVAIL+42, + REPLICA_WRITE, + TERMINATE, + NODE_DEATH + }; +union recv_msgs +{ + struct _pulse pulse; + uint16_t type; +}; + +template +class Thread : public QThread +{ +public: + Thread(T *obj, const QString &name = QString()) : QThread(), m_obj(obj) + { + if (!name.isEmpty()) + setObjectName(name); + } + void run() override + { + m_obj->thread_func(); + } +private: + T *m_obj; +}; + +QT_END_NAMESPACE + +#endif // QNXIPCPRIVATE_GLOBAL_H + diff --git a/src/remoteobjects/qconnection_qnx_qiodevices.cpp b/src/remoteobjects/qconnection_qnx_qiodevices.cpp new file mode 100644 index 0000000..f1f977f --- /dev/null +++ b/src/remoteobjects/qconnection_qnx_qiodevices.cpp @@ -0,0 +1,655 @@ +/**************************************************************************** +** +** Copyright (C) 2017-2016 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qconnection_qnx_global_p.h" +#include "qconnection_qnx_qiodevices.h" +#include "qconnection_qnx_server.h" +#include "qconnection_qnx_qiodevices_p.h" + +QT_BEGIN_NAMESPACE + +QQnxNativeIoPrivate::QQnxNativeIoPrivate() + : QIODevicePrivate() + , serverId(-1) + , channelId(-1) + , connectionId(-1) + , state(QAbstractSocket::UnconnectedState) + , obuffer(new QRingBuffer) + , thread(this, QStringLiteral("NativeIo")) +{ + //This lets us set msgType before any MsgSend + //and have the value sent as the header/type. + SETIOV(tx_iov + 0, &msgType, sizeof(msgType)); + SIGEV_NONE_INIT(&tx_pulse); +} + +QQnxNativeIoPrivate::~QQnxNativeIoPrivate() +{ + teardownConnection(); +} + +bool QQnxNativeIoPrivate::establishConnection() +{ + //On the client side, we need to create the channel/connection + //to listen for the server's send pulse. + if (channelId == -1) { + const int channel = ChannelCreate(0); + if (channel == -1) { + WARNING(ChannelCreate) + return false; + } + channelId = channel; + } + + const int connection = ConnectAttach(ND_LOCAL_NODE, 0, channelId, _NTO_SIDE_CHANNEL, 0); + if (connection == -1) { + WARNING(ConnectAttach) + teardownConnection(); + return false; + } + connectionId = connection; + + SIGEV_PULSE_INIT(&tx_pulse, connection, SIGEV_PULSE_PRIO_INHERIT, SOURCE_TX_RQ, 0); + SIGEV_MAKE_UPDATEABLE(&tx_pulse); + qCDebug(QT_REMOTEOBJECT) << "in establish" << tx_pulse.sigev_code << SOURCE_TX_RQ; + + if (MsgRegisterEvent(&tx_pulse, connectionId) == -1) { + qCWarning(QT_REMOTEOBJECT) << "Unable to register event for server" << serverName; + teardownConnection(); + return false; + } + + const int id = name_open(qPrintable(serverName), 0); + if (id == -1) { + qCWarning(QT_REMOTEOBJECT) << "Unable to connect to server" << serverName; + teardownConnection(); + return false; + } + serverId = id; + + thread.start(); + + Q_Q(QQnxNativeIo); + qCDebug(QT_REMOTEOBJECT) << "Before INIT: ServerId" << id << "name" << serverName << q; + SETIOV(tx_iov + 1, &tx_pulse, sizeof(tx_pulse)); + SETIOV(tx_iov + 2, &channelId, sizeof(channelId)); + + //Send our registration message to the server + msgType = MsgType::REPLICA_INIT; + //We send tx_pulse along. When the server want to + //transmit data, it sends the pulse back to us. + //When we see that (in receive_thread) we send a + //message and get the server's tx data in the reply. + // + //We transmit the channelId as well - it is only used + //if HAM is enabled, but this will prevent a possible + //mismatch between code compiled with vs. without HAM + //(which could happen if we ever use QCONN between + //devices) + if (MsgSendv(serverId, tx_iov, 3, nullptr, 0) == -1) { + WARNING(MsgSendv) + teardownConnection(); + return false; + } + + state = QAbstractSocket::ConnectedState; + emit q->stateChanged(state); + + return true; +} + +void QQnxNativeIoPrivate::teardownConnection() +{ + Q_Q(QQnxNativeIo); + state = QAbstractSocket::ClosingState; + emit q->stateChanged(state); + + stopThread(); + + state = QAbstractSocket::UnconnectedState; + emit q->stateChanged(state); +} + +void QQnxNativeIoPrivate::stopThread() +{ + if (thread.isRunning()) { + for (int count = 0; count < MAX_RETRIES; ++count) { + if (MsgSendPulse(connectionId, -1, TERMINATE, 0) == -1) { + if (errno == EAGAIN) { + usleep(5000 + (rand() % 10) * 10000); //5 to 95 msec + qCWarning(QT_REMOTEOBJECT) << "Retrying terminate pulse"; + continue; + } + qFatal("MsgSendPulse failed on terminate pulse. Error = %s", strerror(errno)); + } + thread.wait(); + return; + } + if (errno == EAGAIN) + qFatal("MsgSendPulse failed on terminate pulse (max retries)"); + } +} + +// method (run in a thread) to watch for connections and handle receiving data +void QQnxNativeIoPrivate::thread_func() +{ + Q_Q(QQnxNativeIo); + + _pulse pulse; + + qCDebug(QT_REMOTEOBJECT) << "Client thread_func running"; + + bool running = true; + int nTxRequestToIgnore = 0; + while (running) { + int rcvid = MsgReceivePulse(channelId, &pulse, sizeof(pulse), nullptr); + if (rcvid == -1) + continue; + + qCDebug(QT_REMOTEOBJECT) << "MsgReceivePulse unblocked, code =" << pulse.code; + + switch (pulse.code) { + case SOURCE_TX_RQ: //The Source object wants to send us data + { + const int len = pulse.value.sival_int; + qCDebug(QT_REMOTEOBJECT, "TX request with len = %d, tx ignore = %d", len, nTxRequestToIgnore); + if (nTxRequestToIgnore) { + --nTxRequestToIgnore; + break; + } + + int bytesLeft; + + msgType = MsgType::SOURCE_TX_RESP; + ibLock.lockForWrite(); + iov_t reply_vector[2]; + SETIOV(reply_vector, &bytesLeft, sizeof(bytesLeft)); + SETIOV(reply_vector+1, buffer.reserve(len), size_t(len)); + const int res = MsgSendv(serverId, tx_iov, 1, reply_vector, 2); + + if (res == -1) { + buffer.chop(len); + ibLock.unlock(); + WARNING(MsgSendv); + break; + } + ibLock.unlock(); + + qCDebug(QT_REMOTEOBJECT) << "Reply said bytesLeft =" << bytesLeft; + + if (bytesLeft) { + msgType = MsgType::SOURCE_TX_RESP_REPEAT; + ibLock.lockForWrite(); + SETIOV(reply_vector, &nTxRequestToIgnore, sizeof(nTxRequestToIgnore)); + SETIOV(reply_vector+1, buffer.reserve(bytesLeft), size_t(bytesLeft)); + const int res = MsgSendv(serverId, tx_iov, 1, reply_vector, 2); + if (res == -1) { + buffer.chop(bytesLeft); + ibLock.unlock(); + WARNING(MsgSendv); + break; + } + ibLock.unlock(); + qCDebug(QT_REMOTEOBJECT) << "Reply2 said nTxRequestToIgnore =" << nTxRequestToIgnore; + } + + QMetaObject::invokeMethod(q, "readyRead", Qt::QueuedConnection); + } + break; + case REPLICA_WRITE: //Our node has data to send + { + const int len = pulse.value.sival_int; + obLock.lockForWrite(); //NAR (Not-An-Error) + const QByteArray payload = obuffer->read(); + obLock.unlock(); + Q_ASSERT(len == payload.length()); + + msgType = MsgType::REPLICA_TX_RECV; + SETIOV(tx_iov + 1, payload.constData(), size_t(len)); + if (MsgSendvs(serverId, tx_iov, 2, nullptr, 0) == -1) { + WARNING(MsgSendvs); + obLock.lockForWrite(); + if (obuffer->isEmpty()) { + obuffer->append(payload); + } else { + //Since QRingBuffer just holds a QList of + //QByteArray, copying the QByteArrays to + //another container is cheap. + QRingBuffer *newBuffer = new QRingBuffer; + newBuffer->append(payload); + while (!obuffer->isEmpty()) + newBuffer->append(obuffer->read()); + obuffer.reset(newBuffer); + } + obLock.unlock(); + WARNING(MsgSendvs); + } + } + break; + case TERMINATE: + running = false; + continue; + case NODE_DEATH: + qCWarning(QT_REMOTEOBJECT) << "Host node died"; + running = false; + emit q->error(QAbstractSocket::RemoteHostClosedError); + continue; + default: + /* some other unexpected message */ + qCWarning(QT_REMOTEOBJECT) << "unexpected pulse type:" << pulse.type << __FILE__ << __LINE__; + WARN_ON_ERROR(MsgError, rcvid, ENOSYS) + break; + } + } + + if (serverId >= 0) { + WARN_ON_ERROR(name_close, serverId) + serverId = -1; + } + + if (tx_pulse.sigev_notify & SIGEV_FLAG_HANDLE) { + WARN_ON_ERROR(MsgUnregisterEvent, &tx_pulse); + SIGEV_NONE_INIT(&tx_pulse); + } + + if (connectionId >= 0) { + WARN_ON_ERROR(ConnectDetach, connectionId) + connectionId = -1; + } + + if (channelId >= 0) { + WARN_ON_ERROR(ChannelDestroy, channelId) + channelId = -1; + } + + qCDebug(QT_REMOTEOBJECT) << "Client thread_func stopped"; +} + +QQnxNativeIo::QQnxNativeIo(QObject *parent) + : QIODevice(*new QQnxNativeIoPrivate, parent) +{ +} + +QQnxNativeIo::~QQnxNativeIo() +{ + close(); +} + +bool QQnxNativeIo::connectToServer(QIODevice::OpenMode openMode) +{ + Q_D(QQnxNativeIo); + Q_UNUSED(openMode) + + if (state() == QAbstractSocket::ConnectedState || + state() == QAbstractSocket::ConnectingState) { + setErrorString(QStringLiteral("Already connected")); + emit error(QAbstractSocket::OperationError); + return false; + } + + const int omMask = QIODevice::Append | QIODevice::Truncate | QIODevice::Text; + if (openMode & omMask) + qCWarning(QT_REMOTEOBJECT, "Tried to open using unsupported open mode flags."); + + d->errorString.clear(); + d->state = QAbstractSocket::ConnectingState; + emit stateChanged(d->state); + + if (d->serverName.isEmpty()) { + setErrorString(QStringLiteral("serverName not set")); + emit error(QAbstractSocket::HostNotFoundError); + return false; + } + + QIODevice::open(openMode & (~omMask)); + + if (!d->establishConnection()) { + QIODevice::close(); + qCWarning(QT_REMOTEOBJECT, "Failed to connect to server"); + emit error(QAbstractSocket::UnknownSocketError); + return false; + } + + emit stateChanged(d->state); + + return true; +} + +bool QQnxNativeIo::connectToServer(const QString &name, QIODevice::OpenMode openMode) +{ + setServerName(name); + return connectToServer(openMode); +} + +void QQnxNativeIo::disconnectFromServer() +{ + close(); +} + +void QQnxNativeIo::setServerName(const QString &name) +{ + Q_D(QQnxNativeIo); + + if (d->state != QAbstractSocket::UnconnectedState) { + qCWarning(QT_REMOTEOBJECT) << "QQnxNativeIo::setServerName() called while not unconnected"; + return; + } + + d->serverName = name; +} + +QString QQnxNativeIo::serverName() const +{ + Q_D(const QQnxNativeIo); + return d->serverName; +} + +void QQnxNativeIo::abort() +{ + Q_D(QQnxNativeIo); + + d->stopThread(); + //Don't need mutex since thread is stopped + d->obuffer->clear(); + d->buffer.clear(); + + d->state = QAbstractSocket::UnconnectedState; + emit stateChanged(d->state); + QIODevice::close(); +} + +bool QQnxNativeIo::isSequential() const +{ + return true; +} + +qint64 QQnxNativeIo::bytesAvailable() const +{ + Q_D(const QQnxNativeIo); + + d->ibLock.lockForRead(); + qint64 size = d->buffer.size(); + d->ibLock.unlock(); + + return size; +} + +qint64 QQnxNativeIo::bytesToWrite() const +{ + Q_D(const QQnxNativeIo); + + d->obLock.lockForRead(); + qint64 size = d->obuffer->size(); + d->obLock.unlock(); + + return size; +} + +bool QQnxNativeIo::open(QIODevice::OpenMode openMode) +{ + const int omMask = QIODevice::Append | QIODevice::Truncate | QIODevice::Text; + if (openMode & omMask) + qCWarning(QT_REMOTEOBJECT, "Tried to open using unsupported open mode flags."); + + return connectToServer(openMode & (~omMask)); +} + +void QQnxNativeIo::close() +{ + Q_D(QQnxNativeIo); + + if (!isOpen()) + return; + + d->teardownConnection(); + + d->obuffer->clear(); + d->buffer.clear(); + QIODevice::close(); +} + +QAbstractSocket::SocketState QQnxNativeIo::state() const +{ + Q_D(const QQnxNativeIo); + return d->state; +} + +bool QQnxNativeIo::waitForBytesWritten(int msecs) +{ + //TODO - This method isn't used by Qt Remote Objects, but would + //need to be implemented before this class could be used as a + //generic QIODevice. + Q_UNUSED(msecs) + Q_ASSERT(false); + return false; +} + +bool QQnxNativeIo::waitForReadyRead(int msecs) +{ + //TODO - This method isn't used by Qt Remote Objects, but would + //need to be implemented before this class could be used as a + //generic QIODevice. + Q_UNUSED(msecs) + Q_ASSERT(false); + return false; +} + +qint64 QQnxNativeIo::readData(char *data, qint64 size) +{ + Q_D(QQnxNativeIo); + qint64 read; + + if (!isReadable()) + return 0; + + d->ibLock.lockForWrite(); //NAR (Not-An-Error) + read = d->buffer.read(data, size); + d->ibLock.unlock(); + + return read; +} + +qint64 QQnxNativeIo::writeData(const char *data, qint64 size) +{ + Q_D(QQnxNativeIo); + + if (!isWritable()) + return 0; + + if (size < 0 || size > INT_MAX) { + qCWarning(QT_REMOTEOBJECT) << "Invalid size (" << size << ") passed to QtRO QNX backend writeData()."; + return -1; + } + + int isize = static_cast(size); + + d->obLock.lockForWrite(); + d->obuffer->append(QByteArray(data, isize)); + d->obLock.unlock(); + + WARN_AND_RETURN_ON_ERROR(MsgSendPulse, -1, d->connectionId, -1, PulseType::REPLICA_WRITE, isize) + + return size; +} + +/* QIOQnxSource ***************************************************************/ + +QIOQnxSourcePrivate::QIOQnxSourcePrivate(int _rcvid) + : QIODevicePrivate() + , rcvid(_rcvid) + , state(QAbstractSocket::ConnectedState) +{ +} + +QIOQnxSource::QIOQnxSource(int rcvid, QObject *parent) + : QIODevice(*new QIOQnxSourcePrivate(rcvid), parent) +{ + setOpenMode(QIODevice::ReadWrite); +} + +QIOQnxSource::~QIOQnxSource() +{ + close(); +} + +bool QIOQnxSource::isSequential() const +{ + return true; +} + +qint64 QIOQnxSource::bytesAvailable() const +{ + Q_D(const QIOQnxSource); + + d->ibLock.lockForRead(); + qint64 size = d->buffer.size(); + d->ibLock.unlock(); + + return size; +} + +qint64 QIOQnxSource::bytesToWrite() const +{ + Q_D(const QIOQnxSource); + + d->obLock.lockForRead(); + qint64 size = d->obuffer.size(); + d->obLock.unlock(); + + return size; +} + +bool QIOQnxSource::open(QIODevice::OpenMode openMode) +{ + Q_UNUSED(openMode) + return false; +} + +void QIOQnxSource::onDisconnected() +{ + close(); + emit disconnected(); +} + +void QIOQnxSource::close() +{ + Q_D(QIOQnxSource); + + if (!isOpen()) + return; + + d->state = QAbstractSocket::ClosingState; + emit stateChanged(d->state); + + d->state = QAbstractSocket::UnconnectedState; + emit stateChanged(d->state); + + d->obuffer.clear(); + d->buffer.clear(); + QIODevice::close(); +} + +QAbstractSocket::SocketState QIOQnxSource::state() const +{ + Q_D(const QIOQnxSource); + return d->state; +} + +bool QIOQnxSource::waitForBytesWritten(int msecs) +{ + //TODO - This method isn't used by Qt Remote Objects, but would + //need to be implemented before this class could be used as a + //generic QIODevice. + Q_UNUSED(msecs) + Q_ASSERT(false); + return false; +} + +bool QIOQnxSource::waitForReadyRead(int msecs) +{ + //TODO - This method isn't used by Qt Remote Objects, but would + //need to be implemented before this class could be used as a + //generic QIODevice. + Q_UNUSED(msecs) + Q_ASSERT(false); + return false; +} + +qint64 QIOQnxSource::readData(char *data, qint64 size) +{ + Q_D(QIOQnxSource); + qint64 read; + + if (!isReadable()) + return 0; + + d->ibLock.lockForWrite(); //NAR (Not-An-Error) + read = d->buffer.read(data, size); + d->ibLock.unlock(); + + return read; +} + +qint64 QIOQnxSource::writeData(const char *data, qint64 size) +{ + Q_D(QIOQnxSource); + + if (!isWritable()) + return 0; + + if (size < 0 || size > INT_MAX) { + qCWarning(QT_REMOTEOBJECT) << "Invalid size (" << size << ") passed to QtRO QNX backend writeData()."; + return -1; + } + + int isize = static_cast(size); + + d->obLock.lockForWrite(); + d->obuffer.append(QByteArray(data, isize)); + d->obLock.unlock(); + + if (!d->m_serverClosing.loadRelaxed()) { + d->m_event.sigev_value.sival_int = isize; + WARN_ON_ERROR(MsgDeliverEvent, d->rcvid, &(d->m_event)) + } + + return size; +} + +QT_END_NAMESPACE diff --git a/src/remoteobjects/qconnection_qnx_qiodevices.h b/src/remoteobjects/qconnection_qnx_qiodevices.h new file mode 100644 index 0000000..a01c8e4 --- /dev/null +++ b/src/remoteobjects/qconnection_qnx_qiodevices.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2017-2016 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQNXNATIVEIO_H +#define QQNXNATIVEIO_H + +#include +#include + +QT_BEGIN_NAMESPACE + +/* + * The implementation of the Source and Replica + * side QIODevice look like they will be fairly + * different, including different APIs. So + * creating a 2nd derived type for the source. + * + * TODO: revisit if these can be combined into a + * single type. + * + * With two types, QQnxNativeIo will need to get + * Source or Replica added. Not sure what intuitive + * names are yet. So for now, QQnxNativeIo is the + * Replica side, QIOQnxSourcePrivate is the Source + * side. Revisit the name as this matures. + * +*/ +class QQnxNativeIoPrivate; +class QIOQnxSourcePrivate; + +class Q_REMOTEOBJECTS_EXPORT QQnxNativeIo : public QIODevice +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QQnxNativeIo) + +public: + explicit QQnxNativeIo(QObject *parent = nullptr); + ~QQnxNativeIo() override; + + bool connectToServer(OpenMode openMode = ReadWrite); + bool connectToServer(const QString &name, OpenMode openMode = ReadWrite); + void disconnectFromServer(); + + void setServerName(const QString &name); + QString serverName() const; + + void abort(); + bool isSequential() const override; + qint64 bytesAvailable() const override; + qint64 bytesToWrite() const override; + bool open(OpenMode openMode = ReadWrite) override; + void close() override; + QAbstractSocket::SocketError error() const; + bool flush(); + bool isValid() const; + + QAbstractSocket::SocketState state() const; + bool waitForBytesWritten(int msecs = 30000) override; + bool waitForConnected(int msecs = 30000); + bool waitForDisconnected(int msecs = 30000); + bool waitForReadyRead(int msecs = 30000) override; + +Q_SIGNALS: + void connected(); + void disconnected(); + void error(QAbstractSocket::SocketError socketError); + void stateChanged(QAbstractSocket::SocketState socketState); + +protected: + qint64 readData(char*, qint64) override; + qint64 writeData(const char*, qint64) override; + +private: + Q_DISABLE_COPY(QQnxNativeIo) +}; +Q_DECLARE_TYPEINFO(QQnxNativeIo, Q_RELOCATABLE_TYPE); + +class Q_REMOTEOBJECTS_EXPORT QIOQnxSource : public QIODevice +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QIOQnxSource) + +public: + explicit QIOQnxSource(int rcvid, QObject *parent = nullptr); + ~QIOQnxSource() override; + + bool isSequential() const override; + qint64 bytesAvailable() const override; + qint64 bytesToWrite() const override; + void close() override; + QAbstractSocket::SocketError error() const; + bool isValid() const; + + QAbstractSocket::SocketState state() const; + bool waitForBytesWritten(int msecs = 30000) override; + bool waitForConnected(int msecs = 30000); + bool waitForDisconnected(int msecs = 30000); + bool waitForReadyRead(int msecs = 30000) override; + +Q_SIGNALS: + void disconnected(); + void error(QAbstractSocket::SocketError socketError); + void stateChanged(QAbstractSocket::SocketState socketState); + +protected: + qint64 readData(char*, qint64) override; + qint64 writeData(const char*, qint64) override; + bool open(OpenMode openMode) override; + +private Q_SLOTS: + void onDisconnected(); + +private: + Q_DISABLE_COPY(QIOQnxSource) + friend class QQnxNativeServerPrivate; + friend class QnxServerIo; +}; +Q_DECLARE_TYPEINFO(QIOQnxSource, Q_RELOCATABLE_TYPE); + +QT_END_NAMESPACE + +#endif // QQNXNATIVEIO_H diff --git a/src/remoteobjects/qconnection_qnx_qiodevices_p.h b/src/remoteobjects/qconnection_qnx_qiodevices_p.h new file mode 100644 index 0000000..a719857 --- /dev/null +++ b/src/remoteobjects/qconnection_qnx_qiodevices_p.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2017-2016 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQNXNATIVEIO_P_H +#define QQNXNATIVEIO_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qconnection_qnx_qiodevices.h" +#include "qconnection_qnx_global_p.h" + +#include +#include + +#include "private/qiodevice_p.h" +#include "private/qringbuffer_p.h" + +QT_BEGIN_NAMESPACE + +class QQnxNativeIoPrivate : public QIODevicePrivate +{ + Q_DECLARE_PUBLIC(QQnxNativeIo) + + mutable QReadWriteLock ibLock; + mutable QReadWriteLock obLock; + +public: + QQnxNativeIoPrivate(); + ~QQnxNativeIoPrivate(); + void thread_func(); + bool establishConnection(); + void teardownConnection(); + void stopThread(); + QString serverName; + int serverId, channelId, connectionId; + sigevent tx_pulse; + QAbstractSocket::SocketState state; + QScopedPointer obuffer; + MsgType msgType; + iov_t tx_iov[3], rx_iov[2]; + Thread thread; +}; + +class QIOQnxSourcePrivate : public QIODevicePrivate +{ + Q_DECLARE_PUBLIC(QIOQnxSource) + + friend class QQnxNativeServerPrivate; + + mutable QReadWriteLock ibLock; + mutable QReadWriteLock obLock; + +public: + QIOQnxSourcePrivate(int _rcvid); + int rcvid; + QAbstractSocket::SocketState state; + MsgType msgType; + sigevent m_event; + QRingBuffer obuffer; + QAtomicInt m_serverClosing; +}; + +QT_END_NAMESPACE + +#endif // QQNXNATIVEIO_P_H + diff --git a/src/remoteobjects/qconnection_qnx_server.cpp b/src/remoteobjects/qconnection_qnx_server.cpp new file mode 100644 index 0000000..6fa16c7 --- /dev/null +++ b/src/remoteobjects/qconnection_qnx_server.cpp @@ -0,0 +1,540 @@ +/**************************************************************************** +** +** Copyright (C) 2017-2016 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qconnection_qnx_global_p.h" +#include "qconnection_qnx_qiodevices_p.h" +#include "qconnection_qnx_server_p.h" + +QT_BEGIN_NAMESPACE + +QQnxNativeServer::QQnxNativeServer(QObject *parent) + : QObject(*new QQnxNativeServerPrivate, parent) +{ +} + +QQnxNativeServer::~QQnxNativeServer() +{ +} + +void QQnxNativeServer::close() +{ + Q_D(QQnxNativeServer); + d->teardownServer(); +} + +bool QQnxNativeServer::hasPendingConnections() const +{ + Q_D(const QQnxNativeServer); + d->mutex.lock(); + const int len = d->pending.length(); + d->mutex.unlock(); + return len > 0; +} + +bool QQnxNativeServer::isListening() const +{ + Q_D(const QQnxNativeServer); + return !(d->serverName.isEmpty()); +} + +bool QQnxNativeServer::listen(const QString &name) +{ + Q_D(QQnxNativeServer); + if (isListening()) { + qCWarning(QT_REMOTEOBJECT) << "QQnxNativeServer::listen() called when already listening"; + return false; + } + + if (name.isEmpty()) { + d->error = QAbstractSocket::HostNotFoundError; + QString function = QLatin1String("QQnxNativeServer::listen"); + d->errorString = tr("%1: Name error").arg(function); + return false; + } + + if (!d->listen(name)) { + d->serverName.clear(); + return false; + } + + d->serverName = name; + return true; +} + +QSharedPointer QQnxNativeServer::nextPendingConnection() +{ + Q_D(QQnxNativeServer); + d->mutex.lock(); + Q_ASSERT(d->pending.length() > 0); + auto io = d->pending.takeFirst(); + d->mutex.unlock(); + return io; +} + +QString QQnxNativeServer::serverName() const +{ + Q_D(const QQnxNativeServer); + return d->serverName; +} + +bool QQnxNativeServer::waitForNewConnection(int msec, bool *timedOut) +{ + //TODO - This method isn't used by Qt Remote Objects, but would + //need to be implemented before this class could be used as a + //connection server (like QTcpServer or QLocalServer). + Q_UNUSED(msec) + Q_UNUSED(timedOut) + Q_ASSERT(false); + return false; +} + +void QQnxNativeServer::onSourceClosed() +{ + Q_D(QQnxNativeServer); + QIOQnxSource *conn = qobject_cast(sender()); + Q_ASSERT(conn); + + d->cleanupIOSource(conn); +} + +QQnxNativeServerPrivate::QQnxNativeServerPrivate() + : error(QAbstractSocket::UnknownSocketError) + , thread(this, QStringLiteral("NativeServer")) +{ +} + +QQnxNativeServerPrivate::~QQnxNativeServerPrivate() +{ + if (thread.isRunning()) + teardownServer(); +} + +// method (run in a thread) to watch for connections and handle receiving data +void QQnxNativeServerPrivate::thread_func() +{ + struct _msg_info msg_info; + recv_msgs recv_buf; + QList resp_repeat_iov(5); + + qCDebug(QT_REMOTEOBJECT) << "Server thread_func running"; + + while (running.loadRelaxed()) { + // wait for messages and pulses + int rcvid = MsgReceive(attachStruct->chid, &recv_buf, sizeof(_pulse), &msg_info); + qCDebug(QT_REMOTEOBJECT) << "MsgReceive unblocked. Rcvid" << rcvid << " Scoid" << msg_info.scoid; + if (rcvid == -1) { + if (errno != ESRCH) // ESRCH means the channel closed + WARNING(MsgReceive) + break; + } + + if (0 == rcvid) { + qCDebug(QT_REMOTEOBJECT) << "Pulse" << recv_buf.pulse.code; + /* we received a pulse + */ + switch (recv_buf.pulse.code) { + case _PULSE_CODE_DISCONNECT: + { + /* a client has disconnected. Verify that it is + * our client, and if so, clean up our saved state + */ + const int scoid = recv_buf.pulse.scoid; + const QSet coids = connections.take(scoid); + for (int coid : coids) + { + const uint64_t uid = static_cast(scoid) << 32 | static_cast(coid); + QSharedPointer io; + mutex.lock(); + if (sources.contains(uid)) + io = sources.take(uid); + mutex.unlock(); +#ifdef USE_HAM + ham_action_t *action = hamActions.take(uid); + ham_action_remove(action, 0); + ham_action_handle_free(action); +#endif + + if (!io.isNull()) { + io->d_func()->m_serverClosing.ref(); + QMetaObject::invokeMethod(io.data(),"onDisconnected",Qt::QueuedConnection); + } + } + + /* always do the ConnectDetach() */ + //Don't care about return value + ConnectDetach(recv_buf.pulse.scoid); + qCDebug(QT_REMOTEOBJECT) << "disconnect from client" << recv_buf.pulse.scoid; + } + break; + case _PULSE_CODE_COIDDEATH: + { + /* a connection has gone away. Verify that it is + * our client, and if so, clean up our saved state + */ + const int coid = recv_buf.pulse.value.sival_int; + + if (ConnectServerInfo(0, coid, nullptr) != coid) { + const int scoid = recv_buf.pulse.scoid; + if (connections.value(scoid).contains(coid)) + connections[scoid].remove(coid); + QSharedPointer io; + const uint64_t uid = static_cast(scoid) << 32 | static_cast(coid); + mutex.lock(); + if (sources.contains(uid)) + io = sources.take(uid); + mutex.unlock(); +#ifdef USE_HAM + ham_action_t *action = hamActions.take(uid); + ham_action_remove(action, 0); + ham_action_handle_free(action); +#endif + + if (!io.isNull()) { + io->d_func()->m_serverClosing.ref(); + QMetaObject::invokeMethod(io.data(),"onDisconnected",Qt::QueuedConnection); + } + qCDebug(QT_REMOTEOBJECT) << "Connection dropped" << coid; + } + break; + } + break; + case _PULSE_CODE_UNBLOCK: + if (running.loadRelaxed()) { + // did we forget to Reply to our client? + qCWarning(QT_REMOTEOBJECT) << "got an unblock pulse, did you forget to reply to your client?"; + WARN_ON_ERROR(MsgError, recv_buf.pulse.value.sival_int, EINTR) + } + break; + default: + qCWarning(QT_REMOTEOBJECT) << "unexpected pulse code: " << recv_buf.pulse.code << __FILE__ << __LINE__; + break; + } + continue; + } + + /* not an error, not a pulse, therefore a message */ + switch (recv_buf.type) + { + qCDebug(QT_REMOTEOBJECT) << "Msg Received" << recv_buf.type; + + case _IO_CONNECT: + /* _IO_CONNECT because someone did a name_open() to us and we are + * in the network case (gns running). We must EOK it. */ + if (connections.contains(msg_info.scoid) + && connections.value(msg_info.scoid).contains(msg_info.coid)) + { + qCWarning(QT_REMOTEOBJECT) << "Already connected rcvid seen" << connections << rcvid; + FATAL_ON_ERROR(MsgError, rcvid, EADDRINUSE) + } else { + if (!connections.contains(msg_info.scoid)) + connections.insert(msg_info.scoid, QSet()); + connections[msg_info.scoid] << msg_info.coid; + qCDebug(QT_REMOTEOBJECT) << "New connection (qns)" << msg_info.coid << msg_info.scoid; + const uint64_t uid = static_cast(msg_info.scoid) << 32 | static_cast(msg_info.coid); + createSource(rcvid, uid, msg_info.pid); // Reads more and then calls MsgReply + } + break; + + case MsgType::REPLICA_INIT: + qCDebug(QT_REMOTEOBJECT) << "MsgType::INIT received" << rcvid << msg_info.scoid << msg_info.tid << msg_info.chid << msg_info.coid; + //Check if this is a new connection (not gns) + if (connections.contains(msg_info.scoid) + && connections.value(msg_info.scoid).contains(msg_info.coid)) + { + qCWarning(QT_REMOTEOBJECT) << "Already connected rcvid seen" << connections << rcvid; + FATAL_ON_ERROR(MsgError, rcvid, EADDRINUSE) + } else { + if (!connections.contains(msg_info.scoid)) + connections.insert(msg_info.scoid, QSet()); + connections[msg_info.scoid] << msg_info.coid; + qCDebug(QT_REMOTEOBJECT) << "New connection (non-gns)" << rcvid << msg_info.coid << msg_info.scoid; + const uint64_t uid = static_cast(msg_info.scoid) << 32 | static_cast(msg_info.coid); + createSource(rcvid, uid, msg_info.pid); // Reads more and then calls MsgReply + } + + break; + case MsgType::SOURCE_TX_RESP: + { + WARN_ON_ERROR(MsgInfo, rcvid, &msg_info); + const uint64_t uid = static_cast(msg_info.scoid) << 32 | static_cast(msg_info.coid); + mutex.lock(); + Q_ASSERT(sources.contains(uid)); + auto io = sources.value(uid); + mutex.unlock(); + + io->d_func()->obLock.lockForWrite(); //NAR (Not-An-Error) + const QByteArray data = io->d_func()->obuffer.read(); + const int bytesLeft = io->d_func()->obuffer.size(); + io->d_func()->obLock.unlock(); + + qCDebug(QT_REMOTEOBJECT) << "server received SOURCE_TX_RESP with length" << msg_info.dstmsglen << "/" << data.length() << "Available:" << bytesLeft; + Q_ASSERT(data.length() == static_cast(msg_info.dstmsglen - sizeof(bytesLeft))); + + iov_t reply_vector[2]; + SETIOV(reply_vector, &bytesLeft, sizeof(bytesLeft)); + SETIOV(reply_vector+1, data.data(), size_t(data.length())); + + FATAL_ON_ERROR(MsgReplyv, rcvid, EOK, reply_vector, 2) + } + break; + case MsgType::SOURCE_TX_RESP_REPEAT: + { + WARN_ON_ERROR(MsgInfo, rcvid, &msg_info); + const uint64_t uid = static_cast(msg_info.scoid) << 32 | static_cast(msg_info.coid); + mutex.lock(); + Q_ASSERT(sources.contains(uid)); + auto io = sources.value(uid); + mutex.unlock(); + + int len_taken = 0; + const int to_send = msg_info.dstmsglen - sizeof(int); //Exclude the buffer count + QByteArrayList qba_array; + io->d_func()->obLock.lockForWrite(); //NAR (Not-An-Error) + qCDebug(QT_REMOTEOBJECT) << "server received SOURCE_TX_RESP_REPEAT with length" << msg_info.dstmsglen << "Available:" << io->d_func()->obuffer.size(); + while (len_taken != to_send) + { + QByteArray data = io->d_func()->obuffer.read(); + qba_array << data; + len_taken += data.length(); + if (data.length() == 0) { // We somehow reached the end + qCWarning(QT_REMOTEOBJECT) << "Reached the end of the buffer before getting the requested amount of data." << Q_FUNC_INFO << __FILE__ << __LINE__; + break; + } + } + qCDebug(QT_REMOTEOBJECT) << "grabbing more data" << len_taken << to_send << qba_array.length(); + io->d_func()->obLock.unlock(); + + Q_ASSERT(len_taken == to_send); + const int buffers_taken = qba_array.length(); + + resp_repeat_iov.resize(buffers_taken+1); + SETIOV(&resp_repeat_iov[0], &buffers_taken, sizeof(buffers_taken)); + for (int i = 1; i <= buffers_taken; ++i) + SETIOV(&resp_repeat_iov[i], qba_array.at(i-1).constData(), size_t(qba_array.at(i-1).length())); + FATAL_ON_ERROR(MsgReplyv, rcvid, EOK, resp_repeat_iov.data(), buffers_taken+1) + } + break; + case MsgType::REPLICA_TX_RECV: + { + FATAL_ON_ERROR(MsgInfo,rcvid, &msg_info) + const uint64_t uid = static_cast(msg_info.scoid) << 32 | static_cast(msg_info.coid); + mutex.lock(); + Q_ASSERT(sources.contains(uid)); + auto io = sources.value(uid); + mutex.unlock(); + + //Long-lock, use buffer+memcpy if we run into trouble + io->d_func()->ibLock.lockForWrite(); + qint32 toRead = msg_info.msglen-sizeof(MsgType); + char *payload = io->d_func()->buffer.reserve(toRead); + + const int res = MsgRead(rcvid, payload, toRead, sizeof(MsgType)); + if (-1 == res) { + io->d_func()->buffer.chop(toRead); + io->d_func()->ibLock.unlock(); + qFatal("MsgRead"); + } + Q_ASSERT(res == toRead); + + if (res < toRead) + io->d_func()->buffer.chop(toRead - res); + io->d_func()->ibLock.unlock(); + + FATAL_ON_ERROR(MsgReply, rcvid, EOK, nullptr, 0) + + qCDebug(QT_REMOTEOBJECT) << "server received REPLICA_TX_RECV" << payload << toRead; + + emit io->readyRead(); + } + break; + default: + /* some other unexpected message */ + qCWarning(QT_REMOTEOBJECT) << "unexpected message type" << recv_buf.type << __FILE__ << __LINE__; + WARN_ON_ERROR(MsgError, rcvid, ENOSYS) + break; + } + } + mutex.lock(); + for (auto io: sources) + io->d_func()->m_serverClosing.ref(); + mutex.unlock(); + name_detach(attachStruct, 0); + attachStruct = nullptr; + qCDebug(QT_REMOTEOBJECT) << "Server thread_func stopped"; +} + +bool QQnxNativeServerPrivate::listen(const QString &name) +{ + attachStruct = name_attach(nullptr, qPrintable(name), 0); + if (attachStruct == nullptr) { + qCDebug(QT_REMOTEOBJECT, "name_attach call failed"); + return false; + } + terminateCoid = ConnectAttach(ND_LOCAL_NODE, 0, attachStruct->chid, _NTO_SIDE_CHANNEL, 0); + if (terminateCoid == -1) { + qCDebug(QT_REMOTEOBJECT, "ConnectAttach failed"); + return false; + } + + running.ref(); + thread.start(); + + return true; +} + +void QQnxNativeServerPrivate::cleanupIOSource(QIOQnxSource *conn) +{ + QSharedPointer io; + mutex.lock(); + for (auto i = sources.begin(), end = sources.end(); i != end; ++i) { + if (i.value().data() == conn) { + io = std::move(i.value()); + sources.erase(i); + break; + } + } + mutex.unlock(); + if (!io.isNull()) { + io->d_func()->m_serverClosing.ref(); + io->close(); + } +} + +void QQnxNativeServerPrivate::teardownServer() +{ + if (attachStruct == nullptr) + return; + + running.deref(); + MsgSendPulse(terminateCoid, SIGEV_PULSE_PRIO_INHERIT, _PULSE_CODE_UNBLOCK, 0); + ConnectDetach(terminateCoid); + thread.wait(); + + //Existing QIOQnxSources will be deleted along with object + //threads gone, don't need to use mutex + sources.clear(); +#ifdef USE_HAM + if (hamAvailable) + closeHamResources(); +#endif +} + +void QQnxNativeServerPrivate::createSource(int rcvid, uint64_t uid, pid_t toPid) +{ + Q_Q(QQnxNativeServer); +#ifndef USE_HAM + Q_UNUSED(toPid) +#endif + auto io = QSharedPointer(new QIOQnxSource(rcvid)); + io->moveToThread(q->thread()); + QObject::connect(io.data(), &QIOQnxSource::aboutToClose, + q, &QQnxNativeServer::onSourceClosed); + + QIOQnxSourcePrivate *iop = io->d_func(); + FATAL_ON_ERROR(MsgRead, rcvid, &(iop->m_event), sizeof(sigevent), sizeof(MsgType)) + int sentChannelId; + FATAL_ON_ERROR(MsgRead, rcvid, &sentChannelId, sizeof(int), sizeof(MsgType)+sizeof(sigevent)) + FATAL_ON_ERROR(MsgReply, rcvid, EOK, nullptr, 0) + + mutex.lock(); + sources.insert(uid, io); + pending.append(io); + mutex.unlock(); + + //push an event into the main threads eventloop to emit newConnection. + QMetaObject::invokeMethod(q,"newConnection",Qt::QueuedConnection); +#ifdef USE_HAM + if (!hamInitialized) { + hamInitialized = true; + hamAvailable = initializeHam(); + } + if (hamAvailable) + configureHamDeath(sentChannelId, toPid, uid); +#endif +} + +#ifdef USE_HAM +bool QQnxNativeServerPrivate::initializeHam() +{ + if (access("/proc/ham",F_OK) != 0) { + WARNING(access(/proc/ham)) + return false; + } + ham_connect(0); + pid_t pid = getpid(); + hamEntityHandle = ham_attach(qPrintable(serverName), ND_LOCAL_NODE, pid, NULL, 0); + if (!hamEntityHandle) { + WARNING(ham_attach) + ham_disconnect(0); + return false; + } + hamConditionHandle = ham_condition(hamEntityHandle, CONDDEATH, "death", 0); + if (!hamConditionHandle) { + WARNING(ham_condition) + ham_detach(hamEntityHandle, 0); + ham_entity_handle_free(hamEntityHandle); + ham_disconnect(0); + return false; + } + qCDebug(QT_REMOTEOBJECT, "HAM initialized for %s (pid = %d)", qPrintable(serverName), pid); + return true; +} + +void QQnxNativeServerPrivate::configureHamDeath(int sentChannelId, pid_t toPid, uint64_t uid) +{ + char identifier[25]; + snprintf(identifier, 25, "%d_%d", toPid, sentChannelId); + ham_action_t *a = ham_action_notify_pulse(hamConditionHandle, identifier, + ND_LOCAL_NODE, toPid, + sentChannelId, NODE_DEATH, 0, 0); + if (!a) + WARNING(ham_action_notify_pulse) + else + hamActions.insert(uid, a); +} + +void QQnxNativeServerPrivate::closeHamResources() +{ + ham_entity_handle_free(hamEntityHandle); + ham_condition_handle_free(hamConditionHandle); + ham_disconnect(0); +} +#endif + +QT_END_NAMESPACE diff --git a/src/remoteobjects/qconnection_qnx_server.h b/src/remoteobjects/qconnection_qnx_server.h new file mode 100644 index 0000000..3b168b1 --- /dev/null +++ b/src/remoteobjects/qconnection_qnx_server.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2017-2016 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQNXNATIVESERVER_H +#define QQNXNATIVESERVER_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQnxNativeServerPrivate; +class QQnxNativeIo; +class QIOQnxSource; + +class Q_REMOTEOBJECTS_EXPORT QQnxNativeServer : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QQnxNativeServer) + +Q_SIGNALS: + void newConnection(); + +public: + explicit QQnxNativeServer(QObject *parent = nullptr); + ~QQnxNativeServer(); + + void close(); + bool hasPendingConnections() const; + bool isListening() const; + bool listen(const QString &name); + QSharedPointer nextPendingConnection(); + QString serverName() const; + bool waitForNewConnection(int msec = 0, bool *timedOut = nullptr); + +private Q_SLOTS: + void onSourceClosed(); + +private: + Q_DISABLE_COPY(QQnxNativeServer) + friend class QIOQnxSource; +}; + +QT_END_NAMESPACE + +#endif // QQNXNATIVESERVER_H diff --git a/src/remoteobjects/qconnection_qnx_server_p.h b/src/remoteobjects/qconnection_qnx_server_p.h new file mode 100644 index 0000000..1f64acf --- /dev/null +++ b/src/remoteobjects/qconnection_qnx_server_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2017-2016 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQNXNATIVESERVER_P_H +#define QQNXNATIVESERVER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qobject_p.h" +#include "qconnection_qnx_server.h" +#include "qconnection_qnx_global_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQnxNativeServerPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QQnxNativeServer) + +public: + QQnxNativeServerPrivate(); + + ~QQnxNativeServerPrivate(); + + void thread_func(); + + void cleanupIOSource(QIOQnxSource *conn); + void teardownServer(); + void createSource(int rcvid, uint64_t uid, pid_t toPid); +#ifdef USE_HAM + bool initializeHam(); + void configureHamDeath(int sentChannelId, pid_t toPid, uint64_t uid); + void closeHamResources(); +#endif + + bool listen(const QString &name); + QString errorString; + QAbstractSocket::SocketError error; + QString serverName; + name_attach_t *attachStruct; + QHash > connections; + QHash> sources; + QList> pending; + QAtomicInt running; + Thread thread; + mutable QMutex mutex; + int terminateCoid; +#ifdef USE_HAM + ham_entity_t *hamEntityHandle; + ham_condition_t *hamConditionHandle; + QHash hamActions; + bool hamAvailable = false; + bool hamInitialized = false; +#endif +}; + +QT_END_NAMESPACE + +#endif // QQNXNATIVESERVER_P_H + diff --git a/src/remoteobjects/qconnection_tcpip_backend.cpp b/src/remoteobjects/qconnection_tcpip_backend.cpp new file mode 100644 index 0000000..5371aa6 --- /dev/null +++ b/src/remoteobjects/qconnection_tcpip_backend.cpp @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qconnection_tcpip_backend_p.h" + +#include + +QT_BEGIN_NAMESPACE + +TcpClientIo::TcpClientIo(QObject *parent) + : QtROClientIoDevice(parent) + , m_socket(new QTcpSocket(this)) +{ + connect(m_socket, &QTcpSocket::readyRead, this, &QtROClientIoDevice::readyRead); + connect(m_socket, &QAbstractSocket::errorOccurred, this, &TcpClientIo::onError); + connect(m_socket, &QTcpSocket::stateChanged, this, &TcpClientIo::onStateChanged); +} + +TcpClientIo::~TcpClientIo() +{ + close(); +} + +QIODevice *TcpClientIo::connection() const +{ + return m_socket; +} + +void TcpClientIo::doClose() +{ + if (m_socket->isOpen()) { + connect(m_socket, &QTcpSocket::disconnected, this, &QObject::deleteLater); + m_socket->disconnectFromHost(); + } else { + this->deleteLater(); + } +} + +void TcpClientIo::doDisconnectFromServer() +{ + m_socket->disconnectFromHost(); +} + +void TcpClientIo::connectToServer() +{ + if (isOpen()) + return; + QHostAddress address(url().host()); + if (address.isNull()) { + const QList addresses = QHostInfo::fromName(url().host()).addresses(); + Q_ASSERT_X(addresses.size() >= 1, Q_FUNC_INFO, url().toString().toLatin1().data()); + address = addresses.first(); + } + + m_socket->connectToHost(address, quint16(url().port())); +} + +bool TcpClientIo::isOpen() const +{ + return (!isClosing() && (m_socket->state() == QAbstractSocket::ConnectedState + || m_socket->state() == QAbstractSocket::ConnectingState)); +} + +void TcpClientIo::onError(QAbstractSocket::SocketError error) +{ + qCDebug(QT_REMOTEOBJECT) << "onError" << error; + + switch (error) { + case QAbstractSocket::HostNotFoundError: //Host not there, wait and try again + case QAbstractSocket::ConnectionRefusedError: + case QAbstractSocket::NetworkError: + emit shouldReconnect(this); + break; + case QAbstractSocket::AddressInUseError: + //... TODO error reporting + break; + default: + break; + } +} + +void TcpClientIo::onStateChanged(QAbstractSocket::SocketState state) +{ + if (state == QAbstractSocket::ClosingState && !isClosing()) { + m_socket->abort(); + emit shouldReconnect(this); + } + if (state == QAbstractSocket::ConnectedState) + initializeDataStream(); +} + + +TcpServerIo::TcpServerIo(QTcpSocket *conn, QObject *parent) + : QtROServerIoDevice(parent), m_connection(conn) +{ + m_connection->setParent(this); + connect(conn, &QIODevice::readyRead, this, &QtROServerIoDevice::readyRead); + connect(conn, &QAbstractSocket::disconnected, this, &QtROServerIoDevice::disconnected); +} + +QIODevice *TcpServerIo::connection() const +{ + return m_connection; +} + +void TcpServerIo::doClose() +{ + m_connection->disconnectFromHost(); +} + + + +TcpServerImpl::TcpServerImpl(QObject *parent) + : QConnectionAbstractServer(parent) +{ + connect(&m_server, &QTcpServer::newConnection, this, &QConnectionAbstractServer::newConnection); +} + +TcpServerImpl::~TcpServerImpl() +{ + close(); +} + +QtROServerIoDevice *TcpServerImpl::configureNewConnection() +{ + if (!m_server.isListening()) + return nullptr; + + return new TcpServerIo(m_server.nextPendingConnection(), this); +} + +bool TcpServerImpl::hasPendingConnections() const +{ + return m_server.hasPendingConnections(); +} + +QUrl TcpServerImpl::address() const +{ + return m_originalUrl; +} + +bool TcpServerImpl::listen(const QUrl &address) +{ + QHostAddress host(address.host()); + if (host.isNull()) { + if (address.host().isEmpty()) { + host = QHostAddress::Any; + } else { + qCWarning(QT_REMOTEOBJECT) << address.host() << " is not an IP address, trying to resolve it"; + QHostInfo info = QHostInfo::fromName(address.host()); + if (info.addresses().isEmpty()) + host = QHostAddress::Any; + else + host = info.addresses().constFirst(); + } + } + + bool ret = m_server.listen(host, quint16(address.port())); + if (ret) { + m_originalUrl.setScheme(QLatin1String("tcp")); + m_originalUrl.setHost(m_server.serverAddress().toString()); + m_originalUrl.setPort(m_server.serverPort()); + } + return ret; +} + +QAbstractSocket::SocketError TcpServerImpl::serverError() const +{ + return m_server.serverError(); +} + +void TcpServerImpl::close() +{ + m_server.close(); +} + +QT_END_NAMESPACE diff --git a/src/remoteobjects/qconnection_tcpip_backend_p.h b/src/remoteobjects/qconnection_tcpip_backend_p.h new file mode 100644 index 0000000..fdb8de6 --- /dev/null +++ b/src/remoteobjects/qconnection_tcpip_backend_p.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2017-2015 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCONNECTIONTCPIPBACKEND_P_H +#define QCONNECTIONTCPIPBACKEND_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qconnectionfactories_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class TcpClientIo final : public QtROClientIoDevice +{ + Q_OBJECT + +public: + explicit TcpClientIo(QObject *parent = nullptr); + ~TcpClientIo() override; + + QIODevice *connection() const override; + void connectToServer() override; + bool isOpen() const override; + +public Q_SLOTS: + void onError(QAbstractSocket::SocketError error); + void onStateChanged(QAbstractSocket::SocketState state); + +protected: + void doClose() override; + void doDisconnectFromServer() override; + +private: + QTcpSocket *m_socket; +}; + +class TcpServerIo final : public QtROServerIoDevice +{ + Q_OBJECT +public: + explicit TcpServerIo(QTcpSocket *conn, QObject *parent = nullptr); + + QIODevice *connection() const override; +protected: + void doClose() override; + +private: + QTcpSocket *m_connection; +}; + +class TcpServerImpl final : public QConnectionAbstractServer +{ + Q_OBJECT + Q_DISABLE_COPY(TcpServerImpl) + +public: + explicit TcpServerImpl(QObject *parent); + ~TcpServerImpl() override; + + bool hasPendingConnections() const override; + QtROServerIoDevice *configureNewConnection() override; + QUrl address() const override; + bool listen(const QUrl &address) override; + QAbstractSocket::SocketError serverError() const override; + void close() override; + +private: + QTcpServer m_server; + QUrl m_originalUrl; // necessary because of a QHostAddress bug +}; + +QT_END_NAMESPACE +#endif // QCONNECTIONTCPIPBACKEND_P_H diff --git a/src/remoteobjects/qconnectionfactories.cpp b/src/remoteobjects/qconnectionfactories.cpp new file mode 100644 index 0000000..e81672f --- /dev/null +++ b/src/remoteobjects/qconnectionfactories.cpp @@ -0,0 +1,396 @@ +/**************************************************************************** +** +** Copyright (C) 2017-2015 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qconnectionfactories_p.h" +#include "qremoteobjectpacket_p.h" + +// BEGIN: Backends +#if defined(Q_OS_QNX) +#include "qconnection_qnx_backend_p.h" +#endif +#include "qconnection_local_backend_p.h" +#include "qconnection_tcpip_backend_p.h" +// END: Backends + +QT_BEGIN_NAMESPACE + +using namespace QtRemoteObjects; + +class QtROFactoryLoader +{ +public: + QtROClientFactory clientFactory; + QtROServerFactory serverFactory; +}; + +Q_GLOBAL_STATIC(QtROFactoryLoader, loader) + +inline bool fromDataStream(QDataStream &in, QRemoteObjectPacketTypeEnum &type, QString &name) +{ + quint16 _type; + in >> _type; + type = Invalid; + switch (_type) { + case Handshake: type = Handshake; break; + case InitPacket: type = InitPacket; break; + case InitDynamicPacket: type = InitDynamicPacket; break; + case AddObject: type = AddObject; break; + case RemoveObject: type = RemoveObject; break; + case InvokePacket: type = InvokePacket; break; + case InvokeReplyPacket: type = InvokeReplyPacket; break; + case PropertyChangePacket: type = PropertyChangePacket; break; + case ObjectList: type = ObjectList; break; + case Ping: type = Ping; break; + case Pong: type = Pong; break; + default: + qCWarning(QT_REMOTEOBJECT_IO) << "Invalid packet received" << _type; + } + if (type == Invalid) + return false; + if (type == ObjectList) + return true; + in >> name; + qCDebug(QT_REMOTEOBJECT_IO) << "Packet received of type" << type << "for object" << name; + return true; +} + +/*! + All communication between nodes happens through some form of QIODevice with + an associated QDataStream to handle marshalling of Qt types. QtROIoDeviceBase + is an abstract base class that provides a consistent interface to QtRO, yet + can be extended to support different types of QIODevice. + */ +QtROIoDeviceBase::QtROIoDeviceBase(QObject *parent) : QObject(*new QtROIoDeviceBasePrivate, parent) { } + +QtROIoDeviceBase::QtROIoDeviceBase(QtROIoDeviceBasePrivate &dptr, QObject *parent) : QObject(dptr, parent) { } + +QtROIoDeviceBase::~QtROIoDeviceBase() +{ +} + +bool QtROIoDeviceBase::read(QRemoteObjectPacketTypeEnum &type, QString &name) +{ + Q_D(QtROIoDeviceBase); + qCDebug(QT_REMOTEOBJECT_IO) << deviceType() << "read()" << d->m_curReadSize << bytesAvailable(); + + if (d->m_curReadSize == 0) { + if (bytesAvailable() < static_cast(sizeof(quint32))) + return false; + + d->m_dataStream >> d->m_curReadSize; + } + + qCDebug(QT_REMOTEOBJECT_IO) << deviceType() << "read()-looking for map" << d->m_curReadSize + << bytesAvailable(); + + if (bytesAvailable() < d->m_curReadSize) + return false; + + d->m_curReadSize = 0; + return fromDataStream(d->m_dataStream, type, name); +} + +void QtROIoDeviceBase::write(const QByteArray &data) +{ + Q_D(QtROIoDeviceBase); + if (connection()->isOpen() && !d->m_isClosing) + connection()->write(data); +} + +void QtROIoDeviceBase::write(const QByteArray &data, qint64 size) +{ + Q_D(QtROIoDeviceBase); + if (connection()->isOpen() && !d->m_isClosing) + connection()->write(data.data(), size); +} + +bool QtROIoDeviceBase::isOpen() const +{ + return !isClosing(); +} + +void QtROIoDeviceBase::close() +{ + Q_D(QtROIoDeviceBase); + d->m_isClosing = true; + doClose(); +} + +qint64 QtROIoDeviceBase::bytesAvailable() const +{ + return connection()->bytesAvailable(); +} + +void QtROIoDeviceBase::initializeDataStream() +{ + Q_D(QtROIoDeviceBase); + d->m_dataStream.setDevice(connection()); + d->m_dataStream.resetStatus(); +} + +bool QtROIoDeviceBase::isClosing() const +{ + Q_D(const QtROIoDeviceBase); + return d->m_isClosing; +} + +void QtROIoDeviceBase::addSource(const QString &name) +{ + Q_D(QtROIoDeviceBase); + d->m_remoteObjects.insert(name); +} + +void QtROIoDeviceBase::removeSource(const QString &name) +{ + Q_D(QtROIoDeviceBase); + d->m_remoteObjects.remove(name); +} + +QSet QtROIoDeviceBase::remoteObjects() const +{ + Q_D(const QtROIoDeviceBase); + return d->m_remoteObjects; +} + +QtROClientIoDevice::QtROClientIoDevice(QObject *parent) : QtROIoDeviceBase(*new QtROClientIoDevicePrivate, parent) +{ +} + +QtROClientIoDevice::~QtROClientIoDevice() +{ + if (!isClosing()) + close(); +} + +void QtROClientIoDevice::disconnectFromServer() +{ + doDisconnectFromServer(); + emit shouldReconnect(this); +} + +QUrl QtROClientIoDevice::url() const +{ + Q_D(const QtROClientIoDevice); + return d->m_url; +} + +QString QtROClientIoDevice::deviceType() const +{ + return QStringLiteral("QtROClientIoDevice"); +} + +void QtROClientIoDevice::setUrl(const QUrl &url) +{ + Q_D(QtROClientIoDevice); + d->m_url = url; +} + +/*! + The Qt servers create QIODevice derived classes from handleConnection. The + problem is that they behave differently, so this class adds some + consistency. + */ +QtROServerIoDevice::QtROServerIoDevice(QObject *parent) : QtROIoDeviceBase(parent) +{ +} + +QString QtROServerIoDevice::deviceType() const +{ + return QStringLiteral("QtROServerIoDevice"); +} + +QConnectionAbstractServer::QConnectionAbstractServer(QObject *parent) + : QObject(parent) +{ +} + +QConnectionAbstractServer::~QConnectionAbstractServer() +{ +} + +QtROServerIoDevice *QConnectionAbstractServer::nextPendingConnection() +{ + QtROServerIoDevice *iodevice = configureNewConnection(); + iodevice->initializeDataStream(); + return iodevice; +} + +QtROExternalIoDevice::QtROExternalIoDevice(QIODevice *device, QObject *parent) + : QtROIoDeviceBase(*new QtROExternalIoDevicePrivate(device), parent) +{ + Q_D(QtROExternalIoDevice); + initializeDataStream(); + connect(device, &QIODevice::aboutToClose, this, [d]() { d->m_isClosing = true; }); + connect(device, &QIODevice::readyRead, this, &QtROExternalIoDevice::readyRead); + auto meta = device->metaObject(); + if (-1 != meta->indexOfSignal(SIGNAL(disconnected()))) + connect(device, SIGNAL(disconnected()), this, SIGNAL(disconnected())); +} + +QIODevice *QtROExternalIoDevice::connection() const +{ + Q_D(const QtROExternalIoDevice); + return d->m_device; +} + +bool QtROExternalIoDevice::isOpen() const +{ + Q_D(const QtROExternalIoDevice); + if (!d->m_device) + return false; + return d->m_device->isOpen() && QtROIoDeviceBase::isOpen(); +} + +void QtROExternalIoDevice::doClose() +{ + Q_D(QtROExternalIoDevice); + if (isOpen()) + d->m_device->close(); +} + +QString QtROExternalIoDevice::deviceType() const +{ + return QStringLiteral("QtROExternalIoDevice"); +} + +/*! + \class QtROServerFactory + \inmodule QtRemoteObjects + \brief A class that holds information about server backends available on the Qt Remote Objects network. +*/ +QtROServerFactory::QtROServerFactory() +{ +#ifdef Q_OS_QNX + registerType(QStringLiteral("qnx")); +#endif +#ifdef Q_OS_LINUX + registerType(QStringLiteral("localabstract")); +#endif + registerType(QStringLiteral("local")); + registerType(QStringLiteral("tcp")); +} + +QtROServerFactory *QtROServerFactory::instance() +{ + return &loader->serverFactory; +} + +/*! + \class QtROClientFactory + \inmodule QtRemoteObjects + \brief A class that holds information about client backends available on the Qt Remote Objects network. +*/ +QtROClientFactory::QtROClientFactory() +{ +#ifdef Q_OS_QNX + registerType(QStringLiteral("qnx")); +#endif +#ifdef Q_OS_LINUX + registerType(QStringLiteral("localabstract")); +#endif + registerType(QStringLiteral("local")); + registerType(QStringLiteral("tcp")); +} + +QtROClientFactory *QtROClientFactory::instance() +{ + return &loader->clientFactory; +} + +/*! + \fn void qRegisterRemoteObjectsClient(const QString &id) + \relates QtROClientFactory + + Registers the Remote Objects client \a id for the type \c{T}. + + If you need a custom transport protocol for Qt Remote Objects, you need to + register the client & server implementation here. + + \note This function requires that \c{T} is a fully defined type at the point + where the function is called. + + This example registers the class \c{CustomClientIo} as \c{"myprotocol"}: + + \code + qRegisterRemoteObjectsClient(QStringLiteral("myprotocol")); + \endcode + + With this in place, you can now instantiate nodes using this new custom protocol: + + \code + QRemoteObjectNode client(QUrl(QStringLiteral("myprotocol:registry"))); + \endcode + + \sa {qRegisterRemoteObjectsServer} +*/ + +/*! + \fn void qRegisterRemoteObjectsServer(const QString &id) + \relates QtROServerFactory + + Registers the Remote Objects server \a id for the type \c{T}. + + If you need a custom transport protocol for Qt Remote Objects, you need to + register the client & server implementation here. + + \note This function requires that \c{T} is a fully defined type at the point + where the function is called. + + This example registers the class \c{CustomServerImpl} as \c{"myprotocol"}: + + \code + qRegisterRemoteObjectsServer(QStringLiteral("myprotocol")); + \endcode + + With this in place, you can now instantiate nodes using this new custom protocol: + + \code + QRemoteObjectNode client(QUrl(QStringLiteral("myprotocol:registry"))); + \endcode + + \sa {qRegisterRemoteObjectsServer} +*/ + +QtROIoDeviceBasePrivate::QtROIoDeviceBasePrivate() : QObjectPrivate() +{ + m_dataStream.setVersion(dataStreamVersion); + m_dataStream.setByteOrder(QDataStream::LittleEndian); +} + +QT_END_NAMESPACE diff --git a/src/remoteobjects/qconnectionfactories.h b/src/remoteobjects/qconnectionfactories.h new file mode 100644 index 0000000..b123ab8 --- /dev/null +++ b/src/remoteobjects/qconnectionfactories.h @@ -0,0 +1,251 @@ +/**************************************************************************** +** +** Copyright (C) 2021 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCONNECTIONFACTORIES_H +#define QCONNECTIONFACTORIES_H + +// +// W A R N I N G +// ------------- +// +// This file is part of the QtRO internal API and is not meant to be used +// in applications. It contains "internal" components, which are exported +// to allow new QIODevice channels to be added to extend QtRO. Usage of these +// APIs may make your code source and binary incompatible with future versions +// of Qt. +// + +#include + +#include + + +QT_BEGIN_NAMESPACE + +class QtROIoDeviceBasePrivate; +class QtROClientIoDevicePrivate; +class QtROExternalIoDevicePrivate; + +class Q_REMOTEOBJECTS_EXPORT QtROIoDeviceBase : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(QtROIoDeviceBase) + +public: + explicit QtROIoDeviceBase(QObject *parent = nullptr); + ~QtROIoDeviceBase() override; + + bool read(QtRemoteObjects::QRemoteObjectPacketTypeEnum &, QString &); + + virtual void write(const QByteArray &data); + virtual void write(const QByteArray &data, qint64); + virtual bool isOpen() const; + virtual void close(); + virtual qint64 bytesAvailable() const; + virtual QIODevice *connection() const = 0; + void initializeDataStream(); + bool isClosing() const; + void addSource(const QString &); + void removeSource(const QString &); + QSet remoteObjects() const; + +Q_SIGNALS: + void readyRead(); + void disconnected(); + +protected: + explicit QtROIoDeviceBase(QtROIoDeviceBasePrivate &, QObject *parent); + virtual QString deviceType() const = 0; + virtual void doClose() = 0; + +private: + Q_DECLARE_PRIVATE(QtROIoDeviceBase) + friend class QRemoteObjectNodePrivate; + friend class QConnectedReplicaImplementation; + friend class QRemoteObjectSourceIo; +}; + +class Q_REMOTEOBJECTS_EXPORT QtROServerIoDevice : public QtROIoDeviceBase +{ + Q_OBJECT + Q_DISABLE_COPY(QtROServerIoDevice) + +public: + explicit QtROServerIoDevice(QObject *parent = nullptr); + +protected: + QString deviceType() const override; +}; + +class Q_REMOTEOBJECTS_EXPORT QConnectionAbstractServer : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(QConnectionAbstractServer) + +public: + explicit QConnectionAbstractServer(QObject *parent = nullptr); + ~QConnectionAbstractServer() override; + + virtual bool hasPendingConnections() const = 0; + QtROServerIoDevice* nextPendingConnection(); + virtual QUrl address() const = 0; + virtual bool listen(const QUrl &address) = 0; + virtual QAbstractSocket::SocketError serverError() const = 0; + virtual void close() = 0; + +protected: + virtual QtROServerIoDevice* configureNewConnection() = 0; + +Q_SIGNALS: + void newConnection(); +}; + +class Q_REMOTEOBJECTS_EXPORT QtROClientIoDevice : public QtROIoDeviceBase +{ + Q_OBJECT + Q_DISABLE_COPY(QtROClientIoDevice) + +public: + explicit QtROClientIoDevice(QObject *parent = nullptr); + ~QtROClientIoDevice() override; + + void disconnectFromServer(); + virtual void connectToServer() = 0; + + QUrl url() const; + +Q_SIGNALS: + void shouldReconnect(QtROClientIoDevice*); + +protected: + virtual void doDisconnectFromServer() = 0; + QString deviceType() const override; + void setUrl(const QUrl &url); + +private: + Q_DECLARE_PRIVATE(QtROClientIoDevice) + friend class QtROClientFactory; +}; + +class QtROServerFactory +{ +public: + Q_REMOTEOBJECTS_EXPORT static QtROServerFactory *instance(); + + QConnectionAbstractServer *create(const QUrl &url, QObject *parent = nullptr) + { + auto creatorFunc = m_creatorFuncs.value(url.scheme()); + return creatorFunc ? (*creatorFunc)(parent) : nullptr; + } + + template + void registerType(const QString &id) + { + m_creatorFuncs[id] = [](QObject *parent) -> QConnectionAbstractServer * { + return new T(parent); + }; + } + + bool isValid(const QUrl &url) + { + return m_creatorFuncs.contains(url.scheme()); + } + +private: + friend class QtROFactoryLoader; + QtROServerFactory(); + + using CreatorFunc = QConnectionAbstractServer * (*)(QObject *); + QHash m_creatorFuncs; +}; + +class QtROClientFactory +{ +public: + Q_REMOTEOBJECTS_EXPORT static QtROClientFactory *instance(); + + /// creates an object from a string + QtROClientIoDevice *create(const QUrl &url, QObject *parent = nullptr) + { + auto creatorFunc = m_creatorFuncs.value(url.scheme()); + if (!creatorFunc) + return nullptr; + + QtROClientIoDevice *res = (*creatorFunc)(parent); + if (res) + res->setUrl(url); + return res; + } + + template + void registerType(const QString &id) + { + m_creatorFuncs[id] = [](QObject *parent) -> QtROClientIoDevice * { + return new T(parent); + }; + } + + bool isValid(const QUrl &url) + { + return m_creatorFuncs.contains(url.scheme()); + } + +private: + friend class QtROFactoryLoader; + QtROClientFactory(); + + using CreatorFunc = QtROClientIoDevice * (*)(QObject *); + QHash m_creatorFuncs; +}; + +template +inline void qRegisterRemoteObjectsClient(const QString &id) +{ + QtROClientFactory::instance()->registerType(id); +} + +template +inline void qRegisterRemoteObjectsServer(const QString &id) +{ + QtROServerFactory::instance()->registerType(id); +} + +QT_END_NAMESPACE + +#endif // QCONNECTIONFACTORIES_H diff --git a/src/remoteobjects/qconnectionfactories_p.h b/src/remoteobjects/qconnectionfactories_p.h new file mode 100644 index 0000000..9365a60 --- /dev/null +++ b/src/remoteobjects/qconnectionfactories_p.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2017-2015 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCONNECTIONFACTORIES_P_H +#define QCONNECTIONFACTORIES_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include + +#include +#include +#include "qremoteobjectpacket_p.h" + +QT_BEGIN_NAMESPACE + +namespace QtRemoteObjects { + +static const int dataStreamVersion = QDataStream::Qt_6_2; +static const QLatin1String protocolVersion("QtRO 2.0"); + +} + +class QtROExternalIoDevice : public QtROIoDeviceBase +{ + Q_OBJECT + +public: + explicit QtROExternalIoDevice(QIODevice *device, QObject *parent=nullptr); + QIODevice *connection() const override; + bool isOpen() const override; + +protected: + void doClose() override; + QString deviceType() const override; +private: + Q_DECLARE_PRIVATE(QtROExternalIoDevice) +}; + +class QtROIoDeviceBasePrivate : public QObjectPrivate +{ +public: + QtROIoDeviceBasePrivate(); + + // TODO Remove stream() + QDataStream &stream() { return m_dataStream; } + + bool m_isClosing = false; + quint32 m_curReadSize = 0; + QDataStream m_dataStream; + QSet m_remoteObjects; + QRemoteObjectPackets::CodecBase *m_codec { nullptr }; + Q_DECLARE_PUBLIC(QtROIoDeviceBase) +}; + +class QtROClientIoDevicePrivate : public QtROIoDeviceBasePrivate +{ +public: + QtROClientIoDevicePrivate() : QtROIoDeviceBasePrivate() { } + QUrl m_url; + Q_DECLARE_PUBLIC(QtROClientIoDevice) +}; + +class QtROExternalIoDevicePrivate : public QtROIoDeviceBasePrivate +{ +public: + QtROExternalIoDevicePrivate(QIODevice *device) : QtROIoDeviceBasePrivate(), m_device(device) { } + QPointer m_device; + Q_DECLARE_PUBLIC(QtROExternalIoDevice) +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/remoteobjects/qremoteobjectabstractitemmodeladapter.cpp b/src/remoteobjects/qremoteobjectabstractitemmodeladapter.cpp new file mode 100644 index 0000000..11f193e --- /dev/null +++ b/src/remoteobjects/qremoteobjectabstractitemmodeladapter.cpp @@ -0,0 +1,295 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qremoteobjectabstractitemmodeladapter_p.h" + +#include + +inline QList createModelRoleData(const QList &roles) +{ + QList roleData; + roleData.reserve(roles.size()); + for (int role : roles) + roleData.emplace_back(role); + return roleData; +} + +// consider evaluating performance difference with item data +inline QVariantList collectData(const QModelIndex &index, const QAbstractItemModel *model, + QModelRoleDataSpan roleDataSpan) +{ + model->multiData(index, roleDataSpan); + + QVariantList result; + result.reserve(roleDataSpan.size()); + for (auto &roleData : roleDataSpan) + result.push_back(std::move(roleData.data())); + + return result; +} + +inline QList filterRoles(const QList &roles, const QList &availableRoles) +{ + if (roles.isEmpty()) + return availableRoles; + + QList neededRoles; + for (int inRole : roles) { + for (int availableRole : availableRoles) + if (inRole == availableRole) { + neededRoles << inRole; + continue; + } + } + return neededRoles; +} + +QAbstractItemModelSourceAdapter::QAbstractItemModelSourceAdapter(QAbstractItemModel *obj, QItemSelectionModel *sel, const QList &roles) + : QObject(obj), + m_model(obj), + m_availableRoles(roles) +{ + QAbstractItemModelSourceAdapter::registerTypes(); + m_selectionModel = sel; + connect(m_model, &QAbstractItemModel::dataChanged, this, &QAbstractItemModelSourceAdapter::sourceDataChanged); + connect(m_model, &QAbstractItemModel::rowsInserted, this, &QAbstractItemModelSourceAdapter::sourceRowsInserted); + connect(m_model, &QAbstractItemModel::columnsInserted, this, &QAbstractItemModelSourceAdapter::sourceColumnsInserted); + connect(m_model, &QAbstractItemModel::rowsRemoved, this, &QAbstractItemModelSourceAdapter::sourceRowsRemoved); + connect(m_model, &QAbstractItemModel::rowsMoved, this, &QAbstractItemModelSourceAdapter::sourceRowsMoved); + connect(m_model, &QAbstractItemModel::layoutChanged, this, &QAbstractItemModelSourceAdapter::sourceLayoutChanged); + if (m_selectionModel) + connect(m_selectionModel, &QItemSelectionModel::currentChanged, this, &QAbstractItemModelSourceAdapter::sourceCurrentChanged); +} + +void QAbstractItemModelSourceAdapter::registerTypes() +{ + static bool alreadyRegistered = false; + if (alreadyRegistered) + return; + + alreadyRegistered = true; + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType>(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); +} + +QItemSelectionModel* QAbstractItemModelSourceAdapter::selectionModel() const +{ + return m_selectionModel; +} + +QSize QAbstractItemModelSourceAdapter::replicaSizeRequest(QtPrivate::IndexList parentList) +{ + QModelIndex parent = toQModelIndex(parentList, m_model); + const int rowCount = m_model->rowCount(parent); + const int columnCount = m_model->columnCount(parent); + const QSize size(columnCount, rowCount); + qCDebug(QT_REMOTEOBJECT_MODELS) << "parent" << parentList << "size=" << size; + return size; +} + +void QAbstractItemModelSourceAdapter::replicaSetData(const QtPrivate::IndexList &index, const QVariant &value, int role) +{ + const QModelIndex modelIndex = toQModelIndex(index, m_model); + Q_ASSERT(modelIndex.isValid()); + const bool result = m_model->setData(modelIndex, value, role); + Q_ASSERT(result); + Q_UNUSED(result) +} + +QtPrivate::DataEntries QAbstractItemModelSourceAdapter::replicaRowRequest(QtPrivate::IndexList start, QtPrivate::IndexList end, QList roles) +{ + qCDebug(QT_REMOTEOBJECT_MODELS) << "Requested rows" << "start=" << start << "end=" << end << "roles=" << roles; + + Q_ASSERT(start.size() == end.size()); + Q_ASSERT(!start.isEmpty()); + + if (roles.isEmpty()) + roles << m_availableRoles; + + QtPrivate::IndexList parentList = start; + Q_ASSERT(!parentList.isEmpty()); + parentList.pop_back(); + QModelIndex parent = toQModelIndex(parentList, m_model); + + const int startRow = start.last().row; + const int startColumn = start.last().column; + const int rowCount = m_model->rowCount(parent); + const int columnCount = m_model->columnCount(parent); + + QtPrivate::DataEntries entries; + if (rowCount <= 0) + return entries; + const int endRow = std::min(end.last().row, rowCount - 1); + const int endColumn = std::min(end.last().column, columnCount - 1); + Q_ASSERT_X(endRow >= 0 && endRow < rowCount, __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 < %2")).arg(endRow).arg(rowCount))); + Q_ASSERT_X(endColumn >= 0 && endColumn < columnCount, __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 < %2")).arg(endColumn).arg(columnCount))); + + auto roleData = createModelRoleData(roles); + for (int row = startRow; row <= endRow; ++row) { + for (int column = startColumn; column <= endColumn; ++column) { + const QModelIndex current = m_model->index(row, column, parent); + Q_ASSERT(current.isValid()); + const QtPrivate::IndexList currentList = QtPrivate::toModelIndexList(current, m_model); + const QVariantList data = collectData(current, m_model, roleData); + const bool hasChildren = m_model->hasChildren(current); + const Qt::ItemFlags flags = m_model->flags(current); + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "current=" << currentList << "data=" << data; + entries.data << QtPrivate::IndexValuePair(currentList, data, hasChildren, flags); + } + } + return entries; +} + +QtPrivate::MetaAndDataEntries QAbstractItemModelSourceAdapter::replicaCacheRequest(size_t size, const QList &roles) +{ + QtPrivate::MetaAndDataEntries res; + res.roles = roles.isEmpty() ? m_availableRoles : roles; + res.data = fetchTree(QModelIndex {}, size, res.roles); + const int rowCount = m_model->rowCount(QModelIndex{}); + const int columnCount = m_model->columnCount(QModelIndex{}); + res.size = QSize{columnCount, rowCount}; + return res; +} + +QVariantList QAbstractItemModelSourceAdapter::replicaHeaderRequest(QList orientations, QList sections, QList roles) +{ + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "orientations=" << orientations << "sections=" << sections << "roles=" << roles; + QVariantList data; + Q_ASSERT(roles.size() == sections.size()); + Q_ASSERT(roles.size() == orientations.size()); + for (int i = 0; i < roles.size(); ++i) { + data << m_model->headerData(sections[i], orientations[i], roles[i]); + } + return data; +} + +void QAbstractItemModelSourceAdapter::replicaSetCurrentIndex(QtPrivate::IndexList index, QItemSelectionModel::SelectionFlags command) +{ + if (m_selectionModel) + m_selectionModel->setCurrentIndex(toQModelIndex(index, m_model), command); +} + +void QAbstractItemModelSourceAdapter::sourceDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, const QList & roles) const +{ + QList neededRoles = filterRoles(roles, availableRoles()); + if (neededRoles.isEmpty()) { + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "Needed roles is empty!"; + return; + } + Q_ASSERT(topLeft.isValid()); + Q_ASSERT(bottomRight.isValid()); + QtPrivate::IndexList start = QtPrivate::toModelIndexList(topLeft, m_model); + QtPrivate::IndexList end = QtPrivate::toModelIndexList(bottomRight, m_model); + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "start=" << start << "end=" << end << "neededRoles=" << neededRoles; + emit dataChanged(start, end, neededRoles); +} + +void QAbstractItemModelSourceAdapter::sourceRowsInserted(const QModelIndex & parent, int start, int end) +{ + QtPrivate::IndexList parentList = QtPrivate::toModelIndexList(parent, m_model); + emit rowsInserted(parentList, start, end); +} + +void QAbstractItemModelSourceAdapter::sourceColumnsInserted(const QModelIndex & parent, int start, int end) +{ + QtPrivate::IndexList parentList = QtPrivate::toModelIndexList(parent, m_model); + emit columnsInserted(parentList, start, end); +} + +void QAbstractItemModelSourceAdapter::sourceRowsRemoved(const QModelIndex & parent, int start, int end) +{ + QtPrivate::IndexList parentList = QtPrivate::toModelIndexList(parent, m_model); + emit rowsRemoved(parentList, start, end); +} + +void QAbstractItemModelSourceAdapter::sourceRowsMoved(const QModelIndex & sourceParent, int sourceRow, int count, const QModelIndex & destinationParent, int destinationChild) const +{ + emit rowsMoved(QtPrivate::toModelIndexList(sourceParent, m_model), sourceRow, count, QtPrivate::toModelIndexList(destinationParent, m_model), destinationChild); +} + +void QAbstractItemModelSourceAdapter::sourceCurrentChanged(const QModelIndex & current, const QModelIndex & previous) +{ + QtPrivate::IndexList currentIndex = QtPrivate::toModelIndexList(current, m_model); + QtPrivate::IndexList previousIndex = QtPrivate::toModelIndexList(previous, m_model); + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "current=" << currentIndex << "previous=" << previousIndex; + emit currentChanged(currentIndex, previousIndex); +} + +void QAbstractItemModelSourceAdapter::sourceLayoutChanged(const QList &parents, QAbstractItemModel::LayoutChangeHint hint) +{ + QtPrivate::IndexList indexes; + for (const QPersistentModelIndex &idx : parents) + indexes << QtPrivate::toModelIndexList((QModelIndex)idx, m_model); + emit layoutChanged(indexes, hint); +} + +QList QAbstractItemModelSourceAdapter::fetchTree(const QModelIndex &parent, size_t &size, const QList &roles) +{ + QList entries; + const int rowCount = m_model->rowCount(parent); + const int columnCount = m_model->columnCount(parent); + if (!columnCount || !rowCount) + return entries; + entries.reserve(std::min(rowCount * columnCount, int(size))); + auto roleData = createModelRoleData(roles); + for (int row = 0; row < rowCount && size > 0; ++row) + for (int column = 0; column < columnCount && size > 0; ++column) { + const auto index = m_model->index(row, column, parent); + const QtPrivate::IndexList currentList = QtPrivate::toModelIndexList(index, m_model); + const QVariantList data = collectData(index, m_model, roleData); + const bool hasChildren = m_model->hasChildren(index); + const Qt::ItemFlags flags = m_model->flags(index); + int rc = m_model->rowCount(index); + int cc = m_model->columnCount(index); + QtPrivate::IndexValuePair rowData(currentList, data, hasChildren, flags, QSize{cc, rc}); + --size; + if (hasChildren) + rowData.children = fetchTree(index, size, roles); + entries.push_back(rowData); + } + return entries; +} diff --git a/src/remoteobjects/qremoteobjectabstractitemmodeladapter_p.h b/src/remoteobjects/qremoteobjectabstractitemmodeladapter_p.h new file mode 100644 index 0000000..73d52d8 --- /dev/null +++ b/src/remoteobjects/qremoteobjectabstractitemmodeladapter_p.h @@ -0,0 +1,310 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QREMOTEOBJECTS_ABSTRACT_ITEM_ADAPTER_P_H +#define QREMOTEOBJECTS_ABSTRACT_ITEM_ADAPTER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qremoteobjectabstractitemmodeltypes_p.h" +#include "qremoteobjectsource.h" + +#include + +QT_BEGIN_NAMESPACE + +class QAbstractItemModel; +class QItemSelectionModel; + +class QAbstractItemModelSourceAdapter : public QObject +{ + Q_OBJECT +public: + Q_INVOKABLE explicit QAbstractItemModelSourceAdapter(QAbstractItemModel *object, QItemSelectionModel *sel, const QList &roles = QList()); + Q_PROPERTY(QList availableRoles READ availableRoles WRITE setAvailableRoles NOTIFY availableRolesChanged) + Q_PROPERTY(QIntHash roleNames READ roleNames) + static void registerTypes(); + QItemSelectionModel* selectionModel() const; + +public Q_SLOTS: + QList availableRoles() const { return m_availableRoles; } + void setAvailableRoles(QList availableRoles) + { + if (availableRoles != m_availableRoles) + { + m_availableRoles = availableRoles; + Q_EMIT availableRolesChanged(); + } + } + + QIntHash roleNames() const {return m_model->roleNames();} + + QSize replicaSizeRequest(QtPrivate::IndexList parentList); + QtPrivate::DataEntries replicaRowRequest(QtPrivate::IndexList start, QtPrivate::IndexList end, QList roles); + QVariantList replicaHeaderRequest(QList orientations, QList sections, QList roles); + void replicaSetCurrentIndex(QtPrivate::IndexList index, QItemSelectionModel::SelectionFlags command); + void replicaSetData(const QtPrivate::IndexList &index, const QVariant &value, int role); + QtPrivate::MetaAndDataEntries replicaCacheRequest(size_t size, const QList &roles); + + void sourceDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, const QList & roles = QList ()) const; + void sourceRowsInserted(const QModelIndex & parent, int start, int end); + void sourceColumnsInserted(const QModelIndex & parent, int start, int end); + void sourceRowsRemoved(const QModelIndex & parent, int start, int end); + void sourceRowsMoved(const QModelIndex & sourceParent, int sourceRow, int count, const QModelIndex & destinationParent, int destinationChild) const; + void sourceCurrentChanged(const QModelIndex & current, const QModelIndex & previous); + void sourceLayoutChanged(const QList &parents, QAbstractItemModel::LayoutChangeHint hint); +Q_SIGNALS: + void availableRolesChanged(); + void dataChanged(QtPrivate::IndexList topLeft, QtPrivate::IndexList bottomRight, QList roles) const; + void rowsInserted(QtPrivate::IndexList parent, int start, int end) const; + void rowsRemoved(QtPrivate::IndexList parent, int start, int end) const; + void rowsMoved(QtPrivate::IndexList sourceParent, int sourceRow, int count, QtPrivate::IndexList destinationParent, int destinationChild) const; + void currentChanged(QtPrivate::IndexList current, QtPrivate::IndexList previous); + void columnsInserted(QtPrivate::IndexList parent, int start, int end) const; + void layoutChanged(QtPrivate::IndexList parents, QAbstractItemModel::LayoutChangeHint hint); + +private: + QAbstractItemModelSourceAdapter(); + QList fetchTree(const QModelIndex &parent, size_t &size, const QList &roles); + + QAbstractItemModel *m_model; + QItemSelectionModel *m_selectionModel; + QList m_availableRoles; +}; + +template +struct QAbstractItemAdapterSourceAPI : public SourceApiMap +{ + QAbstractItemAdapterSourceAPI(const QString &name) + : SourceApiMap() + , m_signalArgTypes {} + , m_methodArgTypes {} + , m_name(name) + { + m_properties[0] = 2; + m_properties[1] = QtPrivate::qtro_property_index(&AdapterType::availableRoles, static_cast (QObject::*)()>(nullptr),"availableRoles"); + m_properties[2] = QtPrivate::qtro_property_index(&AdapterType::roleNames, static_cast(nullptr),"roleNames"); + m_signals[0] = 10; + m_signals[1] = QtPrivate::qtro_signal_index(&AdapterType::availableRolesChanged, static_cast(nullptr),m_signalArgCount+0,&m_signalArgTypes[0]); + m_signals[2] = QtPrivate::qtro_signal_index(&AdapterType::dataChanged, static_cast)>(nullptr),m_signalArgCount+1,&m_signalArgTypes[1]); + m_signals[3] = QtPrivate::qtro_signal_index(&AdapterType::rowsInserted, static_cast(nullptr),m_signalArgCount+2,&m_signalArgTypes[2]); + m_signals[4] = QtPrivate::qtro_signal_index(&AdapterType::rowsRemoved, static_cast(nullptr),m_signalArgCount+3,&m_signalArgTypes[3]); + m_signals[5] = QtPrivate::qtro_signal_index(&AdapterType::rowsMoved, static_cast(nullptr),m_signalArgCount+4,&m_signalArgTypes[4]); + m_signals[6] = QtPrivate::qtro_signal_index(&AdapterType::currentChanged, static_cast(nullptr),m_signalArgCount+5,&m_signalArgTypes[5]); + m_signals[7] = QtPrivate::qtro_signal_index(&ObjectType::modelReset, static_cast(nullptr),m_signalArgCount+6,&m_signalArgTypes[6]); + m_signals[8] = QtPrivate::qtro_signal_index(&ObjectType::headerDataChanged, static_cast(nullptr),m_signalArgCount+7,&m_signalArgTypes[7]); + m_signals[9] = QtPrivate::qtro_signal_index(&AdapterType::columnsInserted, static_cast(nullptr),m_signalArgCount+8,&m_signalArgTypes[8]); + m_signals[10] = QtPrivate::qtro_signal_index(&AdapterType::layoutChanged, static_cast(nullptr),m_signalArgCount+9,&m_signalArgTypes[9]); + m_methods[0] = 6; + m_methods[1] = QtPrivate::qtro_method_index(&AdapterType::replicaSizeRequest, static_cast(nullptr),"replicaSizeRequest(QtPrivate::IndexList)",m_methodArgCount+0,&m_methodArgTypes[0]); + m_methods[2] = QtPrivate::qtro_method_index(&AdapterType::replicaRowRequest, static_cast)>(nullptr),"replicaRowRequest(QtPrivate::IndexList,QtPrivate::IndexList,QList)",m_methodArgCount+1,&m_methodArgTypes[1]); + m_methods[3] = QtPrivate::qtro_method_index(&AdapterType::replicaHeaderRequest, static_cast,QList,QList)>(nullptr),"replicaHeaderRequest(QList,QList,QList)",m_methodArgCount+2,&m_methodArgTypes[2]); + m_methods[4] = QtPrivate::qtro_method_index(&AdapterType::replicaSetCurrentIndex, static_cast(nullptr),"replicaSetCurrentIndex(QtPrivate::IndexList,QItemSelectionModel::SelectionFlags)",m_methodArgCount+3,&m_methodArgTypes[3]); + m_methods[5] = QtPrivate::qtro_method_index(&AdapterType::replicaSetData, static_cast(nullptr),"replicaSetData(QtPrivate::IndexList,QVariant,int)",m_methodArgCount+4,&m_methodArgTypes[4]); + m_methods[6] = QtPrivate::qtro_method_index(&AdapterType::replicaCacheRequest, static_cast)>(nullptr),"replicaCacheRequest(size_t,QList)",m_methodArgCount+5,&m_methodArgTypes[5]); + } + + QString name() const override { return m_name; } + QString typeName() const override { return QStringLiteral("QAbstractItemModelAdapter"); } + int enumCount() const override { return 0; } + int propertyCount() const override { return m_properties[0]; } + int signalCount() const override { return m_signals[0]; } + int methodCount() const override { return m_methods[0]; } + int sourceEnumIndex(int /*index*/) const override + { + return -1; + } + int sourcePropertyIndex(int index) const override + { + if (index < 0 || index >= m_properties[0]) + return -1; + return m_properties[index+1]; + } + int sourceSignalIndex(int index) const override + { + if (index < 0 || index >= m_signals[0]) + return -1; + return m_signals[index+1]; + } + int sourceMethodIndex(int index) const override + { + if (index < 0 || index >= m_methods[0]) + return -1; + return m_methods[index+1]; + } + int signalParameterCount(int index) const override { return m_signalArgCount[index]; } + int signalParameterType(int sigIndex, int paramIndex) const override { return m_signalArgTypes[sigIndex][paramIndex]; } + int methodParameterCount(int index) const override { return m_methodArgCount[index]; } + int methodParameterType(int methodIndex, int paramIndex) const override { return m_methodArgTypes[methodIndex][paramIndex]; } + QByteArrayList signalParameterNames(int index) const override + { + QByteArrayList res; + int count = signalParameterCount(index); + while (count--) + res << QByteArray{}; + return res; + } + int propertyIndexFromSignal(int index) const override + { + switch (index) { + case 0: return m_properties[1]; + } + return -1; + } + int propertyRawIndexFromSignal(int index) const override + { + switch (index) { + case 0: return 0; + } + return -1; + } + const QByteArray signalSignature(int index) const override + { + switch (index) { + case 0: return QByteArrayLiteral("availableRolesChanged()"); + case 1: return QByteArrayLiteral("dataChanged(QtPrivate::IndexList,QtPrivate::IndexList,QList)"); + case 2: return QByteArrayLiteral("rowsInserted(QtPrivate::IndexList,int,int)"); + case 3: return QByteArrayLiteral("rowsRemoved(QtPrivate::IndexList,int,int)"); + case 4: return QByteArrayLiteral("rowsMoved(QtPrivate::IndexList,int,int,QtPrivate::IndexList,int)"); + case 5: return QByteArrayLiteral("currentChanged(QtPrivate::IndexList,QtPrivate::IndexList)"); + case 6: return QByteArrayLiteral("resetModel()"); + case 7: return QByteArrayLiteral("headerDataChanged(Qt::Orientation,int,int)"); + case 8: return QByteArrayLiteral("columnsInserted(QtPrivate::IndexList,int,int)"); + case 9: return QByteArrayLiteral("layoutChanged(QtPrivate::IndexList,QAbstractItemModel::LayoutChangeHint)"); + } + return QByteArrayLiteral(""); + } + const QByteArray methodSignature(int index) const override + { + switch (index) { + case 0: return QByteArrayLiteral("replicaSizeRequest(QtPrivate::IndexList)"); + case 1: return QByteArrayLiteral("replicaRowRequest(QtPrivate::IndexList,QtPrivate::IndexList,QList)"); + case 2: return QByteArrayLiteral("replicaHeaderRequest(QList,QList,QList)"); + case 3: return QByteArrayLiteral("replicaSetCurrentIndex(QtPrivate::IndexList,QItemSelectionModel::SelectionFlags)"); + case 4: return QByteArrayLiteral("replicaSetData(QtPrivate::IndexList,QVariant,int)"); + case 5: return QByteArrayLiteral("replicaCacheRequest(size_t,QList)"); + } + return QByteArrayLiteral(""); + } + QMetaMethod::MethodType methodType(int) const override + { + return QMetaMethod::Slot; + } + const QByteArray typeName(int index) const override + { + switch (index) { + case 0: return QByteArrayLiteral("QSize"); + case 1: return QByteArrayLiteral("QtPrivate::DataEntries"); + case 2: return QByteArrayLiteral("QVariantList"); + case 3: return QByteArrayLiteral(""); + case 5: return QByteArrayLiteral("QtPrivate::MetaAndDataEntries"); + } + return QByteArrayLiteral(""); + } + + QByteArrayList methodParameterNames(int index) const override + { + QByteArrayList res; + int count = methodParameterCount(index); + while (count--) + res << QByteArray{}; + return res; + } + + QByteArray objectSignature() const override { return QByteArray{}; } + bool isAdapterSignal(int index) const override + { + switch (index) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 8: + case 9: + return true; + } + return false; + } + bool isAdapterMethod(int index) const override + { + switch (index) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + return true; + } + return false; + } + bool isAdapterProperty(int index) const override + { + switch (index) { + case 0: + case 1: + return true; + } + return false; + } + + int m_properties[3]; + int m_signals[11]; + int m_methods[7]; + int m_signalArgCount[10]; + const int* m_signalArgTypes[10]; + int m_methodArgCount[6]; + const int* m_methodArgTypes[6]; + QString m_name; +}; + +QT_END_NAMESPACE + +#endif //QREMOTEOBJECTS_ABSTRACT_ITEM_ADAPTER_P_H diff --git a/src/remoteobjects/qremoteobjectabstractitemmodelreplica.cpp b/src/remoteobjects/qremoteobjectabstractitemmodelreplica.cpp new file mode 100644 index 0000000..bf13b36 --- /dev/null +++ b/src/remoteobjects/qremoteobjectabstractitemmodelreplica.cpp @@ -0,0 +1,1174 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qremoteobjectabstractitemmodelreplica.h" +#include "qremoteobjectabstractitemmodelreplica_p.h" + +#include "qremoteobjectnode.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +inline QDebug operator<<(QDebug stream, const RequestedData &data) +{ + return stream.nospace() << "RequestedData[start=" << data.start << ", end=" << data.end << ", roles=" << data.roles << "]"; +} + +CacheData::CacheData(QAbstractItemModelReplicaImplementation *model, CacheData *parentItem) + : replicaModel(model) + , parent(parentItem) + , hasChildren(false) + , columnCount(0) + , rowCount(0) +{ + if (parent) + replicaModel->m_activeParents.insert(parent); +} + +CacheData::~CacheData() { + if (parent && !replicaModel->m_activeParents.empty()) + replicaModel->m_activeParents.erase(this); +} + +QAbstractItemModelReplicaImplementation::QAbstractItemModelReplicaImplementation() + : QRemoteObjectReplica() + , m_selectionModel(nullptr) + , m_rootItem(this) +{ + QAbstractItemModelReplicaImplementation::registerMetatypes(); + initializeModelConnections(); + connect(this, &QAbstractItemModelReplicaImplementation::availableRolesChanged, this, [this]{ + m_availableRoles.clear(); + }); +} + +QAbstractItemModelReplicaImplementation::QAbstractItemModelReplicaImplementation(QRemoteObjectNode *node, const QString &name) + : QRemoteObjectReplica(ConstructWithNode) + , m_selectionModel(nullptr) + , m_rootItem(this) +{ + QAbstractItemModelReplicaImplementation::registerMetatypes(); + initializeModelConnections(); + initializeNode(node, name); + connect(this, &QAbstractItemModelReplicaImplementation::availableRolesChanged, this, [this]{ + m_availableRoles.clear(); + }); +} + +QAbstractItemModelReplicaImplementation::~QAbstractItemModelReplicaImplementation() +{ + m_rootItem.clear(); + qDeleteAll(m_pendingRequests); +} + +void QAbstractItemModelReplicaImplementation::initialize() +{ + QVariantList properties; + properties << QVariant::fromValue(QList()); + properties << QVariant::fromValue(QIntHash()); + setProperties(std::move(properties)); +} + +void QAbstractItemModelReplicaImplementation::registerMetatypes() +{ + static bool alreadyRegistered = false; + if (alreadyRegistered) + return; + + alreadyRegistered = true; + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType>(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); +} + +void QAbstractItemModelReplicaImplementation::initializeModelConnections() +{ + connect(this, &QAbstractItemModelReplicaImplementation::dataChanged, this, &QAbstractItemModelReplicaImplementation::onDataChanged); + connect(this, &QAbstractItemModelReplicaImplementation::rowsInserted, this, &QAbstractItemModelReplicaImplementation::onRowsInserted); + connect(this, &QAbstractItemModelReplicaImplementation::columnsInserted, this, &QAbstractItemModelReplicaImplementation::onColumnsInserted); + connect(this, &QAbstractItemModelReplicaImplementation::rowsRemoved, this, &QAbstractItemModelReplicaImplementation::onRowsRemoved); + connect(this, &QAbstractItemModelReplicaImplementation::rowsMoved, this, &QAbstractItemModelReplicaImplementation::onRowsMoved); + connect(this, &QAbstractItemModelReplicaImplementation::currentChanged, this, &QAbstractItemModelReplicaImplementation::onCurrentChanged); + connect(this, &QAbstractItemModelReplicaImplementation::modelReset, this, &QAbstractItemModelReplicaImplementation::onModelReset); + connect(this, &QAbstractItemModelReplicaImplementation::headerDataChanged, this, &QAbstractItemModelReplicaImplementation::onHeaderDataChanged); + connect(this, &QAbstractItemModelReplicaImplementation::layoutChanged, this, &QAbstractItemModelReplicaImplementation::onLayoutChanged); + +} + +inline void removeIndexFromRow(const QModelIndex &index, const QList &roles, CachedRowEntry *entry) +{ + CachedRowEntry &entryRef = *entry; + if (index.column() < entryRef.size()) { + CacheEntry &entry = entryRef[index.column()]; + if (roles.isEmpty()) { + entry.data.clear(); + } else { + for (int role : roles) + entry.data.remove(role); + } + } +} + +void QAbstractItemModelReplicaImplementation::onReplicaCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous) +{ + Q_UNUSED(previous) + QtPrivate::IndexList currentIndex = QtPrivate::toModelIndexList(current, q); + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "current=" << currentIndex; + replicaSetCurrentIndex(currentIndex, QItemSelectionModel::Clear|QItemSelectionModel::Select|QItemSelectionModel::Current); +} + +void QAbstractItemModelReplicaImplementation::setModel(QAbstractItemModelReplica *model) +{ + q = model; + setParent(model); + m_selectionModel.reset(new QItemSelectionModel(model)); + connect(m_selectionModel.data(), &QItemSelectionModel::currentChanged, this, &QAbstractItemModelReplicaImplementation::onReplicaCurrentChanged); +} + +bool QAbstractItemModelReplicaImplementation::clearCache(const QtPrivate::IndexList &start, const QtPrivate::IndexList &end, const QList &roles = QList()) +{ + Q_ASSERT(start.size() == end.size()); + + bool ok = true; + const QModelIndex startIndex = toQModelIndex(start, q, &ok); + if (!ok) + return false; + const QModelIndex endIndex = toQModelIndex(end, q, &ok); + if (!ok) + return false; + Q_ASSERT(startIndex.isValid()); + Q_ASSERT(endIndex.isValid()); + Q_ASSERT(startIndex.parent() == endIndex.parent()); + Q_UNUSED(endIndex) + QModelIndex parentIndex = startIndex.parent(); + auto parentItem = cacheData(parentIndex); + + const int startRow = start.last().row; + const int lastRow = end.last().row; + const int startColumn = start.last().column; + const int lastColumn = end.last().column; + for (int row = startRow; row <= lastRow; ++row) { + Q_ASSERT_X(row >= 0 && row < parentItem->rowCount, __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 < %2")).arg(row).arg(parentItem->rowCount))); + auto item = parentItem->children.get(row); + if (item) { + CachedRowEntry *entry = &(item->cachedRowEntry); + for (int column = startColumn; column <= lastColumn; ++column) + removeIndexFromRow(q->index(row, column, parentIndex), roles, entry); + } + } + return true; +} + +void QAbstractItemModelReplicaImplementation::onDataChanged(const QtPrivate::IndexList &start, const QtPrivate::IndexList &end, const QList &roles) +{ + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "start=" << start << "end=" << end << "roles=" << roles; + + // we need to clear the cache to make sure the new remote data is fetched if the new data call is happening + if (clearCache(start, end, roles)) { + bool ok = true; + const QModelIndex startIndex = toQModelIndex(start, q, &ok); + if (!ok) + return; + const QModelIndex endIndex = toQModelIndex(end, q, &ok); + if (!ok) + return; + Q_ASSERT(startIndex.parent() == endIndex.parent()); + auto parentItem = cacheData(startIndex.parent()); + int startRow = start.last().row; + int endRow = end.last().row; + bool dataChanged = false; + while (startRow <= endRow) { + for (;startRow <= endRow; startRow++) { + if (parentItem->children.exists(startRow)) + break; + } + + if (startRow > endRow) + break; + + RequestedData data; + data.roles = roles; + data.start = start; + data.start.last().row = startRow; + + while (startRow <= endRow && parentItem->children.exists(startRow)) + ++startRow; + + data.end = end; + data.end.last().row = startRow -1; + + m_requestedData.append(data); + dataChanged = true; + } + + if (dataChanged) + QMetaObject::invokeMethod(this, "fetchPendingData", Qt::QueuedConnection); + } +} + +void QAbstractItemModelReplicaImplementation::onRowsInserted(const QtPrivate::IndexList &parent, int start, int end) +{ + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "start=" << start << "end=" << end << "parent=" << parent; + + bool treeFullyLazyLoaded = true; + const QModelIndex parentIndex = toQModelIndex(parent, q, &treeFullyLazyLoaded, true); + if (!treeFullyLazyLoaded) + return; + + auto parentItem = cacheData(parentIndex); + q->beginInsertRows(parentIndex, start, end); + parentItem->insertChildren(start, end); + for (int i = start; i <= end; ++i) + m_headerData[1].append(CacheEntry()); + q->endInsertRows(); + if (!parentItem->hasChildren && parentItem->columnCount > 0) { + parentItem->hasChildren = true; + emit q->dataChanged(parentIndex, parentIndex); + } +} + +void QAbstractItemModelReplicaImplementation::onColumnsInserted(const QtPrivate::IndexList &parent, int start, int end) +{ + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "start=" << start << "end=" << end << "parent=" << parent; + + bool treeFullyLazyLoaded = true; + const QModelIndex parentIndex = toQModelIndex(parent, q, &treeFullyLazyLoaded); + if (!treeFullyLazyLoaded) + return; + + //Since we need to support QAIM and models that don't emit columnCountChanged + //check if we have a constant columnCount everywhere if thats the case don't insert + //more columns + auto parentItem = cacheData(parentIndex); + auto parentOfParent = parentItem->parent; + if (parentOfParent && parentItem != &m_rootItem) + if (parentOfParent->columnCount == parentItem->columnCount) + return; + q->beginInsertColumns(parentIndex, start, end); + parentItem->columnCount += end - start + 1; + for (int i = start; i <= end; ++i) + m_headerData[0].append(CacheEntry()); + q->endInsertColumns(); + if (!parentItem->hasChildren && parentItem->children.size() > 0) { + parentItem->hasChildren = true; + emit q->dataChanged(parentIndex, parentIndex); + } + +} + +void QAbstractItemModelReplicaImplementation::onRowsRemoved(const QtPrivate::IndexList &parent, int start, int end) +{ + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "start=" << start << "end=" << end << "parent=" << parent; + + bool treeFullyLazyLoaded = true; + const QModelIndex parentIndex = toQModelIndex(parent, q, &treeFullyLazyLoaded); + if (!treeFullyLazyLoaded) + return; + + auto parentItem = cacheData(parentIndex); + q->beginRemoveRows(parentIndex, start, end); + if (parentItem) + parentItem->removeChildren(start, end); + m_headerData[1].erase(m_headerData[1].begin() + start, m_headerData[1].begin() + end + 1); + q->endRemoveRows(); +} + +void QAbstractItemModelReplicaImplementation::onRowsMoved(QtPrivate::IndexList srcParent, int srcRow, int count, QtPrivate::IndexList destParent, int destRow) +{ + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO; + + const QModelIndex sourceParent = toQModelIndex(srcParent, q); + const QModelIndex destinationParent = toQModelIndex(destParent, q); + Q_ASSERT(!sourceParent.isValid()); + Q_ASSERT(!destinationParent.isValid()); + q->beginMoveRows(sourceParent, srcRow, count, destinationParent, destRow); +//TODO misses parents... + QtPrivate::IndexList start, end; + start << QtPrivate::ModelIndex(srcRow, 0); + end << QtPrivate::ModelIndex(srcRow + count, q->columnCount(sourceParent)-1); + clearCache(start, end); + QtPrivate::IndexList start2, end2; + start2 << QtPrivate::ModelIndex(destRow, 0); + end2 << QtPrivate::ModelIndex(destRow + count, q->columnCount(destinationParent)-1); + clearCache(start2, end2); + q->endMoveRows(); +} + +void QAbstractItemModelReplicaImplementation::onCurrentChanged(QtPrivate::IndexList current, QtPrivate::IndexList previous) +{ + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "current=" << current << "previous=" << previous; + Q_UNUSED(previous) + Q_ASSERT(m_selectionModel); + bool ok; + // If we have several tree models sharing a selection model, we + // can't guarantee that all Replicas have the selected cell + // available. + const QModelIndex currentIndex = toQModelIndex(current, q, &ok); + // Ignore selection if we can't find the desired cell. + if (ok) + m_selectionModel->setCurrentIndex(currentIndex, QItemSelectionModel::Clear|QItemSelectionModel::Select|QItemSelectionModel::Current); +} + +void QAbstractItemModelReplicaImplementation::handleInitDone(QRemoteObjectPendingCallWatcher *watcher) +{ + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO; + + handleModelResetDone(watcher); + m_initDone = true; + emit q->initialized(); +} + +void QAbstractItemModelReplicaImplementation::handleModelResetDone(QRemoteObjectPendingCallWatcher *watcher) +{ + QSize size; + if (m_initialAction == QtRemoteObjects::FetchRootSize) + size = watcher->returnValue().toSize(); + else { + Q_ASSERT(watcher->returnValue().canConvert()); + size = watcher->returnValue().value().size; + } + + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "size=" << size; + + q->beginResetModel(); + m_rootItem.clear(); + if (size.height() > 0) { + m_rootItem.rowCount = size.height(); + m_rootItem.hasChildren = true; + } + + m_rootItem.columnCount = size.width(); + m_headerData[0].resize(size.width()); + m_headerData[1].resize(size.height()); + { + QList &headerEntries = m_headerData[0]; + for (int i = 0; i < size.width(); ++i ) + headerEntries[i].data.clear(); + } + { + QList &headerEntries = m_headerData[1]; + for (int i = 0; i < size.height(); ++i ) + headerEntries[i].data.clear(); + } + if (m_initialAction == QtRemoteObjects::PrefetchData) { + auto entries = watcher->returnValue().value(); + for (int i = 0; i < entries.data.size(); ++i) + fillCache(entries.data[i], entries.roles); + } + q->endResetModel(); + m_pendingRequests.removeAll(watcher); + delete watcher; +} + +void QAbstractItemModelReplicaImplementation::handleSizeDone(QRemoteObjectPendingCallWatcher *watcher) +{ + SizeWatcher *sizeWatcher = static_cast(watcher); + const QSize size = sizeWatcher->returnValue().toSize(); + auto parentItem = cacheData(sizeWatcher->parentList); + const QModelIndex parent = toQModelIndex(sizeWatcher->parentList, q); + + if (size.width() != parentItem->columnCount) { + const int columnCount = std::max(0, parentItem->columnCount); + Q_ASSERT_X(size.width() >= parentItem->columnCount, __FUNCTION__, "The column count should only shrink in columnsRemoved!!"); + parentItem->columnCount = size.width(); + if (size.width() > columnCount) { + Q_ASSERT(size.width() > 0); + q->beginInsertColumns(parent, columnCount, size.width() - 1); + q->endInsertColumns(); + } else { + Q_ASSERT_X(size.width() == columnCount, __FUNCTION__, qPrintable(QString(QLatin1String("%1 != %2")).arg(size.width()).arg(columnCount))); + } + } + + Q_ASSERT_X(size.height() >= parentItem->rowCount, __FUNCTION__, "The new size and the current size should match!!"); + if (!parentItem->rowCount) { + if (size.height() > 0) { + q->beginInsertRows(parent, 0, size.height() - 1); + parentItem->rowCount = size.height(); + q->endInsertRows(); + } + } else { + Q_ASSERT_X(parentItem->rowCount == size.height(), __FUNCTION__, qPrintable(QString(QLatin1String("%1 != %2")).arg(parentItem->rowCount).arg(size.height()))); + } + m_pendingRequests.removeAll(watcher); + delete watcher; +} + +void QAbstractItemModelReplicaImplementation::init() +{ + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << this->node()->objectName(); + QRemoteObjectPendingCallWatcher *watcher = doModelReset(); + connect(watcher, &QRemoteObjectPendingCallWatcher::finished, this, &QAbstractItemModelReplicaImplementation::handleInitDone); +} + +QRemoteObjectPendingCallWatcher* QAbstractItemModelReplicaImplementation::doModelReset() +{ + qDeleteAll(m_pendingRequests); + m_pendingRequests.clear(); + QtPrivate::IndexList parentList; + QRemoteObjectPendingCallWatcher *watcher; + if (m_initialAction == QtRemoteObjects::FetchRootSize) { + auto call = replicaSizeRequest(parentList); + watcher = new SizeWatcher(parentList, call); + } else { + auto call = replicaCacheRequest(m_rootItem.children.cacheSize, m_initialFetchRolesHint); + watcher = new QRemoteObjectPendingCallWatcher(call); + } + m_pendingRequests.push_back(watcher); + return watcher; +} + +inline void fillCacheEntry(CacheEntry *entry, const QtPrivate::IndexValuePair &pair, const QList &roles) +{ + Q_ASSERT(entry); + + const QVariantList &data = pair.data; + Q_ASSERT(roles.size() == data.size()); + + entry->flags = pair.flags; + + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "data.size=" << data.size(); + for (int i = 0; i < data.size(); ++i) { + const int role = roles[i]; + const QVariant dataVal = data[i]; + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "role=" << role << "data=" << dataVal; + entry->data[role] = dataVal; + } +} + +inline void fillRow(CacheData *item, const QtPrivate::IndexValuePair &pair, const QAbstractItemModel *model, const QList &roles) +{ + CachedRowEntry &rowRef = item->cachedRowEntry; + const QModelIndex index = toQModelIndex(pair.index, model); + Q_ASSERT(index.isValid()); + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "row=" << index.row() << "column=" << index.column(); + if (index.column() == 0) + item->hasChildren = pair.hasChildren; + bool existed = false; + for (int i = 0; i < rowRef.size(); ++i) { + if (i == index.column()) { + fillCacheEntry(&rowRef[i], pair, roles); + existed = true; + } + } + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "existed=" << existed; + if (!existed) { + CacheEntry entries; + fillCacheEntry(&entries, pair, roles); + rowRef.append(entries); + } +} + +int collectEntriesForRow(QtPrivate::DataEntries* filteredEntries, int row, const QtPrivate::DataEntries &entries, int startIndex) +{ + Q_ASSERT(filteredEntries); + const int size = int(entries.data.size()); + for (int i = startIndex; i < size; ++i) + { + const QtPrivate::IndexValuePair &pair = entries.data[i]; + if (pair.index.last().row == row) + filteredEntries->data << pair; + else + return i; + } + return size; +} + +void QAbstractItemModelReplicaImplementation::fillCache(const QtPrivate::IndexValuePair &pair, const QList &roles) +{ + if (auto item = createCacheData(pair.index)) { + fillRow(item, pair, q, roles); + item->rowCount = pair.size.height(); + item->columnCount = pair.size.width(); + } + for (const auto &it : pair.children) + fillCache(it, roles); +} + +void QAbstractItemModelReplicaImplementation::requestedData(QRemoteObjectPendingCallWatcher *qobject) +{ + RowWatcher *watcher = static_cast(qobject); + Q_ASSERT(watcher); + Q_ASSERT(watcher->start.size() == watcher->end.size()); + + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "start=" << watcher->start << "end=" << watcher->end; + + QtPrivate::IndexList parentList = watcher->start; + Q_ASSERT(!parentList.isEmpty()); + parentList.pop_back(); + auto parentItem = cacheData(parentList); + QtPrivate::DataEntries entries = watcher->returnValue().value(); + + const int rowCount = parentItem->rowCount; + const int columnCount = parentItem->columnCount; + + if (rowCount < 1 || columnCount < 1) + return; + + const int startRow = std::min(watcher->start.last().row, rowCount - 1); + const int endRow = std::min(watcher->end.last().row, rowCount - 1); + const int startColumn = std::min(watcher->start.last().column, columnCount - 1); + const int endColumn = std::min(watcher->end.last().column, columnCount - 1); + Q_ASSERT_X(startRow >= 0 && startRow < parentItem->rowCount, __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 < %2")).arg(startRow).arg(parentItem->rowCount))); + Q_ASSERT_X(endRow >= 0 && endRow < parentItem->rowCount, __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 < %2")).arg(endRow).arg(parentItem->rowCount))); + + for (int i = 0; i < entries.data.size(); ++i) { + QtPrivate::IndexValuePair pair = entries.data[i]; + if (auto item = createCacheData(pair.index)) + fillRow(item, pair, q, watcher->roles); + } + + const QModelIndex parentIndex = toQModelIndex(parentList, q); + const QModelIndex startIndex = q->index(startRow, startColumn, parentIndex); + const QModelIndex endIndex = q->index(endRow, endColumn, parentIndex); + Q_ASSERT(startIndex.isValid()); + Q_ASSERT(endIndex.isValid()); + emit q->dataChanged(startIndex, endIndex, watcher->roles); + m_pendingRequests.removeAll(watcher); + delete watcher; +} + +void QAbstractItemModelReplicaImplementation::fetchPendingData() +{ + if (m_requestedData.isEmpty()) + return; + + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "m_requestedData.size=" << m_requestedData.size(); + + std::vector finalRequests; + RequestedData curData; + for (const RequestedData &data : qExchange(m_requestedData, {})) { + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "REQUESTED start=" << data.start << "end=" << data.end << "roles=" << data.roles; + + Q_ASSERT(!data.start.isEmpty()); + Q_ASSERT(!data.end.isEmpty()); + Q_ASSERT(data.start.size() == data.end.size()); + if (curData.start.isEmpty() || curData.start.last().row == -1 || curData.start.last().column == -1) + curData = data; + if (curData.start.size() != data.start.size()) { + finalRequests.push_back(curData); + curData = data; + } else { + if (data.start.size() > 1) { + for (int i = 0; i < data.start.size() - 1; ++i) { + if (curData.start[i].row != data.start[i].row || + curData.start[i].column != data.start[i].column) { + finalRequests.push_back(curData); + curData = data; + } + } + } + + const QtPrivate::ModelIndex curIndStart = curData.start.last(); + const QtPrivate::ModelIndex curIndEnd = curData.end.last(); + const QtPrivate::ModelIndex dataIndStart = data.start.last(); + const QtPrivate::ModelIndex dataIndEnd = data.end.last(); + const QtPrivate::ModelIndex resStart(std::min(curIndStart.row, dataIndStart.row), std::min(curIndStart.column, dataIndStart.column)); + const QtPrivate::ModelIndex resEnd(std::max(curIndEnd.row, dataIndEnd.row), std::max(curIndEnd.column, dataIndEnd.column)); + QList roles = curData.roles; + if (!curData.roles.isEmpty()) { + for (int role : data.roles) { + if (!curData.roles.contains(role)) + roles.append(role); + } + } + QRect firstRect( QPoint(curIndStart.row, curIndStart.column), QPoint(curIndEnd.row, curIndEnd.column)); + QRect secondRect( QPoint(dataIndStart.row, dataIndStart.column), QPoint(dataIndEnd.row, dataIndEnd.column)); + + const bool borders = (qAbs(curIndStart.row - dataIndStart.row) == 1) || + (qAbs(curIndStart.column - dataIndStart.column) == 1) || + (qAbs(curIndEnd.row - dataIndEnd.row) == 1) || + (qAbs(curIndEnd.column - dataIndEnd.column) == 1); + + if ((resEnd.row - resStart.row < 100) && (firstRect.intersects(secondRect) || borders)) { + QtPrivate::IndexList start = curData.start; + start.pop_back(); + start.push_back(resStart); + QtPrivate::IndexList end = curData.end; + end.pop_back(); + end.push_back(resEnd); + curData.start = start; + curData.end = end; + curData.roles = roles; + Q_ASSERT(!start.isEmpty()); + Q_ASSERT(!end.isEmpty()); + } else { + finalRequests.push_back(curData); + curData = data; + } + } + } + finalRequests.push_back(curData); + //qCDebug(QT_REMOTEOBJECT_MODELS) << "Final requests" << finalRequests; + int rows = 0; + // There is no point to eat more than can chew + for (auto it = finalRequests.rbegin(); it != finalRequests.rend() && size_t(rows) < m_rootItem.children.cacheSize; ++it) { + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "FINAL start=" << it->start << "end=" << it->end << "roles=" << it->roles; + + QRemoteObjectPendingReply reply = replicaRowRequest(it->start, it->end, it->roles); + RowWatcher *watcher = new RowWatcher(it->start, it->end, it->roles, reply); + rows += 1 + it->end.first().row - it->start.first().row; + m_pendingRequests.push_back(watcher); + connect(watcher, &RowWatcher::finished, this, &QAbstractItemModelReplicaImplementation::requestedData); + } +} + +void QAbstractItemModelReplicaImplementation::onModelReset() +{ + if (!m_initDone) + return; + + qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO; + QRemoteObjectPendingCallWatcher *watcher = doModelReset(); + connect(watcher, &QRemoteObjectPendingCallWatcher::finished, this, &QAbstractItemModelReplicaImplementation::handleModelResetDone); +} + +void QAbstractItemModelReplicaImplementation::onHeaderDataChanged(Qt::Orientation orientation, int first, int last) +{ + // TODO clean cache + const int index = orientation == Qt::Horizontal ? 0 : 1; + QList &entries = m_headerData[index]; + for (int i = first; i <= last && i < entries.size(); ++i ) + entries[i].data.clear(); + emit q->headerDataChanged(orientation, first, last); +} + +void QAbstractItemModelReplicaImplementation::fetchPendingHeaderData() +{ + QList roles; + QList sections; + QList orientations; + for (const RequestedHeaderData &data : qAsConst(m_requestedHeaderData)) { + roles.push_back(data.role); + sections.push_back(data.section); + orientations.push_back(data.orientation); + } + QRemoteObjectPendingReply reply = replicaHeaderRequest(orientations, sections, roles); + HeaderWatcher *watcher = new HeaderWatcher(orientations, sections, roles, reply); + connect(watcher, &HeaderWatcher::finished, this, &QAbstractItemModelReplicaImplementation::requestedHeaderData); + m_requestedHeaderData.clear(); + m_pendingRequests.push_back(watcher); +} + +void QAbstractItemModelReplicaImplementation::onLayoutChanged(const QtPrivate::IndexList &parents, + QAbstractItemModel::LayoutChangeHint hint) +{ + QList indexes; + for (const QtPrivate::ModelIndex &parent : qAsConst(parents)) { + const QModelIndex parentIndex = toQModelIndex(QtPrivate::IndexList{parent}, q); + indexes << QPersistentModelIndex(parentIndex); + } + QRemoteObjectPendingCallWatcher *watcher; + auto call = replicaCacheRequest(m_rootItem.children.cacheSize, m_initialFetchRolesHint); + watcher = new QRemoteObjectPendingCallWatcher(call); + m_pendingRequests.push_back(watcher); + connect(watcher, &QRemoteObjectPendingCallWatcher::finished, this, [this, watcher, indexes, hint]() { + Q_ASSERT(watcher->returnValue().canConvert()); + const QSize size = watcher->returnValue().value().size; + + q->layoutAboutToBeChanged(indexes, hint); + m_rootItem.clear(); + if (size.height() > 0) { + m_rootItem.rowCount = size.height(); + m_rootItem.hasChildren = true; + } + + m_rootItem.columnCount = size.width(); + if (m_initialAction == QtRemoteObjects::PrefetchData) { + auto entries = watcher->returnValue().value(); + for (int i = 0; i < entries.data.size(); ++i) + fillCache(entries.data[i], entries.roles); + } + m_pendingRequests.removeAll(watcher); + watcher->deleteLater(); + emit q->layoutChanged(indexes, hint); + }); +} + +static inline QList> listRanges(const QList &list) +{ + QList> result; + if (!list.isEmpty()) { + QPair currentElem = qMakePair(list.first(), list.first()); + const auto end = list.constEnd(); + for (auto it = list.constBegin() + 1; it != end; ++it) { + if (currentElem.first == *it + 1) + currentElem.first = *it; + else if ( currentElem.second == *it -1) + currentElem.second = *it; + else if (currentElem.first <= *it && currentElem.second >= *it) + continue; + else { + result.push_back(currentElem); + currentElem.first = *it; + currentElem.second = *it; + } + } + result.push_back(currentElem); + } + return result; +} + +void QAbstractItemModelReplicaImplementation::requestedHeaderData(QRemoteObjectPendingCallWatcher *qobject) +{ + HeaderWatcher *watcher = static_cast(qobject); + Q_ASSERT(watcher); + + QVariantList data = watcher->returnValue().value(); + Q_ASSERT(watcher->orientations.size() == data.size()); + Q_ASSERT(watcher->sections.size() == data.size()); + Q_ASSERT(watcher->roles.size() == data.size()); + QList horizontalSections; + QList verticalSections; + + for (int i = 0; i < data.size(); ++i) { + if (watcher->orientations[i] == Qt::Horizontal) + horizontalSections.append(watcher->sections[i]); + else + verticalSections.append(watcher->sections[i]); + const int index = watcher->orientations[i] == Qt::Horizontal ? 0 : 1; + const int role = watcher->roles[i]; + QHash &dat = m_headerData[index][watcher->sections[i]].data; + dat[role] = data[i]; + } + QList> horRanges = listRanges(horizontalSections); + QList> verRanges = listRanges(verticalSections); + + for (int i = 0; i < horRanges.size(); ++i) + emit q->headerDataChanged(Qt::Horizontal, horRanges[i].first, horRanges[i].second); + for (int i = 0; i < verRanges.size(); ++i) + emit q->headerDataChanged(Qt::Vertical, verRanges[i].first, verRanges[i].second); + m_pendingRequests.removeAll(watcher); + delete watcher; +} + +/*! + \class QAbstractItemModelReplica + \inmodule QtRemoteObjects + \brief The QAbstractItemModelReplica class serves as a convenience class for + Replicas of Sources based on QAbstractItemModel. + + QAbstractItemModelReplica makes replicating QAbstractItemModels more + efficient by employing caching and pre-fetching. + + \sa QAbstractItemModel +*/ + +/*! + \internal +*/ +QAbstractItemModelReplica::QAbstractItemModelReplica(QAbstractItemModelReplicaImplementation *rep, QtRemoteObjects::InitialAction action, const QList &rolesHint) + : QAbstractItemModel() + , d(rep) +{ + d->m_initialAction = action; + d->m_initialFetchRolesHint = rolesHint; + + rep->setModel(this); + connect(rep, &QAbstractItemModelReplicaImplementation::initialized, d.data(), &QAbstractItemModelReplicaImplementation::init); +} + +/*! + Destroys the instance of QAbstractItemModelReplica. +*/ +QAbstractItemModelReplica::~QAbstractItemModelReplica() +{ +} + +static QVariant findData(const CachedRowEntry &row, const QModelIndex &index, int role, bool *cached = nullptr) +{ + if (index.column() < row.size()) { + const CacheEntry &entry = row[index.column()]; + QHash::ConstIterator it = entry.data.constFind(role); + if (it != entry.data.constEnd()) { + if (cached) + *cached = true; + return it.value(); + } + } + if (cached) + *cached = false; + return QVariant(); +} + +/*! + Returns a pointer to the QItemSelectionModel for the current + QAbstractItemModelReplica. +*/ +QItemSelectionModel* QAbstractItemModelReplica::selectionModel() const +{ + return d->m_selectionModel.data(); +} + +/*! + \reimp +*/ +bool QAbstractItemModelReplica::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (role == Qt::UserRole - 1) { + auto parent = d->cacheData(index); + if (!parent) + return false; + bool ok = true; + auto row = value.toInt(&ok); + if (ok) + parent->ensureChildren(row, row); + return ok; + } + if (!index.isValid()) + return false; + if (index.row() < 0 || index.row() >= rowCount(index.parent())) + return false; + if (index.column() < 0 || index.column() >= columnCount(index.parent())) + return false; + + const QList &availRoles = availableRoles(); + const auto res = std::find(availRoles.begin(), availRoles.end(), role); + if (res == availRoles.end()) { + qCWarning(QT_REMOTEOBJECT_MODELS) << "Tried to setData for index" << index << "on a not supported role" << role; + return false; + } + // sendInvocationRequest to change server side data; + d->replicaSetData(QtPrivate::toModelIndexList(index, this), value, role); + return true; +} + +/*! + Returns the \a role data for the item at \a index if available in cache. + A default-constructed QVariant is returned if the index is invalid, the role + is not one of the available roles, the \l {Replica} is uninitialized or + the data was not available. + If the data was not available in cache it will be requested from the + \l {Source}. + + \sa QAbstractItemModel::data(), hasData(), setData(), isInitialized() +*/ +QVariant QAbstractItemModelReplica::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + QModelRoleData roleData(role); + multiData(index, roleData); + return roleData.data(); +} + +/*! + \reimp +*/ +void QAbstractItemModelReplica::multiData(const QModelIndex &index, + QModelRoleDataSpan roleDataSpan) const +{ + Q_ASSERT(checkIndex(index, CheckIndexOption::IndexIsValid)); + + if (!d->isInitialized()) { + qCDebug(QT_REMOTEOBJECT_MODELS)<<"Data not initialized yet"; + + for (auto &roleData : roleDataSpan) + roleData.clearData(); + return; + } + + QList rolesToFetch; + const auto roles = availableRoles(); + if (auto item = d->cacheData(index); item) { + // If the index is found in cache, try to find the data for each role + for (auto &roleData : roleDataSpan) { + const auto role = roleData.role(); + if (roles.contains(role)) { + bool cached = false; + QVariant result = findData(item->cachedRowEntry, index, role, &cached); + if (cached) { + roleData.setData(std::move(result)); + } else { + roleData.clearData(); + rolesToFetch.push_back(role); + } + } else { + roleData.clearData(); + } + } + } else { + // If the index is not found in cache, schedule all roles for fetching + for (auto &roleData : roleDataSpan) { + const auto role = roleData.role(); + if (roles.contains(role)) + rolesToFetch.push_back(role); + roleData.clearData(); + } + } + + if (rolesToFetch.empty()) + return; + + auto parentItem = d->cacheData(index.parent()); + Q_ASSERT(parentItem); + Q_ASSERT(index.row() < parentItem->rowCount); + const int row = index.row(); + QtPrivate::IndexList parentList = QtPrivate::toModelIndexList(index.parent(), this); + QtPrivate::IndexList start = QtPrivate::IndexList() << parentList << QtPrivate::ModelIndex(row, 0); + QtPrivate::IndexList end = QtPrivate::IndexList() << parentList << QtPrivate::ModelIndex(row, std::max(0, parentItem->columnCount - 1)); + Q_ASSERT(toQModelIndex(start, this).isValid()); + + RequestedData data; + data.start = start; + data.end = end; + data.roles = rolesToFetch; + d->m_requestedData.push_back(data); + qCDebug(QT_REMOTEOBJECT_MODELS) << "FETCH PENDING DATA" << start << end << rolesToFetch; + QMetaObject::invokeMethod(d.data(), "fetchPendingData", Qt::QueuedConnection); +} + +/*! + \reimp +*/ +QModelIndex QAbstractItemModelReplica::parent(const QModelIndex &index) const +{ + if (!index.isValid() || !index.internalPointer()) + return QModelIndex(); + auto parent = static_cast(index.internalPointer()); + Q_ASSERT(parent); + if (parent == &d->m_rootItem) + return QModelIndex(); + if (d->m_activeParents.find(parent) == d->m_activeParents.end() || d->m_activeParents.find(parent->parent) == d->m_activeParents.end()) + return QModelIndex(); + int row = parent->parent->children.find(parent); + Q_ASSERT(row >= 0); + return createIndex(row, 0, parent->parent); +} + +/*! + \reimp +*/ +QModelIndex QAbstractItemModelReplica::index(int row, int column, const QModelIndex &parent) const +{ + auto parentItem = d->cacheData(parent); + if (!parentItem) + return QModelIndex(); + + Q_ASSERT_X((parent.isValid() && parentItem && parentItem != &d->m_rootItem) || (!parent.isValid() && parentItem == &d->m_rootItem), __FUNCTION__, qPrintable(QString(QLatin1String("isValid=%1 equals=%2")).arg(parent.isValid()).arg(parentItem == &d->m_rootItem))); + + // hmpf, following works around a Q_ASSERT-bug in QAbstractItemView::setModel which does just call + // d->model->index(0,0) without checking the range before-hand what triggers our assert in case the + // model is empty when view::setModel is called :-/ So, work around with the following; + if (row < 0 || row >= parentItem->rowCount) + return QModelIndex(); + + if (column < 0 || column >= parentItem->columnCount) + return QModelIndex(); + + if (parentItem != &d->m_rootItem) + parentItem->ensureChildren(row, row); + return createIndex(row, column, reinterpret_cast(parentItem)); +} + +/*! + \reimp +*/ +bool QAbstractItemModelReplica::hasChildren(const QModelIndex &parent) const +{ + auto parentItem = d->cacheData(parent); + if (parent.isValid() && parent.column() != 0) + return false; + else + return parentItem ? parentItem->hasChildren : false; +} + +/*! + \reimp +*/ +int QAbstractItemModelReplica::rowCount(const QModelIndex &parent) const +{ + auto parentItem = d->cacheData(parent); + const bool canHaveChildren = parentItem && parentItem->hasChildren && !parentItem->rowCount && parent.column() == 0; + if (canHaveChildren) { + QtPrivate::IndexList parentList = QtPrivate::toModelIndexList(parent, this); + QRemoteObjectPendingReply reply = d->replicaSizeRequest(parentList); + SizeWatcher *watcher = new SizeWatcher(parentList, reply); + connect(watcher, &SizeWatcher::finished, d.data(), &QAbstractItemModelReplicaImplementation::handleSizeDone); + } else if (parent.column() > 0) { + return 0; + } + + return parentItem ? parentItem->rowCount : 0; +} + +/*! + \reimp +*/ +int QAbstractItemModelReplica::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid() && parent.column() > 0) + return 0; + auto parentItem = d->cacheData(parent); + if (!parentItem) + return 0; + while (parentItem->columnCount < 0 && parentItem->parent) + parentItem = parentItem->parent; + return std::max(0, parentItem->columnCount); +} + +/*! + Returns the data for the given \a role and \a section in the header with the + specified \a orientation. + + If the data is not available it will be requested from the \l {Source}. + + \sa QAbstractItemModel::headerData() +*/ +QVariant QAbstractItemModelReplica::headerData(int section, Qt::Orientation orientation, int role) const +{ + const int index = orientation == Qt::Horizontal ? 0 : 1; + const QList elem = d->m_headerData[index]; + if (section >= elem.size()) + return QVariant(); + + const QHash &dat = elem.at(section).data; + QHash::ConstIterator it = dat.constFind(role); + if (it != dat.constEnd()) + return it.value(); + + RequestedHeaderData data; + data.role = role; + data.section = section; + data.orientation = orientation; + d->m_requestedHeaderData.push_back(data); + QMetaObject::invokeMethod(d.data(), "fetchPendingHeaderData", Qt::QueuedConnection); + return QVariant(); +} + +/*! + \reimp +*/ +Qt::ItemFlags QAbstractItemModelReplica::flags(const QModelIndex &index) const +{ + CacheEntry *entry = d->cacheEntry(index); + return entry ? entry->flags : Qt::NoItemFlags; +} + +/*! + \fn void QAbstractItemModelReplica::initialized() + + The initialized signal is emitted the first time we receive data + from the \l {Source}. + + \sa isInitialized() +*/ + +/*! + Returns \c true if this replica has been initialized with data from the + \l {Source} object. Returns \c false otherwise. + + \sa initialized() +*/ +bool QAbstractItemModelReplica::isInitialized() const +{ + return d->isInitialized(); +} + +/*! + Returns \c true if there exists \a role data for the item at \a index. + Returns \c false in any other case. +*/ +bool QAbstractItemModelReplica::hasData(const QModelIndex &index, int role) const +{ + if (!d->isInitialized() || !index.isValid()) + return false; + auto item = d->cacheData(index); + if (!item) + return false; + bool cached = false; + const CachedRowEntry &entry = item->cachedRowEntry; + QVariant result = findData(entry, index, role, &cached); + Q_UNUSED(result) + return cached; +} + +/*! + Returns the current size of the internal cache. + By default this is set to the value of the \c QTRO_NODES_CACHE_SIZE + environment variable, or a default of \c 1000 if it is invalid or doesn't + exist. + + \sa setRootCacheSize() +*/ +size_t QAbstractItemModelReplica::rootCacheSize() const +{ + return d->m_rootItem.children.cacheSize; +} + +/*! + Sets the size of the internal cache to \a rootCacheSize. + + \sa rootCacheSize() +*/ +void QAbstractItemModelReplica::setRootCacheSize(size_t rootCacheSize) +{ + d->m_rootItem.children.setCacheSize(rootCacheSize); +} + +/*! + Returns a list of available roles. + + \sa QAbstractItemModel +*/ +QList QAbstractItemModelReplica::availableRoles() const +{ + return d->availableRoles(); +} + +/*! + \reimp +*/ +QHash QAbstractItemModelReplica::roleNames() const +{ + return d->roleNames(); +} + +QT_END_NAMESPACE diff --git a/src/remoteobjects/qremoteobjectabstractitemmodelreplica.h b/src/remoteobjects/qremoteobjectabstractitemmodelreplica.h new file mode 100644 index 0000000..a08464b --- /dev/null +++ b/src/remoteobjects/qremoteobjectabstractitemmodelreplica.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QREMOTEOBJECTS_ABSTRACTITEMMODELREPLICA_H +#define QREMOTEOBJECTS_ABSTRACTITEMMODELREPLICA_H + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QAbstractItemModelReplicaImplementation; + +class Q_REMOTEOBJECTS_EXPORT QAbstractItemModelReplica : public QAbstractItemModel +{ + Q_OBJECT +public: + ~QAbstractItemModelReplica() override; + + QItemSelectionModel* selectionModel() const; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const final; + void multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + QModelIndex parent(const QModelIndex & index) const override; + QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const override; + bool hasChildren(const QModelIndex & parent = QModelIndex()) const override; + int rowCount(const QModelIndex & parent = QModelIndex()) const override; + int columnCount(const QModelIndex & parent = QModelIndex()) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + QList availableRoles() const; + QHash roleNames() const override; + + bool isInitialized() const; + bool hasData(const QModelIndex &index, int role) const; + + size_t rootCacheSize() const; + void setRootCacheSize(size_t rootCacheSize); + +Q_SIGNALS: + void initialized(); + +private: + explicit QAbstractItemModelReplica(QAbstractItemModelReplicaImplementation *rep, QtRemoteObjects::InitialAction action, const QList &rolesHint); + QScopedPointer d; + friend class QAbstractItemModelReplicaImplementation; + friend class QRemoteObjectNode; +}; + +QT_END_NAMESPACE + +#endif // QREMOTEOBJECTS_ABSTRACTITEMMODELREPLICA_H diff --git a/src/remoteobjects/qremoteobjectabstractitemmodelreplica_p.h b/src/remoteobjects/qremoteobjectabstractitemmodelreplica_p.h new file mode 100644 index 0000000..57f368a --- /dev/null +++ b/src/remoteobjects/qremoteobjectabstractitemmodelreplica_p.h @@ -0,0 +1,476 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QREMOTEOBJECTS_ABSTRACT_ITEM_REPLICA_P_H +#define QREMOTEOBJECTS_ABSTRACT_ITEM_REPLICA_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qremoteobjectabstractitemmodeltypes_p.h" +#include "qremoteobjectabstractitemmodelreplica.h" +#include "qremoteobjectreplica.h" +#include "qremoteobjectpendingcall.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace { + const int DefaultNodesCacheSize = 1000; +} + +struct CacheEntry +{ + QHash data; + Qt::ItemFlags flags; + + explicit CacheEntry() + : flags(Qt::NoItemFlags) + {} +}; + +using CachedRowEntry = QList; + +template +struct LRUCache +{ + typedef std::pair Pair; + std::list cachedItems; + typedef typename std::list::iterator CacheIterator; + std::unordered_map cachedItemsMap; + size_t cacheSize; + + explicit LRUCache() + { + bool ok; + cacheSize = qEnvironmentVariableIntValue("QTRO_NODES_CACHE_SIZE" , &ok); + if (!ok) + cacheSize = DefaultNodesCacheSize; + } + + ~LRUCache() + { + clear(); + } + + inline void cleanCache() + { + Q_ASSERT(cachedItems.size() == cachedItemsMap.size()); + + auto it = cachedItems.rbegin(); + while (cachedItemsMap.size() > cacheSize) { + // Do not trash elements with children + // Workaround QTreeView bugs which caches the children indexes for very long time + while (it->second->hasChildren && it != cachedItems.rend()) + ++it; + + if (it == cachedItems.rend()) + break; + + cachedItemsMap.erase(it->first); + delete it->second; + cachedItems.erase((++it).base()); + } + Q_ASSERT(cachedItems.size() == cachedItemsMap.size()); + } + + void setCacheSize(size_t rootCacheSize) + { + cacheSize = rootCacheSize; + cleanCache(); + cachedItemsMap.reserve(rootCacheSize); + } + + void changeKeys(Key key, Key delta) { + std::vector> changed; + auto it = cachedItemsMap.begin(); + while (it != cachedItemsMap.end()) { + if (it->first >= key) { + changed.emplace_back(it->first + delta, it->second); + it->second->first += delta; + it = cachedItemsMap.erase(it); + } else { + ++it; + } + } + for (auto pair : changed) + cachedItemsMap[pair.first] = pair.second; + } + + void insert(Key key, Value *value) + { + changeKeys(key, 1); + ensure(key, value); + Q_ASSERT(cachedItems.size() == cachedItemsMap.size()); + } + + void ensure(Key key, Value *value) + { + cachedItems.emplace_front(key, value); + cachedItemsMap[key] = cachedItems.begin(); + cleanCache(); + } + + void remove(Key key) + { + auto it = cachedItemsMap.find(key); + if (it != cachedItemsMap.end()) { + delete it->second->second; + cachedItems.erase(it->second); + cachedItemsMap.erase(it); + } + changeKeys(key, -1); + Q_ASSERT(cachedItems.size() == cachedItemsMap.size()); + } + + Value *get(Key key) + { + auto it = cachedItemsMap.find(key); + if (it == cachedItemsMap.end()) + return nullptr; + + // Move the accessed item to front + cachedItems.splice(cachedItems.begin(), cachedItems, it->second); + Q_ASSERT(it->second->first == key); + return it->second->second; + } + + Key find(Value *val) + { + for (auto it = cachedItemsMap.begin(); it != cachedItemsMap.end(); ++it) { + if (it->second->second == val) + return it->first; + } + Q_ASSERT_X(false, __FUNCTION__, "Value not found"); + return Key{}; + } + + bool exists(Value *val) + { + for (const auto &pair : cachedItems) + if (pair.second == val) + return true; + + return false; + } + + bool exists(Key key) + { + return cachedItemsMap.find(key) != cachedItemsMap.end(); + } + + size_t size() + { + return cachedItemsMap.size(); + } + + void clear() + { + for (const auto &pair : cachedItems) + delete pair.second; + cachedItems.clear(); + cachedItemsMap.clear(); + } +}; + +class QAbstractItemModelReplicaImplementation; +struct CacheData +{ + QAbstractItemModelReplicaImplementation *replicaModel; + CacheData *parent; + CachedRowEntry cachedRowEntry; + + bool hasChildren; + LRUCache children; + int columnCount; + int rowCount; + + explicit CacheData(QAbstractItemModelReplicaImplementation *model, CacheData *parentItem = nullptr); + + ~CacheData(); + + void ensureChildren(int start, int end) + { + for (int i = start; i <= end; ++i) + if (!children.exists(i)) + children.ensure(i, new CacheData(replicaModel, this)); + } + + void insertChildren(int start, int end) { + Q_ASSERT_X(start >= 0 && start <= end, __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 <= %2")).arg(start).arg(end))); + for (int i = start; i <= end; ++i) { + auto cacheData = new CacheData(replicaModel, this); + cacheData->columnCount = columnCount; + children.insert(i, cacheData); + ++rowCount; + } + if (rowCount) + hasChildren = true; + } + void removeChildren(int start, int end) { + Q_ASSERT_X(start >= 0 && start <= end && end < rowCount, __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 <= %2 < %3")).arg(start).arg(end).arg(rowCount))); + for (int i = end; i >= start; --i) { + children.remove(i); + --rowCount; + } + hasChildren = rowCount; + } + void clear() { + cachedRowEntry.clear(); + children.clear(); + hasChildren = false; + columnCount = 0; + rowCount = 0; + } +}; + +struct RequestedData +{ + QtPrivate::IndexList start; + QtPrivate::IndexList end; + QList roles; +}; + +struct RequestedHeaderData +{ + int role; + int section; + Qt::Orientation orientation; +}; + +class SizeWatcher : public QRemoteObjectPendingCallWatcher +{ + Q_OBJECT +public: + SizeWatcher(QtPrivate::IndexList _parentList, const QRemoteObjectPendingReply &reply) + : QRemoteObjectPendingCallWatcher(reply), + parentList(_parentList) {} + QtPrivate::IndexList parentList; +}; + +class RowWatcher : public QRemoteObjectPendingCallWatcher +{ + Q_OBJECT +public: + RowWatcher(QtPrivate::IndexList _start, QtPrivate::IndexList _end, QList _roles, const QRemoteObjectPendingReply &reply) + : QRemoteObjectPendingCallWatcher(reply), + start(_start), + end(_end), + roles(_roles) {} + QtPrivate::IndexList start, end; + QList roles; +}; + +class HeaderWatcher : public QRemoteObjectPendingCallWatcher +{ + Q_OBJECT +public: + HeaderWatcher(QList _orientations, QList _sections, QList _roles, const QRemoteObjectPendingReply &reply) + : QRemoteObjectPendingCallWatcher(reply), + orientations(_orientations), + sections(_sections), + roles(_roles) {} + QList orientations; + QList sections, roles; +}; + +class QAbstractItemModelReplicaImplementation : public QRemoteObjectReplica +{ + Q_OBJECT + //TODO Use an input name for the model on the Replica side + Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, "ServerModelAdapter") + Q_PROPERTY(QList availableRoles READ availableRoles NOTIFY availableRolesChanged) + Q_PROPERTY(QIntHash roleNames READ roleNames) +public: + QAbstractItemModelReplicaImplementation(); + QAbstractItemModelReplicaImplementation(QRemoteObjectNode *node, const QString &name); + ~QAbstractItemModelReplicaImplementation() override; + void initialize() override; + static void registerMetatypes(); + + inline const QList &availableRoles() const + { + if (m_availableRoles.isEmpty()) + m_availableRoles = propAsVariant(0).value>(); + return m_availableRoles; + } + + QHash roleNames() const + { + QIntHash roles = propAsVariant(1).value(); + return roles; + } + + void setModel(QAbstractItemModelReplica *model); + bool clearCache(const QtPrivate::IndexList &start, const QtPrivate::IndexList &end, const QList &roles); + +Q_SIGNALS: + void availableRolesChanged(); + void dataChanged(QtPrivate::IndexList topLeft, QtPrivate::IndexList bottomRight, QList roles); + void rowsInserted(QtPrivate::IndexList parent, int first, int last); + void rowsRemoved(QtPrivate::IndexList parent, int first, int last); + void rowsMoved(QtPrivate::IndexList parent, int start, int end, QtPrivate::IndexList destination, int row); + void currentChanged(QtPrivate::IndexList current, QtPrivate::IndexList previous); + void modelReset(); + void headerDataChanged(Qt::Orientation,int,int); + void columnsInserted(QtPrivate::IndexList parent, int first, int last); + void layoutChanged(QtPrivate::IndexList parents, QAbstractItemModel::LayoutChangeHint hint); +public Q_SLOTS: + QRemoteObjectPendingReply replicaSizeRequest(QtPrivate::IndexList parentList) + { + static int __repc_index = QAbstractItemModelReplicaImplementation::staticMetaObject.indexOfSlot("replicaSizeRequest(QtPrivate::IndexList)"); + QVariantList __repc_args; + __repc_args << QVariant::fromValue(parentList); + return QRemoteObjectPendingReply(sendWithReply(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args)); + } + QRemoteObjectPendingReply replicaRowRequest(QtPrivate::IndexList start, QtPrivate::IndexList end, QList roles) + { + static int __repc_index = QAbstractItemModelReplicaImplementation::staticMetaObject.indexOfSlot("replicaRowRequest(QtPrivate::IndexList,QtPrivate::IndexList,QList)"); + QVariantList __repc_args; + __repc_args << QVariant::fromValue(start) << QVariant::fromValue(end) << QVariant::fromValue(roles); + return QRemoteObjectPendingReply(sendWithReply(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args)); + } + QRemoteObjectPendingReply replicaHeaderRequest(QList orientations, QList sections, QList roles) + { + static int __repc_index = QAbstractItemModelReplicaImplementation::staticMetaObject.indexOfSlot("replicaHeaderRequest(QList,QList,QList)"); + QVariantList __repc_args; + __repc_args << QVariant::fromValue(orientations) << QVariant::fromValue(sections) << QVariant::fromValue(roles); + return QRemoteObjectPendingReply(sendWithReply(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args)); + } + void replicaSetCurrentIndex(QtPrivate::IndexList index, QItemSelectionModel::SelectionFlags command) + { + static int __repc_index = QAbstractItemModelReplicaImplementation::staticMetaObject.indexOfSlot("replicaSetCurrentIndex(QtPrivate::IndexList,QItemSelectionModel::SelectionFlags)"); + QVariantList __repc_args; + __repc_args << QVariant::fromValue(index) << QVariant::fromValue(command); + send(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args); + } + void replicaSetData(QtPrivate::IndexList index, const QVariant &value, int role) + { + static int __repc_index = QAbstractItemModelReplicaImplementation::staticMetaObject.indexOfSlot("replicaSetData(QtPrivate::IndexList,QVariant,int)"); + QVariantList __repc_args; + __repc_args << QVariant::fromValue(index) << QVariant::fromValue(value) << QVariant::fromValue(role); + send(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args); + } + QRemoteObjectPendingReply replicaCacheRequest(size_t size, QList roles) + { + static int __repc_index = QAbstractItemModelReplicaImplementation::staticMetaObject.indexOfSlot("replicaCacheRequest(size_t,QList)"); + QVariantList __repc_args; + __repc_args << QVariant::fromValue(size) << QVariant::fromValue(roles); + return QRemoteObjectPendingReply(sendWithReply(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args)); + } + void onHeaderDataChanged(Qt::Orientation orientation, int first, int last); + void onDataChanged(const QtPrivate::IndexList &start, const QtPrivate::IndexList &end, const QList &roles); + void onRowsInserted(const QtPrivate::IndexList &parent, int start, int end); + void onRowsRemoved(const QtPrivate::IndexList &parent, int start, int end); + void onColumnsInserted(const QtPrivate::IndexList &parent, int start, int end); + void onRowsMoved(QtPrivate::IndexList srcParent, int srcRow, int count, QtPrivate::IndexList destParent, int destRow); + void onCurrentChanged(QtPrivate::IndexList current, QtPrivate::IndexList previous); + void onModelReset(); + void requestedData(QRemoteObjectPendingCallWatcher *); + void requestedHeaderData(QRemoteObjectPendingCallWatcher *); + void init(); + void fetchPendingData(); + void fetchPendingHeaderData(); + void handleInitDone(QRemoteObjectPendingCallWatcher *watcher); + void handleModelResetDone(QRemoteObjectPendingCallWatcher *watcher); + void handleSizeDone(QRemoteObjectPendingCallWatcher *watcher); + void onReplicaCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous); + void fillCache(const QtPrivate::IndexValuePair &pair,const QList &roles); + void onLayoutChanged(const QtPrivate::IndexList &parents, QAbstractItemModel::LayoutChangeHint hint); +public: + QScopedPointer m_selectionModel; + QList m_headerData[2]; + + CacheData m_rootItem; + inline CacheData* cacheData(const QModelIndex &index) const { + if (!index.isValid()) + return const_cast(&m_rootItem); + if (index.internalPointer()) { + auto parent = static_cast(index.internalPointer()); + if (m_activeParents.find(parent) != m_activeParents.end()) + return parent->children.get(index.row()); + } + return nullptr; + } + inline CacheData* cacheData(const QtPrivate::IndexList &index) const { + return cacheData(toQModelIndex(index, q)); + } + inline CacheData* createCacheData(const QtPrivate::IndexList &index) const { + auto modelIndex = toQModelIndex(index, q); + cacheData(modelIndex.parent())->ensureChildren(modelIndex.row() , modelIndex.row()); + return cacheData(modelIndex); + } + inline CacheEntry* cacheEntry(const QModelIndex &index) const { + auto data = cacheData(index); + if (!data || index.column() < 0 || index.column() >= data->cachedRowEntry.size()) + return nullptr; + CacheEntry &entry = data->cachedRowEntry[index.column()]; + return &entry; + } + inline CacheEntry* cacheEntry(const QtPrivate::IndexList &index) const { + return cacheEntry(toQModelIndex(index, q)); + } + + QRemoteObjectPendingCallWatcher *doModelReset(); + void initializeModelConnections(); + + bool m_initDone = false; + QList m_requestedData; + QList m_requestedHeaderData; + QList m_pendingRequests; + QAbstractItemModelReplica *q; + mutable QList m_availableRoles; + std::unordered_set m_activeParents; + QtRemoteObjects::InitialAction m_initialAction; + QList m_initialFetchRolesHint; +}; + +QT_END_NAMESPACE + +#endif // QREMOTEOBJECTS_ABSTRACT_ITEM_REPLICA_P_H diff --git a/src/remoteobjects/qremoteobjectabstractitemmodeltypes_p.h b/src/remoteobjects/qremoteobjectabstractitemmodeltypes_p.h new file mode 100644 index 0000000..f6905c0 --- /dev/null +++ b/src/remoteobjects/qremoteobjectabstractitemmodeltypes_p.h @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QREMOTEOBJECTS_ABSTRACT_ITEM_MODEL_TYPES_P_H +#define QREMOTEOBJECTS_ABSTRACT_ITEM_MODEL_TYPES_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QtPrivate { + +struct ModelIndex +{ + ModelIndex() : row(-1), column(-1) {} + ModelIndex(int row_, int column_) + : row(row_) + , column(column_) + {} + + inline bool operator==(const ModelIndex &other) const { return row == other.row && column == other.column; } + inline bool operator!=(const ModelIndex &other) const { return !(*this == other); } + int row; + int column; +}; + +typedef QList IndexList; + +struct IndexValuePair +{ + explicit IndexValuePair(const IndexList index_ = IndexList(), const QVariantList &data_ = QVariantList(), + bool hasChildren_ = false, const Qt::ItemFlags &flags_ = Qt::ItemFlags(), const QSize &size_ = {}) + : index(index_) + , data(data_) + , flags(flags_) + , hasChildren(hasChildren_) + , size(size_) + {} + + inline bool operator==(const IndexValuePair &other) const { return index == other.index && data == other.data && hasChildren == other.hasChildren && flags == other.flags; } + inline bool operator!=(const IndexValuePair &other) const { return !(*this == other); } + + IndexList index; + QVariantList data; + Qt::ItemFlags flags; + bool hasChildren; + QList children; + QSize size; +}; + +struct DataEntries +{ + inline bool operator==(const DataEntries &other) const { return data == other.data; } + inline bool operator!=(const DataEntries &other) const { return !(*this == other); } + + QList data; +}; + +struct MetaAndDataEntries : DataEntries +{ + QList roles; + QSize size; +}; + +inline QDebug operator<<(QDebug stream, const ModelIndex &index) +{ + return stream.nospace() << "ModelIndex[row=" << index.row << ", column=" << index.column << "]"; +} + +inline QDataStream& operator<<(QDataStream &stream, const ModelIndex &index) +{ + return stream << index.row << index.column; +} + +inline QDataStream& operator>>(QDataStream &stream, ModelIndex &index) +{ + return stream >> index.row >> index.column; +} + +inline QDataStream& operator<<(QDataStream &stream, Qt::Orientation orient) +{ + return stream << static_cast(orient); +} + +inline QDataStream& operator>>(QDataStream &stream, Qt::Orientation &orient) +{ + int val; + QDataStream &ret = stream >> val; + orient = static_cast(val); + return ret; +} + +inline QDataStream& operator<<(QDataStream &stream, QItemSelectionModel::SelectionFlags command) +{ + return stream << static_cast(command); +} + +inline QDataStream& operator>>(QDataStream &stream, QItemSelectionModel::SelectionFlags &command) +{ + int val; + QDataStream &ret = stream >> val; + command = static_cast(val); + return ret; +} + +inline QDebug operator<<(QDebug stream, const IndexValuePair &pair) +{ + return stream.nospace() << "IndexValuePair[index=" << pair.index << ", data=" << pair.data << ", hasChildren=" << pair.hasChildren << ", flags=" << pair.flags << "]"; +} + +inline QDataStream& operator<<(QDataStream &stream, const IndexValuePair &pair) +{ + return stream << pair.index << pair.data << pair.hasChildren << static_cast(pair.flags) << pair.children << pair.size; +} + +inline QDataStream& operator>>(QDataStream &stream, IndexValuePair &pair) +{ + int flags; + QDataStream &ret = stream >> pair.index >> pair.data >> pair.hasChildren >> flags >> pair.children >> pair.size; + pair.flags = static_cast(flags); + return ret; +} + +inline QDebug operator<<(QDebug stream, const DataEntries &entries) +{ + return stream.nospace() << "DataEntries[" << entries.data << "]"; +} + +inline QDataStream& operator<<(QDataStream &stream, const DataEntries &entries) +{ + return stream << entries.data; +} + +inline QDataStream& operator>>(QDataStream &stream, DataEntries &entries) +{ + return stream >> entries.data; +} + +inline QDataStream& operator<<(QDataStream &stream, const MetaAndDataEntries &entries) +{ + return stream << entries.data << entries.roles << entries.size; +} + +inline QDataStream& operator>>(QDataStream &stream, MetaAndDataEntries &entries) +{ + return stream >> entries.data >> entries.roles >> entries.size; +} + +inline QString modelIndexToString(const IndexList &list) +{ + QString s; + QDebug(&s) << list; + return s; +} + +inline QString modelIndexToString(const ModelIndex &index) +{ + QString s; + QDebug(&s) << index; + return s; +} + +inline QModelIndex toQModelIndex(const IndexList &list, const QAbstractItemModel *model, bool *ok = nullptr, bool ensureItem = false) +{ + if (ok) + *ok = true; + QModelIndex result; + for (int i = 0; i < list.count(); ++i) { + const ModelIndex &index = list[i]; + if (ensureItem) + const_cast(model)->setData(result, index.row, Qt::UserRole - 1); + + result = model->index(index.row, index.column, result); + if (!result.isValid()) { + if (ok) { + *ok = false; + } else { + qFatal("Internal error: invalid index=%s in indexList=%s", + qPrintable(modelIndexToString(list[i])), qPrintable(modelIndexToString(list))); + } + return QModelIndex(); + } + } + return result; +} + +inline IndexList toModelIndexList(const QModelIndex &index, const QAbstractItemModel *model) +{ + IndexList list; + if (index.isValid()) { + list << ModelIndex(index.row(), index.column()); + for (QModelIndex curIndex = model->parent(index); curIndex.isValid(); curIndex = model->parent(curIndex)) + list.prepend(ModelIndex(curIndex.row(), curIndex.column())); + } + return list; +} + +} // namespace QtPrivate + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QtPrivate::ModelIndex) +Q_DECLARE_METATYPE(QtPrivate::IndexList) +Q_DECLARE_METATYPE(QtPrivate::DataEntries) +Q_DECLARE_METATYPE(QtPrivate::MetaAndDataEntries) +Q_DECLARE_METATYPE(QtPrivate::IndexValuePair) +Q_DECLARE_METATYPE(Qt::Orientation) +Q_DECLARE_METATYPE(QItemSelectionModel::SelectionFlags) + +#endif // QREMOTEOBJECTS_ABSTRACT_ITEM_MODEL_TYPES_P_H diff --git a/src/remoteobjects/qremoteobjectcontainers.cpp b/src/remoteobjects/qremoteobjectcontainers.cpp new file mode 100644 index 0000000..911cbba --- /dev/null +++ b/src/remoteobjects/qremoteobjectcontainers.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2021 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "qremoteobjectcontainers_p.h" +#include "qremoteobjectpacket_p.h" + +QT_BEGIN_NAMESPACE + +QDataStream &operator>>(QDataStream &ds, QtROSequentialContainer &p) +{ + QByteArray typeName; + quint32 count; + ds >> typeName; + p.setValueType(typeName); + ds >> count; + p.reserve(count); + QVariant value{p.m_valueType, nullptr}; + for (quint32 i = 0; i < count; i++) { + if (!p.m_valueType.load(ds, value.data())) { + qWarning("QSQ_: unable to load type '%s', returning an empty list.", p.m_valueTypeName.constData()); + p.clear(); + break; + } + p.append(value); + } + return ds; +} + +QDataStream &operator<<(QDataStream &ds, const QtROSequentialContainer &p) +{ + ds << p.m_valueTypeName; + auto pos = ds.device()->pos(); + quint32 count = p.count(); + ds << count; + for (quint32 i = 0; i < count; i++) { + if (!p.m_valueType.save(ds, p.at(i).data())) { + ds.device()->seek(pos); + ds.resetStatus(); + ds << quint32(0); + qWarning("QSQ_: unable to save type '%s'.", p.m_valueTypeName.constData()); + break; + } + } + return ds; +} + +const char *descopedName(QMetaType type) { + auto name = QByteArray::fromRawData(type.name(), qstrlen(type.name())); + int index = name.lastIndexOf(':'); // Returns -1 if not found + return type.name() + index + 1; +} + +QDataStream &operator>>(QDataStream &ds, QtROAssociativeContainer &p) +{ + QByteArray keyTypeName, valueTypeName; + quint32 count; + ds >> keyTypeName; + ds >> valueTypeName; + p.setTypes(keyTypeName, valueTypeName); + ds >> count; + p.m_keys.reserve(count); + auto transferType = p.m_keyType; + if (p.m_keyType.flags().testFlag(QMetaType::IsEnumeration)) + transferType = QRemoteObjectPackets::transferTypeForEnum(p.m_keyType); + QVariant key{transferType, nullptr}; + QVariant value{p.m_valueType, nullptr}; + for (quint32 i = 0; i < count; i++) { + if (!transferType.load(ds, key.data())) { + qWarning("QAS_: unable to load key '%s', returning an empty map.", p.m_keyTypeName.constData()); + p.clear(); + break; + } + if (!p.m_valueType.load(ds, value.data())) { + qWarning("QAS_: unable to load value '%s', returning an empty map.", p.m_valueTypeName.constData()); + p.clear(); + break; + } + if (transferType != p.m_keyType) { + bool isFlag = false; + QVariant enumKey(key); + enumKey.convert(p.m_keyType); + p.m_keys.append(enumKey); + if (auto meta = p.m_keyType.metaObject()) { + int index = meta->indexOfEnumerator(descopedName(p.m_keyType)); + isFlag = meta->enumerator(index).isFlag(); + } + // If multiple flag values are set, toString() returns an empty string + // Thus, for flags, we convert the integer value to a string + if (isFlag) + p.insert(key.toString(), value); + else + p.insert(enumKey.toString(), value); + } else { + p.insert(key.toString(), value); + p.m_keys.append(key); + } + } + return ds; +} + +QDataStream &operator<<(QDataStream &ds, const QtROAssociativeContainer &p) +{ + ds << p.m_keyTypeName; + ds << p.m_valueTypeName; + auto pos = ds.device()->pos(); + quint32 count = p.count(); + ds << count; + QAssociativeIterable map(&p); + QAssociativeIterable::const_iterator iter = map.begin(); + auto transferType = p.m_keyType; + if (p.m_keyType.flags().testFlag(QMetaType::IsEnumeration)) + transferType = QRemoteObjectPackets::transferTypeForEnum(p.m_keyType); + bool keySaved; + for (quint32 i = 0; i < count; i++) { + if (transferType != p.m_keyType) { + QVariant intKey(iter.key()); + intKey.convert(transferType); + keySaved = transferType.save(ds, intKey.data()); + } else { + keySaved = transferType.save(ds, iter.key().data()); + } + if (!keySaved) { + ds.device()->seek(pos); + ds.resetStatus(); + ds << quint32(0); + qWarning("QAS_: unable to save type '%s'.", p.m_valueTypeName.constData()); + break; + } + if (!p.m_valueType.save(ds, iter.value().data())) { + ds.device()->seek(pos); + ds.resetStatus(); + ds << quint32(0); + qWarning("QAS_: unable to save type '%s'.", p.m_valueTypeName.constData()); + break; + } + iter++; + } + return ds; +} + +QT_END_NAMESPACE diff --git a/src/remoteobjects/qremoteobjectcontainers_p.h b/src/remoteobjects/qremoteobjectcontainers_p.h new file mode 100644 index 0000000..2be67c8 --- /dev/null +++ b/src/remoteobjects/qremoteobjectcontainers_p.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2021 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QtROSequentialContainer : public QVariantList +{ +public: + QtROSequentialContainer() = default; + QtROSequentialContainer(const QSequentialIterable &lst) + { + m_valueType = lst.metaContainer().valueMetaType(); + reserve(lst.size()); + for (const auto v : lst) + append(v); + } + void setValueType(const QByteArray &valueTypeName) + { + m_valueTypeName = valueTypeName; + m_valueType = QMetaType::fromName(valueTypeName.constData()); + clear(); + } + + QMetaType m_valueType; + QByteArray m_typeName, m_valueTypeName; +}; + +QDataStream &operator>>(QDataStream &ds, QtROSequentialContainer &p); + +QDataStream &operator<<(QDataStream &ds, const QtROSequentialContainer &p); + +class QtROAssociativeContainer : public QVariantMap +{ +public: + QtROAssociativeContainer() = default; + QtROAssociativeContainer(const QAssociativeIterable &map) + { + m_keyType = map.metaContainer().keyMetaType(); + m_valueType = map.metaContainer().mappedMetaType(); + m_keys.reserve(map.size()); + QAssociativeIterable::const_iterator iter = map.begin(); + const QAssociativeIterable::const_iterator end = map.end(); + for ( ; iter != end; ++iter) { + m_keys.append(iter.key()); + insert(iter.key().toString(), iter.value()); + } + } + void setTypes(const QByteArray &keyTypeName, const QByteArray &valueTypeName) + { + m_keyTypeName = keyTypeName; + m_keyType = QMetaType::fromName(keyTypeName.constData()); + m_valueTypeName = valueTypeName; + m_valueType = QMetaType::fromName(valueTypeName.constData()); + clear(); + m_keys.clear(); + } + + QMetaType m_keyType, m_valueType; + QByteArray m_typeName, m_keyTypeName, m_valueTypeName; + QVariantList m_keys; // Map uses QString for key, this doesn't lose information for proxy +}; + +QDataStream &operator>>(QDataStream &ds, QtROAssociativeContainer &p); + +QDataStream &operator<<(QDataStream &ds, const QtROAssociativeContainer &p); + +QT_END_NAMESPACE diff --git a/src/remoteobjects/qremoteobjectdynamicreplica.cpp b/src/remoteobjects/qremoteobjectdynamicreplica.cpp new file mode 100644 index 0000000..bd39000 --- /dev/null +++ b/src/remoteobjects/qremoteobjectdynamicreplica.cpp @@ -0,0 +1,216 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qremoteobjectdynamicreplica.h" +#include "qremoteobjectreplica_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QRemoteObjectDynamicReplica + \inmodule QtRemoteObjects + \brief A dynamically instantiated \l {Replica}. + + There are generated replicas (replicas having the header files produced by + the \l {repc} {Replica Compiler}), and dynamic replicas, that are generated + on-the-fly. This is the class for the dynamic type of replica. + + When the connection to the \l {Source} object is made, the initialization + step passes the current property values (see \l {Replica Initialization}). + In a DynamicReplica, the property/signal/slot details are also sent, + allowing the replica object to be created on-the-fly. This can be convenient + in QML or scripting, but has two primary disadvantages. First, the object is + in effect "empty" until it is successfully initialized by the \l {Source}. + Second, in C++, calls must be made using QMetaObject::invokeMethod(), as the + moc generated lookup will not be available. + + This class does not have a public constructor. It can only be instantiated + by using the dynamic QRemoteObjectNode::acquire method. +*/ + +QRemoteObjectDynamicReplica::QRemoteObjectDynamicReplica() + : QRemoteObjectReplica() +{ +} + +QRemoteObjectDynamicReplica::QRemoteObjectDynamicReplica(QRemoteObjectNode *node, const QString &name) + : QRemoteObjectReplica(ConstructWithNode) +{ + initializeNode(node, name); +} + +/*! + Destroys the dynamic replica. + + \sa {Replica Ownership} +*/ +QRemoteObjectDynamicReplica::~QRemoteObjectDynamicReplica() +{ +} + +/*! + \internal + Returns a pointer to the dynamically generated meta-object of this object, or + QRemoteObjectDynamicReplica's metaObject if the object is not initialized. This + function overrides the QObject::metaObject() virtual function to provide the same + functionality for dynamic replicas. + + \sa QObject::metaObject(), {Replica Initialization} +*/ +const QMetaObject* QRemoteObjectDynamicReplica::metaObject() const +{ + auto impl = qSharedPointerCast(d_impl); + // Returning nullptr will likely result in a crash if this type is used before the + // definition is received. Note: QRemoteObjectDynamicReplica doesn't include the + // QObject macro, so it's metaobject would resolve to QRemoteObjectReplica::metaObject() + // if we weren't overriding it. + if (!impl->m_metaObject) { + qWarning() << "Dynamic metaobject is not assigned, returning generic Replica metaObject."; + qWarning() << "This may cause issues if used for more than checking the Replica state."; + return QRemoteObjectReplica::metaObject(); + } + + return impl->m_metaObject; +} + +/*! + \internal + This function overrides the QObject::qt_metacast() virtual function to provide the same functionality for dynamic replicas. + + \sa QObject::qt_metacast() +*/ +void *QRemoteObjectDynamicReplica::qt_metacast(const char *name) +{ + if (!name) + return nullptr; + + if (!strcmp(name, "QRemoteObjectDynamicReplica")) + return static_cast(const_cast(this)); + + // not entirely sure that one is needed... TODO: check + auto impl = qSharedPointerCast(d_impl); + if (QString::fromLatin1(name) == impl->m_objectName) + return static_cast(const_cast(this)); + + return QObject::qt_metacast(name); +} + +/*! + \internal + This function overrides the QObject::qt_metacall() virtual function to provide the same functionality for dynamic replicas. + + \sa QObject::qt_metacall() +*/ +int QRemoteObjectDynamicReplica::qt_metacall(QMetaObject::Call call, int id, void **argv) +{ + static const bool debugArgs = qEnvironmentVariableIsSet("QT_REMOTEOBJECT_DEBUG_ARGUMENTS"); + + auto impl = qSharedPointerCast(d_impl); + + int saved_id = id; + id = QRemoteObjectReplica::qt_metacall(call, id, argv); + if (id < 0 || impl->m_metaObject == nullptr) + return id; + + if (call == QMetaObject::ReadProperty || call == QMetaObject::WriteProperty) { + QMetaProperty mp = metaObject()->property(saved_id); + + if (call == QMetaObject::WriteProperty) { + QVariantList args; + if (mp.userType() == QMetaType::QVariant) + args << *reinterpret_cast(argv[0]); + else + args << QVariant(mp.metaType(), argv[0]); + QRemoteObjectReplica::send(QMetaObject::WriteProperty, saved_id, args); + } else { + if (mp.userType() == QMetaType::QVariant) + *reinterpret_cast(argv[0]) = impl->m_propertyStorage[id]; + else { + const QVariant value = propAsVariant(id); + mp.metaType().destruct(argv[0]); + mp.metaType().construct(argv[0], value.data()); + } + } + + id = -1; + } else if (call == QMetaObject::InvokeMetaMethod) { + if (id < impl->m_numSignals) { + qCDebug(QT_REMOTEOBJECT) << "DynamicReplica Activate" << impl->m_metaObject->method(saved_id).methodSignature(); + // signal relay from Source world to Replica + QMetaObject::activate(this, impl->m_metaObject, id, argv); + + } else { + // method relay from Replica to Source + const QMetaMethod mm = impl->m_metaObject->method(saved_id); + const int nParam = mm.parameterCount(); + QVariantList args; + args.reserve(nParam); + for (int i = 0; i < nParam; ++i) { + const auto metaType = mm.parameterMetaType(i); + if (metaType.flags().testFlag(QMetaType::IsEnumeration)) { + auto transferType = QRemoteObjectPackets::transferTypeForEnum(metaType); + args.push_back(QVariant(transferType, argv[i + 1])); + } else + args.push_back(QVariant(metaType, argv[i + 1])); + } + + if (debugArgs) { + qCDebug(QT_REMOTEOBJECT) << "method" << mm.methodSignature() << "invoked - args:" << args; + } else { + qCDebug(QT_REMOTEOBJECT) << "method" << mm.methodSignature() << "invoked"; + } + + if (mm.returnType() == QMetaType::Void) + QRemoteObjectReplica::send(QMetaObject::InvokeMetaMethod, saved_id, args); + else { + QRemoteObjectPendingCall call = QRemoteObjectReplica::sendWithReply(QMetaObject::InvokeMetaMethod, saved_id, args); + if (argv[0]) + *(static_cast(argv[0])) = call; + } + } + + id = -1; + } + + return id; +} + +QT_END_NAMESPACE diff --git a/src/remoteobjects/qremoteobjectdynamicreplica.h b/src/remoteobjects/qremoteobjectdynamicreplica.h new file mode 100644 index 0000000..f30d0d0 --- /dev/null +++ b/src/remoteobjects/qremoteobjectdynamicreplica.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDYNAMICREMOTEOBJECT_H +#define QDYNAMICREMOTEOBJECT_H + +#include + +QT_BEGIN_NAMESPACE + +class Q_REMOTEOBJECTS_EXPORT QRemoteObjectDynamicReplica : public QRemoteObjectReplica +{ +public: + ~QRemoteObjectDynamicReplica() override; + + const QMetaObject *metaObject() const override; + void *qt_metacast(const char *name) override; + int qt_metacall(QMetaObject::Call call, int id, void **argv) override; + +private: + explicit QRemoteObjectDynamicReplica(); + explicit QRemoteObjectDynamicReplica(QRemoteObjectNode *node, const QString &name); + friend class QRemoteObjectNodePrivate; + friend class QRemoteObjectNode; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/remoteobjects/qremoteobjectnode.cpp b/src/remoteobjects/qremoteobjectnode.cpp new file mode 100644 index 0000000..82d1def --- /dev/null +++ b/src/remoteobjects/qremoteobjectnode.cpp @@ -0,0 +1,2824 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtRemoteObjects module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qmetaobjectbuilder_p.h" + +#include "qremoteobjectcontainers_p.h" +#include "qremoteobjectnode.h" +#include "qremoteobjectnode_p.h" + +#include "qremoteobjectregistry.h" +#include "qremoteobjectdynamicreplica.h" +#include "qremoteobjectpacket_p.h" +#include "qremoteobjectregistrysource_p.h" +#include "qremoteobjectreplica_p.h" +#include "qremoteobjectsource_p.h" +#include "qremoteobjectabstractitemmodelreplica_p.h" +#include "qremoteobjectabstractitemmodeladapter_p.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace QtRemoteObjects; +using namespace QRemoteObjectStringLiterals; + +using GadgetType = QVariantList; + +struct ManagedGadgetTypeEntry +{ + GadgetType gadgetType; + QMetaType gadgetMetaType; + QList enumMetaTypes; + std::shared_ptr metaObject; + + void unregisterMetaTypes() + { + QMetaType::unregisterMetaType(gadgetMetaType); + for (auto enumMetaType : enumMetaTypes) + QMetaType::unregisterMetaType(enumMetaType); + } +}; + +static QMutex s_managedTypesMutex; +static QHash s_managedTypes; +static QHash> s_trackedConnections; + +static void GadgetsStaticMetacallFunction(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::ReadProperty) { + GadgetType *_t = reinterpret_cast(_o); + if (_id < _t->size()) { + const auto &prop = _t->at(_id); + prop.metaType().destruct(_a[0]); + prop.metaType().construct(_a[0], prop.constData()); + } + } else if (_c == QMetaObject::WriteProperty) { + GadgetType *_t = reinterpret_cast(_o); + if (_id < _t->size()) { + auto & prop = (*_t)[_id]; + prop = QVariant(prop.metaType(), _a[0]); + } + } +} + +static void GadgetTypedDestructor(const QtPrivate::QMetaTypeInterface *, void *ptr) +{ + reinterpret_cast(ptr)->~GadgetType(); +} + +static void GadgetTypedConstructor(const QtPrivate::QMetaTypeInterface *interface, void *where) +{ + GadgetType *gadget = new(where) GadgetType; + QMutexLocker lock(&s_managedTypesMutex); + auto it = s_managedTypes.find(interface->typeId); + if (it == s_managedTypes.end()) { + delete gadget; + gadget = nullptr; + return; + } + *gadget = it->gadgetType; +} + +static void GadgetTypedCopyConstructor(const QtPrivate::QMetaTypeInterface *, void *where, const void *copy) +{ + new(where) GadgetType(*reinterpret_cast(copy)); +} + +static void GadgetTypedMoveConstructor(const QtPrivate::QMetaTypeInterface *, void *where, void *copy) +{ + new(where) GadgetType(std::move(*reinterpret_cast(copy))); +} + +static bool GadgetEqualsFn(const QtPrivate::QMetaTypeInterface *, const void *a, const void *b) +{ + return *reinterpret_cast(a) == *reinterpret_cast(b); +} + +static void GadgetDebugStreamFn(const QtPrivate::QMetaTypeInterface *, QDebug &dbg, const void *a) +{ + const GadgetType *gadgetProperties = reinterpret_cast(a); + for (const auto &prop : *gadgetProperties) + dbg << prop; +} + +static void GadgetDataStreamOutFn(const QtPrivate::QMetaTypeInterface *, QDataStream &ds, const void *a) +{ + const GadgetType *gadgetProperties = reinterpret_cast(a); + for (const auto &prop : *gadgetProperties) + ds << prop; +} + +static void GadgetDataStreamInFn(const QtPrivate::QMetaTypeInterface *, QDataStream &ds, void *a) +{ + GadgetType *gadgetProperties = reinterpret_cast(a); + for (auto &prop : *gadgetProperties) + ds >> prop; +} + +// Like the Q_GADGET static methods above, we need constructor/destructor methods +// in order to use dynamically defined enums with QVariant or as signal/slot +// parameters (i.e., the queued connection mechanism, which QtRO leverages). +// +// We will need the enum methods to support different sizes when typed scope enum +// support is added, so might as well use that now. +template +static void EnumDestructor(const QtPrivate::QMetaTypeInterface *, void *ptr) +{ + static_cast(ptr)->~T(); +} + +template +static void EnumConstructor(const QtPrivate::QMetaTypeInterface *, void *where) +{ + new(where) T; +} + +template +static void EnumCopyConstructor(const QtPrivate::QMetaTypeInterface *, void *where, const void *copy) +{ + new(where) T(*static_cast(copy)); +} + +template +static void EnumMoveConstructor(const QtPrivate::QMetaTypeInterface *, void *where, void *copy) +{ + new(where) T(std::move(*static_cast(copy))); +} + +// Not used, but keeping these in case we end up with a need for save/load. +template +static void EnumSaveOperator(QDataStream & out, const void *data) +{ + const T value = *static_cast(data); + out << value; +} + +template +static void EnumLoadOperator(QDataStream &in, void *data) +{ + T value = *static_cast(data); + in >> value; +} + +template +static bool EnumEqualsFn(const QtPrivate::QMetaTypeInterface *, const void *a, const void *b) +{ + return *static_cast(a) == *static_cast(b); +} + +template +static bool EnumLessThanFn(const QtPrivate::QMetaTypeInterface *, const void *a, const void *b) +{ + return *static_cast(a) < *static_cast(b); +} + +template +static void EnumDebugStreamFn(const QtPrivate::QMetaTypeInterface *, QDebug &dbg, const void *a) +{ + dbg << *static_cast(a); +} + +template +static void EnumDataStreamOutFn(const QtPrivate::QMetaTypeInterface *, QDataStream &ds, const void *a) +{ + ds << *static_cast(a); +} + +template +static void EnumDataStreamInFn(const QtPrivate::QMetaTypeInterface *, QDataStream &ds, void *a) +{ + ds >> *static_cast(a); +} + +static QString name(const QMetaObject * const mobj) +{ + const int ind = mobj->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE); + return ind >= 0 ? QString::fromLatin1(mobj->classInfo(ind).value()) : QString(); +} + +QString QtRemoteObjects::getTypeNameAndMetaobjectFromClassInfo(const QMetaObject *& meta) { + QString typeName; + const int ind = meta->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE); + if (ind != -1) { //We have an object created from repc or at least with QCLASSINFO defined + typeName = QString::fromLatin1(meta->classInfo(ind).value()); + while (true) { + Q_ASSERT(meta->superClass());//This recurses to QObject, which doesn't have QCLASSINFO_REMOTEOBJECT_TYPE + //At the point superclass doesn't have the same QCLASSINFO_REMOTEOBJECT_TYPE, + //we have the metaobject we should work from + if (ind != meta->superClass()->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE)) + break; + meta = meta->superClass(); + } + } + return typeName; +} + +template +bool map_contains(const QMap &map, const Query &key, typename QMap::const_iterator &result) +{ + const typename QMap::const_iterator it = map.find(key); + if (it == map.end()) + return false; + result = it; + return true; +} + +/*! + \qmltype Node + \instantiates QRemoteObjectNode + \inqmlmodule QtRemoteObjects + \brief A node on a Qt Remote Objects network. + + The Node type provides an entry point to a Qt Remote Objects network. A network + can be as simple as two nodes, or an arbitrarily complex set of processes and devices. + + A Node does not have a url that other nodes can connect to, and thus is able to acquire + replicas only. It is not able to share source objects. + +*/ + +QRemoteObjectNodePrivate::QRemoteObjectNodePrivate() + : QObjectPrivate() + , registry(nullptr) + , retryInterval(250) + , lastError(QRemoteObjectNode::NoError) + , persistedStore(nullptr) +{ } + +QRemoteObjectNodePrivate::~QRemoteObjectNodePrivate() +{ +} + +QRemoteObjectSourceLocations QRemoteObjectNodePrivate::remoteObjectAddresses() const +{ + if (registry) + return registry->sourceLocations(); + return QRemoteObjectSourceLocations(); +} + +QRemoteObjectSourceLocations QRemoteObjectRegistryHostPrivate::remoteObjectAddresses() const +{ + if (registrySource) + return registrySource->sourceLocations(); + return QRemoteObjectSourceLocations(); +} + +/*! + \reimp +*/ +void QRemoteObjectNode::timerEvent(QTimerEvent*) +{ + Q_D(QRemoteObjectNode); + + for (auto it = d->pendingReconnect.begin(), end = d->pendingReconnect.end(); it != end; /*erasing*/) { + const auto &conn = *it; + if (conn->isOpen()) { + it = d->pendingReconnect.erase(it); + } else { + conn->connectToServer(); + ++it; + } + } + + if (d->pendingReconnect.isEmpty()) + d->reconnectTimer.stop(); + + qRODebug(this) << "timerEvent" << d->pendingReconnect.size(); +} + +/*! + \qmlproperty int Node::heartbeatInterval + + Heartbeat interval in ms. + + The heartbeat (only helpful for socket connections) will periodically send a + message to connected nodes to detect whether the connection was disrupted. + Qt Remote Objects will try to reconnect automatically if it detects a dropped + connection. This function can help with that detection since the client will + only detect that the server is unavailable when it tries to send data. + + A value of \c 0 (the default) will disable the heartbeat. +*/ + + +/*! + \property QRemoteObjectNode::heartbeatInterval + \brief Heartbeat interval in ms. + + The heartbeat (only helpful for socket connections) will periodically send a + message to connected nodes to detect whether the connection was disrupted. + Qt Remote Objects will try to reconnect automatically if it detects a dropped + connection. This function can help with that detection since the client will + only detect that the server is unavailable when it tries to send data. + + A value of \c 0 (the default) will disable the heartbeat. +*/ +int QRemoteObjectNode::heartbeatInterval() const +{ + Q_D(const QRemoteObjectNode); + return d->m_heartbeatInterval; +} + +void QRemoteObjectNode::setHeartbeatInterval(int interval) +{ + Q_D(QRemoteObjectNode); + if (d->m_heartbeatInterval == interval) + return; + d->m_heartbeatInterval = interval; + emit heartbeatIntervalChanged(interval); +} + +/*! + \since 5.12 + \typedef QRemoteObjectNode::RemoteObjectSchemaHandler + + Typedef for a std::function method that can take a QUrl input and is + responsible for creating the communications channel between this node and + the node hosting the desired \l Source. As some types of QIODevices (e.g., + QSslSocket) require additional steps before the device is ready for use, + the method is responsible for calling \l addClientSideConnection once the + connection is fully established. +*/ + +/*! + \since 5.12 + \brief Provide a custom method to handle externally provided schemas + + This method is tied to the \l Registry and \l {External Schemas}. By + registering a std::function handler for an external schema, the registered + method will be called when the registry is notified of a \l Source you've + acquired being available. Without this registration, QtRO would only be + able to handle the "built-in" schemas. + + The provided method, \a handler, will be called when the registry sees a \l + Source object on a new (not yet connected) Node with a {QUrl::schema()} of + \a schema. The \a handler, of type \l + QRemoteObjectNode::RemoteObjectSchemaHandler will get the \l QUrl of the + Node providing the \l Source as an input parameter, and is responsible for + establishing the communications channel (a \l QIODevice of some sort) and + calling \l addClientSideConnection with it. + + \sa RemoteObjectSchemaHandler +*/ +void QRemoteObjectNode::registerExternalSchema(const QString &schema, QRemoteObjectNode::RemoteObjectSchemaHandler handler) +{ + Q_D(QRemoteObjectNode); + d->schemaHandlers.insert(schema, handler); +} + +/*! + \since 5.11 + \brief Forward Remote Objects from another network + + The proxy functionality is useful when you want to share \l Source objects + over multiple networks. For instance, if you have an embedded target using + target-only connections (like local) and you want to make some of those + same objects available externally. + + As a concrete example, say you have a set of processes talking to each + other on your target hardware using a registry, with the \l Registry at + "local:registry" and separate processes using a node at "local:MyHost" that + holds \l Source objects. If you wanted to access these objects, but over + tcp, you could create a new proxyNode like so: + +\code + // myInternalHost is a node only visible on the device... + QRemoteObjectHost myInternalHost("local:MyHost"); + myInternalHost.enableRemoting(&someObject); + + // Regular host node, listening on port 12123, so visible to other + // devices + QRemoteObjectHost proxyNode("tcp://localhost:12123"); + + // Enable proxying objects from nodes on the local machine's internal + // QtRO bus + proxyNode.proxy("local:registry"); +\endcode + + And from another device you create another node: + +\code + // NB: localhost resolves to a different ip address than proxyNode + QRemoteObjectHost nodeOnRemoteDevice("tcp://localhost:23234"); + + // Connect to the target's proxyNode directly, or use a tcp registry... + nodeOnRemoteDevice.connectToNode("tcp://:12123"); + + // Because of the proxy, we can get the object over tcp/ip port 12123, + // even though we can't connect directly to "local:MyHost" + SomeObject *so = nodeOnRemoteDevice.acquire(); +\endcode + + This would (internally) create a node in proxyNode, which (again + internally/automatically) connects to the provided registry (given by the + \a registryUrl parameter, "local:registry" in this example). Whenever + local:registry emits the \l remoteObjectAdded signal, the + \c QRemoteObjectSourceLocation is passed to the \a filter given to the proxy + call. If this method returns true (the default filter simply returns true + without any filtering), the object is acquired() from the internal node and + enableRemoting() (once the replica is initialized) is called on proxyNode. + + If a \a hostUrl is provided (which is required to enable reverseProxy, but + not needed otherwise), the internal node will be a \l QRemoteObjectHost node + configured with the provided address. If no \a hostUrl is provided, the + internal node will be a QRemoteObjectNode (not HostNode). + + Returns \c true if the object is acquired from the internal node. + + \sa reverseProxy() +*/ +bool QRemoteObjectHostBase::proxy(const QUrl ®istryUrl, const QUrl &hostUrl, RemoteObjectNameFilter filter) +{ + Q_D(QRemoteObjectHostBase); + if (!registryUrl.isValid() || !QtROClientFactory::instance()->isValid(registryUrl)) { + qROWarning(this) << "Can't proxy to registryUrl (invalid url or schema)" << registryUrl; + return false; + } + + if (!hostUrl.isEmpty() && !QtROClientFactory::instance()->isValid(hostUrl)) { + qROWarning(this) << "Can't proxy using hostUrl (invalid schema)" << hostUrl; + return false; + } + + if (d->proxyInfo) { + qROWarning(this) << "Proxying from multiple objects is currently not supported."; + return false; + } + + QRemoteObjectNode *node; + if (hostUrl.isEmpty()) { + node = new QRemoteObjectNode(registryUrl); + } else { + node = new QRemoteObjectHost(hostUrl, registryUrl); + } + d->proxyInfo = new ProxyInfo(node, this, filter); + return true; +} + +/*! + \since 5.11 + \brief Forwards remote objects to another network. + + The reverseProxy() function allows the \l proxy() functionality to be + extended, in effect mirroring the proxy functionality in the "reverse" + direction. These are distinct, because node communication is not symmetric, + one side calls enableRemoting() with a \l Source object, the other side + calls acquire() to get a \l Replica. Using \l proxy() allows you to + "observe" objects on a target device remotely via acquire, but it does not + allow off-target \l Source objects to be acquired from the device's local:* + network. That is where \l reverseProxy() comes in. If a proxyNode is + created like so: + +\code + // myInternalHost is a node only visible on the device... + QRemoteObjectHost myInternalHost("local:MyHost", "local:registry"); + + // RegistryHost node, listening on port 12123, so visible to other + // devices. The node must be a RegistryHost, so the Sources on + // the "outside" network can be forwarded to the inner network. + QRemoteObjectRegistryHost proxyNode("tcp://0.0.0.0:12123"); + + // Enable proxying objects from nodes on the local machine's internal + // QtRO bus. Note the hostUrl parameter is now needed. + proxyNode.proxy("local:registry", "local:fromProxy"); + proxyNode.reverseProxy(); +\endcode + + And from another device you create another node: + +\code + // Listen on a local port, and connect to "proxyNode" as the registry. + // NB: localhost resolves to a different ip address than proxyNode + QRemoteObjectHost nodeOnRemoteDevice("tcp://localhost:23234", + "tcp://:12123"); + + // Because of the reverseProxy, we can expose objects on this device + // and they will make their way to proxyNode... + nodeOnRemoteDevice.enableRemoting(&otherObject); +\endcode + +\code + // Acquire() can now see the objects on other devices through proxyNode, + // due to the reverseProxy call. + OtherObject *oo = myInternalHost.acquire(); +\endcode + + While the \l proxy() functionality allows \l Source objects on another + network to be acquired(), reverseProxy() allows \l Source objects to be + "pushed" to an otherwise inaccessible network. + + \note proxy() needs to be called before \l reverseProxy(), and a + hostUrl needs to be provided to \l proxy for \l reverseProxy() to work. The + \l reverseProxy() method allows a separate \a filter to be applied. This + reverseProxy specific filter will receive notifications of new \l Source + objects on \c proxyNode and acquire them on the internal node if they pass the + \a filter. + + Returns \c true on success, \c false otherwise. + + \note Currently the reverse proxy functionality is supported only for + QRemoteObjectRegistryHost. Calling this method on a QRemoteObjectHost node + will always return \c false. + + \sa proxy() +*/ +bool QRemoteObjectHostBase::reverseProxy(QRemoteObjectHostBase::RemoteObjectNameFilter filter) +{ + Q_D(QRemoteObjectHostBase); + + if (!d->proxyInfo) { + qROWarning(this) << "proxy() needs to be called before setting up reverse proxy."; + return false; + } + + QRemoteObjectHost *host = qobject_cast(d->proxyInfo->proxyNode); + if (!host) { + qROWarning(this) << "proxy() needs called with host-url to enable reverse proxy."; + return false; + } + + return d->proxyInfo->setReverseProxy(filter); +} + +/*! + \internal The replica needs to have a default constructor to be able + to create a replica from QML. In order for it to be properly + constructed, there needs to be a way to associate the replica with a + node and start the replica initialization. Thus we need a public + method on node to facilitate that. That's initializeReplica. +*/ +void QRemoteObjectNode::initializeReplica(QRemoteObjectReplica *instance, const QString &name) +{ + Q_D(QRemoteObjectNode); + if (instance->inherits("QRemoteObjectDynamicReplica")) { + d->setReplicaImplementation(nullptr, instance, name); + } else { + const QMetaObject *meta = instance->metaObject(); + // This is a templated acquire, so we tell the Source we don't need + // them to send the class definition. Thus we need to store the + // metaObject for this class - if this is a nested class, the QObject + // could be a nullptr or updated from the source, + d->dynamicTypeManager.addFromMetaObject(meta); + d->setReplicaImplementation(meta, instance, name.isEmpty() ? ::name(meta) : name); + } +} + +void QRemoteObjectNodePrivate::setLastError(QRemoteObjectNode::ErrorCode errorCode) +{ + Q_Q(QRemoteObjectNode); + lastError = errorCode; + emit q->error(lastError); +} + +void QRemoteObjectNodePrivate::setReplicaImplementation(const QMetaObject *meta, QRemoteObjectReplica *instance, const QString &name) +{ + qROPrivDebug() << "Starting setReplicaImplementation for" << name; + openConnectionIfNeeded(name); + QMutexLocker locker(&mutex); + if (hasInstance(name)) { + qCDebug(QT_REMOTEOBJECT)<<"setReplicaImplementation - using existing instance"; + QSharedPointer rep = qSharedPointerCast(replicas.value(name).toStrongRef()); + Q_ASSERT(rep); + instance->d_impl = rep; + rep->configurePrivate(instance); + } else { + instance->d_impl.reset(handleNewAcquire(meta, instance, name)); + instance->initialize(); + replicas.insert(name, instance->d_impl.toWeakRef()); + qROPrivDebug() << "setReplicaImplementation - Created new instance" << name<registry; +} + +/*! + \class QRemoteObjectAbstractPersistedStore + \inmodule QtRemoteObjects + \brief A class which provides the methods for setting PROP values of a + replica to value they had the last time the replica was used. + + This can be used to provide a "reasonable" value to be displayed until the + connection to the source is established and current values are available. + + This class must be overridden to provide an implementation for saving (\l + QRemoteObjectAbstractPersistedStore::saveProperties) and restoring (\l + QRemoteObjectAbstractPersistedStore::restoreProperties) PROP values. The derived + type can then be set for a node, and any replica acquired from that node + will then automatically store PERSISTED properties when the replica + destructor is called, and retrieve the values when the replica is + instantiated. +*/ + +/*! + Constructs a QRemoteObjectAbstractPersistedStore with the given \a parent. + The default value of \a parent is \nullptr. +*/ +QRemoteObjectAbstractPersistedStore::QRemoteObjectAbstractPersistedStore(QObject *parent) + : QObject(parent) +{ +} + +QRemoteObjectAbstractPersistedStore::~QRemoteObjectAbstractPersistedStore() +{ +} + +/*! + \fn virtual void QRemoteObjectAbstractPersistedStore::saveProperties(const QString &repName, const QByteArray &repSig, const QVariantList &values) + + This method will be provided the replica class's \a repName, \a repSig and the list of + \a values that PERSISTED properties have when the replica destructor was + called. It is the responsibility of the inheriting class to store the + information in a manner consistent for \l + QRemoteObjectAbstractPersistedStore::restoreProperties to retrieve. + + \sa QRemoteObjectAbstractPersistedStore::restoreProperties +*/ + +/*! + \fn virtual QVariantList QRemoteObjectAbstractPersistedStore::restoreProperties(const QString &repName, const QByteArray &repSig) + + This method will be provided the replica class's \a repName and \a repSig when the + replica is being initialized. It is the responsibility of the inheriting + class to get the last values persisted by \l + QRemoteObjectAbstractPersistedStore::saveProperties and return them. An empty + QVariantList should be returned if no values are available. + + \sa QRemoteObjectAbstractPersistedStore::saveProperties +*/ + + +QRemoteObjectAbstractPersistedStore *QRemoteObjectNode::persistedStore() const +{ + Q_D(const QRemoteObjectNode); + return d->persistedStore; +} + +/*! + \qmlproperty QRemoteObjectAbstractPersistedStore Node::persistedStore + + Allows setting a \l QRemoteObjectAbstractPersistedStore instance for the node. + + Allows replica \l PROP members with the PERSISTED trait to save their current value when the + replica is deleted and restore a stored value the next time the replica is started. + + Requires a \l QRemoteObjectAbstractPersistedStore class implementation to control where and how + persistence is handled. A default QSettings-based implementation is provided by SettingsStore. +*/ + +/*! + \since 5.11 + \property QRemoteObjectNode::persistedStore + \brief Allows setting a \l QRemoteObjectAbstractPersistedStore instance for the node. + + Allows replica \l PROP members with the PERSISTED trait to save their current value when the + replica is deleted and restore a stored value the next time the replica is started. + + Requires a \l QRemoteObjectAbstractPersistedStore class implementation to control where and how + persistence is handled. +*/ +void QRemoteObjectNode::setPersistedStore(QRemoteObjectAbstractPersistedStore *persistedStore) +{ + Q_D(QRemoteObjectNode); + d->persistedStore = persistedStore; +} + +QRemoteObjectAbstractPersistedStore::QRemoteObjectAbstractPersistedStore(QRemoteObjectAbstractPersistedStorePrivate &dptr, QObject *parent) + : QObject(dptr, parent) +{ +} + +QRemoteObjectAbstractPersistedStorePrivate::QRemoteObjectAbstractPersistedStorePrivate() +{ +} + +QRemoteObjectAbstractPersistedStorePrivate::~QRemoteObjectAbstractPersistedStorePrivate() +{ +} + +QRemoteObjectMetaObjectManager::~QRemoteObjectMetaObjectManager() +{ + for (QMetaObject *mo : dynamicTypes) { + for (auto metaType : enumTypes[mo]) + QMetaType::unregisterMetaType(metaType); + enumTypes.remove(mo); + free(mo); //QMetaObjectBuilder uses malloc, not new + } +} + +const QMetaObject *QRemoteObjectMetaObjectManager::metaObjectForType(const QString &type) +{ + qCDebug(QT_REMOTEOBJECT) << "metaObjectForType: looking for" << type << "static keys:" << staticTypes.keys() << "dynamic keys:" << dynamicTypes.keys(); + Q_ASSERT(staticTypes.contains(type) || dynamicTypes.contains(type)); + auto it = staticTypes.constFind(type); + if (it != staticTypes.constEnd()) + return it.value(); + return dynamicTypes.value(type); +} + +static void trackConnection(int typeId, QtROIoDeviceBase *connection) +{ + QMutexLocker lock(&s_managedTypesMutex); + if (s_trackedConnections[typeId].contains(connection)) + return; + s_trackedConnections[typeId].insert(connection); + auto unregisterIfNotUsed = [typeId, connection]{ + QMutexLocker lock(&s_managedTypesMutex); + Q_ASSERT(s_trackedConnections.contains(typeId)); + Q_ASSERT(s_trackedConnections[typeId].contains(connection)); + s_trackedConnections[typeId].remove(connection); + if (s_trackedConnections[typeId].isEmpty()) { + s_trackedConnections.remove(typeId); + s_managedTypes[typeId].unregisterMetaTypes(); + s_managedTypes.remove(typeId); // Destroys the meta types + } + }; + + // Unregister the type only when the connection is destroyed + // Do not unregister types when the connections is discconected, because + // if it gets reconnected it will not register the types again + QObject::connect(connection, &QtROIoDeviceBase::destroyed, unregisterIfNotUsed); +} + +struct EnumPair { + QByteArray name; + int value; +}; + +struct EnumData { + QByteArray name; + bool isFlag, isScoped; + quint32 keyCount, size; + QList values; +}; + +struct GadgetProperty { + QByteArray name; + QByteArray type; +}; + +struct GadgetData { + QList properties; + QList enums; +}; + +static const char *strDup(const QByteArray &s) +{ + auto result = new char[uint(s.size()) + 1]; + auto end = std::copy(s.cbegin(), s.cend(), result); + *end = 0; + return result; +} + +using Gadgets = QHash; +struct TypeInfo : public QtPrivate::QMetaTypeInterface +{ + const QMetaObject *metaObject; +}; +static const QMetaObject *metaObjectFn(const QtPrivate::QMetaTypeInterface *self) +{ + return static_cast(self)->metaObject; +} + +template +static TypeInfo *enumMetaType(const QByteArray &name, uint size, const QMetaObject *meta=nullptr) +{ + static const auto flags = QMetaType::IsEnumeration | QMetaType::NeedsConstruction + | QMetaType::NeedsDestruction; + + auto typeInfo = new TypeInfo { + { + 0, alignof(Int), size, uint(flags), 0, metaObjectFn, strDup(name), + EnumConstructor, + EnumCopyConstructor, + EnumMoveConstructor, + EnumDestructor, + EnumEqualsFn, + EnumLessThanFn, + EnumDebugStreamFn, + EnumDataStreamOutFn, + EnumDataStreamInFn, + nullptr + }, meta + }; + return typeInfo; +} + +static TypeInfo *registerEnum(const QByteArray &name, uint size=4u) +{ + TypeInfo *result = nullptr; + if (QMetaType::fromName(name).isValid()) + return result; + switch (size) { + case 1: + result = enumMetaType(name, size); + break; + case 2: + result = enumMetaType(name, size); + break; + case 4: + result = enumMetaType(name, size); + break; + // Qt currently only supports enum values of 4 or less bytes (QMetaEnum value(index) returns int) +// case 8: id = QMetaType::registerType(name.constData(), nullptr, nullptr, &EnumDestructor, +// &EnumConstructor, size, flags, meta); +// break; + default: + qWarning() << "Invalid enum detected" << name << "with size" << size << ". Defaulting to register as int."; + size = 4; + result = enumMetaType(name, size); + break; + } +#ifdef QTRO_VERBOSE_PROTOCOL + qDebug() << "Registering new enum" << name << "size:" << size; +#endif + return result; +} + +static int registerGadgets(QtROIoDeviceBase *connection, Gadgets &gadgets, QByteArray typeName) +{ + const auto &gadget = gadgets.take(typeName); + // TODO Look at having registerGadgets return QMetaType index of the id of the type + int typeId = QMetaType::fromName(typeName).id(); + if (typeId != QMetaType::UnknownType) { + trackConnection(typeId, connection); + return typeId; + } + + ManagedGadgetTypeEntry entry; + + QMetaObjectBuilder gadgetBuilder; + gadgetBuilder.setClassName(typeName); + gadgetBuilder.setFlags(DynamicMetaObject | PropertyAccessInStaticMetaCall); + for (const auto &prop : gadget.properties) { + int propertyType = QMetaType::fromName(prop.type).id(); + if (!propertyType && gadgets.contains(prop.type)) + propertyType = registerGadgets(connection, gadgets, prop.type); + entry.gadgetType.push_back(QVariant(QMetaType(propertyType))); + auto dynamicProperty = gadgetBuilder.addProperty(prop.name, prop.type); + dynamicProperty.setWritable(true); + dynamicProperty.setReadable(true); + } + QList enumsToBeAssignedMetaObject; + enumsToBeAssignedMetaObject.reserve(gadget.enums.length()); + for (const auto &enumData: gadget.enums) { + auto enumBuilder = gadgetBuilder.addEnumerator(enumData.name); + enumBuilder.setIsFlag(enumData.isFlag); + enumBuilder.setIsScoped(enumData.isScoped); + + for (quint32 k = 0; k < enumData.keyCount; ++k) { + const auto pair = enumData.values.at(k); + enumBuilder.addKey(pair.name, pair.value); + } + const QByteArray registeredName = QByteArray(typeName).append("::").append(enumData.name); + auto typeInfo = registerEnum(registeredName, enumData.size); + if (typeInfo) + enumsToBeAssignedMetaObject.append(typeInfo); + } + auto meta = gadgetBuilder.toMetaObject(); + entry.metaObject = std::shared_ptr{meta, [](QMetaObject *ptr){ ::free(ptr); }}; + for (auto typeInfo : enumsToBeAssignedMetaObject) { + typeInfo->metaObject = meta; + auto metaType = QMetaType(typeInfo); + entry.enumMetaTypes.append(metaType); + auto id = metaType.id(); + qCDebug(QT_REMOTEOBJECT) << "Registering new gadget enum with id" << id << typeInfo->name << "size:" << typeInfo->size; + } + + QMetaType::TypeFlags flags = QMetaType::IsGadget; + if (meta->propertyCount()) { + meta->d.static_metacall = &GadgetsStaticMetacallFunction; + meta->d.superdata = nullptr; + flags |= QMetaType::NeedsConstruction | QMetaType::NeedsDestruction; + auto typeInfo = new TypeInfo { + { + 0, alignof(GadgetType), sizeof(GadgetType), uint(flags), 0, metaObjectFn, + strDup(typeName), + GadgetTypedConstructor, + GadgetTypedCopyConstructor, + GadgetTypedMoveConstructor, + GadgetTypedDestructor, + GadgetEqualsFn, + nullptr, /* LessThanFn */ + GadgetDebugStreamFn, + GadgetDataStreamOutFn, + GadgetDataStreamInFn, + nullptr /* LegacyRegisterOp */ + }, + meta + }; + entry.gadgetMetaType = QMetaType(typeInfo); + } else { + auto typeInfo = new TypeInfo { + { + 0, alignof(GadgetType), sizeof(GadgetType), uint(flags), 0, metaObjectFn, + strDup(typeName), + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr + }, + meta + }; + entry.gadgetMetaType = QMetaType(typeInfo); + } + const int gadgetTypeId = entry.gadgetMetaType.id(); + trackConnection(gadgetTypeId, connection); + QMutexLocker lock(&s_managedTypesMutex); + s_managedTypes.insert(gadgetTypeId, entry); + return gadgetTypeId; +} + +static void registerAllGadgets(QtROIoDeviceBase *connection, Gadgets &gadgets) +{ + while (!gadgets.isEmpty()) + registerGadgets(connection, gadgets, gadgets.constBegin().key()); +} + +static void deserializeEnum(QDataStream &ds, EnumData &enumData) +{ + ds >> enumData.name; + ds >> enumData.isFlag; + ds >> enumData.isScoped; + ds >> enumData.size; + ds >> enumData.keyCount; + for (quint32 i = 0; i < enumData.keyCount; i++) { + EnumPair pair; + ds >> pair.name; + ds >> pair.value; + enumData.values.push_back(pair); + } +} + +static void parseGadgets(QtROIoDeviceBase *connection, QDataStream &in) +{ + quint32 qtEnums, numGadgets; + in >> qtEnums; // Qt enums - just need registration + for (quint32 i = 0; i < qtEnums; ++i) { + QByteArray enumName; + in >> enumName; + QMetaType type(enumMetaType(enumName, 4, &Qt::staticMetaObject)); + type.id(); + } + in >> numGadgets; + if (numGadgets == 0) + return; + Gadgets gadgets; + for (quint32 i = 0; i < numGadgets; ++i) { + QByteArray type; + in >> type; + quint32 numProperties, numEnums; + in >> numProperties; + auto &properties = gadgets[type].properties; + for (quint32 p = 0; p < numProperties; ++p) { + GadgetProperty prop; + in >> prop.name; + in >> prop.type; + properties.push_back(prop); + } + in >> numEnums; + auto &enums = gadgets[type].enums; + for (quint32 e = 0; e < numEnums; ++e) { + EnumData enumData; + deserializeEnum(in, enumData); + enums.push_back(enumData); + } + } + registerAllGadgets(connection, gadgets); +} + +QMetaObject *QRemoteObjectMetaObjectManager::addDynamicType(QtROIoDeviceBase *connection, QDataStream &in) +{ + QMetaObjectBuilder builder; + builder.setSuperClass(&QRemoteObjectReplica::staticMetaObject); + builder.setFlags(DynamicMetaObject); + + QString typeString; + QByteArray type; + quint32 numEnums = 0; + quint32 numSignals = 0; + quint32 numMethods = 0; + quint32 numProperties = 0; + QHash classEnums; + + in >> typeString; + type = typeString.toLatin1(); + builder.addClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE, type); + builder.setClassName(type); + + in >> numEnums; + QList enumSizes(numEnums); + enumsToBeAssignedMetaObject.reserve(numEnums); + for (quint32 i = 0; i < numEnums; ++i) { + EnumData enumData; + deserializeEnum(in, enumData); + auto enumBuilder = builder.addEnumerator(enumData.name); + enumBuilder.setIsFlag(enumData.isFlag); + enumBuilder.setIsScoped(enumData.isScoped); + enumSizes[i] = enumData.size; + + for (quint32 k = 0; k < enumData.keyCount; ++k) { + const auto pair = enumData.values.at(k); + enumBuilder.addKey(pair.name, pair.value); + } + const QByteArray registeredName = QByteArray(type).append("::").append(enumData.name); + classEnums[enumData.name] = registeredName; + auto typeInfo = registerEnum(registeredName, enumData.size); + if (typeInfo) { + enumsToBeAssignedMetaObject[typeInfo] = QMetaType(typeInfo); + int id = enumsToBeAssignedMetaObject[typeInfo].id(); + qCDebug(QT_REMOTEOBJECT) << "Registering new class enum with id" << id << typeInfo->name << "size:" << typeInfo->size; + } + } + parseGadgets(connection, in); + + int curIndex = 0; + + in >> numSignals; + for (quint32 i = 0; i < numSignals; ++i) { + QByteArray signature; + QByteArrayList paramNames; + in >> signature; + in >> paramNames; + ++curIndex; + auto mmb = builder.addSignal(signature); + mmb.setParameterNames(paramNames); + } + + in >> numMethods; + for (quint32 i = 0; i < numMethods; ++i) { + QByteArray signature, returnType; + QByteArrayList paramNames; + in >> signature; + in >> returnType; + in >> paramNames; + ++curIndex; + const bool isVoid = returnType.isEmpty() || returnType == QByteArrayLiteral("void"); + QMetaMethodBuilder mmb; + if (isVoid) + mmb = builder.addMethod(signature); + else + mmb = builder.addMethod(signature, QByteArrayLiteral("QRemoteObjectPendingCall")); + mmb.setParameterNames(paramNames); + } + + in >> numProperties; + + for (quint32 i = 0; i < numProperties; ++i) { + QByteArray name; + QByteArray typeName; + QByteArray signalName; + in >> name; + in >> typeName; + in >> signalName; + + auto choppedName = QByteArray::fromRawData(typeName.constData(), + typeName.size() - 1); // Remove trailing null + // The typeName for class enums is qualified with the class name. + // Need to remove the class name before checking if it's a class enum. + if (auto idx = choppedName.indexOf("::"); idx >= 0) { + choppedName = choppedName.sliced(idx + 2); + if (classEnums.contains(choppedName)) + typeName = classEnums[choppedName] + '\0'; // Update to the enum's registered name + } + + if (signalName.isEmpty()) + builder.addProperty(name, typeName); + else + builder.addProperty(name, typeName, builder.indexOfSignal(signalName)); + } + + auto meta = builder.toMetaObject(); + for (auto typeInfo : enumsToBeAssignedMetaObject.keys()) { + auto typeInfoWithMetaObject = static_cast(typeInfo); + typeInfoWithMetaObject->metaObject = meta; + enumTypes[meta].append(enumsToBeAssignedMetaObject.take(typeInfo)); + } + dynamicTypes.insert(typeString, meta); + return meta; +} + +void QRemoteObjectMetaObjectManager::addFromMetaObject(const QMetaObject *metaObject) +{ + QString className = QLatin1String(metaObject->className()); + if (!className.endsWith(QLatin1String("Replica"))) + return; + if (className == QLatin1String("QRemoteObjectDynamicReplica") || staticTypes.contains(className)) + return; + className.chop(7); //Remove 'Replica' from name + staticTypes.insert(className, metaObject); +} + +void QRemoteObjectNodePrivate::connectReplica(QObject *object, QRemoteObjectReplica *instance) +{ + int nConnections = 0; + const QMetaObject *us = instance->metaObject(); + const QMetaObject *them = object->metaObject(); + + static const int memberOffset = QRemoteObjectReplica::staticMetaObject.methodCount(); + for (int idx = memberOffset; idx < us->methodCount(); ++idx) { + const QMetaMethod mm = us->method(idx); + + qROPrivDebug() << idx << mm.name(); + if (mm.methodType() != QMetaMethod::Signal) + continue; + + // try to connect to a signal on the parent that has the same method signature + QByteArray sig = QMetaObject::normalizedSignature(mm.methodSignature().constData()); + qROPrivDebug() << sig; + if (them->indexOfSignal(sig.constData()) == -1) + continue; + + sig.prepend(QSIGNAL_CODE + '0'); + const char * const csig = sig.constData(); + const bool res = QObject::connect(object, csig, instance, csig); + Q_UNUSED(res) + ++nConnections; + + qROPrivDebug() << sig << res; + } + + qROPrivDebug() << "# connections =" << nConnections; +} + +void QRemoteObjectNodePrivate::openConnectionIfNeeded(const QString &name) +{ + qROPrivDebug() << Q_FUNC_INFO << name << this; + if (!remoteObjectAddresses().contains(name)) { + qROPrivDebug() << name << "not available - available addresses:" << remoteObjectAddresses(); + return; + } + + if (!initConnection(remoteObjectAddresses().value(name).hostUrl)) + qROPrivWarning() << "failed to open connection to" << name; +} + +bool QRemoteObjectNodePrivate::initConnection(const QUrl &address) +{ + Q_Q(QRemoteObjectNode); + if (requestedUrls.contains(address)) { + qROPrivDebug() << "Connection already requested for " << address.toString(); + return true; + } + + requestedUrls.insert(address); + + if (schemaHandlers.contains(address.scheme())) { + schemaHandlers[address.scheme()](address); + return true; + } + + QtROClientIoDevice *connection = QtROClientFactory::instance()->create(address, q); + if (!connection) { + qROPrivWarning() << "Could not create QtROClientIoDevice for client. Invalid url/scheme provided?" << address; + return false; + } + qROPrivDebug() << "Opening connection to" << address.toString(); + qROPrivDebug() << "Replica Connection isValid" << connection->isOpen(); + QObject::connect(connection, &QtROClientIoDevice::shouldReconnect, q, [this, connection]() { + onShouldReconnect(connection); + }); + QObject::connect(connection, &QtROIoDeviceBase::readyRead, q, [this, connection]() { + onClientRead(connection); + }); + connection->connectToServer(); + + return true; +} + +bool QRemoteObjectNodePrivate::hasInstance(const QString &name) +{ + if (!replicas.contains(name)) + return false; + + QSharedPointer rep = replicas.value(name).toStrongRef(); + if (!rep) { //already deleted + replicas.remove(name); + return false; + } + + return true; +} + +static QDebug operator<<(QDebug debug, + const QHash> &hash) +{ + const QDebugStateSaver saver(debug); + debug.nospace() << "QHash("; + for (auto it = hash.cbegin(); it != hash.cend(); ++it) + debug << '(' << it.key() << ", " << it.value().isNull() << ')'; + debug << ')'; + return debug; +} + +void QRemoteObjectNodePrivate::onRemoteObjectSourceAdded(const QRemoteObjectSourceLocation &entry) +{ + qROPrivDebug() << "onRemoteObjectSourceAdded" << entry << replicas << replicas.contains(entry.first); + if (!entry.first.isEmpty()) { + QRemoteObjectSourceLocations locs = registry->sourceLocations(); + locs[entry.first] = entry.second; + //TODO Is there a way to extend QRemoteObjectSourceLocations in place? + registry->d_impl->setProperty(0, QVariant::fromValue(locs)); + registry->notifySourceLocationsChanged(); + qROPrivDebug() << "onRemoteObjectSourceAdded, now locations =" << locs; + } + if (replicas.contains(entry.first)) //We have a replica waiting on this remoteObject + { + QSharedPointer rep = replicas.value(entry.first).toStrongRef(); + if (!rep) { //replica has been deleted, remove from list + replicas.remove(entry.first); + return; + } + + initConnection(entry.second.hostUrl); + + qROPrivDebug() << "Called initConnection due to new RemoteObjectSource added via registry" << entry.first; + } +} + +void QRemoteObjectNodePrivate::onRemoteObjectSourceRemoved(const QRemoteObjectSourceLocation &entry) +{ + if (!entry.first.isEmpty()) { + QRemoteObjectSourceLocations locs = registry->sourceLocations(); + locs.remove(entry.first); + registry->d_impl->setProperty(0, QVariant::fromValue(locs)); + registry->notifySourceLocationsChanged(); + } +} + +void QRemoteObjectNodePrivate::onRegistryInitialized() +{ + qROPrivDebug() << "Registry Initialized" << remoteObjectAddresses(); + + const auto remotes = remoteObjectAddresses(); + for (auto i = remotes.cbegin(), end = remotes.cend(); i != end; ++i) { + if (replicas.contains(i.key())) //We have a replica waiting on this remoteObject + { + QSharedPointer rep = replicas.value(i.key()).toStrongRef(); + if (rep && !requestedUrls.contains(i.value().hostUrl)) + initConnection(i.value().hostUrl); + else if (!rep) //replica has been deleted, remove from list + replicas.remove(i.key()); + + continue; + } + } +} + +void QRemoteObjectNodePrivate::onShouldReconnect(QtROClientIoDevice *ioDevice) +{ + Q_Q(QRemoteObjectNode); + + const auto remoteObjects = ioDevice->remoteObjects(); + for (const QString &remoteObject : remoteObjects) { + connectedSources.remove(remoteObject); + ioDevice->removeSource(remoteObject); + if (replicas.contains(remoteObject)) { //We have a replica waiting on this remoteObject + QSharedPointer rep = qSharedPointerCast(replicas.value(remoteObject).toStrongRef()); + if (rep && !rep->connectionToSource.isNull()) { + rep->setDisconnected(); + } else if (!rep) { + replicas.remove(remoteObject); + } + } + } + if (requestedUrls.contains(ioDevice->url())) { + // Only try to reconnect to URLs requested via connectToNode + // If we connected via registry, wait for the registry to see the node/source again + pendingReconnect.insert(ioDevice); + if (!reconnectTimer.isActive()) { + reconnectTimer.start(retryInterval, q); + qROPrivDebug() << "Starting reconnect timer"; + } + } else { + qROPrivDebug() << "Url" << ioDevice->url().toDisplayString().toLatin1() + << "lost. We will reconnect Replicas if they reappear on the Registry."; + } +} + +//This version of handleNewAcquire creates a QConnectedReplica. If this is a +//host node, the QRemoteObjectHostBasePrivate overload is called instead. +QReplicaImplementationInterface *QRemoteObjectNodePrivate::handleNewAcquire(const QMetaObject *meta, QRemoteObjectReplica *instance, const QString &name) +{ + Q_Q(QRemoteObjectNode); + QConnectedReplicaImplementation *rp = new QConnectedReplicaImplementation(name, meta, q); + rp->configurePrivate(instance); + if (connectedSources.contains(name)) { //Either we have a peer connections, or existing connection via registry + handleReplicaConnection(connectedSources[name].objectSignature, rp, connectedSources[name].device); + } else { + //No existing connection, but we know we can connect via registry + const auto &sourceLocations = remoteObjectAddresses(); + const auto it = sourceLocations.constFind(name); + // This will try the connection, and if successful, the remoteObjects will be sent + // The link to the replica will be handled then + if (it != sourceLocations.constEnd()) + initConnection(it.value().hostUrl); + } + return rp; +} + +void QRemoteObjectNodePrivate::handleReplicaConnection(const QString &name) +{ + QSharedPointer rep = qSharedPointerCast(replicas.value(name).toStrongRef()); + if (!rep) { //replica has been deleted, remove from list + replicas.remove(name); + return; + } + + if (rep->isShortCircuit()) + return; + + QConnectedReplicaImplementation *connectedRep = static_cast(rep.data()); + if (connectedRep->connectionToSource.isNull()) { + const auto sourceInfo = connectedSources.value(name); + handleReplicaConnection(sourceInfo.objectSignature, connectedRep, sourceInfo.device); + } +} + +void QRemoteObjectNodePrivate::handleReplicaConnection(const QByteArray &sourceSignature, QConnectedReplicaImplementation *rep, QtROIoDeviceBase *connection) +{ + if (!checkSignatures(rep->m_objectSignature, sourceSignature)) { + qROPrivWarning() << "Signature mismatch for" << rep->m_metaObject->className() << (rep->m_objectName.isEmpty() ? QLatin1String("(unnamed)") : rep->m_objectName); + rep->setState(QRemoteObjectReplica::SignatureMismatch); + return; + } + rep->setConnection(connection); +} + +//Host Nodes can use the more efficient InProcess Replica if we (this Node) hold the Source for the +//requested Replica. If not, fall back to the Connected Replica case. +QReplicaImplementationInterface *QRemoteObjectHostBasePrivate::handleNewAcquire(const QMetaObject *meta, QRemoteObjectReplica *instance, const QString &name) +{ + QMap::const_iterator mapIt; + if (remoteObjectIo && map_contains(remoteObjectIo->m_sourceObjects, name, mapIt)) { + Q_Q(QRemoteObjectHostBase); + QInProcessReplicaImplementation *rp = new QInProcessReplicaImplementation(name, meta, q); + rp->configurePrivate(instance); + connectReplica(mapIt.value()->m_object, instance); + rp->connectionToSource = mapIt.value(); + return rp; + } + return QRemoteObjectNodePrivate::handleNewAcquire(meta, instance, name); +} + +void QRemoteObjectNodePrivate::onClientRead(QObject *obj) +{ + using namespace QRemoteObjectPackets; + QtROIoDeviceBase *connection = qobject_cast(obj); + QRemoteObjectPacketTypeEnum packetType; + Q_ASSERT(connection); + auto &codec = connection->d_func()->m_codec; + + do { + if (!connection->read(packetType, rxName)) + return; + + if (packetType != Handshake && codec == nullptr) { + qROPrivWarning() << "Expected Handshake, got " << packetType; + setLastError(QRemoteObjectNode::ProtocolMismatch); + connection->close(); + break; + } + + switch (packetType) { + case QRemoteObjectPacketTypeEnum::Pong: + { + QSharedPointer rep = qSharedPointerCast(replicas.value(rxName).toStrongRef()); + if (rep) + rep->notifyAboutReply(0, {}); + else //replica has been deleted, remove from list + replicas.remove(rxName); + break; + } + case QRemoteObjectPacketTypeEnum::Handshake: + if (rxName != QtRemoteObjects::protocolVersion) { + qWarning() << "*** Protocol Mismatch, closing connection ***. Got" << rxName << "expected" << QtRemoteObjects::protocolVersion; + setLastError(QRemoteObjectNode::ProtocolMismatch); + connection->close(); + } else { + // TODO should have some sort of manager for the codec + codec = new QRemoteObjectPackets::QDataStreamCodec; + } + break; + case QRemoteObjectPacketTypeEnum::ObjectList: + { + codec->deserializeObjectListPacket(connection->d_func()->stream(), rxObjects); + qROPrivDebug() << "newObjects:" << rxObjects; + // We need to make sure all of the source objects are in connectedSources before we add connections, + // otherwise nested QObjects could fail (we want to acquire children before parents, and the object + // list is unordered) + for (const auto &remoteObject : qAsConst(rxObjects)) { + qROPrivDebug() << " connectedSources.contains(" << remoteObject << ")" << connectedSources.contains(remoteObject.name) << replicas.contains(remoteObject.name); + if (!connectedSources.contains(remoteObject.name)) { + connectedSources[remoteObject.name] = SourceInfo{connection, remoteObject.typeName, remoteObject.signature}; + connection->addSource(remoteObject.name); + // Make sure we handle Registry first if it is available + if (remoteObject.name == QLatin1String("Registry") && replicas.contains(remoteObject.name)) + handleReplicaConnection(remoteObject.name); + } + } + for (const auto &remoteObject : qAsConst(rxObjects)) { + if (replicas.contains(remoteObject.name)) //We have a replica waiting on this remoteObject + handleReplicaConnection(remoteObject.name); + } + break; + } + case QRemoteObjectPacketTypeEnum::InitPacket: + { + qROPrivDebug() << "InitPacket-->" << rxName << this; + QSharedPointer rep = qSharedPointerCast(replicas.value(rxName).toStrongRef()); + //Use m_rxArgs (a QVariantList to hold the properties QVariantList) + codec->deserializeInitPacket(connection->d_func()->stream(), rxArgs); + if (rep) + { + handlePointerToQObjectProperties(rep.data(), rxArgs); + rep->initialize(std::move(rxArgs)); + } else { //replica has been deleted, remove from list + replicas.remove(rxName); + } + break; + } + case QRemoteObjectPacketTypeEnum::InitDynamicPacket: + { + qROPrivDebug() << "InitDynamicPacket-->" << rxName << this; + const QMetaObject *meta = dynamicTypeManager.addDynamicType(connection, connection->d_func()->stream()); + codec->deserializeInitPacket(connection->d_func()->stream(), rxArgs); + QSharedPointer rep = qSharedPointerCast(replicas.value(rxName).toStrongRef()); + if (rep) + { + rep->setDynamicMetaObject(meta); + handlePointerToQObjectProperties(rep.data(), rxArgs); + rep->setDynamicProperties(std::move(rxArgs)); + } else { //replica has been deleted, remove from list + replicas.remove(rxName); + } + break; + } + case QRemoteObjectPacketTypeEnum::RemoveObject: + { + qROPrivDebug() << "RemoveObject-->" << rxName << this; + connectedSources.remove(rxName); + connection->removeSource(rxName); + if (replicas.contains(rxName)) { //We have a replica using the removed source + QSharedPointer rep = qSharedPointerCast(replicas.value(rxName).toStrongRef()); + if (rep && !rep->connectionToSource.isNull()) { + rep->connectionToSource.clear(); + rep->setState(QRemoteObjectReplica::Suspect); + } else if (!rep) { + replicas.remove(rxName); + } + } + break; + } + case QRemoteObjectPacketTypeEnum::PropertyChangePacket: + { + int propertyIndex; + codec->deserializePropertyChangePacket(connection->d_func()->stream(), propertyIndex, rxValue); + QSharedPointer rep = qSharedPointerCast(replicas.value(rxName).toStrongRef()); + if (rep) { + QConnectedReplicaImplementation *connectedRep = nullptr; + if (!rep->isShortCircuit()) { + connectedRep = static_cast(rep.data()); + if (!connectedRep->childIndices().contains(propertyIndex)) + connectedRep = nullptr; //connectedRep will be a valid pointer only if propertyIndex is a child index + } + if (connectedRep) + rep->setProperty(propertyIndex, handlePointerToQObjectProperty(connectedRep, propertyIndex, rxValue)); + else { + const QMetaProperty property = rep->m_metaObject->property(propertyIndex + rep->m_metaObject->propertyOffset()); + if (property.userType() == QMetaType::QVariant && rxValue.canConvert()) { + // This is a type that requires registration + QRO_ typeInfo = rxValue.value(); + QDataStream in(typeInfo.classDefinition); + parseGadgets(connection, in); + QDataStream ds(typeInfo.parameters); + ds >> rxValue; + } + rep->setProperty(propertyIndex, decodeVariant(std::move(rxValue), property.metaType())); + } + } else { //replica has been deleted, remove from list + replicas.remove(rxName); + } + break; + } + case QRemoteObjectPacketTypeEnum::InvokePacket: + { + int call, index, serialId, propertyIndex; + codec->deserializeInvokePacket(connection->d_func()->stream(), call, index, rxArgs, serialId, propertyIndex); + QSharedPointer rep = qSharedPointerCast(replicas.value(rxName).toStrongRef()); + if (rep) { + static QVariant null(QMetaType::fromType(), nullptr); + QVariant paramValue; + // Qt usually supports 9 arguments, so ten should be usually safe + QVarLengthArray param(rxArgs.size() + 1); + param[0] = null.data(); //Never a return value + if (rxArgs.size()) { + auto signal = rep->m_metaObject->method(index+rep->m_signalOffset); + for (int i = 0; i < rxArgs.size(); i++) { + if (signal.parameterType(i) == QMetaType::QVariant) + param[i + 1] = const_cast(reinterpret_cast(&rxArgs.at(i))); + else { + rxArgs[i] = decodeVariant(std::move(rxArgs[i]), signal.parameterMetaType(i)); + param[i + 1] = const_cast(rxArgs.at(i).data()); + } + } + } else if (propertyIndex != -1) { + param.resize(2); + paramValue = rep->getProperty(propertyIndex); + param[1] = paramValue.data(); + } + qROPrivDebug() << "Replica Invoke-->" << rxName << rep->m_metaObject->method(index+rep->m_signalOffset).name() << index << rep->m_signalOffset; + // We activate on rep->metaobject() so the private metacall is used, not m_metaobject (which + // is the class thie replica looks like) + QMetaObject::activate(rep.data(), rep->metaObject(), index+rep->m_signalOffset, param.data()); + } else { //replica has been deleted, remove from list + replicas.remove(rxName); + } + break; + } + case QRemoteObjectPacketTypeEnum::InvokeReplyPacket: + { + int ackedSerialId; + codec->deserializeInvokeReplyPacket(connection->d_func()->stream(), ackedSerialId, rxValue); + QSharedPointer rep = qSharedPointerCast(replicas.value(rxName).toStrongRef()); + if (rep) { + qROPrivDebug() << "Received InvokeReplyPacket ack'ing serial id:" << ackedSerialId; + rep->notifyAboutReply(ackedSerialId, rxValue); + } else { //replica has been deleted, remove from list + replicas.remove(rxName); + } + break; + } + case QRemoteObjectPacketTypeEnum::AddObject: + case QRemoteObjectPacketTypeEnum::Invalid: + case QRemoteObjectPacketTypeEnum::Ping: + qROPrivWarning() << "Unexpected packet received"; + } + } while (connection->bytesAvailable()); // have bytes left over, so do another iteration +} + +/*! + \class QRemoteObjectNode + \inmodule QtRemoteObjects + \brief A node on a Qt Remote Objects network. + + The QRemoteObjectNode class provides an entry point to a QtRemoteObjects + network. A network can be as simple as two nodes, or an arbitrarily complex + set of processes and devices. + + A QRemoteObjectNode does not have a url that other nodes can connect to, + and thus is able to acquire replicas only. It is not able to share source + objects (only QRemoteObjectHost and QRemoteObjectRegistryHost Nodes can + share). + + Nodes may connect to each other directly using \l connectToNode, or + they can use the QRemoteObjectRegistry to simplify connections. + + The QRemoteObjectRegistry is a special replica available to every node that + connects to the Registry Url. It knows how to connect to every + QRemoteObjectSource object on the network. + + \sa QRemoteObjectHost, QRemoteObjectRegistryHost +*/ + +/*! + \class QRemoteObjectHostBase + \inmodule QtRemoteObjects + \brief The QRemoteObjectHostBase class provides base functionality common to \l + {QRemoteObjectHost} {Host} and \l {QRemoteObjectRegistryHost} {RegistryHost} classes. + + QRemoteObjectHostBase is a base class that cannot be instantiated directly. + It provides the enableRemoting and disableRemoting functionality shared by + all host nodes (\l {QRemoteObjectHost} {Host} and \l + {QRemoteObjectRegistryHost} {RegistryHost}) as well as the logic required + to expose \l {Source} objects on the Remote Objects network. +*/ + +/*! + \class QRemoteObjectHost + \inmodule QtRemoteObjects + \brief A (Host) Node on a Qt Remote Objects network. + + The QRemoteObjectHost class provides an entry point to a QtRemoteObjects + network. A network can be as simple as two nodes, or an arbitrarily complex + set of processes and devices. + + QRemoteObjectHosts have the same capabilities as QRemoteObjectNodes, but + they can also be connected to and can share source objects on the network. + + Nodes may connect to each other directly using \l connectToNode, or they + can use the QRemoteObjectRegistry to simplify connections. + + The QRemoteObjectRegistry is a special replica available to every node that + connects to the registry Url. It knows how to connect to every + QRemoteObjectSource object on the network. + + \sa QRemoteObjectNode, QRemoteObjectRegistryHost +*/ + +/*! + \class QRemoteObjectRegistryHost + \inmodule QtRemoteObjects + \brief A (Host/Registry) node on a Qt Remote Objects network. + + The QRemoteObjectRegistryHost class provides an entry point to a QtRemoteObjects + network. A network can be as simple as two Nodes, or an arbitrarily complex + set of processes and devices. + + A QRemoteObjectRegistryHost has the same capability that a + QRemoteObjectHost has (which includes everything a QRemoteObjectNode + supports), and in addition is the owner of the Registry. Any + QRemoteObjectHost node that connects to this Node will have all of their + Source objects made available by the Registry. + + Nodes only support connection to one \l registry, calling \l + QRemoteObjectNode::setRegistryUrl when a Registry is already set is + considered an error. For something like a secure and insecure network + (where different Registries would be applicable), the recommendation is to + create separate Nodes to connect to each, in effect creating two + independent Qt Remote Objects networks. + + Nodes may connect to each other directly using \l connectToNode, or they + can use the QRemoteObjectRegistry to simplify connections. + + The QRemoteObjectRegistry is a special Replica available to every Node that + connects to the Registry Url. It knows how to connect to every + QRemoteObjectSource object on the network. + + \sa QRemoteObjectNode, QRemoteObjectHost +*/ + +/*! + \enum QRemoteObjectNode::ErrorCode + + This enum type specifies the various error codes associated with QRemoteObjectNode errors: + + \value NoError No error. + \value RegistryNotAcquired The registry could not be acquired. + \value RegistryAlreadyHosted The registry is already defined and hosting Sources. + \value NodeIsNoServer The given QRemoteObjectNode is not a host node. + \value ServerAlreadyCreated The host node has already been initialized. + \value UnintendedRegistryHosting An attempt was made to create a host QRemoteObjectNode and connect to itself as the registry. + \value OperationNotValidOnClientNode The attempted operation is not valid on a client QRemoteObjectNode. + \value SourceNotRegistered The given QRemoteObjectSource is not registered on this node. + \value MissingObjectName The given QObject does not have objectName() set. + \value HostUrlInvalid The given url has an invalid or unrecognized scheme. + \value ProtocolMismatch The client and the server have different protocol versions. + \value ListenFailed Can't listen on the specified host port. +*/ + +/*! + \enum QRemoteObjectHostBase::AllowedSchemas + + This enum is used to specify whether a Node will accept a url with an + unrecognized schema for the hostUrl. By default only urls with known + schemas are accepted, but using \c AllowExternalRegistration will enable + the \l Registry to pass your external (to QtRO) url to client Nodes. + + \value BuiltInSchemasOnly Only allow the hostUrl to be set to a QtRO + supported schema. This is the default value, and causes a Node error to be + set if an unrecognized schema is provided. + \value AllowExternalRegistration The provided schema is registered as an + \l {External Schemas}{External Schema} + + \sa QRemoteObjectHost +*/ + +/*! + \fn ObjectType *QRemoteObjectNode::acquire(const QString &name) + + Returns a pointer to a Replica of type ObjectType (which is a template + parameter and must inherit from \l QRemoteObjectReplica). That is, the + template parameter must be a \l {repc} generated type. The \a name + parameter can be used to specify the \a name given to the object + during the QRemoteObjectHost::enableRemoting() call. +*/ + +void QRemoteObjectNodePrivate::initialize() +{ + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); //For queued qnx error() + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + // To support dynamic MODELs, we need to make sure the types are registered + QAbstractItemModelSourceAdapter::registerTypes(); +} + +bool QRemoteObjectNodePrivate::checkSignatures(const QByteArray &a, const QByteArray &b) +{ + // if any of a or b is empty it means it's a dynamic ojects or an item model + if (a.isEmpty() || b.isEmpty()) + return true; + return a == b; +} + + +void QRemoteObjectNode::persistProperties(const QString &repName, const QByteArray &repSig, const QVariantList &props) +{ + Q_D(QRemoteObjectNode); + if (d->persistedStore) { + d->persistedStore->saveProperties(repName, repSig, props); + } else { + qCWarning(QT_REMOTEOBJECT) << qPrintable(objectName()) << "Unable to store persisted properties for" << repName; + qCWarning(QT_REMOTEOBJECT) << " No persisted store set."; + } +} + +QVariantList QRemoteObjectNode::retrieveProperties(const QString &repName, const QByteArray &repSig) +{ + Q_D(QRemoteObjectNode); + if (d->persistedStore) { + return d->persistedStore->restoreProperties(repName, repSig); + } + qCWarning(QT_REMOTEOBJECT) << qPrintable(objectName()) << "Unable to retrieve persisted properties for" << repName; + qCWarning(QT_REMOTEOBJECT) << " No persisted store set."; + return QVariantList(); +} + +/*! + Default constructor for QRemoteObjectNode with the given \a parent. A Node + constructed in this manner can not be connected to, and thus can not expose + Source objects on the network. It also will not include a \l + QRemoteObjectRegistry, unless set manually using setRegistryUrl. + + \sa connectToNode, setRegistryUrl +*/ +QRemoteObjectNode::QRemoteObjectNode(QObject *parent) + : QObject(*new QRemoteObjectNodePrivate, parent) +{ + Q_D(QRemoteObjectNode); + d->initialize(); +} + +/*! + QRemoteObjectNode connected to a {QRemoteObjectRegistry} {Registry}. A Node + constructed in this manner can not be connected to, and thus can not expose + Source objects on the network. Finding and connecting to other (Host) Nodes + is handled by the QRemoteObjectRegistry specified by \a registryAddress. + + \sa connectToNode, setRegistryUrl, QRemoteObjectHost, QRemoteObjectRegistryHost +*/ +QRemoteObjectNode::QRemoteObjectNode(const QUrl ®istryAddress, QObject *parent) + : QObject(*new QRemoteObjectNodePrivate, parent) +{ + Q_D(QRemoteObjectNode); + d->initialize(); + d->setRegistryUrlNodeImpl(registryAddress); +} + +QRemoteObjectNode::QRemoteObjectNode(QRemoteObjectNodePrivate &dptr, QObject *parent) + : QObject(dptr, parent) +{ + Q_D(QRemoteObjectNode); + d->initialize(); +} + +/*! + \qmltype Host + \instantiates QRemoteObjectHost + \inqmlmodule QtRemoteObjects + \brief A host node on a Qt Remote Objects network. + + The Host type provides an entry point to a Qt Remote Objects network. A network + can be as simple as two nodes, or an arbitrarily complex set of processes and devices. + + Hosts have the same capabilities as Nodes, but they can also be connected to and can + share source objects on the network. +*/ + +/*! + \internal This is a base class for both QRemoteObjectHost and + QRemoteObjectRegistryHost to provide the shared features/functions for + sharing \l Source objects. +*/ +QRemoteObjectHostBase::QRemoteObjectHostBase(QRemoteObjectHostBasePrivate &d, QObject *parent) + : QRemoteObjectNode(d, parent) +{ } + +/*! + Constructs a new QRemoteObjectHost Node (i.e., a Node that supports + exposing \l Source objects on the QtRO network) with the given \a parent. + This constructor is meant specific to support QML in the future as it will + not be available to connect to until \l {QRemoteObjectHost::}{setHostUrl} is called. + + \sa setHostUrl(), setRegistryUrl() +*/ +QRemoteObjectHost::QRemoteObjectHost(QObject *parent) + : QRemoteObjectHostBase(*new QRemoteObjectHostPrivate, parent) +{ } + +/*! + Constructs a new QRemoteObjectHost Node (i.e., a Node that supports + exposing \l Source objects on the QtRO network) with address \a address. If + set, \a registryAddress will be used to connect to the \l + QRemoteObjectRegistry at the provided address. The \a allowedSchemas + parameter is only needed (and should be set to \l + {QRemoteObjectHostBase::AllowExternalRegistration} + {AllowExternalRegistration}) if the schema of the url should be used as an + \l {External Schemas} {External Schema} by the registry. + + \sa setHostUrl(), setRegistryUrl() +*/ +QRemoteObjectHost::QRemoteObjectHost(const QUrl &address, const QUrl ®istryAddress, + AllowedSchemas allowedSchemas, QObject *parent) + : QRemoteObjectHostBase(*new QRemoteObjectHostPrivate, parent) +{ + if (!address.isEmpty()) { + if (!d_func()->setHostUrlBaseImpl(address, allowedSchemas)) + return; + } + + if (!registryAddress.isEmpty()) + d_func()->setRegistryUrlNodeImpl(registryAddress); +} + +/*! + Constructs a new QRemoteObjectHost Node (i.e., a Node that supports + exposing \l Source objects on the QtRO network) with a url of \a + address and the given \a parent. This overload is provided as a convenience for specifying a + QObject parent without providing a registry address. + + \sa setHostUrl(), setRegistryUrl() +*/ +QRemoteObjectHost::QRemoteObjectHost(const QUrl &address, QObject *parent) + : QRemoteObjectHostBase(*new QRemoteObjectHostPrivate, parent) +{ + if (!address.isEmpty()) + d_func()->setHostUrlBaseImpl(address); +} + +/*! + \internal QRemoteObjectHost::QRemoteObjectHost +*/ +QRemoteObjectHost::QRemoteObjectHost(QRemoteObjectHostPrivate &d, QObject *parent) + : QRemoteObjectHostBase(d, parent) +{ } + +QRemoteObjectHost::~QRemoteObjectHost() {} + +/*! + Constructs a new QRemoteObjectRegistryHost Node with the given \a parent. RegistryHost Nodes have + the same functionality as \l QRemoteObjectHost Nodes, except rather than + being able to connect to a \l QRemoteObjectRegistry, the provided Host QUrl + (\a registryAddress) becomes the address of the registry for other Nodes to + connect to. +*/ +QRemoteObjectRegistryHost::QRemoteObjectRegistryHost(const QUrl ®istryAddress, QObject *parent) + : QRemoteObjectHostBase(*new QRemoteObjectRegistryHostPrivate, parent) +{ + if (registryAddress.isEmpty()) + return; + + d_func()->setRegistryUrlRegistryHostImpl(registryAddress); +} + +/*! + \internal +*/ +QRemoteObjectRegistryHost::QRemoteObjectRegistryHost(QRemoteObjectRegistryHostPrivate &d, QObject *parent) + : QRemoteObjectHostBase(d, parent) +{ } + +QRemoteObjectRegistryHost::~QRemoteObjectRegistryHost() {} + +QRemoteObjectNode::~QRemoteObjectNode() +{ } + +QRemoteObjectHostBase::~QRemoteObjectHostBase() +{ } + +/*! + Sets \a name as the internal name for this Node. This + is then output as part of the logging (if enabled). + This is primarily useful if you merge log data from multiple nodes. +*/ +void QRemoteObjectNode::setName(const QString &name) +{ + setObjectName(name); +} + +/*! + Similar to QObject::setObjectName() (which this method calls), but this + version also applies the \a name to internal classes as well, which are + used in some of the debugging output. +*/ +void QRemoteObjectHostBase::setName(const QString &name) +{ + Q_D(QRemoteObjectHostBase); + setObjectName(name); + if (d->remoteObjectIo) + d->remoteObjectIo->setObjectName(name); +} + +/*! + \internal The HostBase version of this method is protected so the method + isn't exposed on RegistryHost nodes. +*/ +QUrl QRemoteObjectHostBase::hostUrl() const +{ + Q_D(const QRemoteObjectHostBase); + if (d->remoteObjectIo) + return d->remoteObjectIo->serverAddress(); + return QUrl(); +} + +/*! + \internal The HostBase version of this method is protected so the method + isn't exposed on RegistryHost nodes. +*/ +bool QRemoteObjectHostBase::setHostUrl(const QUrl &hostAddress, AllowedSchemas allowedSchemas) +{ + return d_func()->setHostUrlBaseImpl(hostAddress, allowedSchemas); +} + +bool QRemoteObjectHostBasePrivate::setHostUrlBaseImpl( + const QUrl &hostAddress, QRemoteObjectHostBase::AllowedSchemas allowedSchemas) +{ + Q_Q(QRemoteObjectHostBase); + if (remoteObjectIo) { + setLastError(QRemoteObjectHostBase::ServerAlreadyCreated); + return false; + } + + if (allowedSchemas == QRemoteObjectHostBase::AllowedSchemas::BuiltInSchemasOnly && !QtROServerFactory::instance()->isValid(hostAddress)) { + setLastError(QRemoteObjectHostBase::HostUrlInvalid); + return false; + } + + if (allowedSchemas == QRemoteObjectHostBase::AllowedSchemas::AllowExternalRegistration && QtROServerFactory::instance()->isValid(hostAddress)) { + qWarning() << qPrintable(q->objectName()) << "Overriding a valid QtRO url (" << hostAddress << ") with AllowExternalRegistration is not allowed."; + setLastError(QRemoteObjectHostBase::HostUrlInvalid); + return false; + } + remoteObjectIo = new QRemoteObjectSourceIo(hostAddress, q); + + if (allowedSchemas == QRemoteObjectHostBase::AllowedSchemas::BuiltInSchemasOnly && !remoteObjectIo->startListening()) { + setLastError(QRemoteObjectHostBase::ListenFailed); + delete remoteObjectIo; + remoteObjectIo = nullptr; + return false; + } + + //If we've given a name to the node, set it on the sourceIo as well + if (!q->objectName().isEmpty()) + remoteObjectIo->setObjectName(q->objectName()); + //Since we don't know whether setHostUrl or setRegistryUrl/setRegistryHost will be called first, + //break it into two pieces. setHostUrl connects the RemoteObjectSourceIo->[add/remove]RemoteObjectSource to QRemoteObjectReplicaNode->[add/remove]RemoteObjectSource + //setRegistry* calls appropriately connect RemoteObjecSourcetIo->[add/remove]RemoteObjectSource to the registry when it is created + QObject::connect(remoteObjectIo, &QRemoteObjectSourceIo::remoteObjectAdded, q, &QRemoteObjectHostBase::remoteObjectAdded); + QObject::connect(remoteObjectIo, &QRemoteObjectSourceIo::remoteObjectRemoved, q, &QRemoteObjectHostBase::remoteObjectRemoved); + + return true; +} + +/*! + \qmlproperty url Host::hostUrl + + The host address for the node. + + This is the address where source objects remoted by this node will reside. +*/ + +/*! + \property QRemoteObjectHost::hostUrl + \brief The host address for the node. + + This is the address where source objects remoted by this node will reside. +*/ + +/*! + Returns the host address for the QRemoteObjectNode as a QUrl. If the Node + is not a Host node, returns an empty QUrl. + + \sa setHostUrl() +*/ +QUrl QRemoteObjectHost::hostUrl() const +{ + return QRemoteObjectHostBase::hostUrl(); +} + +/*! + Sets the \a hostAddress for a host QRemoteObjectNode. + + Returns \c true if the Host address is set, otherwise \c false. + + The \a allowedSchemas parameter is only needed (and should be set to \l + {QRemoteObjectHostBase::AllowExternalRegistration} + {AllowExternalRegistration}) if the schema of the url should be used as an + \l {External Schemas} {External Schema} by the registry. +*/ +bool QRemoteObjectHost::setHostUrl(const QUrl &hostAddress, AllowedSchemas allowedSchemas) +{ + return d_func()->setHostUrlHostImpl(hostAddress, allowedSchemas); +} + +bool QRemoteObjectHostPrivate::setHostUrlHostImpl( + const QUrl &hostAddress, QRemoteObjectHostBase::AllowedSchemas allowedSchemas) +{ + bool success = setHostUrlBaseImpl(hostAddress, allowedSchemas); + if (success) + q_func()->hostUrlChanged(); + return success; +} + +/*! + This method can be used to set the address of this Node to \a registryUrl + (used for other Nodes to connect to this one), if the QUrl isn't set in the + constructor. Since this Node becomes the Registry, calling this setter + method causes this Node to use the url as the host address. All other + Node's use the \l {QRemoteObjectNode::setRegistryUrl} method initiate a + connection to the Registry. + + Returns \c true if the registry address is set, otherwise \c false. + + \sa QRemoteObjectRegistryHost(), QRemoteObjectNode::setRegistryUrl +*/ +bool QRemoteObjectRegistryHost::setRegistryUrl(const QUrl ®istryUrl) +{ + return d_func()->setRegistryUrlRegistryHostImpl(registryUrl); +} + +bool QRemoteObjectRegistryHostPrivate::setRegistryUrlRegistryHostImpl(const QUrl ®istryUrl) +{ + Q_Q(QRemoteObjectRegistryHost); + if (setHostUrlBaseImpl(registryUrl)) { + if (!remoteObjectIo) { + setLastError(QRemoteObjectNode::ServerAlreadyCreated); + return false; + } else if (registry) { + setLastError(QRemoteObjectNode::RegistryAlreadyHosted); + return false; + } + + QRegistrySource *remoteObject = new QRegistrySource(q); + q->enableRemoting(remoteObject); + registryAddress = remoteObjectIo->serverAddress(); + registrySource = remoteObject; + //Connect RemoteObjectSourceIo->remoteObject[Added/Removde] to the registry Slot + QObject::connect(q, &QRemoteObjectRegistryHost::remoteObjectAdded, registrySource, &QRegistrySource::addSource); + QObject::connect(q, &QRemoteObjectRegistryHost::remoteObjectRemoved, registrySource, &QRegistrySource::removeSource); + QObject::connect(remoteObjectIo, &QRemoteObjectSourceIo::serverRemoved, registrySource, &QRegistrySource::removeServer); + //onAdd/Remove update the known remoteObjects list in the RegistrySource, so no need to connect to the RegistrySource remoteObjectAdded/Removed signals + setRegistry(q->acquire()); + return true; + } + return false; +} + +/*! + Returns the last error set. +*/ +QRemoteObjectNode::ErrorCode QRemoteObjectNode::lastError() const +{ + Q_D(const QRemoteObjectNode); + return d->lastError; +} + +/*! + \qmlproperty url Node::registryUrl + + The address of the \l {QRemoteObjectRegistry} {Registry} used by this node. + + This is an empty QUrl if there is no registry in use. +*/ + +/*! + \property QRemoteObjectNode::registryUrl + \brief The address of the \l {QRemoteObjectRegistry} {Registry} used by this node. + + This is an empty QUrl if there is no registry in use. +*/ +QUrl QRemoteObjectNode::registryUrl() const +{ + Q_D(const QRemoteObjectNode); + return d->registryAddress; +} + +bool QRemoteObjectNode::setRegistryUrl(const QUrl ®istryAddress) +{ + Q_D(QRemoteObjectNode); + return d->setRegistryUrlNodeImpl(registryAddress); +} + +bool QRemoteObjectNodePrivate::setRegistryUrlNodeImpl(const QUrl ®istryAddr) +{ + Q_Q(QRemoteObjectNode); + if (registry) { + setLastError(QRemoteObjectNode::RegistryAlreadyHosted); + return false; + } + + registryAddress = registryAddr; + setRegistry(q->acquire()); + //Connect remoteObject[Added/Removed] to the registry Slot + QObject::connect(q, &QRemoteObjectNode::remoteObjectAdded, registry, &QRemoteObjectRegistry::addSource); + QObject::connect(q, &QRemoteObjectNode::remoteObjectRemoved, registry, &QRemoteObjectRegistry::removeSource); + q->connectToNode(registryAddress); + return true; +} + +void QRemoteObjectNodePrivate::setRegistry(QRemoteObjectRegistry *reg) +{ + Q_Q(QRemoteObjectNode); + registry = reg; + reg->setParent(q); + //Make sure when we get the registry initialized, we update our replicas + QObject::connect(reg, &QRemoteObjectRegistry::initialized, q, [this]() { + onRegistryInitialized(); + }); + //Make sure we handle new RemoteObjectSources on Registry... + QObject::connect(reg, &QRemoteObjectRegistry::remoteObjectAdded, + q, [this](const QRemoteObjectSourceLocation &location) { + onRemoteObjectSourceAdded(location); + }); + QObject::connect(reg, &QRemoteObjectRegistry::remoteObjectRemoved, + q, [this](const QRemoteObjectSourceLocation &location) { + onRemoteObjectSourceRemoved(location); + }); +} + +QVariant QRemoteObjectNodePrivate::handlePointerToQObjectProperty(QConnectedReplicaImplementation *rep, int index, const QVariant &property) +{ + Q_Q(QRemoteObjectNode); + using namespace QRemoteObjectPackets; + + QVariant retval; + + Q_ASSERT(property.canConvert()); + QRO_ childInfo = property.value(); + qROPrivDebug() << "QRO_:" << childInfo.name << replicas.contains(childInfo.name) << replicas.keys(); + if (childInfo.isNull) { + // Either the source has changed the pointer and we need to update it, or the source pointer is a nullptr + if (replicas.contains(childInfo.name)) + replicas.remove(childInfo.name); + if (childInfo.type == ObjectType::CLASS) + retval = QVariant::fromValue(nullptr); + else + retval = QVariant::fromValue(nullptr); + return retval; + } + + const bool newReplica = !replicas.contains(childInfo.name) || rep->isInitialized(); + if (newReplica) { + if (rep->isInitialized()) { + auto childRep = qSharedPointerCast(replicas.take(childInfo.name)); + if (childRep && !childRep->isShortCircuit()) { + qCDebug(QT_REMOTEOBJECT) << "Checking if dynamic type should be added to dynamicTypeManager (type =" << childRep->m_metaObject->className() << ")"; + dynamicTypeManager.addFromMetaObject(childRep->m_metaObject); + } + } + if (childInfo.type == ObjectType::CLASS) + retval = QVariant::fromValue(q->acquireDynamic(childInfo.name)); + else + retval = QVariant::fromValue(q->acquireModel(childInfo.name)); + } else //We are receiving the initial data for the QObject + retval = rep->getProperty(index); //Use existing value so changed signal isn't emitted + + QSharedPointer childRep = qSharedPointerCast(replicas.value(childInfo.name).toStrongRef()); + if (childRep->connectionToSource.isNull()) + childRep->connectionToSource = rep->connectionToSource; + QVariantList parameters; + QDataStream ds(childInfo.parameters); + if (childRep->needsDynamicInitialization()) { + if (childInfo.classDefinition.isEmpty()) { + auto typeName = childInfo.typeName; + if (typeName == QLatin1String("QObject")) { + // The sender would have included the class name if needed + // So the acquire must have been templated, and we have the typeName + typeName = QString::fromLatin1(rep->getProperty(index).typeName()); + if (typeName.endsWith(QLatin1String("Replica*"))) + typeName.chop(8); + } + childRep->setDynamicMetaObject(dynamicTypeManager.metaObjectForType(typeName)); + } else { + QDataStream in(childInfo.classDefinition); + childRep->setDynamicMetaObject(dynamicTypeManager.addDynamicType(rep->connectionToSource, in)); + } + if (!childInfo.parameters.isEmpty()) + ds >> parameters; + handlePointerToQObjectProperties(childRep.data(), parameters); + childRep->setDynamicProperties(std::move(parameters)); + } else { + if (!childInfo.parameters.isEmpty()) + ds >> parameters; + handlePointerToQObjectProperties(childRep.data(), parameters); + childRep->initialize(std::move(parameters)); + } + + return retval; +} + +void QRemoteObjectNodePrivate::handlePointerToQObjectProperties(QConnectedReplicaImplementation *rep, QVariantList &properties) +{ + for (const int index : rep->childIndices()) + properties[index] = handlePointerToQObjectProperty(rep, index, properties.at(index)); +} + +/*! + Blocks until this Node's \l Registry is initialized or \a timeout (in + milliseconds) expires. Returns \c true if the \l Registry is successfully + initialized upon return, or \c false otherwise. +*/ +bool QRemoteObjectNode::waitForRegistry(int timeout) +{ + Q_D(QRemoteObjectNode); + if (!d->registry) { + qCWarning(QT_REMOTEOBJECT) << qPrintable(objectName()) << "waitForRegistry() error: No valid registry url set"; + return false; + } + + return d->registry->waitForSource(timeout); +} + +/*! + Connects a client node to the host node at \a address. + + Connections will remain valid until the host node is deleted or no longer + accessible over a network. + + Once a client is connected to a host, valid Replicas can then be acquired + if the corresponding Source is being remoted. + + Return \c true on success, \c false otherwise (usually an unrecognized url, + or connecting to already connected address). +*/ +bool QRemoteObjectNode::connectToNode(const QUrl &address) +{ + Q_D(QRemoteObjectNode); + if (!d->initConnection(address)) { + d->setLastError(RegistryNotAcquired); + return false; + } + return true; +} + +/*! + \since 5.12 + + In order to \l QRemoteObjectNode::acquire() \l Replica objects over \l + {External QIODevices}, Qt Remote Objects needs access to the communications + channel (a \l QIODevice) between the respective nodes. It is the + addClientSideConnection() call that enables this, taking the \a ioDevice as + input. Any acquire() call made without calling addClientSideConnection will + still work, but the Node will not be able to initialize the \l Replica + without being provided the connection to the Host node. + + \sa {QRemoteObjectHostBase::addHostSideConnection} +*/ +void QRemoteObjectNode::addClientSideConnection(QIODevice *ioDevice) +{ + Q_D(QRemoteObjectNode); + if (!ioDevice || !ioDevice->isOpen()) { + qWarning() << "A null or closed QIODevice was passed to addClientSideConnection(). Ignoring."; + return; + } + QtROExternalIoDevice *device = new QtROExternalIoDevice(ioDevice, this); + connect(device, &QtROIoDeviceBase::readyRead, this, [d, device]() { + d->onClientRead(device); + }); + if (device->bytesAvailable()) + d->onClientRead(device); +} + +/*! + \fn void QRemoteObjectNode::remoteObjectAdded(const QRemoteObjectSourceLocation &loc) + + This signal is emitted whenever a new \l {Source} object is added to + the Registry. The signal will not be emitted if there is no Registry set + (i.e., Sources over connections made via connectToNode directly). The \a + loc parameter contains the information about the added Source, including + name, type and the QUrl of the hosting Node. + + \sa remoteObjectRemoved(), instances() +*/ + +/*! + \fn void QRemoteObjectNode::remoteObjectRemoved(const QRemoteObjectSourceLocation &loc) + + This signal is emitted whenever a known \l {Source} object is + removed from the Registry. The signal will not be emitted if there is no + Registry set (i.e., Sources over connections made via connectToNode + directly). The \a loc parameter contains the information about the removed + Source, including name, type and the QUrl of the hosting Node. + + \sa remoteObjectAdded, instances +*/ + +/*! + \fn QStringList QRemoteObjectNode::instances() const + + This templated function (taking a \l repc generated type as the template parameter) will + return the list of names of every instance of that type on the Remote + Objects network. For example, if you have a Shape class defined in a .rep file, + and Circle and Square classes inherit from the Source definition, they can + be shared on the Remote Objects network using \l {QRemoteObjectHostBase::enableRemoting} {enableRemoting}. + \code + Square square; + Circle circle; + myHost.enableRemoting(&square, "Square"); + myHost.enableRemoting(&circle, "Circle"); + \endcode + Then instance can be used to find the available instances of Shape. + \code + QStringList instances = clientNode.instances(); + // will return a QStringList containing "Circle" and "Square" + auto instance1 = clientNode.acquire("Circle"); + auto instance2 = clientNode.acquire("Square"); + ... + \endcode +*/ + +/*! + \overload instances() + + This convenience function provides the same result as the templated + version, but takes the name of the \l {Source} class as a parameter (\a + typeName) rather than deriving it from the class type. +*/ +QStringList QRemoteObjectNode::instances(QStringView typeName) const +{ + Q_D(const QRemoteObjectNode); + QStringList names; + for (auto it = d->connectedSources.cbegin(), end = d->connectedSources.cend(); it != end; ++it) { + if (it.value().typeName == typeName) { + names << it.key(); + } + } + return names; +} + +/*! + \keyword dynamic acquire + Returns a QRemoteObjectDynamicReplica of the Source \a name. +*/ +QRemoteObjectDynamicReplica *QRemoteObjectNode::acquireDynamic(const QString &name) +{ + return new QRemoteObjectDynamicReplica(this, name); +} + +/*! + \qmlmethod bool Host::enableRemoting(object object, string name) + Enables a host node to dynamically provide remote access to the QObject \a + object. Client nodes connected to the node hosting this object may obtain + Replicas of this Source. + + The optional \a name defines the lookup-name under which the QObject can be acquired + using \l QRemoteObjectNode::acquire() . If not explicitly set then the name + given in the QCLASSINFO_REMOTEOBJECT_TYPE will be used. If no such macro + was defined for the QObject then the \l QObject::objectName() is used. + + Returns \c false if the current node is a client node, or if the QObject is already + registered to be remoted, and \c true if remoting is successfully enabled + for the dynamic QObject. + + \sa disableRemoting() +*/ + +/*! + Enables a host node to dynamically provide remote access to the QObject \a + object. Client nodes connected to the node + hosting this object may obtain Replicas of this Source. + + The optional \a name defines the lookup-name under which the QObject can be acquired + using \l QRemoteObjectNode::acquire() . If not explicitly set then the name + given in the QCLASSINFO_REMOTEOBJECT_TYPE will be used. If no such macro + was defined for the QObject then the \l QObject::objectName() is used. + + Returns \c false if the current node is a client node, or if the QObject is already + registered to be remoted, and \c true if remoting is successfully enabled + for the dynamic QObject. + + \sa disableRemoting() +*/ +bool QRemoteObjectHostBase::enableRemoting(QObject *object, const QString &name) +{ + Q_D(QRemoteObjectHostBase); + if (!d->remoteObjectIo) { + d->setLastError(OperationNotValidOnClientNode); + return false; + } + + const QMetaObject *meta = object->metaObject(); + QString _name = name; + QString typeName = getTypeNameAndMetaobjectFromClassInfo(meta); + if (typeName.isEmpty()) { //This is a passed in QObject, use its API + if (_name.isEmpty()) { + _name = object->objectName(); + if (_name.isEmpty()) { + d->setLastError(MissingObjectName); + qCWarning(QT_REMOTEOBJECT) << qPrintable(objectName()) << "enableRemoting() Error: Unable to Replicate an object that does not have objectName() set."; + return false; + } + } + } else if (_name.isEmpty()) + _name = typeName; + return d->remoteObjectIo->enableRemoting(object, meta, _name, typeName); +} + +/*! + This overload of enableRemoting() is specific to \l QAbstractItemModel types + (or any type derived from \l QAbstractItemModel). This is useful if you want + to have a model and the HMI for the model in different processes. + + The three required parameters are the \a model itself, the \a name by which + to lookup the model, and the \a roles that should be exposed on the Replica + side. If you want to synchronize selection between \l Source and \l + Replica, the optional \a selectionModel parameter can be used. This is only + recommended when using a single Replica. + + Behind the scenes, Qt Remote Objects batches data() lookups and prefetches + data when possible to make the model interaction as responsive as possible. + + Returns \c false if the current node is a client node, or if the QObject is already + registered to be remoted, and \c true if remoting is successfully enabled + for the QAbstractItemModel. + + \sa disableRemoting() + */ +bool QRemoteObjectHostBase::enableRemoting(QAbstractItemModel *model, const QString &name, const QList roles, QItemSelectionModel *selectionModel) +{ + //This looks complicated, but hopefully there is a way to have an adapter be a template + //parameter and this makes sure that is supported. + QObject *adapter = QAbstractItemModelSourceAdapter::staticMetaObject.newInstance(Q_ARG(QAbstractItemModel*, model), + Q_ARG(QItemSelectionModel*, selectionModel), + Q_ARG(QList, roles)); + QAbstractItemAdapterSourceAPI *api = + new QAbstractItemAdapterSourceAPI(name); + if (!this->objectName().isEmpty()) + adapter->setObjectName(this->objectName().append(QLatin1String("Adapter"))); + return enableRemoting(model, api, adapter); +} + +/*! + \fn template